AAC是高级音频编码(Advanced Audio Coding)的缩写,出现于1997年,最初是基于MPEG-2的音频编码技术。由Fraunhofer IIS、Dolby Laboratories、AT&T、Sony等公司共同开发,目的是取代MP3格式。2000年,MPEG-4标准出台,AAC重新集成了其它技术(PS,SBR),为区别于传统的MPEG-2 AAC,故含有SBR或PS特性的AAC又称为MPEG-4 AAC。
AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS,SBR等),衍生出了LC-AAC,HE-AAC,HE-AACv2三种主要的编码,LC-AAC就是比较传统的AAC,相对而言,主要用于中高码率(>=80Kbps),HE-AAC(相当于AAC+SBR)主要用于中低码(<=80Kbps),而新近推出的HE-AACv2(相当于AAC+SBR+PS)主要用于低码率(<=48Kbps),事实上大部分编码器设成<=48Kbps自动启用PS技术,而>48Kbps就不加PS,就相当于普通的HE-AAC。
一、AAC音频文件格式
1. AAC的音频文件格式有ADIF & ADTS
ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。AAC的ADIF格式见下图:
ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。AAC的ADTS的一般格式见下图:
图中表示出了ADTS一帧的简明结构,其两边的空白矩形表示一帧前后的数据。
2. ADIF和ADTS的header
ADIF 的头信息
ADIF头信息位于AAC文件的起始处,接下来就是连续的 raw data blocks。 组成ADIF头信息的各个域如下所示:
ADTS头信息
ADTS头分 为固定头和可变头,共计7字节。固定头信息中的数据每一帧都相同,而可变头信息则在帧与帧之间可变。
ADTS 的固定头信息:
ADTS的可变头信息:
adts_fixed_header(){
syncword: 12 bslbf
ID: 1 bslbf
layer: 2 uimsbf
protection_absent: 1 bslbf
profile: 2 uimsbf
sampling_frequency_index: 4 uimsbf
private_bit: 1 bslbf
channel_configuration: 3 uimsbf
original/copy: 1 bslbf
home: 1 bslbf
}
adts_variable_header(){
copyright_identification_bit: 1 bslbf
copyright_identification_start: 1 bslbf
frame_length: 13 bslbf
adts_buffer_fullness: 11 bslbf
number_of_raw_data_blocks_in_frame: 2 uimsfb
}
syncword 同步字为12比特的“1111 1111 1111”,说明一个ADTS帧的开始。
ID MPEG 标示符, 设置为1。
layer Indicates which layer is used,Set to ‘00’
protection_absent 表示是否误码校验
profile 表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC
sampling_frequency_index 表示使用的采样率下标
sampling_frequency_index sampling frequeny [Hz]
0x0 96000
0x1 88200
0x2 64000
0x3 48000
0x4 44100
0x5 32000
0x6 24000
0x7 22050
0x8 16000
0x9 2000
0xa 11025
0xb 8000
0xc reserved
0xd reserved
0xe reserved
0xf reserved
channel_configuration 表示声道数。
frame_length 一个ADTS帧的长度包括ADTS头和raw data block。
adts_buffer_fullness 0x7FF 说明是码率可变的码流
number_of_raw_data_blocks_in_frame表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。所以说number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
二、AAC帧解析
如下程序拷贝自leixiaohua,视音频数据处理入门:AAC音频码流解析。
注:一个aac原始帧包含1024个采样点,aac编码后帧大小不定。AAC帧,采集数据为双通道,16位数据时,根据公式, 一帧数据量大小 = 1024*2 *16/8 = 4096。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getADTSframe(unsigned char* buffer, int buf_size, unsigned char* data ,int* data_size){
int size = 0;
if(!buffer || !data || !data_size ){
return -1;
}
while(1){
if(buf_size < 7 ){
return -1;
}
//Sync words
if((buffer[0] == 0xff) && ((buffer[1] & 0xf0) == 0xf0) ){
size |= ((buffer[3] & 0x03) <<11); //high 2 bit
size |= buffer[4]<<3; //middle 8 bit
size |= ((buffer[5] & 0xe0)>>5); //low 3bit
break;
}
--buf_size;
++buffer;
}
if(buf_size < size){
return 1;
}
memcpy(data, buffer, size);
*data_size = size;
return 0;
}
int simplest_aac_parser(char *url)
{
int data_size = 0;
int size = 0;
int cnt=0;
int offset=0;
//FILE *myout=fopen("output_log.txt","wb+");
FILE *myout=stdout;
unsigned char *aacframe=(unsigned char *)malloc(1024*5);
unsigned char *aacbuffer=(unsigned char *)malloc(1024*1024);
FILE *ifile = fopen(url, "rb");
if(!ifile){
printf("Open file error");
return -1;
}
printf("-----+- ADTS Frame Table -+------+\n");
printf(" NUM | Profile | Frequency| Size |\n");
printf("-----+---------+----------+------+\n");
while(!feof(ifile)){
data_size = fread(aacbuffer+offset, 1, 1024*1024-offset, ifile);
unsigned char* input_data = aacbuffer;
while(1)
{
int ret=getADTSframe(input_data, data_size, aacframe, &size);
if(ret==-1){
break;
}else if(ret==1){
memcpy(aacbuffer,input_data,data_size);
offset=data_size;
break;
}
char profile_str[10]={0};
char frequence_str[10]={0};
unsigned char profile=aacframe[2]&0xC0;
profile=profile>>6;
switch(profile){
case 0: sprintf(profile_str,"Main");break;
case 1: sprintf(profile_str,"LC");break;
case 2: sprintf(profile_str,"SSR");break;
default:sprintf(profile_str,"unknown");break;
}
unsigned char sampling_frequency_index=aacframe[2]&0x3C;
sampling_frequency_index=sampling_frequency_index>>2;
switch(sampling_frequency_index){
case 0: sprintf(frequence_str,"96000Hz");break;
case 1: sprintf(frequence_str,"88200Hz");break;
case 2: sprintf(frequence_str,"64000Hz");break;
case 3: sprintf(frequence_str,"48000Hz");break;
case 4: sprintf(frequence_str,"44100Hz");break;
case 5: sprintf(frequence_str,"32000Hz");break;
case 6: sprintf(frequence_str,"24000Hz");break;
case 7: sprintf(frequence_str,"22050Hz");break;
case 8: sprintf(frequence_str,"16000Hz");break;
case 9: sprintf(frequence_str,"12000Hz");break;
case 10: sprintf(frequence_str,"11025Hz");break;
case 11: sprintf(frequence_str,"8000Hz");break;
default:sprintf(frequence_str,"unknown");break;
}
fprintf(myout,"%5d| %8s| %8s| %5d|\n",cnt,profile_str ,frequence_str,size);
data_size -= size;
input_data += size;
cnt++;
}
}
fclose(ifile);
free(aacbuffer);
free(aacframe);
return 0;
}
simplest_aac_parser("nocturne.aac");
统计结果如下:
-----+- ADTS Frame Table -+------+
NUM | Profile | Frequency| Size |
-----+---------+----------+------+
0| LC| 44100Hz| 371|
1| LC| 44100Hz| 372|
2| LC| 44100Hz| 371|
3| LC| 44100Hz| 372|
4| LC| 44100Hz| 371|
5| LC| 44100Hz| 372|
6| LC| 44100Hz| 371|
7| LC| 44100Hz| 372|
8| LC| 44100Hz| 371|
......
1285| LC| 44100Hz| 371|
1286| LC| 44100Hz| 372|
1287| LC| 44100Hz| 371|
1288| LC| 44100Hz| 372|
1289| LC| 44100Hz| 371|
1290| LC| 44100Hz| 372|
1291| LC| 44100Hz| 371|