使用FFmpeg库把PCM文件编码为AAC文件,FFmpeg版本为4.4.2-0
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int ret = -1;
int64_t pts = 0;
const char *input_file = argv[1];
const char *output_file = argv[2];
FILE *input_pcm = NULL;
AVFormatContext *format_context = NULL;
AVCodecContext *codec_context = NULL;
AVStream *stream = NULL;
AVCodec *codec = NULL;
AVFrame *frame = NULL;
AVPacket *packet = NULL;
struct SwrContext *swr_ctx = NULL;
enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_S16; // 输入pcm文件的采样格式
int in_sample_rate = 44100; // 输入pcm文件的采样率
uint64_t in_channel_layout = AV_CH_LAYOUT_STEREO; // 输入pcm文件的声道布局
if (argc < 3)
{
fprintf(stderr, "Usage: %s
", argv[0]);
return -1;
}
input_pcm = fopen(input_file, "rb");
if (!input_pcm)
{
fprintf(stderr, "Could not open input file %s
", input_file);
goto end;
}
// 分配输出格式上下文
avformat_alloc_output_context2(&format_context, NULL, NULL, output_file);
if (!format_context)
{
fprintf(stderr, "Could not allocate output format context
");
goto end;
}
// 查找编码器, 这里使用ffmpeg内置的aac编码器,
// 如果需要使用其他编码器, 可以使用 avcodec_find_encoder_by_name 按名称查找
codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec)
{
fprintf(stderr, "Codec not found
");
goto end;
}
// 创建新的音频流
stream = avformat_new_stream(format_context, NULL);
if (!stream)
{
fprintf(stderr, "Could not allocate stream
");
goto end;
}
// 分配编码器上下文
codec_context = avcodec_alloc_context3(codec);
if (!codec_context)
{
fprintf(stderr, "Could not allocate codec context
");
goto end;
}
/* 设置编码器参数 */
// 编码器ID
codec_context->codec_id = AV_CODEC_ID_AAC;
// 媒体类型
codec_context->codec_type = AVMEDIA_TYPE_AUDIO;
// 设置编码器接收的输入音频样本的采样格式,这里设置为内置aac编码器支持的采样格式,
// 不同的编码器支持的采样格式可能不同。
codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
// 设置采样率
codec_context->sample_rate = in_sample_rate;
// 设置声道布局
codec_context->channel_layout = in_channel_layout;
// 设置声道数
codec_context->channels = av_get_channel_layout_nb_channels(codec_context->channel_layout);
// 设置比特率
codec_context->bit_rate = 128000;
// 设置AAC的profile
codec_context->profile = FF_PROFILE_AAC_LOW;
// 打开编码器
if (avcodec_open2(codec_context, codec, NULL) codecpar, codec_context);
if (result oformat->flags & AVFMT_NOFILE)) // 检查输出格式是否需要文件存储
{
result = avio_open(&format_context->pb, output_file, AVIO_FLAG_WRITE);
if (result < 0)
{
fprintf(stderr, "Could not open output file %s
", output_file);
goto end;
}
}
// 写文件头
result = avformat_write_header(format_context, NULL);
if (result nb_samples = codec_context->frame_size; // 一帧音频数据的采样个数,AAC编码器的frame_size默认为1024
frame->format = codec_context->sample_fmt;
frame->channel_layout = codec_context->channel_layout;
// 分配帧数据缓冲区
result = av_frame_get_buffer(frame, 0);
if (result channel_layout, codec_context->sample_fmt, codec_context->sample_rate,
codec_context->channel_layout, in_sample_fmt, codec_context->sample_rate,
0, NULL);
if (!swr_ctx || swr_init(swr_ctx) nb_samples * av_get_bytes_per_sample(in_sample_fmt) * codec_context->channels;
// 分配缓冲区
uint8_t *input_buffer = (uint8_t *)av_malloc(fsize);
if (!input_buffer)
{
fprintf(stderr, "Could not allocate input buffer
");
goto end;
}
// 编码循环
while (1)
{
// 读取PCM数据到缓冲区
result = fread(input_buffer, 1, fsize, input_pcm);
if (result <= 0)
{
break;
}
// 处理不足一帧的情况,不足一帧的数据用0填充
if (result data, frame->nb_samples,
(const uint8_t **)&input_buffer, frame->nb_samples);
if (result pts = pts;
pts += frame->nb_samples; // 计算下一帧的pts,每个帧的时间戳应该是前一个帧的时间戳加上该帧的样本数
// 发送帧到编码器
result = avcodec_send_frame(codec_context, frame);
if (result = 0)
{
result = avcodec_receive_packet(codec_context, packet);
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF)
{
break;
}
else if (result stream_index = stream->index;
// 将时间戳从编码器时间基转换到流时间基
av_packet_rescale_ts(packet, codec_context->time_base, stream->time_base);
// 写数据包到输出文件
result = av_interleaved_write_frame(format_context, packet);
if (result = 0)
{
result = avcodec_receive_packet(codec_context, packet);
if (result == AVERROR_EOF)
{
break;
}
else if (result stream_index = stream->index;
av_packet_rescale_ts(packet, codec_context->time_base, stream->time_base);
result = av_interleaved_write_frame(format_context, packet);
if (result < 0)
{
fprintf(stderr, "Error writing audio packet
");
av_packet_unref(packet);
goto end;
}
av_packet_unref(packet);
}
// 写文件尾
av_write_trailer(format_context);
ret = 0;
end:
if (frame)
av_frame_free(&frame);
if (packet)
av_packet_free(&packet);
if (codec_context)
avcodec_free_context(&codec_context);
if (format_context)
avformat_free_context(format_context);
if (swr_ctx)
swr_free(&swr_ctx);
if (input_pcm)
fclose(input_pcm);
return ret;
}