ffmpeg SDK编码MP4 AAC的一处小坑
在最新版的ffmpeg SDK中,如果我们按照一般的编码音频的步骤编码AAC并封入MP4,我们往往会写入一个很奇怪的音频Stream。它的MediaInfo会长这样:
如图所示,解码器不能理解这个流,会认为它就是一个ER Parametric而不能理解它是AAC。ffprobe查看stream其配置也会很奇怪:
[STREAM]
index=1
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=-1
codec_type=audio
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=48000
channels=2
channel_layout=stereo
bits_per_sample=0
initial_padding=0
id=0x2
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/48000
start_pts=0
start_time=0.000000
duration_ts=728064
duration=15.168000
bit_rate=126300
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=712
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
DISPOSITION:captions=0
DISPOSITION:descriptions=0
DISPOSITION:metadata=0
DISPOSITION:dependent=0
DISPOSITION:still_image=0
TAG:language=und
TAG:handler_name=SoundHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
ffprobe理解这个AAC流的profile是-1。很明显存在问题。
解决的方法是,要在使用avcodec_open2
打开音频编码器之后,再执行avcodec_parameters_from_context
拷贝参数。如果在打开编码器之前拷贝参数或者没有拷贝参数,打开编码器的过程所修改的一些参数就不会更新到流信息中,AAC信息也就无法被解析。
也就是说,我们需要:
// 先执行
avError = avcodec_open2(oAudioEncoderCxt, oAudioEncoder, 0);
// 再执行
avError = avcodec_parameters_from_context(oAudioStream->codecpar, oAudioEncoderCxt);
这样,编码器的一些参数就会在打开编码器后被更新到流信息里,即可正确编码可以被识别的AAC。
同时,如果有必要,建议为编码器上下文添加AV_CODEC_FLAG_GLOBAL_HEADER
这个flag。也就是在初始化编码器上下文时配置:
oAudioEncoderCxt -> flags |= AV_CODEC_FLAG_GLOBAL_HEADER;