MAD(libmad)是一个开源的高精度MPEG音频解码库。libmad提供24-bit的PCM输出,完全定点计算。使用libmad提供的一系列API可以实现MP3文件的解码。
libmad通过回调函数机制来实现解码,当mad_decoder_init初始化完成后,程序执行 mad_decoder_run,这时候程序就会不断调用回调函数来进行每帧数据的解码。
每个回调函数执行完毕后会返回一个枚举类型mad_flow的返回值,通过mad_flow可以控制解码的过程。MAD在每进行一帧的解码结束后都会询问mad_flow的状态,以决定是否进行下一帧的解码。
以下仅介绍简单的用法,用于对该库的理解:
1. 首先下载(https://www.underbit.com/products/mad/)libmad的源码包 libmad-0.15.1b.tar.gz并解压,
2. 在解压出来的目录下编译规则文件Makefile, ./configure, 会生成Makefile文件
3. make编译(注意:编译可能会出错,查找原因后,在Makefile文件中去掉-fforce-mem即可),在当前目录下.libs文件夹下可看到编译生成的动态库libmad.so。
4. 将头文件mad.h和动态库拷出,即可调用mad相关的API来对MP3文件进行解码。
5. 源码包下的minimad.c是一次性对整个MP3文件解码,并且将解码结果输出到console的例程,可将该文件稍微修改,将输出改为pcm文件。
更改output函数如下,其中out1是FILE ×类型,需要实现创建及打开(fopen()返回的)。
更改main中输入的信息源STDIN_FILENO为一个mp3文件,调用open()返回一个fd,替换STDIN_FILENO。
static
enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *pcm)
{
unsigned int nchannels, nsamples;
mad_fixed_t const *left_ch, *right_ch;
nchannels = pcm->channels;
nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
printf("channels = %d, nsamples=%d \n",pcm->channels,pcm->length);
char tmp = 0;
while (nsamples--) {
signed int sample; sample = scale(*left_ch++);
tmp = (sample >> 0) & 0xff;
fwrite(&tmp,1,1,out1); //替换原来的putchar
tmp = (sample >> 8) & 0xff;
fwrite(&tmp,1,1,out1);
// putchar((sample >> 0) & 0xff);
// putchar((sample >> 8) & 0xff);
if (nchannels == 2) {
sample = scale(*right_ch++);
fputc((sample >> 0) & 0xff,out1);
fputc((sample >> 8) & 0xff,out1);
// putchar((sample >> 0) & 0xff);
// putchar((sample >> 8) & 0xff);
} }
main()文件中的替换代码
//打开的音频文件
char *file="in.mp3";
printf("%s\n",file);
int fd = open(file, O_RDONLY); //fd替换原来的STDIN_FILENO
if (fstat(fd, &stat) == -1 || stat.st_size == 0) {
printf("fstat() failed \n"); return 2; }
fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
6.gcc -o mp3 minimad.c -L . -lmad //编译
7.运行mp3,即可将in.mp3的内容转换为pcm文件,转换后的pcm文件大小大概是原本文件的10倍。这也很好解释了压缩音频对存储的重要性。