请选择 进入手机版 | 继续访问电脑版

期翼嘻嘻即时通讯综合平台

 找回密码
 立即注册
查看: 281|回复: 0

快速理解AAC编码格式 [复制链接]

Rank: 9Rank: 9Rank: 9

发表于 2020-7-29 22:05:09 |显示全部楼层
转贴:https://www.jianshu.com/p/379f106b1bfc
本文包含两部分内容:介绍AAC编码格式,以及如何解决ffmpeg获取aac文件时长不准的问题。
写在前面:想要自己详细学习AAC编码格式细节的朋友们当然更推荐直接去看标准文档《MPEG-4 Audio: ISO/IEC 14496-3:2009》
AAC格式介绍首先需要了解的是AAC文件格式有ADIF和ADTS两种,其中ADIF(Audio Data Interchange Format 音频数据交换格式)的特征是解码必须在明确定义的开始处进行,不能从数据流中间开始;而ADTS(Audio Data Transport Stream 音频数据传输流)则相反,这种格式的特征是有同步字,解码可以在这个流中任何位置开始,正如它的名字一样,这是一种和TS流类似的格式。
ADTS格式中每一帧都有头信息,具备流特征,适合于网络传输与处理,而ADIF只有一个统一的头,并且这两种格式的header格式也是不同的。目前主流使用的都是ADTS格式,本文也将以ADTS为重点进行介绍。
ADTS AAC文件格式如下
[td]
ADTS_headerAAC ESADTS_headerAAC ES...ADTS_headerAAC ES
可以看到每一帧都有头信息,即ADTS_header,其中包含采样率、声道数、帧长度等信息。一般ADTS头信息都是7字节,如果有CRC则为9字节。
ADTS帧首部结构如下
[td]
序号长度(bits)说明
1Syncword12all bits must be 1
2MPEG version10 for MPEG-4, 1 for MPEG-2
3Layer2always 0
4Protection Absent1set to 1 if there is no CRC and 0 if there is CRC
5Profile2the MPEG-4 Audio Object Type minus 1
6MPEG-4 Sampling Frequency Index4MPEG-4 Sampling Frequency Index (15 is forbidden)
7Private Stream1set to 0 when encoding, ignore when decoding
8MPEG-4 Channel Configuration3MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE)
9Originality1set to 0 when encoding, ignore when decoding
10Home1set to 0 when encoding, ignore when decoding
11Copyrighted Stream1set to 0 when encoding, ignore when decoding
12Copyrighted Start1set to 0 when encoding, ignore when decoding
13Frame Length13this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
14Buffer Fullness11buffer fullness
15Number of AAC Frames2number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame
16CRC16CRC if protection absent is 0
下面来说一下几个关键字段的含义
profile很多文章都说一个aac帧包含1024个sample,其实这是错误的。正确的说法是不同profile决定了每个aac帧含有多少个sample,具体来说,对应关系如下
[td]
PROFILESAMPLES
HE-AAC v1/v22048
AAC-LC1024
AAC-LD/AAC-ELD480/512
所谓LC即Low Complexity,HE即High Efficiency。
那么profile的取值含义又如何呢?其实在ffmpeg源码中已经有了详细的对应关系,在libavcodec/avcodec.h中,如下
#define FF_PROFILE_AAC_MAIN 0#define FF_PROFILE_AAC_LOW  1#define FF_PROFILE_AAC_SSR  2#define FF_PROFILE_AAC_LTP  3#define FF_PROFILE_AAC_HE   4#define FF_PROFILE_AAC_HE_V2 28#define FF_PROFILE_AAC_LD   22#define FF_PROFILE_AAC_ELD  38#define FF_PROFILE_MPEG2_AAC_LOW 128 [size=1em]#[size=1em]define[size=1em] FF_PROFILE_MPEG2_AAC_HE  131所以当我们读到profile为28时,就知道这是一个he-aac v2的aac文件了,其每帧sample数目为2048.
Sampling Frequency Index表示使用的采样率下标,通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值,对应关系如下:
[td]
096000 Hz
188200 Hz
264000 Hz
348000 Hz
444100 Hz
532000 Hz
624000 Hz
722050 Hz
816000 Hz
912000 Hz
1011025 Hz
118000 Hz
127350 Hz
13Reserved
14Reserved
15frequency is written explictly
Channel Configuration这个就简单了,就是声道数,对应关系如下
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved
解决ffmpeg解析aac文件时长不准确的问题当我们想要利用ffmpeg去获取一个aac文件时长的时候,会发现ffmpeg输出了这么一行warning信息:
[aac @ 000000529d929ec0] Estimating duration from bitrate, this may be inaccurate在前面的小节中我们看到,aac文件格式中并没有明确的duration信息,因此ffmpeg选择通过filesize / bitrate来估算时长。
我们闭着眼睛想也知道这种估算方法是不准确的,事实也是如此,而且特别有意思的是,ffmpeg 3.0之前和之后的版本估算出来的结果还不一样,所以开发人员也很贴心的给我们输出了这么一行warning信息。
估算时长这一部分逻辑的代码位于libavformat/utils.c#estimate_timings中
if ((!strcmp(ic->iformat->name, "mpeg") ||         !strcmp(ic->iformat->name, "mpegts")) &&        file_size && (ic->pb->seekable & AVIO_SEEKABLE_NORMAL)) {        /* get accurate estimate from the PTSes */        estimate_timings_from_pts(ic, old_offset);        ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS;    } else if (has_duration(ic)) {        /* at least one component has timings - we use them for all         * the components */        fill_all_stream_timings(ic);        /* nut demuxer estimate the duration from PTS */        if(!strcmp(ic->iformat->name, "nut"))            ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS;        else            ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM;    } else {        //aac文件解析时长的时候就会走到这里        /* less precise: use bitrate info */        estimate_timings_from_bit_rate(ic);        ic->duration_estimation_method = AVFMT_DURATION_FROM_BITRATE;    }那么如何才能获取准确的时长呢?通过上一节的介绍,相信大家都能想到,应该是通过adts frame header取总帧数*每帧时长的值作为duration。
具体来说,获取总帧数就是把整个文件“过”一遍,伪代码如下
while (offset < total_size) {        frame_length = get_adts_frame_length(offset)        offset += frame_length;        num_frames++;    }而获取每帧时长就更简单了:ffmpeg能正确读到每帧的nb_samples和总体的sample_rate,那么两者相除就是每帧的时长了。
完整的解析时长代码可以关注我的公众号灰度五十,回复“解析aac时长”获取~



作者:zhanghuicuc
链接:https://www.jianshu.com/p/379f106b1bfc
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

Archiver|手机版|期翼嘻嘻论坛企业即时通讯综合平台 ( 京 ICP 备 10015350 )

GMT+8, 2020-10-1 07:50 , Processed in 0.139961 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部