【AAC文件数据解析和ADTS frame】

本文介绍了如何在VS2010环境下使用雷神的代码解析AAC音频文件,提供步骤指导,从文件加载到数据解析,包括ADTS frame结构解析和AAC帧信息展示,适合初学者入门学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考雷神的博客,我使用的是VS2010,加载AAC文件,读取数据解析,如果没有AAC文件的,可以网上下载一个格式工厂,转换出一个AAC文件出来,注意文件尽量小一点

工程:

效果:

代码是使用雷神的代码,然后我加了一些注释,让刚入门的能降低理解难度:

// my1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
//C++中malloc、free的头文件
#include <stdlib.h>


//解析ADTS frame结构
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)
	{
		//ADTS header占用的大小为7字节或者9字节,区别在于结尾是否有CRC效验
		//adts_fixed_header部分中的protection_absent为1时没有效验,为0时有效验,大小小于7字节就没有意义了
        if(buf_size  < 7 )
		{
            return -1;
        }
		//syncword占用12位,所以判断前12位,是否为0xFFF,用来分离AAC码流中每个ADTS frame
        if((buffer[0] == 0xff) && ((buffer[1] & 0xf0) == 0xf0) )
		{
			//frame_length是ADTS frame长度,按位存放,(第四个字节最后两位,第五个字节,第六个字节前3位)
            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;
    }

	//每次获取一个ADTS frame
    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=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))
	{
		//返回读取对象个数,ifile中读取1024*1024-offset,到aacbuffer+offset
        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};

			//使用的AAC级别,2位,0为AAC Main,1为 AAC LC (Low Complexity),2为 AAC SSR (Scalable Sampling Rate)
            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;
            }

			//采样率sampling_frequency_index,Sampling Frequencies[ ]数组查询对于采样率
            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 _tmain(int argc, _TCHAR* argv[])
{
	simplest_aac_parser("F:/123.aac");//acc文件路径

	return 0;
}

注意:

1、自己准备一个AAC的文件放在自己觉得方便的路径

2、使用调试模式打断点查看结果,在_tmain函数的return 0,打上断点,不要一下跑完了,

ADTS frame结构和信息:

参数长度 (bits)描述
syncword12同步字,占12bit,值固定,都是0xFFF,转成二进制就是111111111111,
ID1MPEG的版本,0表示MPEG-4,1表示MPEG-2
layer2固定值都是00
protection_absent1是否同步CRC效验,0说有,1说没有,长度差两个字节
profile2使用的AAC级别,0为AAC Main,1为 AAC LC (Low Complexity),2为 AAC SSR (Scalable Sampling Rate)
sampling_frequency_index4对应采样率
private_bit1私有流,编码时设置为0,解码时忽略
channel_configuration3

声道数,LF RF表示左右声道

original_copy1原创性,编码时设置为0,解码时忽略
home1编码时设置为0,解码时忽略
copyright_identification_bit 1受版权保护的流,编码时设置为0,解码时忽略
copyright_identification_start1版权开始,编码时设置为0,解码时忽略
frame_length13一个ADTS帧的长度包括ADTS头和AAC原始流
adts_buffer_fullness11缓冲区充满度,0x7FF 说明是码率可变的码流。
number_of_raw_data_blocks_in_frame2

表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。
所以说number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有一个AAC数据块。
(一个AAC原始帧包含一段时间内1024个采样及相关数据)

ADTS帧中的AAC帧(RDB)数减去1,为实现最大兼容性,每个ADTS帧始终使用1个AAC帧

CRC效验位16如果没有保护,这位为0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值