Chinaunix首页 | 论坛 | 博客
  • 博客访问: 219473
  • 博文数量: 45
  • 博客积分: 669
  • 博客等级: 上士
  • 技术积分: 675
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-27 17:59
文章分类
文章存档

2015年(5)

2014年(6)

2013年(4)

2012年(30)

分类: 嵌入式

2012-09-01 20:11: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 层数、声道模式、流比特率、采样比特率。声道模式包括单声道、双声道、联合立体混音道以及一般立体声

3 解码流程
MP3解码有同步方式和异步方式两种,libmad是以桢为单位对MP3进行解码的,所谓同步方式是指解码函数在解码完一帧后才返回并带回出错信息,异步方式是指解码函数在调用后立即返回,通过消息传递解码状态信息。 mad API的调用顺序:

  • 1)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回调函数在异步工作模式下必选,其他回调函数都可选。
  • 2)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 */ };
  • 3)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,而是根据工作模式的不同在它的内部调用了另外不同的函数进行解码。函数返回后解码就完成了。
  • 4)mad_decoder_finish()【decoder.h】最后调用mad_decoder_finish()进行最后的清理工作。

4 主要函数

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 占用的资源等。

阅读(4946) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册