《2022年怎么使用libmad》由会员分享,可在线阅读,更多相关《2022年怎么使用libmad(12页珍藏版)》请在金锄头文库上搜索。
1、libmad 是一个开源 mp3 解码库,其对 mp3 解码算法做了很多优化,性能较好,很多播放器如 mplayer 、xmms 等都是使用这个开源库进行解码的;如果要设计mp3 播放器而又不想研究mp3 解码算法的话, libmad 是个不错的选择,可是问题来了:libmad 配套的相关文档太少,可以说几乎没有,只有一个示例程序minimad.c ,但没有一定经验的人根本不知道怎么编译这个minimad.c ,就算是编译了也不知道怎么运行、怎么播放mp3;网上讲 libmad 和 minimad.c 的文章很多,但能解释清楚的少之又少,大家都是抄来抄去, 要么是不懂装懂, 要么是懂了一点就自
2、以为精通了,这样一来的结果是:在网上搜两天也弄不明白libmad 究竟怎么使用。所幸手里有 Altera 公司的一个工程, 借助对该工程的分析、 minimad.c 中少的可怜的注释和网上搜索的Linux 音频方面的相关知识,反复思考编码,总算把libmad 库用起来了,现记录一下其使用方法,在帮助别人的同时也方便自己回头查询。 在开始之前,最好先把mp3 文件格式和 Linux 音频编程方面的知识先学习一下,不然后面有的东西可能听不懂,还有就是一定要熟悉Linux 系统,后面的代码都是在 linux 系统中用 gcc 编译的,在 Windows 下不能用的。首先看下面几个问题, 这也是我一开
3、始最迷惑的, 弄明白这几个问题了, 也就对 libmad库的使用相当熟悉了:1. minimad.c 怎么编译?编译后怎么运行?运行时的输入输出分别是什么,或者说运行时什么效果?2. 怎样播放 minimad 输出的数据?或者说怎么播放解码后的数据?3. minimad 运行时, mp3 数据来源是标准输入,能不能改为从文件中读入数据?该怎么改?4. minimad 运行时首先要将整个mp3 文件读入内存,能不能改成边解码边读入的形式, 比如每次读入 16K,解码完再读入 16K,而又不影响播放的连贯性,这样可以节省内存开销,方便在嵌入式系统中使用;5. 怎样用 libmad 做一个简单的 m
4、p3 播放器 ? 一个一个来讲吧。1. minimad.c 怎么编译?编译后怎么运行?运行时的输入输出分别是什么,或者说运行时什么效果?在 Linux 下(我前面说了,本文所有的工作都是在Linux 进行)先安装 libmad ,说白了就是把 libmad 库导入 C 标准库,安装方法见 libmad-0.15.1b 中的README 和 INSTALL 文件。 安装 libmad 后,新建一个文件夹,将libmad-0.15.1b 中的 minimad.c 和mad.h 复制过来, 用 gcc 编译 minimad.c ,编译命令为 (假设要生成的可执行程序为minimad) : gcc -
5、o minimad 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 12 页 - - - - - - - - - minimad.c -lmad minimad 程序从标准输入读入mp3 文件,然后将解码后的音频数据送到标准输出, 我们可以用重定向的方式从文件中读入数据并将结果写至文件,命令如下:./minimad tmp.pcm2. 怎样播放 minimad 输出的数据?或者说怎么播放解码后的数据?假设你有 Linux 音频编程方面的基础的话, 这个应该不成问题, 如果
6、没有也没关系,在 Linux 的设计理念中,一切皆是文件,音频设备也是文件,只需要打开/dev/dsp (音频设备 )这个文件,然后将解码后的数据写入这个文件即可实现播放,新建pcmplay.c 文件,拷入如下代码:#include #include #include #include #include #include int main(int argc, char *argv) int id, fd, i; char buf1024; int rate; /*simple rate 44.1KHz*/ int format; /*quatize args*/ int channels; /
7、*sound channel*/ if(argc != 2) fprintf(stderr, usage : %s n, argv0); exit(-1); if(fd = open(argv1, O_RDONLY) fpos flen) unproc_data_size = stream-bufend - stream-next_frame; memcpy(mp3fp-fbuf, mp3fp-fbuf+mp3fp-fbsize-unproc_data_size, unproc_data_size); copy_size = BUFSIZE - unproc_data_size; if(mp3
8、fp-fpos + copy_size mp3fp-flen) copy_size = mp3fp-flen - mp3fp-fpos; fread(mp3fp-fbuf+unproc_data_size, 1, copy_size, mp3fp-fp); mp3fp-fbsize = unproc_data_size + copy_size; mp3fp-fpos += copy_size; /*Hand off the buffer to the mp3 input stream*/ mad_stream_buffer(stream, mp3fp-fbuf, mp3fp-fbsize);
9、ret_code = MAD_FLOW_CONTINUE; else 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 12 页 - - - - - - - - - ret_code = MAD_FLOW_STOP; return ret_code; 注意:在上面的代码中涉及到了断桢问题,即一桢跨了两个BUFSIZE ,这时候应该将缓冲区中的剩余数据先移至缓冲区头部,然后再从文件中读出数据填充缓冲区。5. 怎样用 libmad 设计一个简单的 mp3 播放器 ? 修改 ou
10、tput() 函数。 我在上面说过了, 解码后的数据通过output() 函数进行处理, 在 minimad.c 中 output() 函数直接将解码后的数据送到标准输出,其实只要将这里修改为送到音频设备就可以实现播放了。还有一点需要说明的是: mp3 文件的采样率不是固定不变的,解码后的数据中包括采样率,在播放过程中,一旦采样率发生变化,要重新设置一下音频设备。新建一个 mp3player.c 文件,然后将下面的代码复制进去,编译生成mp3player , 这就是一个简单的mp3 播放器了,可以用 ./mp3player 1.mp3命令来播放 1.mp3 文件。#include #inclu
11、de #include #include #include #include #include #include #include #include mad.h #define BUFSIZE 8192 /* * This is a private message structure. A generic pointer to this structure * is passed to each of the callback functions. Put here any data you need * to access from within the callbacks. */ 名师资料
12、总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 12 页 - - - - - - - - - struct buffer FILE *fp; /*file pointer*/ unsigned int flen; /*file length*/ unsigned int fpos; /*current position*/ unsigned char fbufBUFSIZE; /*buffer*/ unsigned int fbsize; /*indeed size of buf
13、fer*/ ; typedef struct buffer mp3_file; int soundfd; /*soundcard file*/ unsigned int prerate = 0; /*the pre simple rate*/ int writedsp(int c) return write(soundfd, (char *)&c, 1); void set_dsp() int format = AFMT_S16_LE; int channels = 2; soundfd = open(/dev/dsp, O_WRONLY); ioctl(soundfd, SNDCTL_DSP
14、_SETFMT, &format); ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels); /* * This is perhaps the simplest example use of the MAD high-level API. * Standard input is mapped into memory via mmap(), then the high-level API * is invoked with three callbacks: input, output, and error. The output * callback co
15、nverts MADs high-resolution PCM samples to 16 bits, then * writes them to standard output in little-endian, stereo-interleaved 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 12 页 - - - - - - - - - * format. */ static int decode(mp3_file *mp3fp); int main(int ar
16、gc, char *argv) long flen, fsta, fend; int dlen; mp3_file *mp3fp; if (argc != 2) return 1; mp3fp = (mp3_file *)malloc(sizeof(mp3_file); if(mp3fp-fp = fopen(argv1, r) = NULL) printf(cant open source file.n); return 2; fsta = ftell(mp3fp-fp); fseek(mp3fp-fp, 0, SEEK_END); fend = ftell(mp3fp-fp); flen
17、= fend - fsta; if(flen fp, 0, SEEK_SET); fread(mp3fp-fbuf, 1, BUFSIZE, mp3fp-fp); mp3fp-fbsize = BUFSIZE; mp3fp-fpos = BUFSIZE; mp3fp-flen = flen; set_dsp(); decode(mp3fp); close(soundfd); fclose(mp3fp-fp); return 0; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页
18、,共 12 页 - - - - - - - - - /* * This is the input callback. The purpose of this callback is to (re)fill * the stream buffer which is to be decoded. In this example, an entire file * has been mapped into memory, so we just call mad_stream_buffer() with the * address and length of the mapping. When thi
19、s callback is called a second * time, we are finished decoding. */ static enum mad_flow input(void *data, struct mad_stream *stream) mp3_file *mp3fp; int ret_code; int unproc_data_size; /*the unprocessed datas size*/ int copy_size; mp3fp = (mp3_file *)data; if(mp3fp-fpos flen) unproc_data_size = str
20、eam-bufend - stream-next_frame; memcpy(mp3fp-fbuf, mp3fp-fbuf+mp3fp-fbsize-unproc_data_size, unproc_data_size); copy_size = BUFSIZE - unproc_data_size; if(mp3fp-fpos + copy_size mp3fp-flen) copy_size = mp3fp-flen - mp3fp-fpos; fread(mp3fp-fbuf+unproc_data_size, 1, copy_size, mp3fp-fp); mp3fp-fbsize
21、= unproc_data_size + copy_size; mp3fp-fpos += copy_size; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 12 页 - - - - - - - - - /*Hand off the buffer to the mp3 input stream*/ mad_stream_buffer(stream, mp3fp-fbuf, mp3fp-fbsize); ret_code = MAD_FLOW_CONTINUE; els
22、e ret_code = MAD_FLOW_STOP; return ret_code; /* * The following utility routine performs simple rounding, clipping, and * scaling of MADs high-resolution samples down to 16 bits. It does not * perform any dithering or noise shaping, which would be recommended to * obtain any exceptional audio qualit
23、y. It is therefore not recommended to * use this routine if high-quality output is desired. */ static inline signed int scale(mad_fixed_t sample) /* round */ sample += (1L (MAD_F_FRACBITS + 1 - 16); /* * This is the output callback function. It is called after each frame of 名师资料总结 - - -精品资料欢迎下载 - -
24、- - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 12 页 - - - - - - - - - * MPEG audio data has been completely decoded. The purpose of this callback * is to output (or play) the decoded PCM audio. */ static enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *
25、pcm) unsigned int nchannels, nsamples; unsigned int rate; mad_fixed_t const *left_ch, *right_ch; /* pcm-samplerate contains the sampling frequency */ rate= pcm-samplerate; nchannels = pcm-channels; nsamples = pcm-length; left_ch = pcm-samples0; right_ch = pcm-samples1; /* update the sample rate of d
26、sp*/ if(rate != prerate) ioctl(soundfd, SNDCTL_DSP_SPEED, &rate); prerate = rate; while (nsamples-) signed int sample; /* output sample(s) in 16-bit signed little-endian PCM */ sample = scale(*left_ch+); writedsp(sample 0) & 0xff); writedsp(sample 8) & 0xff); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - -
27、 - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 12 页 - - - - - - - - - if (nchannels = 2) sample = scale(*right_ch+); writedsp(sample 0) & 0xff); writedsp(sample 8) & 0xff); return MAD_FLOW_CONTINUE; /* * This is the error callback function. It is called whenever a decoding * error occurs. The error
28、is indicated by stream-error; the list of * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h) * header file. */ static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame) mp3_file *mp3fp = data; fprintf(stderr, decoding error 0x%04x (%s) at byte offs
29、et %un, stream-error, mad_stream_errorstr(stream), stream-this_frame - mp3fp-fbuf); /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ return MAD_FLOW_CONTINUE; /* * This is the function called by main() above to perform all the 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - -
30、- - - - - 名师精心整理 - - - - - - - 第 11 页,共 12 页 - - - - - - - - - decoding. * It instantiates a decoder object and configures it with the input, * output, and error callback functions above. A single call to * mad_decoder_run() continues until a callback function returns * MAD_FLOW_STOP (to stop decodi
31、ng) or MAD_FLOW_BREAK (to stop decoding and * signal an error). */ static int decode(mp3_file *mp3fp) struct mad_decoder decoder; int result; /* configure input, output, and error functions */ mad_decoder_init(&decoder, mp3fp, input, 0 /* header */, 0 /* filter */, output, error, 0 /* message */); /* start decoding */ result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); /* release the decoder */ mad_decoder_finish(&decoder); return result; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 12 页 - - - - - - - - -