天天看点

AAC音频转PCM原始码流

前言

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

继续阅读