您的位置:首页 > 其它

AAC音频格式详解

2016-02-27 19:59 309 查看



关于AAC音频格式基本情况,可参考维基百科http://en.wikipedia.org/wiki/Advanced_Audio_Coding

AAC音频格式分析

AAC音频格式有ADIF和ADTS:

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

ADTS:AudioDataTransportStream音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。

简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。

语音系统对实时性要求较高,基本是这样一个流程,采集音频数据,本地编码,数据上传,服务器处理,数据下发,本地解码

ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。

ADTS帧结构:
header
body
ADTS帧首部结构:
序号长度(bits)说明
1Syncword12allbitsmustbe1
2MPEGversion10forMPEG-4,1forMPEG-2
3Layer2always0
4ProtectionAbsent1etto1ifthereisnoCRCand0ifthereisCRC
5Profile2theMPEG-4AudioObjectTypeminus1
6MPEG-4SamplingFrequencyIndex4MPEG-4SamplingFrequencyIndex(15isforbidden)
7PrivateStream1setto0whenencoding,ignorewhendecoding
8MPEG-4ChannelConfiguration3MPEG-4ChannelConfiguration(inthecaseof0,thechannelconfigurationissentviaaninband
PCE)
9Originality1setto0whenencoding,ignorewhendecoding
10Home1setto0whenencoding,ignorewhendecoding
11CopyrightedStream1setto0whenencoding,ignorewhendecoding
12CopyrightedStart1setto0whenencoding,ignorewhendecoding
13FrameLength13thisvaluemustinclude7or9bytesofheaderlength:FrameLength=(ProtectionAbsent==1?7:9)+size(AACFrame)
14BufferFullness11bufferfullness
15NumberofAACFrames2numberofAACframes(RDBs)inADTSframeminus1,formaximumcompatibilityalwaysuse1AACframeperADTSframe
16CRC16CRCifprotectionabsentis0
AAC解码

在解码方面,使用了开源的FAAD,http://www.audiocoding.com/faad2.html

sdk解压缩后,docs目录有详细的api说明文档,主要用到的有以下几个:
NeAACDecHandleNEAACAPINeAACDecOpen(void);
创建解码环境并返回一个句柄
voidNEAACAPINeAACDecClose(NeAACDecHandlehDecoder);
关闭解码环境
NeAACDecConfigurationPtrNEAACAPINeAACDecGetCurrentConfiguration(NeAACDecHandlehDecoder);
获取当前解码器库的配置
unsignedcharNEAACAPINeAACDecSetConfiguration(NeAACDecHandlehDecoder,NeAACDecConfigurationPtrconfig);
为解码器库设置一个配置结构
longNEAACAPINeAACDecInit(NeAACDecHandlehDecoder,unsignedchar*buffer,unsignedlongbuffer_size,unsignedlong*samplerate,unsignedchar*channels);
初始化解码器库
void*NEAACAPINeAACDecDecode(NeAACDecHandlehDecoder,NeAACDecFrameInfo*hInfo,unsignedchar*buffer,unsignedlongbuffer_size);
解码AAC数据


对以上api做了简单封装,写了一个解码类,涵盖了FAAD库的基本用法,感兴趣的朋友可以看看

MyAACDecoder.h:

/**

*

*filename:MyAACDecoder.h

*summary:convertaactowave

*author:caosiyang

*email:csy3228@gmail.com

*

*/

#ifndef__MYAACDECODER_H__

#define__MYAACDECODER_H__



#include"Buffer.h"

#include"mytools.h"

#include"WaveFormat.h"

#include"faad.h"

#include<iostream>

usingnamespacestd;



classMyAACDecoder{

public:

MyAACDecoder();

~MyAACDecoder();


int32_tDecode(char*aacbuf,uint32_taacbuflen);


constchar*WavBodyData()const{

return_mybuffer.Data();

}


uint32_tWavBodyLength()const{

return_mybuffer.Length();

}


constchar*WavHeaderData()const{

return_wave_format.getHeaderData();


}


uint32_tWavHeaderLength()const{

return_wave_format.getHeaderLength();

}


private:

MyAACDecoder(constMyAACDecoder&dec);

MyAACDecoder&operator=(constMyAACDecoder&rhs);


//initAACdecoder

int32_t_init_aac_decoder(char*aacbuf,int32_taacbuflen);


//destroyaacdecoder

void_destroy_aac_decoder();


//parseAACADTSheader,getframelength

uint32_t_get_frame_length(constchar*aac_header)const;


//AACdecoderproperties

NeAACDecHandle_handle;

unsignedlong_samplerate;

unsignedchar_channel;


Buffer_mybuffer;

WaveFormat_wave_format;

};



