分享

记录点滴 ? Blog Archive ? libmad音频解码库简介及其数据结构

 shaobin0604@163.com 2011-12-22
  1. 简介
    MAD(libmad)是一个开源的高精度MPEG音频解码库,支持MPEG-1(Layer I, Layer II 和LayerIII-也就是 MP3)。LIBMAD提供24-bit的PCM输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用libmad 提供的一系列API,就可以非常简单地实现 MP3数据解码工作。在libmad 的源代码文件目录下的 mad.h 文件中,可以看到绝大部分该库的数据结构和API等。
  2. libmad中的主要数据结构
    主要数据结构 作用
    struct mad_stream 存放解码前的Bitstream 数据
    struct mad_synth 存放解码合成滤波后的PCM数据
    struct mad_pcm 定义了音频的采样率,声道个数和PCM 采样数据, 用来初始化音频
    struct mad_frame 记录MPEG 帧解码后PCM 数据的数据结构,其中的mad_header 用来记录MPEG 帧的基本信息,比如MPEG 层数、声道模式、流比特率、采样比特率。声道模式包括单声道、双声道、联合立体混音道以及一般立体声

    struct mad_stream

    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) */
    };

    mad_synth

    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_pcm

    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] */
    };

    mad_frame

    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 */
    };
  3. 解码流程
    MP3解码有同步方式和异步方式两种,libmad是以桢为单位对MP3进行解码的,所谓同步方式是指解码函数在解码完一帧后才返回并带回出错信息,异步方式是指解码函数在调用后立即返回,通过消息传递解码状态信息。

    mad API的调用顺序

    • mad_decoder_init()【decoder.h】
      Minimad.c中给出了一个函数调用过程的实例。首先定义一个mad_decoder变量(解码器对象),这时不需要对解码器对象进行任何初始化。调 用mad_decoder_init()函数对刚才创建的decoder对象进行初始化,mad_decoder_init()函数定义于 decoder.h头文件中。原型如下:
      void mad_decoder_init(struct mad_decoder *, //解码器对象指针
      void *,//自定义消息指针,这个值被复制进mad_decoder的cb_data成员
                          enum mad_flow (*)(void *, struct mad_stream *),//input回调函数
                          enum mad_flow (*)(void *, struct mad_header const *),//header回调函数
                          enum mad_flow (*)(void *,struct mad_stream const *,struct mad_frame *),//filter回调函数
                          enum mad_flow (*)(void *,struct mad_header const *,struct mad_pcm *),//output回调函数
                          enum mad_flow (*)(void *,struct mad_stream *,struct mad_frame *),//error回调函数
                          enum mad_flow (*)(void *, void *, unsigned int *)//message回调函数
      );

      其中的input回到函数和output回调函数是必须定义并传递给mad_decoder_init()的,message回调函数在异步工作模式下必选,其他回调函数都可选。

    • mad_stream_buffer()【stream.h】
      Input回调函数具有两个参数,第一个参数是个void指针,指向自定义消息结构,在input回调函数内部对消息进行解释并调用 mad_stream_buffer()函数对输入流进行初始化,具体参考minimad.c中input函数的写法。 mad_stream_buffer()函数原型如下:
      void mad_stream_buffer(struct mad_stream *,//输入流指针
      unsigned char const *, //文件起始地址
      unsigned long//文件长度
      );

      第一个参数指向一个mad_stream变量,mad_stream结构定义在stream.h头文件里,用于记录文件的地址和当前处理的位置。第 二、三个参数分别是mp3文件在内存中映像的起始地址和文件长度。mad_stream_buffer()函数将mp3文件与mad_stream结构进 行关联。Input回调函数在解码器启动后会被调用一次,在整个解码过程中都不再被调用。

      Output回调函数的原型是:

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

      Output回调函数将解码得到的原始PCM块作为参数传入,在这里可以进行一些解码后的操作如加入均衡器等。MadLib使用的PCM结构mad_pcm在头文件synth.h中定义:

      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] */
      };

      Madlib解码器是以帧为单位进行解码的,mad_pcm每次携带最多1152个PCM采样数据(左右声道共2*1152个),每个采样使用 32bit存放,只使用了其中的24bit,但目前大多数的音频设备支持的是16bit量化分辨率,所以在交给声卡输出前还要自己进行转换,将24bit 分辨率降低为16bit。length成员指定了当前PCM数据块的实际大小。

      另外两个参数分别将自定义消息结构和已解码帧的帧头传入,以处理用户消息和获取帧信息。Output回调函数在madlib每解码完成一个帧后被调用,直到全部解码完成或出错。

      Input和output回调函数的返回值是一个mad_folw枚举类型,在decoder.h头文件中定义如下:

      enum mad_flow {
        MAD_FLOW_CONTINUE = 0x0000,     /* continue normally */
        MAD_FLOW_STOP     = 0x0010,      /* stop decoding normally */
        MAD_FLOW_BREAK    = 0x0011,     /* stop decoding and signal an error */
        MAD_FLOW_IGNORE   = 0x0020      /* ignore the current frame */
      };
    • mad_decoder_run()【decoder.h】
      获取了待解吗的mp3文件后解码器开始运行。mad_decoder_run()函数可以看作是mad解码器的运行入口。其原型如下:
      int mad_decoder_run(struct mad_decoder * decoder, enum mad_decoder_mode mode)

      第一、二个参数将初始化好的decoder变量和解码器工作模式(同步或异步)进行关联。后面我们会看到真正完成解码工作的并不是mad_decoder_run,而是根据工作模式的不同在它的内部调用了另外不同的函数进行解码。函数返回后解码就完成了。

    • mad_decoder_finish()【decoder.h】
      最后调用mad_decoder_finish()进行最后的清理工作。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多