一、AAC编码概述
AAC是高级音频编码(Advanced Audio Coding)的缩写,被认为是MP3的继任者,相对MP3有更高的压缩效率。由Fraunhofer IIS、杜比实验室、AT&T、Sony(索尼)等公司共同开发。出现于1997年,最初是基于MPEG-2的音频编码技术,目的是取代MP3格式。2000年,MPEG-4标准出台,AAC重新集成了其它技术包括SBR或PS特性,目前AAC可以定义为⼀种由 MPEG-4 标准定义的有损音频压缩格式。AAC被iPhone、iTunes以及大多数便携式设备所使用。
二、AAC编码规格简述
AAC共有9种规格,以适应不同的场合的需要:
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)---这种规格适合用于低码率编码,有Nero ACC 编码器支持
流行的Nero AAC编码程序只支持LC,HE,HEv2这三种规格,编码后的AAC音频,规格显示都是LC。HE其实就是AAC(LC)+ SBR技术,HEv2就是AAC(LC)+ SBR + PS技术;
这里再说明一下HE和HEv2的相关内容:
HE:HE-AAC v1(又称AACPlusV1,SBR),用容器的方法实现了AAC(LC)+SBR技术。SBR其实代表的是Spectral Band Replication(频段复制)。简要叙述一下,音乐的主要频谱集中在低频段,高频段幅度很小,但很重要,决定了音质。如果对整个频段编码,若是为了保护高频就会造成低频段编码过细以致文件巨大;若是保存了低频的主要成分而失去高频成分就会丧失音质。SBR把频谱切割开来,低频单独编码保存主要成分,高频单独放大编码保存音质,“统筹兼顾”了,在减少文件大小的情况下还保存了音质,完美的化解这一矛盾。
HEv2:用容器的方法包含了HE-AAC v1和PS技术。PS指“parametric stereo”(参数立体声)。原来的立体声文件文件大小是一个声道的两倍。但是两个声道的声音存在某种相似性,根据香农信息熵编码定理,相关性应该被去掉才能减小文件大小。所以PS技术存储了一个声道的全部信息,然后,花很少的字节用参数描述另一个声道和它不同的地方。
三、AAC编码的特点
(1). AAC是一种高压缩比的音频压缩算法,但它的压缩比要远超过较老的音频压缩算法,如AC-3、MP3等。并且其质量可以同未压缩的CD音质相媲美。
(2). 同其他类似的音频编码算法一样,AAC也是采用了变换编码算法,但AAC使用了分辨率更高的滤波器组,因此它可以达到更高的压缩比。
(3). AAC使用了临时噪声重整、后向自适应线性预测、联合立体声技术和量化哈夫曼编码等最新技术,这些新技术的使用都使压缩比得到进一步的提高。
(4). AAC支持更多种采样率和比特率、支持1个到48个音轨、支持多达15个低频音轨、具有多种语言的兼容能力、还有多达15个内嵌数据流。
(5). AAC支持更宽的声音频率范围,最高可达到96kHz,最低可达8KHz,远宽于MP3的16KHz-48kHz的范围。
(6). 不同于MP3及WMA,AAC几乎不损失声音频率中的甚高、甚低频率成分,并且比WMA在频谱结构上更接近于原始音频,因而声音的保真度更好。
(7). AAC采用优化的算法达到了更高的解码效率,解码时只需较少的处理能力。
四、开源软件
FAAD2:开源的MPEG-4和MPEG-2 AAC解码器。
fdk-aac:Fraunhofer IIS
开发的开源项目的aac编解码库,包含在android项目中。
五、AAC和MP3的关键性不同
AAC是在MP3基础上开发出来的,所以两者的编码系统有一些相同之处。但是对比一下两者的编码流程图,你会发现AAC的编码工序更为复杂。
滤波器组(Filter bank):
时域噪音修整(Temporal Noise Shaping,TNS):这项神奇的技术可以通过在频率域上的预测,来修整时域上的量化噪音的分布。在一些特殊的语音和剧烈变化信号的量化上,TNS技术对音质的提高贡献巨大!
预测(Prediction):对音频信号进行预测可以减少重复冗余信号的处理,提高效率。
量化(Quantization):AAC的量化过程是使用两个巢状循环进行反复运算。通过对量化分析的良好控制,比特率能够被更高效地利用。
比特流格式(Bit-stream format):在AAC中,信息的传输都要经过熵编码,以保证冗余尽可能少。此外AAC拥有一个弹性的比特流结构,使得编码效率进一步提高。
长时期预测(Long Term Prediction,LTP):这是一个MPEG-4 AAC中才有的工具,它用来减少连续两个编码音框之间的信号冗余,对于处理低码率的语音非常有效。
知觉噪音代替(Perceptual Noise Substitution,PNS):这也是MPEG-4 AAC中才有的工具,当编码器发现类似噪音的信号时,并不对其进行量化,而是作个标记就忽略过去,当解码时再还原出来,这样就提高了效率。
六 帧格式
AAC音频格式有:
ADIF(Audio Data Interchage Format),音频数据交换格式:只有一个统一的头,必须得到所有数据后解码,适用于本地文件。
ADTS(Audio Data Transport Stream),音视数据传输流:每一帧都有头信息,任意帧解码,适用于传输流。
我们主要介绍ADTS。
ADTS的组成单元是ADTS Frame。
ADTS Frame由ADTS_Header和AAC ES组成。
ADTS_Header包含采样率、声道数、帧长度的信息。
ADTS头信息的长度是7个字节或9字节(有CRC的情况)。
ADTS_Header的可以分为以下三部分:
adts_fixed_header:每一帧的内容是不变的。
adts_variable_header:每一帧的内容是存在变化的。
crc:16bits,protection_absent字段为0时存在。
adts_fixed_header:
字段 比特数 说明
syncword 12 所有位必须为1,即0xFFF。
ID 1 0代表MPEG-4, 1代表MPEG-2。
layer 2 所有位必须为0。
protection_absent 1 1代表没有CRC,0代表有。
profile 2 配置级别(Table1.17)
sampling_frequency_index 4 标识使用的采样频率,具体见下表Table35。
private_bit 1 see ISO/IEC 11172-3, subclause 2.4.2.3 (Table 8).
channel_configuration 3 取值为0时,通过inband 的PCE设置channel configuration。
original/copy 1 编码时设置为0,解码时忽略。
home 1 编码时设置为0,解码时忽略。
在MPEG-2 AAC中定义了3种profile:
MPEG-2 AAC Main
MPEG-2 AAC LC (Low Complexity)
MPEG-2 AAC SSR (Scalable Sampling Rate)
在MPEG-4 AAC中定义了6种profile:
MPEG-4 AAC Main
MPEG-4 AAC LC (Low Complexity)
MPEG-4 AAC SSR (Scalable Sample Rate)
MPEG-4 AAC LTP (Long Term Predicition)
MPEG-4 AAC LD (Low Delay)
MPEG-4 AAC HE (High Efficiency) AACPlusV1/V2(3GPP)
adts_variable_header:
字段 比特数 说明
copyright_identification_bit 1 编码时设置为0,解码时忽略。
copyright_identification_start 1 编码时设置为0,解码时忽略
frame_length 13 帧长度,包括header和crc的长度,单位byte
adts_buffer_fullness 11
number_of_raw_data_blocks_in_frame 2 number of AAC Frames(RDBs) in ADTS frame minus 1, 为了最大的兼容性通常每个ADTS frame 包含一个AAC frame。
看一段具体的代码:
void adts_header(char *szAdtsHeader, int dataLen){
int audio_object_type = 2;
int sampling_frequency_index = 7;
int channel_config = 2;
int adtsLen = dataLen + 7;
szAdtsHeader[0] = 0xff; //syncword:0xfff 高8bits
szAdtsHeader[1] = 0xf0; //syncword:0xfff 低4bits
szAdtsHeader[1] |= (0 << 3); //MPEG Version:0 for MPEG-4,1 for MPEG-2 1bit
szAdtsHeader[1] |= (0 << 1); //Layer:0 2bits
szAdtsHeader[1] |= 1; //protection absent:1 1bit
szAdtsHeader[2] = (audio_object_type - 1)<<6; //profile:audio_object_type - 1 2bits
szAdtsHeader[2] |= (sampling_frequency_index & 0x0f)<<2; //sampling frequency index:sampling_frequency_index 4bits
szAdtsHeader[2] |= (0 << 1); //private bit:0 1bit
szAdtsHeader[2] |= (channel_config & 0x04)>>2; //channel configuration:channel_config 高1bit
szAdtsHeader[3] = (channel_config & 0x03)<<6; //channel configuration:channel_config 低2bits
szAdtsHeader[3] |= (0 << 5); //original:0 1bit
szAdtsHeader[3] |= (0 << 4); //home:0 1bit
szAdtsHeader[3] |= (0 << 3); //copyright id bit:0 1bit
szAdtsHeader[3] |= (0 << 2); //copyright id start:0 1bit
szAdtsHeader[3] |= ((adtsLen & 0x1800) >> 11); //frame length:value 高2bits
szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3); //frame length:value 中间8bits
szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5); //frame length:value 低3bits
szAdtsHeader[5] |= 0x1f; //buffer fullness:0x7ff 高5bits
szAdtsHeader[6] = 0xfc;
}
AAC文件处理流程:
(1). 判断文件格式,确定为ADIF或ADTS
(2). 若为ADIF,解ADIF头信息,跳至第6步。
(3). 若为ADTS,寻找同步头。
(4). 解ADTS帧头信息。
(5). 若有错误检测,进行错误检测。
(6). 解块信息。
(7). 解元素信息。
注意:有时候在处理AAC音频流的时候 (比如:把 AAC 音频的 ES 流从 FLV 封装格式中抽出来送给硬件解码器),编码后的 AAC 文件在PC或者手机上不能播放,导致播放错误,很大可能的原因是 AAC 文件的每一帧缺少 ADTS 头信息文件的包装拼接,这时需要加上头文件 ADTS 即可。
看看ffmpeg中添加ADTS头的代码,可以很清晰的了解ADTS头的结构:
static int adts_write_frame_header(ADTSContext *ctx,
uint8_t *buf, int size, int pce_size)
{
PutBitContext pb;
unsigned full_frame_size = (unsigned)ADTS_HEADER_SIZE + size + pce_size;
if (full_frame_size > ADTS_MAX_FRAME_BYTES) {
av_log(NULL, AV_LOG_ERROR, "ADTS frame size too large: %u (max %d)\n",
full_frame_size, ADTS_MAX_FRAME_BYTES);
return AVERROR_INVALIDDATA;
}
init_put_bits(&pb, buf, ADTS_HEADER_SIZE);
/* adts_fixed_header */
put_bits(&pb, 12, 0xfff); /* syncword */
put_bits(&pb, 1, 0); /* ID */
put_bits(&pb, 2, 0); /* layer */
put_bits(&pb, 1, 1); /* protection_absent */
put_bits(&pb, 2, ctx->objecttype); /* profile_objecttype */
put_bits(&pb, 4, ctx->sample_rate_index);
put_bits(&pb, 1, 0); /* private_bit */
put_bits(&pb, 3, ctx->channel_conf); /* channel_configuration */
put_bits(&pb, 1, 0); /* original_copy */
put_bits(&pb, 1, 0); /* home */
/* adts_variable_header */
put_bits(&pb, 1, 0); /* copyright_identification_bit */
put_bits(&pb, 1, 0); /* copyright_identification_start */
put_bits(&pb, 13, full_frame_size); /* aac_frame_length */
put_bits(&pb, 11, 0x7ff); /* adts_buffer_fullness */
put_bits(&pb, 2, 0); /* number_of_raw_data_blocks_in_frame */
flush_put_bits(&pb);
return 0;
}