简介
AAC⾳频格式:Advanced Audio Coding(⾼级⾳频解码),是⼀种由MPEG-4 标准定义的有损⾳频压缩格式,由Fraunhofer发展,Dolby, Sony和AT&T是主 要的贡献者。
通常会将AAC与ADTS等容器格式混淆,但它们其实是不同的概念。AAC是编码规范,ADTS/ADIF是它的容器格式。
-
ADIF (Audio Data Interchange Format):
- ADIF是一种AAC音频的文件封装格式,它将AAC编码后的数据直接存储在文件中。
- ADIF文件中不包含任何帧头信息,整个文件就是纯AAC编码数据。
- ADIF格式不适合流媒体传输,因为无法实现随机访问。
-
ADTS (Audio Data Transport Stream):
- ADTS是AAC音频的一种容器格式,常用于流媒体传输。
- ADTS在AAC编码数据前添加了帧头信息,包括一些同步字节、采样率、声道数等。
- ADTS格式允许随机访问,非常适合用于流式传输。
- ADTS通常用于MP4、TS等容器格式中的AAC音频部分。
简单说,ADTS可以在任意帧解码,也就是说它每⼀帧都有头信息。ADIF只有⼀ 个统⼀的头,所以必须得到所有的数据后解码。
且这两种的header的格式也是不同的,⽬前⼀般编码后的和抽取出的都是 ADTS格式的⾳频流。两者具体的组织结构如下所示:
有的时候当你编码AAC裸流的时候,会遇到写出来的AAC⽂件并不能在PC和⼿ 机上播放,很⼤的可能就是AAC⽂件的每⼀帧⾥缺少了ADTS头信息⽂件的包装 拼接。
ADIF 分析
这个格式比较少见,简单认识一下即可,ADIF 是一种用于存储 MP3 编码音频数据的容器格式。下图是ADIF格式的序列,由adif_header、byte_alignment、raw_data_stream三部分组成。byte_alignment是用来做字节对齐的,也就是说,ADIF格式由一个ADIF头信息(adif_header) 和 原始数据流(raw_data_stream) 构成。
ADTS分析
ADTS格式每⼀帧由ADTS Header和AAC Audio Data组成。结构体如 下:
每⼀帧的ADTS的头⽂件都包含了⾳频的采样率,声道,帧⻓度等信息,这样解码器才能解析读取。
⼀般情况下ADTS的头信息都是7个字节,分为2部分:
adts_fixed_header();
adts_variable_header();其⼀为固定头信息,紧接着是可变头信息。固定头信息中的数据每⼀帧都相同,⽽可变头信息则在帧与帧之间可变。
adts_fixed_header();
同步字头(Sync word, 12 位)
- 值为 0xFFF,用于标识 ADTS 帧的开始位置。
ID (1 位)
- 0 表示 MPEG-4 音频,1 表示 MPEG-2 音频。
层(Layer, 2 位)
- 0 表示不使用任何层1、2、3 分别表示使用第 1、2、3 层
无保护(Protection absent, 1 位) 决定7/9B
- 0 表示有 CRC 校验 1 表示没有 CRC 校验
编码 Profile (Profile object type, 2 位)
- 0 表示保留
- 1 表示 AAC main
- 2 表示 AAC LC (Low Complexity)
- 3 表示 AAC SSR (Scalable Sampling Rate)
- 4 表示 AAC LTP (Long Term Prediction)
采样率索引(Sampling frequency index, 4 位)
- 指示音频的采样率
私有位(Private bit, 1 位)
- 可由应用自由使用 占用 1 bit,编码时设置为0,解码时忽略;
声道配置(Channel configuration, 3 位)
- 指示音频的声道数配置
原始/拷贝(Original/copy, 1 位)
- 占用 1 bit,编码时设置为0,解码时忽略; 0 表示拷贝1 表示原始
家庭(Home, 1 位)
- 通常设为 0
采样率 编码格式 声道数
下图可知,id字段决定了mpeg-2还是mpeg-4,
这里画错了,不是absent字段。
profile字段依赖id字段,给出了多种aac版本,官方文档定义的是要在给定值-1操作,才能正确取出对应值。
ffmpeg则自定义了宏,无需+1-1操作。
声道位
下面给出预定义好的声道和采样率 方便以后使用
sampling_frequencies表示使⽤的采样率下标,通过这个下标在数组中查找得知采样率的值
const int sampling_frequencies[] = {
96000, // 0x0
88200, // 0x1
64000, // 0x2
48000, // 0x3
44100, // 0x4
32000, // 0x5
24000, // 0x6
22050, // 0x7
16000, // 0x8
12000, // 0x9
11025, // 0xa
8000, // 0xb
7350 // 0xc
// 0xd e f是保留的
};
sampling_frequencies 表示声道数,⽐如2表示⽴体声双声道
FFmpeg 提供了一些常用的声道宏定
AV_CH_FRONT_LEFT:前左声道
AV_CH_FRONT_RIGHT:前右声道
AV_CH_FRONT_CENTER:前中声道
AV_CH_LOW_FREQUENCY:低频声道
AV_CH_BACK_LEFT:后左声道
AV_CH_BACK_RIGHT:后右声道
AV_CH_FRONT_LEFT_OF_CENTER:前左中声道
AV_CH_FRONT_RIGHT_OF_CENTER:前右中声道
AV_CH_BACK_CENTER:后中声道
AV_CH_SIDE_LEFT:左侧声道
AV_CH_SIDE_RIGHT:右侧声道
AV_CH_TOP_CENTER:顶中声道
AV_CH_TOP_FRONT_LEFT:前左顶声道
AV_CH_TOP_FRONT_CENTER:前中顶声道
AV_CH_TOP_FRONT_RIGHT:前右顶声道
AV_CH_TOP_BACK_LEFT:后左顶声道
AV_CH_TOP_BACK_CENTER:后中顶声道
AV_CH_TOP_BACK_RIGHT:后右顶声道
adts_variable_header();
ADTS 可变头部包含的字段:
版权标识位(Copyright Identification Bit):
这是 1 位的标志位
表示当前 ADTS 帧是否有版权保护
值为 0 表示没有版权保护
值为 1 表示有版权保护
版权标识起始(Copyright Identification Start):
这也是 1 位的标志位
表示当前 ADTS 帧是否为版权数据的起始
值为 0 表示当前帧不是版权数据的起始
值为 1 表示当前帧是版权数据的起始
AAC 帧长度 (AAC Frame Length): 13 位,表示整个 ADTS 帧的长度,包括头部和负载数据,单位为字节。包括 ADTS 头部长度和 AAC 原始数据长度protection_absent 为 0 时,头部长度为 9 字节 aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame)
ADTS 缓冲区满溢 (ADTS Buffer Fullness): 11 位,表示当前帧的缓冲区填充程度。用于码率控制和帧间同步。 默认0x7FF 说明是码率可变的码流。0x000 表示固定码率的码流;
原始数据块数 (Number of Raw Data Blocks in Frame): 2 位,表示当前帧包含的原始数据块数。一般为 0(ADTS 帧中只有 1 个 AAC 数据块)。表示 ADTS 帧中包含的 AAC 原始数据块数,当 number_of_raw_data_blocks_in_frame == 0 时,表示 ADTS 帧中只有 1 个 AAC 数据块
总结作用:
- 版权标识: 表示当前帧是否受版权保护。
- 帧长度: 解码器需要知道帧的长度以正确解析数据。
- 缓冲区满溢: 用于码率控制和帧间同步。
- 原始数据块数: 用于支持一个 ADTS 帧包含多个原始数据块的情况。
adts与aac文件存储排布分析
头部 28bit固定 28bit可变
0xFF 0xF1 0x4C 0x40 0x20 0xFF 0xFC
0xFF 0xF1:
0xfff 同步字头
0001
0 ID:MPEG-4 音频
00 Layer:不使用任何层
1 保护位:没有 CRC 校验
0x4c: 0100 1100
01 编码Profile:AAC main
00 11 音频的采样率(Sampling frequency index)指示 48000
0 暂定位 Private:可由应用自由使用
0x40: 0100 0000
0 01 声道配置(Channel configuration):中前扬声器
0 原始/拷贝(Original/copy):拷贝
0 home:位
以上是adts_fixed_header
接下来是 adts_variable_header
0 版权标识位(Copyright Identification):没有版权保护
0 版权标识起始(Copyright Identification Start):不是版权数据的起始
0x20 ->0010 0000
0xFF -> 1111 1111
00 0010 0000 111 AAC 帧长度 (AAC Frame Length): 转换成⼗进制为263
0xFC -> 1111 1100
1 1111 1111 11
ADTS 缓冲区满溢 (ADTS Buffer Fullness):默认0x7FF 说明是码率可变的码流。
00-> 原始数据块数:表示 ADTS 帧中包含的 AAC 原始数据块数
当 number_of_raw_data_blocks_in_frame == 0 时,表示 ADTS 帧中只有 1 个 AAC 数据块
解析AAC文件的C语言代码
代码来源于:视音频数据处理入门:AAC音频码流解析
/**
* 最简单的视音频数据处理示例
* Simplest MediaData Test
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.youkuaiyun.com/leixiaohua1020
*
* 本项目包含如下几种视音频测试示例:
* (1)像素数据处理程序。包含RGB和YUV像素格式处理的函数。
* (2)音频采样数据处理程序。包含PCM音频采样格式处理的函数。
* (3)H.264码流分析程序。可以分离并解析NALU。
* (4)AAC码流分析程序。可以分离并解析ADTS帧。
* (5)FLV封装格式分析程序。可以将FLV中的MP3音频码流分离出来。
* (6)UDP-RTP协议分析程序。可以将分析UDP/RTP/MPEG-TS数据包。
*
* This project contains following samples to handling multimedia data:
* (1) Video pixel data handling program. It contains several examples to handle RGB and YUV data.
* (2) Audio sample data handling program. It contains several examples to handle PCM data.
* (3) H.264 stream analysis program. It can parse H.264 bitstream and analysis NALU of stream.
* (4) AAC stream analysis program. It can parse AAC bitstream and analysis ADTS frame of stream.
* (5) FLV format analysis program. It can analysis FLV file and extract MP3 audio stream.
* (6) UDP-RTP protocol analysis program. It can analysis UDP/RTP/MPEG-TS Packet.
*
*/
#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\n");
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;
}
int main()
{
simplest_aac_parser((char*)"./audio.aac");
return 0;
}
总结
AAC是编码格式,ADTS是一种容器格式,在处理AAC音频时需要注意两者的区别和联系。
ADTS格式在每个AAC音频帧的开头添加了一些头部信息,如采样率、声道数等,用于指示这个音频帧的属性。这样可以方便接收方识别和解析音频数据。
参考资料
【音视频 | AAC】AAC格式音频文件解析_aac 格式 详解-优快云博客
学习资料分享