android: AAC檔案解析

yangxi_001發表於2015-08-24

AAC音訊格式分析

AAC音訊格式有ADIF和ADTS:

ADIF:Audio Data Interchange Format 音訊資料交換格式。這種格式的特徵是可以確定的找到這個音訊資料的開始,不需進行在音訊資料流中間開始的解碼,即它的解碼必須在明確定義的開始處進行。故這種格式常用在磁碟檔案中。

ADTS:Audio Data Transport Stream 音訊資料傳輸流。這種格式的特徵是它是一個有同步字的位元流,解碼可以在這個流中任何位置開始。它的特徵類似於mp3資料流格式。

簡單說,ADTS可以在任意幀解碼,也就是說它每一幀都有頭資訊。ADIF只有一個統一的頭,所以必須得到所有的資料後解碼。且這兩種的header的格式也是不同的,目前一般編碼後的和抽取出的都是ADTS格式的音訊流。

語音系統對實時性要求較高,基本是這樣一個流程,採集音訊資料,本地編碼,資料上傳,伺服器處理,資料下發,本地解碼

ADTS是幀序列,本身具備流特徵,在音訊流的傳輸與處理方面更加合適。

 

ADTS幀結構:

header

body

ADTS幀首部結構:

序號 長度(bits) 說明
1 Syncword 12 all bits must be 1
2 MPEG version 1 0 for MPEG-4, 1 for MPEG-2
3 Layer 2 always 0
4 Protection Absent 1 et to 1 if there is no CRC and 0 if there is CRC
5 Profile 2 the MPEG-4 Audio Object Type minus 1
6 MPEG-4 Sampling Frequency Index 4 MPEG-4 Sampling Frequency Index (15 is forbidden)
7 Private Stream 1 set to 0 when encoding, ignore when decoding
8 MPEG-4 Channel Configuration 3 MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE)
9 Originality 1 set to 0 when encoding, ignore when decoding
10 Home 1 set to 0 when encoding, ignore when decoding
11 Copyrighted Stream 1 set to 0 when encoding, ignore when decoding
12 Copyrighted Start 1 set to 0 when encoding, ignore when decoding
13 Frame Length 13 this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
14 Buffer Fullness 11 buffer fullness
15 Number of AAC Frames 2 number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame
16 CRC 16 CRC if protection absent is 0

 

 

AAC解碼

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

sdk解壓縮後,docs目錄有詳細的api說明文件,主要用到的有以下幾個:

NeAACDecHandle NEAACAPI NeAACDecOpen(void);
建立解碼環境並返回一個控制程式碼
void NEAACAPI NeAACDecClose(NeAACDecHandle hDecoder);
關閉解碼環境
NeAACDecConfigurationPtr NEAACAPI NeAACDecGetCurrentConfiguration(NeAACDecHandle hDecoder);
獲取當前解碼器庫的配置
unsigned char NEAACAPI NeAACDecSetConfiguration(NeAACDecHandle hDecoder, NeAACDecConfigurationPtr config);
為解碼器庫設定一個配置結構
long NEAACAPI NeAACDecInit(NeAACDecHandle hDecoder, unsigned char *buffer, unsigned long buffer_size, unsigned long *samplerate, unsigned char *channels);
初始化解碼器庫
void* NEAACAPI NeAACDecDecode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo, unsigned char *buffer, unsigned long buffer_size);
解碼AAC資料

 

 

對以上api做了簡單封裝,寫了一個解碼類,涵蓋了FAAD庫的基本用法,感興趣的朋友可以看看

MyAACDecoder.h:

<span class="rem" style="color: rgb(0, 128, 0);">/**</span>
 *
<span class="rem" style="color: rgb(0, 128, 0);"> * filename: MyAACDecoder.h</span>
 * summary: convert aac to wave
<span class="rem" style="color: rgb(0, 128, 0);"> * author: caosiyang </span>
 * email: csy3228@gmail.com
<span class="rem" style="color: rgb(0, 128, 0);"> *</span>
 */
