赞
踩
音频格式的介绍文章系列:
音频编解码格式介绍(1) ADPCM:adpcm编解码原理及其代码实现
音频编解码格式介绍(2) MP3 :音频格式之MP3:(1)MP3封装格式简介
音频编解码格式介绍(2) MP3 :音频格式之MP3:(2)MP3编解码原理详解
音频编解码格式介绍(3) AAC :音频格式之AAC:(1)AAC简介
音频编解码格式介绍(3) AAC :音频格式之AAC:(2)AAC封装格式ADIF,ADTS,LATM,extradata及AAC ES存储格式
音频编解码格式介绍(3) AAC :音频格式之AAC:(3)AAC编解码原理详解
本文主要1-3部分介绍AAC封装格式ADIF,ADTS和LATM,同时因为从mp4等封装容器有extradata模式,故也第4部分介绍extradata模式。最后第5部分介绍AAC压缩数据存储方式。
说明如下:
1:本文主要介绍AAC封装格式,一个只有aac格式的编码的文件可能使用这三种后缀名:aac、m4a、mp4.
2:其中m4a后缀一般只有apple使用,只含有aac音频格式,没有视频。其实就是mp4封装格式,
对于m4a和mp4后缀属于mp4封装,不在这里介绍,后续会单独开篇介绍封装格式之mp4.
3:其中AAC格式包括ADIF,ADTS和LATM.
需要说明的是ADIF,ADTS和LATM只是AAC的三种封装方式,即只是封装方式不同,里面的编码数据都是和extradata模式一样的。
区别在于:
1:ADIF:只有一个头,其余后面都跟着raw data,文件存储体积小,智能从开始处一帧一帧解码,无法跳播,无法从中间位置解码。
2:ADTS:每帧都有7个字节的头,方便跳播,从任何位置都可以直接进行解码。
3:LATM:LATM格式具有很大的灵活性,每帧的音频配置单元既可以带内传输,又可以带外传输。正因为如此,LATM不仅适用于流传输还可以用于RTP传输,特别时CMMB广播默认码流格式为LATM。
4:extradata:这种模式一般是mp4,flv等封装格式中。extradata在header里面,解码时先传输extradata信息,然后开始传输raw data。每个文件只有一个extradata。其余全部时AAC ES。
主要参考资料为:ISO/IEC 13818-7和ISO/IEC 14496-3
ADIF,Audio Data Interchange Format 音频数据交换格式,该格式一般应用在将音频通过写文件方式存储在磁盘里的场景,不能进行随机访问,不允许在文件中间开始进行解码;只能从文件头开始解码,无法跳播。
ADIF文件存储格式如下:
adif_header | byte_alignment | raw_data_stream |
---|
其中adif_header和raw_data_stream如下表:
说明如下:
1:byte_alignment 为了保持字节对齐用。
2:可以看到adif只有一个header,里面没有关于每帧信息,因为每帧不是固定大小,故只能按照顺序进行解码,也无法跳播或快进快退。除非自己解码遍历整个文件建立每帧位置表。
ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。这种格式可以用于广播电视。
简言之。ADIF只有一个文件头,ADTS每个包前面有一个文件头。
最常见的ADTS文件存储格式如下:
1:aac的adts封装格式类似mp3封装格式,一帧一帧存储,每帧都有同步头,两帧直接允许有冗余数据
2:adts header为7个字节(固定(每帧都一样)header 28bit+变化(每帧之间可能不一样)header28bit)+ 2(crc,可选,一般adts没有crc校验)
详细的adts封装如下:
其中adts_fixed_header结构如下:
ADTS fixed_header 帧头各字段含义
字段 | 长度 bits | 说明 | 解释 |
---|---|---|---|
Syncword | 12 | all bits must be 1 | 总是0xFFF,代表一个ADTS帧的开始,作为分界符,用于同步每帧起始位置 |
ID | 1 | 0 for MPEG-4, 1 for MPEG-2 | |
Layer | 2 | always 0 | |
Protection Absent | 1 | set to 1 if there is no CRC and 0 if there is CRC | |
Profile | 2 | the MPEG-4 Audio Object Type minus 1 | 代表使用哪个级别和规范的 AAC,其中 01 代表 Low Complexity(LC),其中 profile 等于 Audio Object Type 的值减1 |
Sampling Frequency Index | 4 | MPEG-4 Sampling Frequency Index (15 is forbidden) | 采样率下标,由于 AAC 的采样率范围是 8KHz-96KHz,所以具体用那个,由该字段决定 |
Private Bit | 1 | set to 0 when encoding, ignore when decoding | |
Channel Configuration | 3 | MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE) | 通道配置即声道数,一般 2 表示立体声双声道 |
Originality copy | 1 | set to 0 when encoding, ignore when decoding | |
Home | 1 | set to 0 when encoding, ignore when decoding |
profile定义如下:
profile ObjectType | MPEG-2 profile(ID==1) | MPEG-4 object type(ID==0) |
---|---|---|
0 | Main profile | AAC Main |
1 | Low Complexity profile(LC) | AAC LC |
2 | Scalable Sampling Rate profile(SSR) | AAC SSR |
3 | (reserved) | AAC LTP |
profile在 MPEG-4 Audio Object Type(profile_ObjectType+1)参见14496-3的1.5.2.1如下图:
adts_variable_header结构如下:
ADTS variable_header 帧头各字段含义
字段 | 长度 bits | 说明 | 解释 |
---|---|---|---|
Copyrighted identification bit | 1 | set to 0 when encoding, ignore when decoding | |
Copyrighted identification Start | 1 | set to 0 when encoding, ignore when decoding | |
Aac Frame Length | 13 | this value must include 7 or 9 bytes of header length FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame) | 一个 ADTS 帧的长度包括 ADTS 头和 AAC 原始流 |
ADTS Buffer Fullness | 11 | buffer fullness | 0x7FF 表示码率可变的码流,0x000 表示固定码率的码流 |
Number of AAC Frames | 2 | number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame | ADTS 帧中有 number_of_raw_data_blocks_in_frame + 1 个 AAC 原始帧;则 number_of_raw_data_blocks_in_frame == 0 表示 ADTS 帧中有一个 AAC 数据块;(一个 AAC 原始帧包含一段时间内 1024 个采样及相关数据) |
Error detection如下:
LATM 的全称为“Low-overhead MPEG-4 Audio TransportMultiplex”(低开销音频传输复用),是MPEG-4 AAC制定的一种高效率的码流传输方式,MPEG-2 TS 流也采用LATM作为AAC 音频码流的封装格式之 一。
文件存储格式如下:
latm_frame1 | latm_frame2 | … |
---|
每帧latm_frame存储格式如下:
latm_header | byte_alignment | raw_data_stream |
---|
latm_header格式如下:
字段 | 长度 bits | 说明 | 解释 |
---|---|---|---|
syncword | 11 | always:0x2b7 | 同步头,必须是0x2b7 |
audioMuxLengthBytes | 13 | audio mux length | 帧长,不包括前面(11+13)bit |
AudioMuxElement结构如下:
StreamMuxConfig,PayloadLengthInfo,PayloadMux参见ISO/IEC 14496-3。
LATM格式也以帧为单位,主要由AudioSpecificConfig(音频特定配置单元)与音频负载组成。AudioSpecificConfig 描述了一个LATM 帧的信息,音频负载主要由PayloadLengthInfo(负载长度信息)和PayloadMux(负载净荷)组成。
AudioSpecificConfig 信息可以是带内传,也可以是带外传。所谓带内传,就是指每一个LATM 帧,都含有一个AudioSpecificConfig 信息;而带外传,则每一个LATM帧都不含有AudioSpecificConfig 信息,而通过其他方式把AudioSpecificConfig信息发送到解码端,由于AudioSpecificConfig 信息一般是不变的,所以只需发送一次即可。由此可见,
AudioSpecificConfig 信息采用带内传输可适应音频编码信息不断变化的情况,而采用带外传输,可以节省音频传输码率。带内或带外传,由muxconfigPresent 标志位决定。例如流媒体应用中,muxconfigPresent 可设置为0,这样LATM帧中将不含有AudioSpecificConfig 信息,LATM帧通过RTP包发送出去,AudioSpecificConfig 可通过SDP文件一次性传送到解码端。
AudioSpecificConfig 主要参数
参数 | 含义 |
---|---|
numSubFrames | 子帧的数目 |
numProgram | 复用的节目数 |
numLayer | 复用的层数 |
frameLengthType | 负载的帧长度类型,包括固定长度与可变长度 |
audioObjectType | 音频对象类型 |
samplingFrequency | 采样率 |
channelConfiguration | 声道配置 |
音频负载由若干子帧组成,每个子帧由PayloadLengthInfo和PayloadMux组成,与ADTS帧净荷一样,音频负载主要包含原始帧数据。
AAC打包成TS流通常有两种方式,分别是先打包成ADTS或LATM。ADTS的每一帧都有个帧头,在
每个帧头信息都一样的状况下,会有很大的冗余。LATM格式具有很大的灵活性,每帧的音频配置单元既可以带内传输,又可以带外传输。正因为如此,LATM不仅适用于流传输还可以用于RTP传输,
RTP传输时,若音频数据配置信息是保持不变,可以先通过SDP会话先传输StreamMuxConfig(AudioSpecificConfig)信息,由于LATM流由一个包含了一个或多个音频帧的audioMuxElements序列组成。一个完整或部分完整的audioMuxElement可直接映射到一个RTP负载上。
需要说明在开始解码的时候,需要先找到AudioSpecificConfig,才能获取解码信息,才能开始解码。AudioSpecificConfig并不是每帧都含有的
当CMMB中音频压缩标准为AAC时,默认采用LATM封装。StreamMuxConfig采用带外传输。
StreamMuxConifg中的若干默认参数如下:audioMuxVersion:0标志流语法版本号为0,
allStreamsSameTimeFraming标志复用到PayLoadMux()中的所有负载共享一个共同的时基音频子帧.
audioObjectType:2 AAC-LC
freameLengthType:0 帧长度是可变的
latmBufferFullness:0xFF 码率可变的码流
这种模式一般是mp4,flv等封装格式中。extradata在header里面,解码时先传输extradata信息,然后开始传输raw data。
extradata存储格式如下:
object_type | sample_rate | chan_config | … |
---|---|---|---|
5(+6)bits | 4(+24)bits | 4bits | … |
具体查看ffmpeg的decode_audio_specific_config函数:
/** * Decode audio specific configuration; reference: table 1.13. * * @param ac pointer to AACContext, may be null * @param avctx pointer to AVCCodecContext, used for logging * @param m4ac pointer to MPEG4AudioConfig, used for parsing * @param gb buffer holding an audio specific config * @param get_bit_alignment relative alignment for byte align operations * @param sync_extension look for an appended sync extension * * @return Returns error status or number of consumed bits. <0 - error */ static int decode_audio_specific_config_gb(AACContext *ac, AVCodecContext *avctx, MPEG4AudioConfig *m4ac, GetBitContext *gb, int get_bit_alignment, int sync_extension) { int i, ret; GetBitContext gbc = *gb; MPEG4AudioConfig m4ac_bak = *m4ac; if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension, avctx)) < 0) { *m4ac = m4ac_bak; return AVERROR_INVALIDDATA; } if (m4ac->sampling_index > 12) { av_log(avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", m4ac->sampling_index); *m4ac = m4ac_bak; return AVERROR_INVALIDDATA; } if (m4ac->object_type == AOT_ER_AAC_LD && (m4ac->sampling_index < 3 || m4ac->sampling_index > 7)) { av_log(avctx, AV_LOG_ERROR, "invalid low delay sampling rate index %d\n", m4ac->sampling_index); *m4ac = m4ac_bak; return AVERROR_INVALIDDATA; } skip_bits_long(gb, i); switch (m4ac->object_type) { case AOT_AAC_MAIN: case AOT_AAC_LC: case AOT_AAC_SSR: case AOT_AAC_LTP: case AOT_ER_AAC_LC: case AOT_ER_AAC_LD: if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment, m4ac, m4ac->chan_config)) < 0) return ret; break; case AOT_ER_AAC_ELD: if ((ret = decode_eld_specific_config(ac, avctx, gb, m4ac, m4ac->chan_config)) < 0) return ret; break; default: avpriv_report_missing_feature(avctx, "Audio object type %s%d", m4ac->sbr == 1 ? "SBR+" : "", m4ac->object_type); return AVERROR(ENOSYS); } ff_dlog(avctx, "AOT %d chan config %d sampling index %d (%d) SBR %d PS %d\n", m4ac->object_type, m4ac->chan_config, m4ac->sampling_index, m4ac->sample_rate, m4ac->sbr, m4ac->ps); return get_bits_count(gb); } static int decode_audio_specific_config(AACContext *ac, AVCodecContext *avctx, MPEG4AudioConfig *m4ac, const uint8_t *data, int64_t bit_size, int sync_extension) { int i, ret; GetBitContext gb; if (bit_size < 0 || bit_size > INT_MAX) { av_log(avctx, AV_LOG_ERROR, "Audio specific config size is invalid\n"); return AVERROR_INVALIDDATA; } ff_dlog(avctx, "audio specific config size %d\n", (int)bit_size >> 3); for (i = 0; i < bit_size >> 3; i++) ff_dlog(avctx, "%02x ", data[i]); ff_dlog(avctx, "\n"); if ((ret = init_get_bits(&gb, data, bit_size)) < 0) return ret; return decode_audio_specific_config_gb(ac, avctx, m4ac, &gb, 0, sync_extension); }
ff_mpeg4audio_get_config_gb函数参考ffmpeg中的mpeg4audio.c如下:
/* * MPEG-4 Audio common code * Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr> * Copyright (c) 2009 Alex Converse <alex.converse@gmail.com> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "get_bits.h" #include "mpeg4audio.h" /** * Parse MPEG-4 audio configuration for ALS object type. * @param[in] gb bit reader context * @param[in] c MPEG4AudioConfig structure to fill * @return on success 0 is returned, otherwise a value < 0 */ static int parse_config_ALS(GetBitContext *gb, MPEG4AudioConfig *c, void *logctx) { if (get_bits_left(gb) < 112) return AVERROR_INVALIDDATA; if (get_bits_long(gb, 32) != MKBETAG('A','L','S','\0')) return AVERROR_INVALIDDATA; // override AudioSpecificConfig channel configuration and sample rate // which are buggy in old ALS conformance files c->sample_rate = get_bits_long(gb, 32); if (c->sample_rate <= 0) { av_log(logctx, AV_LOG_ERROR, "Invalid sample rate %d\n", c->sample_rate); return AVERROR_INVALIDDATA; } // skip number of samples skip_bits_long(gb, 32); // read number of channels c->chan_config = 0; c->channels = get_bits(gb, 16) + 1; return 0; } const uint8_t ff_mpeg4audio_channels[15] = { 0, 1, // mono (1/0) 2, // stereo (2/0) 3, // 3/0 4, // 3/1 5, // 3/2 6, // 3/2.1 8, // 5/2.1 0, 0, 0, 7, // 3/3.1 8, // 3/2/2.1 24, // 3/3/3 - 5/2/3 - 3/0/0.2 8, // 3/2.1 - 2/0 }; static inline int get_object_type(GetBitContext *gb) { int object_type = get_bits(gb, 5); if (object_type == AOT_ESCAPE) object_type = 32 + get_bits(gb, 6); return object_type; } static inline int get_sample_rate(GetBitContext *gb, int *index) { *index = get_bits(gb, 4); return *index == 0x0f ? get_bits(gb, 24) : ff_mpeg4audio_sample_rates[*index]; } int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb, int sync_extension, void *logctx) { int specific_config_bitindex, ret; int start_bit_index = get_bits_count(gb); c->object_type = get_object_type(gb); c->sample_rate = get_sample_rate(gb, &c->sampling_index); c->chan_config = get_bits(gb, 4); if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels)) c->channels = ff_mpeg4audio_channels[c->chan_config]; else { av_log(logctx, AV_LOG_ERROR, "Invalid chan_config %d\n", c->chan_config); return AVERROR_INVALIDDATA; } c->sbr = -1; c->ps = -1; if (c->object_type == AOT_SBR || (c->object_type == AOT_PS && // check for W6132 Annex YYYY draft MP3onMP4 !(show_bits(gb, 3) & 0x03 && !(show_bits(gb, 9) & 0x3F)))) { if (c->object_type == AOT_PS) c->ps = 1; c->ext_object_type = AOT_SBR; c->sbr = 1; c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index); c->object_type = get_object_type(gb); if (c->object_type == AOT_ER_BSAC) c->ext_chan_config = get_bits(gb, 4); } else { c->ext_object_type = AOT_NULL; c->ext_sample_rate = 0; } specific_config_bitindex = get_bits_count(gb); if (c->object_type == AOT_ALS) { skip_bits(gb, 5); if (show_bits(gb, 24) != MKBETAG('\0','A','L','S')) skip_bits(gb, 24); specific_config_bitindex = get_bits_count(gb); ret = parse_config_ALS(gb, c, logctx); if (ret < 0) return ret; } if (c->ext_object_type != AOT_SBR && sync_extension) { while (get_bits_left(gb) > 15) { if (show_bits(gb, 11) == 0x2b7) { // sync extension get_bits(gb, 11); c->ext_object_type = get_object_type(gb); if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(gb)) == 1) { c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index); if (c->ext_sample_rate == c->sample_rate) c->sbr = -1; } if (get_bits_left(gb) > 11 && get_bits(gb, 11) == 0x548) c->ps = get_bits1(gb); break; } else get_bits1(gb); // skip 1 bit } } //PS requires SBR if (!c->sbr) c->ps = 0; //Limit implicit PS to the HE-AACv2 Profile if ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01) c->ps = 0; return specific_config_bitindex - start_bit_index; } int avpriv_mpeg4audio_get_config2(MPEG4AudioConfig *c, const uint8_t *buf, int size, int sync_extension, void *logctx) { GetBitContext gb; int ret; if (size <= 0) return AVERROR_INVALIDDATA; ret = init_get_bits8(&gb, buf, size); if (ret < 0) return ret; return ff_mpeg4audio_get_config_gb(c, &gb, sync_extension, logctx); }
具体查看ffmpeg文件,网址:https://github.com/FFmpeg/FFmpeg
AAC ES是AAC的压缩数据.
element | elementChan1 | elementChan2 |
---|
element存储格式如下:
element ID (3bits) | element tag |
---|
AAC元素信息(element)不同,element tag信息不同。具体来说:
在AAC中,原始数据块的组成可能有七种不同的元素:
SCE: Single Channel Element单通道元素。单通道元素基本上只由一个ICS组成。一个原始数据块最可能由16个SCE组成。
CPE: Channel Pair Element 双通道元素,由两个可能共享边信息的ICS和一些联合立体声编码信息组成。一个原始数据块最多可能由16个SCE组成。
CCE: Coupling Channel Element 藕合通道元素。代表一个块的多通道联合立体声信息或者多语种程序的对话信息。
LFE: Low Frequency Element 低频元素。包含了一个加强低采样频率的通道。
DSE: Data Stream Element 数据流元素,包含了一些并不属于音频的附加信息。
PCE: Program Config Element 程序配置元素。包含了声道的配置信息。它可能出现在ADIF 头部信息中。
FIL: Fill Element 填充元素。包含了一些扩展信息。如SBR,动态范围控制信息等。
element不同,包含的elementChan数不同,具体来说elementChan包含数量如下:
element | SCE | CPE | CCE | LFE | DSE | PCE | FIL | END |
---|---|---|---|---|---|---|---|---|
elementChan | 1 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
每个elementChan数据存储格式如下图:
具体可以查看ISO/IEC 14496-3之 4.4.2.7
[1] : 【网络通信 – 直播】音频流编码 – AAC 基础
https://blog.csdn.net/qq_27788177/article/details/113758541
[2]:AAC 文件解析及解码流程
https://zhuanlan.zhihu.com/p/347992887
[3]:AAC ADTS/LATM格式总结
https://blog.csdn.net/av_geek/article/details/18445347
[4]:ISO/IEC 14496-3
https://csclub.uwaterloo.ca/~ehashman/ISO14496-3-2009.pdf
[5]:ISO/IEC 13818-7
http://www.telemidia.puc-rio.br/~rafaeldiniz/public_files/normas/ISO-13818/ISO_IEC_13818-7_2006(E).pdf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。