使用FFmpeg把PCM裸数据编码成AAC音频流,具体步骤跟YUV编码成H264差不多。
1、命令行
ffmpeg -f s16le -ar 44100 -ac 2 -i bb1.pcm output.aac
-f
PCM数据为s16le
-ar
采样率为44100
-ac
通道数为2
这样就通过命令把PCM数据编码成AAC了。
2、使用API编码
FFmpeg内部AAC格式只支持AV_SAMPLE_FMT_FLTP格式的PCM,由于我们的PCM数据是s16le的,因此我们需要把s16le格式转换成fltp格式再进行编码。我们可以在AVCodec结构体中的sample_fmts字段中判断编码器是否支持你的格式。
-
初始化输出文件上下文
int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat, const char *format_name, const char *filename);
ctx
输出文件的上下文oformat
输出文件的AVOutputFormat,传NULL,FFmpeg会根据filename的格式初始化oformatformat_name
输出文件的格式, 传NULL,FFmpeg会根据filename的格式初始化format_namefilename
输出文件路径 -
初始化编码器上下文
dec = avcodec_find_encoder(ofmt_ctx->oformat->audio_codec); if (!dec) { printf("avcodec_find_encoder fail \n"); goto __FAIL; } dec_ctx = avcodec_alloc_context3(dec); dec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; if (!check_sample_fmt(dec, dec_ctx->sample_fmt)) { fprintf(stderr, "Encoder does not support sample format %s", av_get_sample_fmt_name(dec_ctx->sample_fmt)); goto __FAIL; } dec_ctx->channel_layout = select_channel_layout(dec); dec_ctx->channels = av_get_channel_layout_nb_channels(dec_ctx->channel_layout); dec_ctx->sample_rate = select_sample_rate(dec); dec_ctx->bit_rate = 64000; ret = avcodec_open2(dec_ctx, dec, NULL);
FFmpeg内部AAC音频流只支持fltp格式的PCM,使用check_sample_fmt函数可以检测编码器是否支持AV_SAMPLE_FMT_FLTP,通过select_channel_layout函数选择最佳的音频通道布局,通过select_sample_rate函数选择最佳的采样率。
检测是否支持AVSampleFormat
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt) { const enum AVSampleFormat *p = codec->sample_fmts; while (*p != AV_SAMPLE_FMT_NONE) { if (*p == sample_fmt) return 1; p++; } return 0; }
选择最佳采样率
static int select_sample_rate(const AVCodec *codec) { const int *p; int best_samplerate = 0; if (!codec->supported_samplerates) return 44100; p = codec->supported_samplerates; while (*p) { if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate)) best_samplerate = *p; p++; } return best_samplerate; }
选择最佳通道布局
static int select_channel_layout(const AVCodec *codec) { const uint64_t *p; uint64_t best_ch_layout = 0; int best_nb_channels = 0; if (!codec->channel_layouts) return AV_CH_LAYOUT_STEREO; p = codec->channel_layouts; while (*p) { int nb_channels = av_get_channel_layout_nb_channels(*p); if (nb_channels > best_nb_channels) { best_ch_layout = *p; best_nb_channels = nb_chann