网站内页标题修改,网站seo搜索,赣州章贡区天气预报15天,wordpress 评论者链接音视频入门基础#xff1a;AAC专题系列文章#xff1a;
音视频入门基础#xff1a;AAC专题#xff08;1#xff09;——AAC官方文档下载
音视频入门基础#xff1a;AAC专题#xff08;2#xff09;——使用FFmpeg命令生成AAC裸流文件
音视频入门基础#xff1a;AAC…
音视频入门基础AAC专题系列文章
音视频入门基础AAC专题1——AAC官方文档下载
音视频入门基础AAC专题2——使用FFmpeg命令生成AAC裸流文件
音视频入门基础AAC专题3——AAC的ADTS格式简介
音视频入门基础AAC专题4——ADTS格式的AAC裸流实例分析
音视频入门基础AAC专题5——FFmpeg源码中判断某文件是否为AAC裸流文件的实现
音视频入门基础AAC专题6——FFmpeg源码中解码ADTS格式的AAC的Header的实现
音视频入门基础AAC专题7——FFmpeg源码中计算AAC裸流每个packet的size值的实现
音视频入门基础AAC专题8——FFmpeg源码中计算AAC裸流AVStream的time_base的实现
音视频入门基础AAC专题9——FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现
音视频入门基础AAC专题10——FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现
音视频入门基础AAC专题11——AudioSpecificConfig简介
音视频入门基础AAC专题12——FFmpeg源码中解码AudioSpecificConfig的实现
音视频入门基础AAC专题13——FFmpeg源码中获取ADTS格式的AAC裸流音频信息的实现 一、引言
对于携带Audio Specific Config的媒体文件比如音频压缩编码格式为AAC的FLV文件FFmpeg一般通过解码其Audio Tag中Audio Specific Config获取其音频信息。而通过《音视频入门基础AAC专题2——使用FFmpeg命令生成AAC裸流文件》生成的AAC裸流文件和TS流中的AAC是没有Audio Specific Config的只有ADTS Header这时就得通过解码ADTS Header获取其音频信息音频压缩编码格式的profile、音频采样率、音频声道数、码率等 本文讲述FFmpeg源码中获取ADTS格式的AAC裸流音频信息的实现。 二、音频压缩编码格式
具体获取方法可以参考《音视频入门基础AAC专题5——FFmpeg源码中判断某文件是否为AAC裸流文件的实现》 三、音频压缩编码格式的profile
音频压缩编码格式还有附带的profile规格。比如如果音频压缩编码格式为AAC根据《ISO14496-3-2009.pdf》第124页还有AAC Main、AAC LC、AAC SSR、AAC LTP这几种规格 FFmpeg获取AAC裸流的音频压缩编码格式的profile是根据ADTS Header中的profile_ObjectType属性获取的。由《音视频入门基础AAC专题3——AAC的ADTS格式简介》可以知道ADTS Header中存在一个占2位的profile_ObjectType属性表示AAC的规格。 由《音视频入门基础AAC专题6——FFmpeg源码中解码ADTS格式的AAC的Header的实现》可以知道FFmpeg源码中通过ff_adts_header_parse函数解码ADTS格式的AAC的Header。而ff_adts_header_parse函数中通过下面语句将profile_ObjectType属性的值加1赋值给hdr-object_type
hdr-object_type aot 1; 然后在parse_adts_frame_header函数中将hdr-object_type赋值给ac-oc[1].m4ac.object_type
static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size ff_adts_header_parse(gb, hdr_info);if (size 0) {//...ac-oc[1].m4ac.object_type hdr_info.object_type;//...}
//...
} 之后通过aac_decode_frame_int函数将ac-oc[1].m4ac.object_type的值减1赋值给AVCodecContext的profile这样AVCodecContext的profile就会得到原本的profile_ObjectType属性
static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame,int *got_frame_ptr, GetBitContext *gb,const AVPacket *avpkt)
{
//...// The AV_PROFILE_AAC_* defines are all object_type - 1// This may lead to an undefined profile being signaledac-avctx-profile ac-oc[1].m4ac.object_type - 1;
//...
} 然后在dump_stream_format函数中通过avcodec_string函数中的语句profile avcodec_profile_name(enc-codec_id, enc-profile)拿到上一步中得到的AVCodecContext的profile。最后再在dump_stream_format函数中将profile打印出来
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...profile avcodec_profile_name(enc-codec_id, enc-profile);
//...
} 所以FFmpeg获取AAC裸流文件的音频压缩编码格式的profile获取的是ADTS Header中的profile_ObjectType属性 四、音频采样率
FFmpeg获取AAC裸流的音频采样频率是根据ADTS Header中的samplingFrequencyIndex属性获取的。 由《音视频入门基础AAC专题3——AAC的ADTS格式简介》可以知道ADTS Header中存在一个占4位的samplingFrequencyIndex属性表示音频采样频率 ff_adts_header_parse函数中通过下面语句将samplingFrequencyIndex属性的值赋值给hdr-sampling_index。将音频采样频率单位为Hz赋值给hdr-sample_rate hdr-sampling_index sr;hdr-sample_rate ff_mpeg4audio_sample_rates[sr]; 然后在parse_adts_frame_header函数中将hdr-sample_rate赋值给ac-oc[1].m4ac.sample_rate
static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size ff_adts_header_parse(gb, hdr_info);if (size 0) {//...ac-oc[1].m4ac.sample_rate hdr_info.sample_rate;//...}
//...
} 之后通过aac_decode_frame_int函数将ac-oc[1].m4ac.sample_rate赋值给AVCodecContext的sample_rate
static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame,int *got_frame_ptr, GetBitContext *gb,const AVPacket *avpkt)
{
//...if (ac-oc[1].status audio_found) {avctx-sample_rate ac-oc[1].m4ac.sample_rate multiplier;avctx-frame_size samples;ac-oc[1].status OC_LOCKED;}
//...
} 然后在dump_stream_format函数中通过avcodec_string函数中的语句av_bprintf(bprint, %d Hz, , enc-sample_rate)拿到上一步中得到的AVCodecContext的sample_rate。最后再在dump_stream_format函数中将其打印出来
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...switch (enc-codec_type) {case AVMEDIA_TYPE_AUDIO:av_bprintf(bprint, %s, separator);if (enc-sample_rate) {av_bprintf(bprint, %d Hz, , enc-sample_rate);}
//...}
//...
} 所以FFmpeg获取AAC裸流文件的音频采样率获取的是ADTS Header中的samplingFrequencyIndex属性 五、音频声道数
FFmpeg获取AAC裸流的音频声道数是根据ADTS Header中的channel_configuration属性获取的。 由《音视频入门基础AAC专题3——AAC的ADTS格式简介》可以知道ADTS Header中存在一个占3位的channel_configuration属性表示音频声道数 ff_adts_header_parse函数中通过下面语句将音频声道数赋值给hdr-chan_config
hdr-chan_config ch; 然后在parse_adts_frame_header函数中将hdr-chan_config赋值给AVCodecContext的ch_layout
static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size ff_adts_header_parse(gb, hdr_info);if (size 0) {//...if (hdr_info.chan_config) {ac-oc[1].m4ac.chan_config hdr_info.chan_config;if ((ret set_default_channel_config(ac, ac-avctx,layout_map,layout_map_tags,hdr_info.chan_config)) 0)return ret;if ((ret output_configure(ac, layout_map, layout_map_tags,FFMAX(ac-oc[1].status,OC_TRIAL_FRAME), 0)) 0)return ret;}//...}
//...
}然后在dump_stream_format函数中通过avcodec_string函数中的语句:av_channel_layout_describe_bprint(enc-ch_layout, bprint)拿到AVCodecContext的ch_layout对应的音频声道数目。最后再在dump_stream_format函数中将音频声道数目打印出来
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...switch (enc-codec_type) {case AVMEDIA_TYPE_AUDIO:av_channel_layout_describe_bprint(enc-ch_layout, bprint);//...break;}
//...
} 所以FFmpeg获取AAC裸流文件的音频声道数获取的是ADTS Header中的channel_configuration属性 六、Bit depth
FFmpeg获取AAC裸流的Bit depth又叫位深度、位元深度、采样深度、采样位数、采样格式获取到的值是没有意义的。当音频压缩编码格式为AAC时FFmpeg会强制把Bit depth设置为fltp。这是因为对于有损压缩编解码器如MP3和AACBit depth是在编码期间计算的并且可以因采样而异Bit depth只对PCM数字信号有意义。具体可以参考《音视频入门基础AAC专题3——AAC的ADTS格式简介》。 可以看到在aac_decode_init函数中该函数定义在libavcodec/aacdec_template.c强制把音频采样格式设置成了AV_SAMPLE_FMT_FLTP
static av_cold int aac_decode_init(AVCodecContext *avctx)
{
//...avctx-sample_fmt AV_SAMPLE_FMT_FLTP;
//...
} 所以如果音频压缩编码格式为AAC通过FFmpeg获取到的音频采样格式固定为fltp该值没有意义 七、音频码率
通过解码ADTS Header无法直接获得音频码率但是可以通过里面的属性间接计算出音频码率。 ff_adts_header_parse函数中将该ADTS音频帧中原始数据块的个数乘以1024得到的结果赋值给hdr-samples。FFmpeg源码内部强制默认AACAAC Main、AAC LC、AAC SSR、AAC LTP的samples是1024。hdr-samples为该ADTS音频帧中采样的次数
hdr-samples (rdb 1) * 1024; 通过公式得到该ADTS音频帧的码率单位为bits/s赋值给hdr-bit_rate
hdr-bit_rate size * 8 * hdr-sample_rate / hdr-samples; 然后ff_aac_ac3_parse函数中通过下面代码得到实际的以bps为单位的音频码率赋值给AVCodecContext的bit_rate
int ff_aac_ac3_parse(AVCodecParserContext *s1,AVCodecContext *avctx,const uint8_t **poutbuf, int *poutbuf_size,const uint8_t *buf, int buf_size)
{
//...if (got_frame) {//...int bit_rate;if (avctx-codec_id ! AV_CODEC_ID_AAC) {//...}else{AACADTSHeaderInfo hdr, *phrd hdr;int ret avpriv_adts_header_parse(phrd, buf, buf_size);if (ret 0)return i;bit_rate hdr.bit_rate;}/* Calculate the average bit rate */s-frame_number;if (!CONFIG_EAC3_DECODER || avctx-codec_id ! AV_CODEC_ID_EAC3) {avctx-bit_rate (bit_rate - avctx-bit_rate) / s-frame_number;}}
//...
} 然后在dump_stream_format函数中通过avcodec_string函数中的语句bitrate get_bit_rate(enc)拿到AVCodecContext的bit_rate。最后再把它除以1000得到以kb/s为单位的音频码率打印出来
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...bitrate get_bit_rate(enc);if (bitrate ! 0) {av_bprintf(bprint, , %PRId64 kb/s, bitrate / 1000);
//...
} 所以FFmpeg获取AAC裸流文件的音频码率是根据ADTS Header中的属性计算出来的