AAC音频格式分析与解码
2015-11-19 15:54
288 查看
转自: http://www.cnblogs.com/caosiyang/archive/2012/07/16/2594029.html
关于AAC音频格式基本情况,可参考维基百科http://en.wikipedia.org/wiki/Advanced_Audio_Coding
AAC音频格式分析
AAC音频格式有ADIF和ADTS:
ADIF:AudioDataInterchangeFormat音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
ADTS:AudioDataTransportStream音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。
语音系统对实时性要求较高,基本是这样一个流程,采集音频数据,本地编码,数据上传,服务器处理,数据下发,本地解码
ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。
ADTS帧结构:
ADTS帧首部结构:
AAC解码
在解码方面,使用了开源的FAAD,http://www.audiocoding.com/faad2.html
sdk解压缩后,docs目录有详细的api说明文档,主要用到的有以下几个:
对以上api做了简单封装,写了一个解码类,涵盖了FAAD库的基本用法,感兴趣的朋友可以看看
MyAACDecoder.h:
MyAACDecoder.cpp:
Fromhttp://www.cnblogs.com/caosiyang/
关于AAC音频格式基本情况,可参考维基百科
AAC音频格式分析
AAC音频格式有ADIF和ADTS:
ADIF:AudioDataInterchangeFormat音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
ADTS:AudioDataTransportStream音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。
语音系统对实时性要求较高,基本是这样一个流程,采集音频数据,本地编码,数据上传,服务器处理,数据下发,本地解码
ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。
ADTS帧结构:
header | body |
序号 | 域 | 长度(bits) | 说明 |
1 | Syncword | 12 | allbits must be1 |
2 | MPEGversion | 1 | 0forMPEG-4,1forMPEG-2 |
3 | Layer | 2 | always0 |
4 | ProtectionAbsent | 1 | etto1ifthereisnoCRCand0ifthereisCRC |
5 | Profile | 2 | the |
6 | MPEG-4SamplingFrequencyIndex | 4 | |
7 | PrivateStream | 1 | setto0whenencoding,ignorewhendecoding |
8 | MPEG-4ChannelConfiguration | 3 | |
9 | Originality | 1 | setto0whenencoding,ignorewhendecoding |
10 | Home | 1 | setto0whenencoding,ignorewhendecoding |
11 | CopyrightedStream | 1 | setto0whenencoding,ignorewhendecoding |
12 | CopyrightedStart | 1 | setto0whenencoding,ignorewhendecoding |
13 | FrameLength | 13 | thisvaluemustinclude7or9bytesofheaderlength:FrameLength=(ProtectionAbsent==1?7:9)+size(AACFrame) |
14 | BufferFullness | 11 | bufferfullness |
15 | NumberofAACFrames | 2 | numberofAACframes(RDBs)inADTSframe minus1,formaximumcompatibilityalwaysuse1AACframeperADTSframe |
16 | CRC | 16 | CRCif protectionabsent is0 |
AAC解码
在解码方面,使用了开源的FAAD,
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;
}
}
From
相关文章推荐
- SSH:Struts1框架(采用struts上传文件)
- 输入设备驱动之按键设备驱动_笔记
- 关于学习angularJS 的一些心得
- oracle数据同比的时候除数为0该怎么处理
- VVDocumenter-Xcode在Xcode升级后不能用的解决办法
- 有人向我提了一个 Bug,说 5 分钟就可以搞定
- 策略模式与简单工厂模式
- Android官方提供的支持不同屏幕大小的全部方法(转)
- 监视在input框中按下回车(enter) js实现
- JS 原生方法封装
- Mac安装非app store下载的软件
- android canvas.drawText()的研究
- 实习心得
- iOS 9 适配中出现的坑
- Netty Memory Leak Error
- Linux_Grub2、系统启动流程_RHEL7
- webView 显示一段 html 代码
- 芯片软件复位不成功
- HTML常用标签大全及html标签的特点
- 一次纠结与喜悦的liunx+apache+php+mysql的安装过程