MadLib是以帧为单位解码mp3文件的,所谓同步方式是指解码函数在解码完一帧后才返回并带回出错信息,异步方式是指解码函数在调用后立即返回,通过消息传递解码状态信息。
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()进行最后的清理工作。