前言
AAC是一种音频压缩格式,用于替代MP33格式,在最开始是基于MPEG-2的音频编码技术,后来加入了无损压缩的SBR技术和PS技术,为了区别于传统的MPEG-2 AAC又称为MPEG-4 AAC。
AAC 的分类
AAC LC
也就是低复杂度的AAC,没有添加无损压缩技术。
AAC HE V1
高效的AAC,适合用于低码率编码,在AAC LC的基础上 添加了SBR(频段复制)技术,在保存低频音频时,大量的高频并没有使用,数据量庞大,而去除高频会造成数据失真,使用SBR技术,将高低频分开保存,低频保存主要数据,高频保存为数不多的音质数据,使文件更小,在比较理想状态下,大小降低一半。
AAC HE V2
在 AAC HE V1的基础上,添加了 PS(参数立体声)技术,在保存双声道音频时,需要保存两份声道数据,而使用PS技术,只保存一份数据,另一份只保留一部分参数,通过第一份数据和第二份的参数计算出第二份的声道数据,在比较理想状态下,大小降低一半。
AAC 格式分类
AAC帧格式都是由两部分组成 head和data。
ADIF格式
Audio Data Interchange Format 音频数据交换格式。这种格式,HEAD都放在文件的前面,故这种格式常用在磁盘文件中。
HEAD | DATA | DATA |
ADTS格式
Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。ADTS可以在任意帧解码,也就是说它每一帧都有头信息,常用于网络传输。
HEAD | DATA | HEAD | DATA |
HEAD用于保存一些帧的数据。在HEAD中的前 12byte是同步字且为0XFFF,用于区分每一个帧,也就是每个帧的帧头都由0xFFF开始。帧头的大小可以是7字节,也可以是9字节(在7字节后面多了2字节的CRC校验),在后面就是一定长度的DATA.
如下,一个帧头的构成(9字节)
固定头信息 | 可变头信息 | CRC校验 |
28b | 28b | 16b |
如下,帧头的参数
参数 | 解释 | 占用byte大小 |
syncword同步字 | 总是0XFFF | 12 |
id | 0 为MPEG-4 1为MPEG-2 | 1 |
layer | 总是00 | 2 |
protection_absent | 1 为无crc 0为 有crc | 1 |
profile | 0 aac main , 1 aac lc ,2 aac ssr, 3 aac ltp | 2 |
sampling_frequency_index | 采样率0x0 --0xc | 4 |
private_bit | 1 | |
channel_confuguration | 声道数 | 3 |
original_copy | 1 | |
home | 1 | |
copy_identification_bit | 1 | |
aac_frame_length | 一个adts帧的长度包括adts头(7/9)和aac原始流,也就是说,原始流长度在这个值减去7/9 | 13 |
adts_buffer_fullness | 0x7ff说明是码率可变的码流 | 11 |
number_of_raw_data_blocks_in_frame | 表示adts中有这个值加1个aac原始帧 | 2 |
crc | crc校验 | 16 |
AAC LC 低复杂度的 ADTS转pcm代码
简单转换pcm代码,存储的data就是pcm原始码流情况下
// url[in] aac data url_out[out] pcm data
#include<iostream>
#include<windows.h>
int aac2pcm(char * url, char * url_out)
{
int RunStep = 0;
int CrcStau = 0;
int sampling = 0;//采样率
unsigned int size = 0;//数据长度
FILE *file = fopen(url, "rb");
FILE *file_out = fopen(url_out, "wb+");
if (!file || !file_out) {
printf("Open file error");
return -1;
}
while (!feof(file))
{
int data_size = 0;
if (RunStep == 0)
{
unsigned char buff;
while ((data_size = fread(&buff, 1, 1, file)) == 1)
{
if (buff == 0xff)
{
data_size = fread(&buff, 1, 1, file);
if (data_size == 1 && (buff & 0xf0) == 0xf0)
{
printf("fff--");
if (buff & 0x08 == 0x08)//id
{
printf("MPEG-2--");
}
else
{
printf("MPEG-4--");
}
unsigned char buffer = buff & 0x1;
if (buffer << 7 != 0)//protection_absent
{
printf("no crc--");
CrcStau = 0;
}
else
{
printf("crc--");
CrcStau = 1;
}
RunStep = 1;
break;
}
}
}
printf("\n");
}
if (RunStep == 1)
{
unsigned char buff[5];
data_size = fread(&buff, 1, 5, file);
if (data_size < 5)
{
printf("error \n");
fclose(file);
fclose(file_out);
return 0;
}
if (buff[0] & 0xc0 != 0x40)//profile
{
printf(" 非 lc的aac--");
}
else
{
printf(" 为 lc的aac--");
}
int sampling_buff = sampling;//获得采样率
unsigned char buffer = buff[0] & 0x3c;
switch (buffer >> 2)
{
case 0x0:
sampling = 96000;
break;
break;
case 0x1:
sampling = 88200;
break;
case 0x2:
sampling = 64000;
break;
case 0x3:
sampling = 48000;
break;
case 0x4:
sampling = 44100;
break;
case 0x5:
sampling = 32000;
break;
case 0x6:
sampling = 24000;
break;
case 0x7:
sampling = 22050;
break;
case 0x8:
sampling = 16000;
break;
case 0x9:
sampling = 12000;
break;
case 0xa:
sampling = 11025;
break;
case 0xb:
sampling = 8000;
break;
case 0xc:
sampling = 7350;
break;
default:
break;
}
printf("采样率:%d--", sampling);
if ((buff[0] & 0x01 != 0) || (buff[1] & 0xc0 != 0x80))//非双声道
{
printf("非双声道--");
}
size |= ((buff[1] & 0x03) << 11); //high 2 bit
size |= buff[2] << 3; //middle 8 bit
size |= ((buff[3] & 0xe0) >> 5); //low 3bit
RunStep = 2;
printf("\n");
}
if (RunStep == 2)
{
unsigned char *data = (unsigned char *)malloc((size - 7));
unsigned char * p_data=data;
data_size = fread(data, 1, (size - 7), file);
if (data_size< size - 7)
{
printf("error\n");
fclose(file);
fclose(file_out);
system("pause");
return -1;
}
else
{
data += CrcStau * 2;
fwrite(data, 1, size - 7 - CrcStau * 2, file_out);
RunStep = 0;
}
//Sleep(500);
free(p_data);
}
}
fclose(file);
fclose(file_out);
}