前言

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);
}