AD(libmad) 是一個開源的高精度 MPEG 音頻解碼庫,支援 MPEG-1 標準。
libmad 提供 24-bit 的 PCM 輸出,完全定點計算,非常適合在沒有浮點支援的嵌入式硬體平台上使用。
使用 libmad 提供的一系列 API 可以實現 MP3 檔案的解碼。
"mad.h"標頭檔案定義了 libmad 的數據架構及 API 函數。
libmad 中的主要數據架構
主要數據架構 作用
struct mad_stream 存放解碼前的 Bitstream 數據。
struct mad_synth 存放解碼合成濾波後的 PCM 數據。
struct mad_pcm 定義了音頻的採樣率,聲道個數和 PCM 採樣數據,用來初始化音頻。
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() 實現初始化。
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);
留言列表