第六章的内容有点多,现在学习一下音视频的软编和硬编。
使用libfdk_aac进行编码
书上的源码是采用ffmpeg的api进行编码的,当然你也可单独编译libfdk_aac来进行编码。首先我们还是需要配置采样率,声道,码率等参数进行初始化。
接着我们探测输出文件,让ffmpeg自动根据文件名探测格式。
int ret;
av_register_all();
avFormatContext = avformat_alloc_context();
LOGI("aacFilePath is %s ", aacFilePath);
//一种方法
//先探测格式,然后设置到avFormatContext中
// AVOutputFormat *fmt = av_guess_format(NULL, aacFilePath, NULL);
// avFormatContext->oformat = fmt;
//直接根据输出文件的名字来自动探测格式
if ((ret = avformat_alloc_output_context2(&avFormatContext, nullptr, nullptr, aacFilePath)) !=
0) {
LOGI("avFormatContext alloc failed : %s", av_err2str(ret));
return -1;
}
if (ret = avio_open2(&avFormatContext->pb, aacFilePath, AVIO_FLAG_WRITE, nullptr, nullptr)) {
LOGI("Could not avio open fail %s", av_err2str(ret));
return -1;
}
接下来我们创建一个音频流,并且获取音频流的编解码器上下文。
AVCodec *codec;
AVSampleFormat preferedSampleFMT = AV_SAMPLE_FMT_S16;
int preferedChannels = audioChannels;
int preferedSampleRate = audioSampleRate;
audioStream = avformat_new_stream(avFormatContext, nullptr);
audioStream->id = 1;
avCodecContext = audioStream->codec;
配置编解码上下文的参数,主要需要配置的有
- 编解码器类型
- 采样率
- 比特率
- 解码器的id,从之前探测的oformat可以获取
- 采样格式
- 通道数
- AAC的规格,大概一下集中
MPEG-2 AAC LC 低复杂度规格(Low Complexity)
MPEG-2 AAC Main 主规格
MPEG-2 AAC SSR 可变采样率规格(Scaleable Sample Rate)
MPEG-4 AAC LC 低复杂度规格(Low Complexity),现在的手机比较常见的 MP4 文件中的音频部份就包括了该规格音频文件
MPEG-4 AAC Main 主规格
MPEG-4 AAC SSR 可变采样率规格(Scaleable Sample Rate)
MPEG-4 AAC LTP 长时期预测规格(Long Term Predicition)
MPEG-4 AAC LD 低延迟规格(Low Delay)
MPEG-4 AAC HE 高效率规格(High Efficiency)
avCodecContext->codec_type = AVMEDIA_TYPE_AUDIO;
avCodecContext->sample_rate = audioSampleRate;
if (publishBitRate > 0) {
avCodecContext->bit_rate = publishBitRate;
} else {
avCodecContext->bit_rate = PUBLISH_BITE_RATE;
}
avCodecContext->codec_id = avFormatContext->oformat->audio_codec;
avCodecContext->sample_fmt = preferedSampleFMT;
LOGI("audioChannels is %d", audioChannels);
avCodecContext->channel_layout =
preferedChannels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
avCodecContext->channels = av_get_channel_layout_nb_channels(avCodecContext->channel_layout);
//配置编码aac规格
avCodecContext->profile = FF_PROFILE_AAC_LOW;
LOGI("avCodecContext->channels is %d", avCodecContext->channels);
if (avFormatContext->oformat->flags & AVFMT_GLOBALHEADER) {
avCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
找到对应的编解码器,并获取编解码器支持的采样格式,采样率,并进行一定条件下的筛选。书上的代码是如果采样格式不支持就直接使用支持的格式的第一个,采样率选取的是最接近的一个。
//使用之前探测格式来找
codec = avcodec_find_encoder(avCodecContext->codec_id);
if (!codec) {
LOGI("Couldn't find a valid audio codec");
return -1;
}
if (codec->sample_fmts) {
/* check if the prefered sample format for this codec is supported.
* this is because, depending on th