音频格式aac

时间:2024-03-05 17:47:41

 AAC是高级音频编码(Advanced Audio Coding)的缩写,出现于1997年,最初是基于MPEG-2的音频编码技术。由Fraunhofer IIS、Dolby Laboratories、AT&T、Sony等公司共同开发,目的是取代MP3格式。2000年,MPEG-4标准出台,AAC重新集成了其它技术(PS,SBR),为区别于传统的MPEG-2 AAC,故含有SBR或PS特性的AAC又称为MPEG-4 AAC。

AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS,SBR等),衍生出了LC-AAC,HE-AAC,HE-AACv2三种主要的编码,LC-AAC就是比较传统的AAC,相对而言,主要用于中高码率(>=80Kbps),HE-AAC(相当于AAC+SBR)主要用于中低码(<=80Kbps),而新近推出的HE-AACv2(相当于AAC+SBR+PS)主要用于低码率(<=48Kbps),事实上大部分编码器设成<=48Kbps自动启用PS技术,而>48Kbps就不加PS,就相当于普通的HE-AAC。

一、AAC音频文件格式

1. AAC的音频文件格式有ADIF & ADTS

       ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。AAC的ADIF格式见下图:

      

       ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。AAC的ADTS的一般格式见下图:

      图中表示出了ADTS一帧的简明结构,其两边的空白矩形表示一帧前后的数据。

2. ADIF和ADTS的header

ADIF 的头信息

ADIF头信息位于AAC文件的起始处,接下来就是连续的 raw data blocks。 组成ADIF头信息的各个域如下所示:

ADTS头信息

ADTS头分 为固定头和可变头,共计7字节。固定头信息中的数据每一帧都相同,而可变头信息则在帧与帧之间可变。

ADTS 的固定头信息:

 

ADTS的可变头信息:

    

adts_fixed_header(){
    syncword: 12 bslbf
    ID: 1 bslbf
    layer: 2 uimsbf
    protection_absent: 1 bslbf
    profile: 2 uimsbf
    sampling_frequency_index: 4 uimsbf
    private_bit: 1 bslbf
    channel_configuration: 3 uimsbf
    original/copy: 1 bslbf
    home: 1 bslbf
 }
adts_variable_header(){
    copyright_identification_bit: 1 bslbf
    copyright_identification_start: 1 bslbf
    frame_length: 13 bslbf
    adts_buffer_fullness: 11 bslbf
    number_of_raw_data_blocks_in_frame: 2 uimsfb
}

syncword 同步字为12比特的“1111 1111 1111”,说明一个ADTS帧的开始。

ID MPEG 标示符, 设置为1。

layer Indicates which layer is used,Set to ‘00’

protection_absent 表示是否误码校验

profile 表示使用哪个级别的AAC,如01  Low Complexity(LC)--- AACLC

sampling_frequency_index 表示使用的采样率下标

sampling_frequency_index sampling frequeny [Hz]
       0x0       96000
       0x1           88200
       0x2          64000
       0x3          48000
       0x4          44100
       0x5          32000
       0x6            24000
       0x7          22050
       0x8          16000
       0x9          2000
       0xa          11025
       0xb          8000
       0xc          reserved
       0xd          reserved
       0xe          reserved
       0xf           reserved

channel_configuration 表示声道数。

frame_length 一个ADTS帧的长度包括ADTS头和raw data block。

adts_buffer_fullness  0x7FF 说明是码率可变的码流

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

二、AAC帧解析

如下程序拷贝自leixiaohua,视音频数据处理入门:AAC音频码流解析

注:一个aac原始帧包含1024个采样点,aac编码后帧大小不定。AAC帧,采集数据为双通道,16位数据时,根据公式, 一帧数据量大小 = 1024*2 *16/8 = 4096

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

simplest_aac_parser("nocturne.aac");

统计结果如下:

-----+- ADTS Frame Table -+------+
 NUM | Profile | Frequency| Size |
-----+---------+----------+------+
    0|       LC|   44100Hz|   371|
    1|       LC|   44100Hz|   372|
    2|       LC|   44100Hz|   371|
    3|       LC|   44100Hz|   372|
    4|       LC|   44100Hz|   371|
    5|       LC|   44100Hz|   372|
    6|       LC|   44100Hz|   371|
    7|       LC|   44100Hz|   372|
    8|       LC|   44100Hz|   371|
......
 1285|       LC|   44100Hz|   371|
 1286|       LC|   44100Hz|   372|
 1287|       LC|   44100Hz|   371|
 1288|       LC|   44100Hz|   372|
 1289|       LC|   44100Hz|   371|
 1290|       LC|   44100Hz|   372|
 1291|       LC|   44100Hz|   371|

 

参考:

1. AAC格式简介  leixiaohua

2. 视音频数据处理入门:AAC音频码流解析 leixiaohua

3. AAC 格式分析 

4. aac和mp3的区别