#ifndef __MYAACDECODER_H__
#define __MYAACDECODER_H__
 
 
#include <span class="str" style="color: rgb(0, 96, 128);">"Buffer.h"</span>
#include "mytools.h"
#include <span class="str" style="color: rgb(0, 96, 128);">"WaveFormat.h"</span>
#include "faad.h"
#include <iostream>
using namespace std;
 
 
<span class="kwrd" style="color: rgb(0, 0, 255);">class</span> MyAACDecoder {
public:
    MyAACDecoder();
    ~MyAACDecoder();
 
    int32_t Decode(char *aacbuf, uint32_t aacbuflen);
 
    const char* WavBodyData() const {
        <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> _mybuffer.Data();
    }
 
    uint32_t WavBodyLength() const {
        <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> _mybuffer.Length();
    }
 
    const char* WavHeaderData() const {
        <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> _wave_format.getHeaderData();
 
    }
 
    uint32_t WavHeaderLength() <span class="kwrd" style="color: rgb(0, 0, 255);">const</span> {
        return _wave_format.getHeaderLength();
    }
 
<span class="kwrd" style="color: rgb(0, 0, 255);">private</span>:
    MyAACDecoder(const MyAACDecoder &dec);
    MyAACDecoder& <span class="kwrd" style="color: rgb(0, 0, 255);">operator</span>=(<span class="kwrd" style="color: rgb(0, 0, 255);">const</span> MyAACDecoder &rhs);
 
    <span class="rem" style="color: rgb(0, 128, 0);">//init AAC decoder</span>
    int32_t _init_aac_decoder(char *aacbuf, int32_t aacbuflen);
 
    //destroy aac decoder
    <span class="kwrd" style="color: rgb(0, 0, 255);">void</span> _destroy_aac_decoder();
 
    <span class="rem" style="color: rgb(0, 128, 0);">//parse AAC ADTS header, get frame length</span>
    uint32_t _get_frame_length(const char *aac_header) const;
 
    //AAC decoder properties
    NeAACDecHandle _handle;
    unsigned long _samplerate;
    unsigned <span class="kwrd" style="color: rgb(0, 0, 255);">char</span> _channel;
 
    Buffer _mybuffer;
    WaveFormat _wave_format;
};
 
 
#endif /*__MYAACDECODER_H__*/

 

MyAACDecoder.cpp:

