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

openkk 12年前發布 | 64K 次閱讀 libmad 多媒體處理
MAD(libmad)是一個開源的高精度MPEG音頻解碼庫,支持MPEG-1標準。libmad提供24-bitPCM輸出,完全定點計算,非常適合在沒有浮點支持的嵌入式硬件平臺上使用。使用libmad提供的一系列API可以實現MP3文件的解碼。

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

4 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()實現初始化[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 占用的資源等。

 

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!