#endif/*__MYAACDECODER_H__*/


MyAACDecoder.cpp:

#include"MyAACDecoder.h"



MyAACDecoder::MyAACDecoder():_handle(NULL),_samplerate(44100),_channel(2),_mybuffer(4096,4096){

}



MyAACDecoder::~MyAACDecoder(){

_destroy_aac_decoder();

}



int32_tMyAACDecoder::Decode(char*aacbuf,uint32_taacbuflen){

int32_tres=0;

if(!_handle){

if(_init_aac_decoder(aacbuf,aacbuflen)!=0){

ERR1("::::initaacdecoderfailed::::");

return-1;

}

}


//clean_mybuffer

_mybuffer.Clean();


uint32_tdonelen=0;

uint32_twav_data_len=0;

while(donelen<aacbuflen){

uint32_tframelen=_get_frame_length(aacbuf+donelen);


if(donelen+framelen>aacbuflen){

break;

}


//decode

NeAACDecFrameInfoinfo;

void*buf=NeAACDecDecode(_handle,&info,(unsignedchar*)aacbuf+donelen,framelen);

if(buf&&info.error==0){

if(info.samplerate==44100){

//44100Hz

//src:2048samples,4096bytes

//dst:2048samples,4096bytes

uint32_ttmplen=info.samples*16/8;

_mybuffer.Fill((constchar*)buf,tmplen);

wav_data_len+=tmplen;

}elseif(info.samplerate==22050){

//22050Hz

//src:1024samples,2048bytes

//dst:2048samples,4096bytes

short*ori=(short*)buf;

shorttmpbuf[info.samples*2];

uint32_ttmplen=info.samples*16/8*2;

for(int32_ti=0,j=0;i<info.samples;i+=2){

tmpbuf[j++]=ori[i];

tmpbuf[j++]=ori[i+1];

tmpbuf[j++]=ori[i];

tmpbuf[j++]=ori[i+1];

}

_mybuffer.Fill((constchar*)tmpbuf,tmplen);

wav_data_len+=tmplen;

}

}else{

ERR1("NeAACDecDecode()failed");

}


donelen+=framelen;

}


//generateWaveheader

_wave_format.setSampleRate(_samplerate);

_wave_format.setChannel(_channel);

_wave_format.setSampleBit(16);

_wave_format.setBandWidth(_samplerate*16*_channel/8);

_wave_format.setDataLength(wav_data_len);

_wave_format.setTotalLength(wav_data_len+44);

_wave_format.GenerateHeader();


return0;

}



uint32_tMyAACDecoder::_get_frame_length(constchar*aac_header)const{

uint32_tlen=*(uint32_t*)(aac_header+3);

len=ntohl(len);//LittleEndian

len=len<<6;

len=len>>19;

returnlen;

}



int32_tMyAACDecoder::_init_aac_decoder(char*aacbuf,int32_taacbuflen){

unsignedlongcap=NeAACDecGetCapabilities();

_handle=NeAACDecOpen();

if(!_handle){

ERR1("NeAACDecOpen()failed");

_destroy_aac_decoder();

return-1;

}


NeAACDecConfigurationPtrconf=NeAACDecGetCurrentConfiguration(_handle);

if(!conf){

ERR1("NeAACDecGetCurrentConfiguration()failed");

_destroy_aac_decoder();

return-1;

}

NeAACDecSetConfiguration(_handle,conf);


longres=NeAACDecInit(_handle,(unsignedchar*)aacbuf,aacbuflen,&_samplerate,&_channel);

if(res<0){

ERR1("NeAACDecInit()failed");

_destroy_aac_decoder();

return-1;

}

//fprintf(stdout,"SampleRate=%d\n",_samplerate);

//fprintf(stdout,"Channel=%d\n",_channel);

//fprintf(stdout,"::::initaacdecoderdone::::\n");


return0;

}



voidMyAACDecoder::_destroy_aac_decoder(){

if(_handle){

NeAACDecClose(_handle);

_handle=NULL;

}

}




1.ADTS是个啥

ADTS全称是(AudioDataTransportStream),是AAC的一种十分常见的传输格式。