#include <span class="str" style="color: rgb(0, 96, 128);">"MyAACDecoder.h"</span>
 
 
MyAACDecoder::MyAACDecoder(): _handle(NULL), _samplerate(44100), _channel(2), _mybuffer(4096, 4096) {
}
 
 
MyAACDecoder::~MyAACDecoder() {
    _destroy_aac_decoder();
}
 
 
int32_t MyAACDecoder::Decode(<span class="kwrd" style="color: rgb(0, 0, 255);">char</span> *aacbuf, uint32_t aacbuflen) {
    int32_t res = 0;
    <span class="kwrd" style="color: rgb(0, 0, 255);">if</span> (!_handle) {
        if (_init_aac_decoder(aacbuf, aacbuflen) != 0) {
            ERR1(<span class="str" style="color: rgb(0, 96, 128);">":::: init aac decoder failed ::::"</span>);
            return -1;
        }
    }
 
    //clean _mybuffer
    _mybuffer.Clean();
 
    uint32_t donelen = 0;
    uint32_t wav_data_len = 0;
    <span class="kwrd" style="color: rgb(0, 0, 255);">while</span> (donelen < aacbuflen) {
        uint32_t framelen = _get_frame_length(aacbuf + donelen);
 
        if (donelen + framelen > aacbuflen) {
            <span class="kwrd" style="color: rgb(0, 0, 255);">break</span>;
        }
 
        //decode
        NeAACDecFrameInfo info;
        void *buf = NeAACDecDecode(_handle, &info, (unsigned char*)aacbuf + donelen, framelen);
        <span class="kwrd" style="color: rgb(0, 0, 255);">if</span> (buf && info.error == 0) {
            if (info.samplerate == 44100) {
                <span class="rem" style="color: rgb(0, 128, 0);">//44100Hz</span>
                //src: 2048 samples, 4096 bytes
                <span class="rem" style="color: rgb(0, 128, 0);">//dst: 2048 samples, 4096 bytes</span>
                uint32_t tmplen = info.samples * 16 / 8;
                _mybuffer.Fill((<span class="kwrd" style="color: rgb(0, 0, 255);">const</span> <span class="kwrd" style="color: rgb(0, 0, 255);">char</span>*)buf, tmplen);
                wav_data_len += tmplen;
            } <span class="kwrd" style="color: rgb(0, 0, 255);">else</span> <span class="kwrd" style="color: rgb(0, 0, 255);">if</span> (info.samplerate == 22050) {
                //22050Hz
                <span class="rem" style="color: rgb(0, 128, 0);">//src: 1024 samples, 2048 bytes</span>
                //dst: 2048 samples, 4096 bytes
                <span class="kwrd" style="color: rgb(0, 0, 255);">short</span> *ori = (<span class="kwrd" style="color: rgb(0, 0, 255);">short</span>*)buf;
                short tmpbuf[info.samples * 2];
                uint32_t tmplen = info.samples * 16 / 8 * 2;
                for (int32_t i = 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((const char*)tmpbuf, tmplen);
                wav_data_len += tmplen;
            }
        } <span class="kwrd" style="color: rgb(0, 0, 255);">else</span> {
            ERR1("NeAACDecDecode() failed");
        }
 
        donelen += framelen;
    }
 
    //generate Wave header
    _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();
 
    <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> 0;
}
 
 
uint32_t MyAACDecoder::_get_frame_length(<span class="kwrd" style="color: rgb(0, 0, 255);">const</span> <span class="kwrd" style="color: rgb(0, 0, 255);">char</span> *aac_header) <span class="kwrd" style="color: rgb(0, 0, 255);">const</span> {
    uint32_t len = *(uint32_t *)(aac_header + 3);
    len = ntohl(len); <span class="rem" style="color: rgb(0, 128, 0);">//Little Endian</span>
    len = len << 6;
    len = len >> 19;
    return len;
}
 
 
int32_t MyAACDecoder::_init_aac_decoder(char* aacbuf, int32_t aacbuflen) {
    unsigned <span class="kwrd" style="color: rgb(0, 0, 255);">long</span> cap = NeAACDecGetCapabilities();
    _handle = NeAACDecOpen();
    <span class="kwrd" style="color: rgb(0, 0, 255);">if</span> (!_handle) {
        ERR1("NeAACDecOpen() failed");
        _destroy_aac_decoder();
        return -1;
    }
 
    NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(_handle);
    if (!conf) {
        ERR1(<span class="str" style="color: rgb(0, 96, 128);">"NeAACDecGetCurrentConfiguration() failed"</span>);
        _destroy_aac_decoder();
        <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> -1;
    }
    NeAACDecSetConfiguration(_handle, conf);
 
    <span class="kwrd" style="color: rgb(0, 0, 255);">long</span> res = NeAACDecInit(_handle, (unsigned <span class="kwrd" style="color: rgb(0, 0, 255);">char</span> *)aacbuf, aacbuflen, &_samplerate, &_channel);
    if (res < 0) {
        ERR1(<span class="str" style="color: rgb(0, 96, 128);">"NeAACDecInit() failed"</span>);
        _destroy_aac_decoder();
        <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> -1;
    }
    <span class="rem" style="color: rgb(0, 128, 0);">//fprintf(stdout, "SampleRate = %d\n", _samplerate);</span>
    //fprintf(stdout, "Channel    = %d\n", _channel);
    <span class="rem" style="color: rgb(0, 128, 0);">//fprintf(stdout, ":::: init aac decoder done ::::\n");</span>
 
    <span class="kwrd" style="color: rgb(0, 0, 255);">return</span> 0;
}
 
 
<span class="kwrd" style="color: rgb(0, 0, 255);">void</span> MyAACDecoder::_destroy_aac_decoder() {
    if (_handle) {
        NeAACDecClose(_handle);
        _handle = NULL;
    }
}

相關文章