libmad音頻解碼庫分析--libmad簡介

MAD(libmad)是一個開源的高精度MPEG音頻解碼庫,支持MPEG-1標準。libmad提供24-bitPCM輸出,徹底定點計算,很是適合在沒有浮點支持的嵌入式硬件平臺上使用。使用libmad提供的一系列API能夠實現MP3文件的解碼。

mad.h」頭文件定義了libmad的數據結構及API函數[15]編程

4 libmad中的主要數據結構數據結構

主要數據結構函數

做用this

struct mad_streamspa

存放解碼前的Bitstream數據指針

struct mad_synthcode

存放解碼合成濾波後的PCM數據orm

struct mad_pcmip

定義了音頻的採樣率,聲道個數和PCM採樣數據,用來初始化音頻ci

struct mad_frame

記錄MPEG幀解碼後PCM數據的數據結構,其中的mad_header用來記錄MPEG幀的基本信息,好比MPEG層數、聲道模式、流比特率、採樣比特率。聲道模式包括單聲道、雙聲道、聯合立體混音道以及通常立體聲。

     MAD經過回調函數機制來實現解碼,每一個回調函數會返回一個枚舉類型mad_flow,經過mad_flow能夠控制解碼的過程。在未經處理的狀況下,MAD通常輸出32bit,以little endian格式存放在mad_fixed_t中的數據。可是大多數的聲卡並不能支持輸出高達32bit精度的數據,於是還必須對mad_fixed_t進行量化,圓滑處理以及抖動,使到採樣信號降到16bit精度。MAD負責的只是解碼的過程,它工做過程是:從外部獲取輸入,逐幀解碼,在解碼的過程當中返回信息,而後獲得解碼結果。開發人員要手動設置輸入輸出。

   編程實現解碼的方法爲:初始化mad_decoder,裏面包含了指向輸入、輸出、濾波、錯誤和消息回調函數的指針。經過mad_decoder_init()實現初始化[16]

struct mad_decoder decoder;

struct my_playbuf playbuf;                            //設置數據緩衝區

mad_decoder_init(&decoder,&playbuf,input_func,header_func,/*filter*/0, output_func, /*error*/ 0, /* message */ 0);

在這個初始化函數裏面,回調輸入函數指向了input_func,處理幀頭信息的函數指向了header_func,而輸出函數則爲output_func。其它的濾波,錯誤和信息函數沒有設置,置0

接着,MAD進入了一個解碼的循環過程:

當解碼函數裏面的數據解碼完畢時,調用input_func函數;

input_func函數告知解碼函數所有數據已經解碼完畢,則MAD處理退出;

對幀頭進行解碼,調用header_func函數;

對幀中的主數據進行解碼;

調用filter_func函數;

將解碼數據輸出,調用output_func函數;

重複上述步驟。

MAD在每進行一幀的解碼結束後都會詢問mad_flow的狀態,以決定是否進行下一幀的解碼。enum mad_flow的數據結構定義以下:

enum mad_flow{

MAD_FLOW_CONTINUE = 0x0000,             /*繼續進行下一幀的解碼*/

MAD_FLOW_STOP = 0x0010,        /*中止對該比特流的解碼並正常退出*/

MAD_FLOW_BREAK = 0x0010,       /*中止對該比特流的解碼並返回錯誤*/

MAD_FLOW_IGNORE = 0x0020              /*不解碼該幀,跳入下一幀*/

}

大多數狀況下回調函數會返回MAD_FLOW_CONTINUE。要自定義實現的回調函數的聲明格式爲:

enum mad_flow (*input_func)(void *, struct mad_stream *);

enum mad_flow (*header_func)(void *, struct mad_header const *);

enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct mad_frame *);

enum mad_flow (*output_func)(void *, struct mad_header const *, struct mad_pcm *);

enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);

enum mad_flow (*message_func)(void *, void *, unsigned int *);

其中void *指針將緩衝數據傳遞給這些回調函數,由回調函數對數據進行處理。Input_func函數通常會執行如下操做:

if (more_data_available)

buffer = refill_buffer();

mad_stream_buffer(stream, buffer, length_of_buffer);

return MAD_FLOW_CONTINUE;

else return MAD_FLOW_STOP;

header_func函數會根據mad_header指向的幀頭從中讀取重要的幀信息,如將讀取到的幀長度賦值給mad_timer_t,能夠從mad.h中得知存放這些信息的數據結構。

output_func函數中,利用指向PCM數據的指針mad_pcm,執行相似如下操做:

mad_fixed_t *left_ch = pcm->samples[0], *right_ch =pcm->samples[1];                       //將採樣數據分別輸出到左右聲道

int nsamples = pcm->length;

signed int sample;

unsigned char * buffer = some_buffer;

unsigned char * ptr = buffer;

while (nsamples--)

{

sample = (signed int) do_downsample(*left_ch++)

*ptr++ = (unsigned char) (sample >> 0);

   *ptr++ = (unsigned char) (sample >> 8);

sample = (signed int) do_downsample(*right_ch++)

   *ptr++ = (unsigned char) (sample >> 0);

*ptr++ = (unsigned char) (sample >> 8);

       //處理左右聲道採樣數據,輸出16bit little endian格式PCM

}

定義好各回調函數以後,即可以開始解碼:

mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

解碼完畢後,調用mad_decoder_finish(&decoder);

libmad簡介

MAD (libmad)是一個開源的高精度 MPEG 音頻解碼庫,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3)。LIBMAD 提供 24-bit 的 PCM 輸出,徹底是定點計算,很是適合沒有浮點支持的平臺上使用。使用 libmad 提供的一系列 API,就能夠很是簡單地實現 MP3 數據解碼工做。在 libmad 的源代碼文件目錄下的 mad.h 文件中,能夠看到絕大部分該庫的數據結構和 API 等。

本文用到的 libmad 中的主要數據結構有:struct mad_stream, struct mad_synth, struct mad_frame。它們的定義以下:


清單 1:libmad 中的主要數據結構

struct mad_stream { unsigned char const *buffer; /* input bitstream buffer */ unsigned char const *bufend; /* end of buffer */ unsigned long skiplen; /* bytes to skip before next frame */ int sync; /* stream sync found */ unsigned long freerate; /* free bitrate (fixed) */ unsigned char const *this_frame; /* start of current frame */ unsigned char const *next_frame; /* start of next frame */ struct mad_bitptr ptr; /* current processing bit pointer */ struct mad_bitptr anc_ptr; /* ancillary bits pointer */ unsigned int anc_bitlen; /* number of ancillary bits */ unsigned char (*main_data)[MAD_BUFFER_MDLEN]; /* Layer III main_data() */ unsigned int md_len; /* bytes in main_data */ int options; /* decoding options (see below) */ enum mad_error error; /* error code (see above) */ };

若是緩衝區最後一個 MPEG 數據幀只有部分數據包括在緩衝區中,那麼 struct mad_stream 中的 next_frame 域指到不完整數據的開始地址。因爲緩衝區的 MPEG 數據幀不必定完整,因此不完整的 MPEG 幀的數據必須拷貝到下一次解碼操做的緩衝區中,進行再次解碼。這裏咱們還看到 bufend 指向緩衝區數據的最後地址,也就是最後一字節的地址加 1 的位置。mad_stream.bufend – mad_stream.next_frame 就是剩餘的未被解碼的 MPEG 幀的數據的字節數量(假設此幀在緩衝區中不完整)。mad_streamerror 域用來記錄操做 mad_stream 獲得的錯誤代碼。錯誤代碼在 mad.h 中有很詳細的定義。


清單 2:錯誤代碼在 mad.h 中的詳細定義

struct mad_synth { mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */ /* [ch][eo][peo][s][v] */ unsigned int phase; /* current processing phase */ struct mad_pcm pcm; /* PCM output */ };

mad_synth 中的關鍵域 pcm 保存解碼和合成後獲得的 PCM 數據。


清單 3:mad_synth 中的關鍵域

struct mad_pcm { unsigned int samplerate; /* sampling frequency (Hz) */ unsigned short channels; /* number of channels */ unsigned short length; /* number of samples per channel */ mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ };

struct mad_pcm 定義了音頻的採樣率、每一個聲道個數以及最後的 PCM 採樣數據。這些參數可用來初始化音頻設備。


清單 4:struct mad_pcm

struct mad_frame { struct mad_header header; /* MPEG audio header */ int options; /* decoding options (from stream) */ mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */ mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */ };

mad_frame 是記錄 MPEG 幀解碼後的數據的數據結構,其中的 mad_header 尤爲重要,其用來記錄 MPEG 幀的一些基本信息,好比 MPEG 層數、聲道模式、流比特率、採樣比特率等等。聲道模式包括單聲道、雙聲道、聯合立體混音聲以及通常立體聲。


清單 5:mad_frame

enum mad_mode { MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */ MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */ MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */ MAD_MODE_STEREO = 3 /* normal LR stereo */ }; struct mad_header { enum mad_layer layer; /* audio layer (1, 2, or 3) */ enum mad_mode mode; /* channel mode */ int mode_extension; /* additional mode info */ enum mad_emphasis emphasis; /* de-emphasis to use */ unsigned long bitrate; /* stream bitrate (bps) */ unsigned int samplerate; /* sampling frequency (Hz) */ unsigned short crc_check; /* frame CRC accumulator */ unsigned short crc_target; /* final target CRC checksum */ int flags; /* flags */ int private_bits; /* private bits */ mad_timer_t duration; /* audio playing time of frame */ };

下面就本文使用的 API 的功能作簡單介紹。

在本文中用到的 API 包括:

void mad_stream_init(struct mad_stream *) void mad_synth_init(struct mad_synth *); void mad_frame_init(struct mad_frame *);

以上3個 API 初始化解碼須要的數據結構。

void mad_stream_buffer(struct mad_stream *, unsigned char const *, unsigned long);

此函數把原始的未解碼的 MPEG 數據和 mad_stream 數據結構關聯,以便使用 mad_frame_decode( ) 來解碼 MPEG 幀數據。

int mad_frame_decode(struct mad_frame *, struct mad_stream *);

mad_stream 中的 MPEG 幀數據解碼。

void mad_synth_frame(struct mad_synth *, struct mad_frame const *);

把解碼後的音頻數據合成 PCM 採樣。

void mad_stream_finish(struct mad_stream *); void mad_frame_finish(struct mad_frame *); mad_synth_finish(struct mad_synth);

以上 3 個 API 在解碼完畢後使用,釋放 libmad 佔用的資源等。
相關文章
相關標籤/搜索