记得第一次做demux的时候,把AAC音频的ES流从FLV封装格式中抽出来送给硬件解码器时,不能播;保存到本地用pc的播放器播时,我靠也不能播。当时崩溃了,后来通过查找资料才知道。一般的AAC解码器都需要把AAC的ES流打包成ADTS的格式,一般是在AACES流前添加7个字节的ADTSheader。也就是说你可以吧ADTS这个头看作是AAC的frameheader。

ADTSAAC

ADTS_headerAACESADTS_headerAACES[align=center]...[/align]
ADTS_headerAACES

2.ADTS内容及结构

ADTS头中相对有用的信息采样率、声道数、帧长度。想想也是,我要是解码器的话,你给我一堆得AAC音频ES流我也解不出来。每一个带ADTS头信息的AAC流会清晰的告送解码器他需要的这些信息。

一般情况下ADTS的头信息都是7个字节,分为2部分:

adts_fixed_header();

adts_variable_header();






syncword:同步头总是0xFFF,allbitsmustbe1,代表着一个ADTS帧的开始

ID:MPEGVersion:0forMPEG-4,1forMPEG-2

Layer:always:'00'

profile:表示使用哪个级别的AAC,有些芯片只支持AACLC。在MPEG-2AAC中定义了3种:



sampling_frequency_index:表示使用的采样率下标,通过这个下标在SamplingFrequencies[]数组中查找得知采样率的值。

Thereare13supportedfrequencies:

0:96000Hz
1:88200Hz
2:64000Hz
3:48000Hz
4:44100Hz
5:32000Hz
6:24000Hz
7:22050Hz
8:16000Hz
9:12000Hz
10:11025Hz
11:8000Hz
12:7350Hz
13:Reserved
14:Reserved
15:frequencyiswrittenexplictly

channel_configuration:表示声道数

0:DefinedinAOTSpecifcConfig
1:1channel:front-center
2:2channels:front-left,front-right
3:3channels:front-center,front-left,front-right
4:4channels:front-center,front-left,front-right,back-center
5:5channels:front-center,front-left,front-right,back-left,back-right
6:6channels:front-center,front-left,front-right,back-left,back-right,LFE-channel
7:8channels:front-center,front-left,front-right,side-left,side-right,back-left,back-right,LFE-channel
8-15:Reserved



frame_length:一个ADTS帧的长度包括ADTS头和AAC原始流.

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

3.将AAC打包成ADTS格式

如果是通过嵌入式高清解码芯片做产品的话,一般情况的解码工作都是由硬件来完成的。所以大部分的工作是把AAC原始流打包成ADTS的格式,然后丢给硬件就行了。

通过对ADTS格式的了解,很容易就能把AAC打包成ADTS。我们只需得到封装格式里面关于音频采样率、声道数、元数据长度、aac格式类型等信息。然后在每个AAC原始流前面加上个ADTS头就OK了。

贴上ffmpeg中添加ADTS头的代码,就可以很清晰的了解ADTS头的结构:

[html]view
plaincopy

intff_adts_write_frame_header(ADTSContext*ctx,

uint8_t*buf,intsize,intpce_size)

{

PutBitContextpb;

init_put_bits(&pb,buf,ADTS_HEADER_SIZE);

/*adts_fixed_header*/

put_bits(&pb,12,0xfff);/*syncword*/

put_bits(&pb,1,0);/*ID*/

put_bits(&pb,2,0);/*layer*/

put_bits(&pb,1,1);/*protection_absent*/

put_bits(&pb,2,ctx->objecttype);/*profile_objecttype*/

put_bits(&pb,4,ctx->sample_rate_index);

put_bits(&pb,1,0);/*private_bit*/

put_bits(&pb,3,ctx->channel_conf);/*channel_configuration*/

put_bits(&pb,1,0);/*original_copy*/

put_bits(&pb,1,0);/*home*/

/*adts_variable_header*/

put_bits(&pb,1,0);/*copyright_identification_bit*/

put_bits(&pb,1,0);/*copyright_identification_start*/

put_bits(&pb,13,ADTS_HEADER_SIZE+size+pce_size);/*aac_frame_length*/

put_bits(&pb,11,0x7ff);/*adts_buffer_fullness*/

put_bits(&pb,2,0);/*number_of_raw_data_blocks_in_frame*/

flush_put_bits(&pb);

return0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: