Linux下基于Libmad库的MP3音乐播放器编写
linux下基于Libmad庫的MP3音樂播放器編寫
? ? ? ?libmad是一個開源mp3解碼庫,其對mp3解碼算法做了很多優(yōu)化,性能較好,很多播放器如mplayer、xmms等都是使用這個開源庫進行解碼的;如果要設計mp3播放器而又不想研 ? ? ? ?究mp3解碼算法的話,libmad是個不錯的選擇。關于該庫的使用,敘述如下。
一:安裝Libmad:
? ?1、在網(wǎng)上下載:Libmad庫的使用.pdf文檔和libmad-0.15.lb.tar.gz壓縮包( http://down.51cto.com/data/1087041(免費下載))
? ?2、解壓:tar -zxvf libmad-0.15.lb.tar.gz
? ?以下過程在Readme和INSTALL文件中列了出來,應學會自己看選項進行操作:
? ?3、cd libmad-0.15.lb
? ?4、./configure
? ?5、make
? ?6、make check
? ?7、make install
? ?(若最后有錯誤信息,說明你用的gcc版本太高,該版本的gcc有"-fforce-mem"參數(shù),打開根目錄下的Makefile去掉里面的"-fforce-mem"就OK了。)
? ?結(jié)果:產(chǎn)生一個 .libs 目錄
--------------------------------------------------------------------------------------------------------------————————————————
然后按照Libmad庫的使用.pdf文檔中的提示繼續(xù)往下進行。
二:查看示例代碼 minimad.c:
? ?minimad.c
/** libmad - MPEG audio decoder library* Copyright (C) 2000-2004 Underbit Technologies, Inc.** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA** $Id: minimad.c,v 1.4 2004/01/23 09:41:32 rob Exp $*/ # include <stdio.h> # include <unistd.h> # include <sys/stat.h> # include <sys/mman.h> # include "mad.h" /** 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 converts MAD's high-resolution PCM samples to 16 bits, then* writes them to standard output in little-endian, stereo-interleaved* format.*/ static int decode(unsigned char const *, unsigned long); int main(int argc, char *argv[]) {struct stat stat;void *fdm;if (argc != 1)return 1;if (fstat(STDIN_FILENO, &stat) == -1 ||stat.st_size == 0)return 2;fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0);if (fdm == MAP_FAILED)return 3;decode(fdm, stat.st_size);if (munmap(fdm, stat.st_size) == -1)return 4;return 0; } /** 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.*/ struct buffer {unsigned char const *start;unsigned long length; }; /** 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 this callback is called a second* time, we are finished decoding.*/ static enum mad_flow input(void *data,struct mad_stream *stream) {struct buffer *buffer = data;if (!buffer->length)return MAD_FLOW_STOP;mad_stream_buffer(stream, buffer->start, buffer->length);buffer->length = 0;return MAD_FLOW_CONTINUE; } /** The following utility routine performs simple rounding, clipping, and* scaling of MAD's 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 quality. 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 - 16));/* clip */if (sample >= MAD_F_ONE)sample = MAD_F_ONE - 1;else if (sample < -MAD_F_ONE)sample = -MAD_F_ONE;/* quantize */return sample >> (MAD_F_FRACBITS + 1 - 16); } /** This is the output callback function. It is called after each frame of* 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 *pcm) {unsigned int nchannels, nsamples;mad_fixed_t const *left_ch, *right_ch;/* pcm->samplerate contains the sampling frequency */nchannels = pcm->channels;nsamples = pcm->length;left_ch = pcm->samples[0];right_ch = pcm->samples[1];while (nsamples--) {signed int sample;/* output sample(s) in 16-bit signed little-endian PCM */sample = scale(*left_ch++);putchar((sample >> 0) & 0xff);putchar((sample >> 8) & 0xff);if (nchannels == 2) {sample = scale(*right_ch++);putchar((sample >> 0) & 0xff);putchar((sample >> 8) & 0xff);}}return MAD_FLOW_CONTINUE; } /** This is the error callback function. It is called whenever a decoding* error occurs. The error 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) {struct buffer *buffer = data;fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",stream->error, mad_stream_errorstr(stream),stream->this_frame - buffer->start);/* 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 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 decoding) or MAD_FLOW_BREAK (to stop decoding and* signal an error).*/ static int decode(unsigned char const *start, unsigned long length) {struct buffer buffer;struct mad_decoder decoder;int result;/* initialize our private message structure */buffer.start = start;buffer.length = length;/* configure input, output, and error functions */mad_decoder_init(&decoder, &buffer,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; }? ?編譯: gcc -o minimad minimad.c –lmad
? ?運行: ./minimad <test.mp3 >test.pcm
? ?以上是將:1、標準輸入重定向到MP3文件
? ? ? ? ? ? ?2、標準輸出重定向到解碼以后的 pcm 文件
? ?下面將pcm數(shù)據(jù)寫入音頻設備(即pcmplay.c程序):
? ? ? ( A.設備文件/dev/dsp
B.ioctl設置音頻屬性: ? ? (記得加<sys/soundcard.h>頭文件)
a.采樣格式
b.采樣頻率
c.聲道
C.將pcm文件寫入音頻設備)
? ?文檔中pcmplay.c程序中void writefully(int fd,void *buf,int size);函數(shù)未給出,下面已補全。
? ?pcmplay.c代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <string.h> #include <sys/soundcard.h> void writefully(int fd,void *buf,int size) {int n = write(fd,buf,size);if(n < 0){fprintf(stderr,"writefully error!",strerror(errno));exit(-1);} } int main(int argc, char *argv[]) {int handle, fd;char buf[1024];if (argc != 2){fprintf(stderr, "usage : %s \n", argv[0]);exit(-1);}if ((fd = open(argv[1], O_RDONLY)) < 0){fprintf(stderr, "Can't open sound file!\n");exit(-2);}if ((handle = open("/dev/dsp", O_WRONLY))<0){fprintf(stderr, "Can't open system file /dev/dsp!\n");exit(-2);}#if 1//設置聲道int channels = 2;int result = ioctl(handle, SNDCTL_DSP_CHANNELS, &channels);if ( result == -1 ){perror("ioctl channel number");return -1;}//設置采樣格式:AFMT_S16_LEint format = AFMT_S16_LE;result = ioctl(handle, SNDCTL_DSP_SETFMT, &format);if ( result == -1 ){perror("ioctl sample format");return -1;}//設置采樣頻率44.1//int rate = 22050;int rate = 44100;result = ioctl(handle, SNDCTL_DSP_SPEED, &rate);if ( result == -1 ){perror("ioctl sample format");return -1;}#endifint n;while((n=read(fd,buf,sizeof(buf)))){writefully(handle,buf,n);}close(fd);close(handle);exit(0); } ? ?編譯: gcc -o pcmplay pcmplay.c
? ?運行: ./pcmplay test.pcm
? ?如此即可先將.mp3文件整個解壓到.pcm文件中,再通過將.pcm文件寫入音頻設備進行.mp3音樂播放。
? ?下面簡易實現(xiàn).mp3音樂文件的編解碼邊播放程序的編寫。
------------------------------------------------------------------------------------------------—————————————————————
三:編解碼邊播放,用Libmad設計一個簡單的MP3播放器:
? “Libmad庫的使用.pdf”文檔中MP3player.c程序有些許缺失或錯誤,現(xiàn)已改正,程序如下:
? ?MP3player.c
#include "mad.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <sys/soundcard.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. */ struct buffer {FILE *fp; /*file pointer*/unsigned int flen; /*file length*/unsigned int fpos; /*current position*/unsigned char fbuf[BUFSIZE]; /*buffer*/unsigned int fbsize; /*indeed size of buffer*/ }; 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 rate = 44100; // int rate = 96000;int format = AFMT_S16_LE;int channels = 2;int value;soundfd = open("/dev/dsp", O_WRONLY);ioctl(soundfd,SNDCTL_DSP_SPEED,&rate);ioctl(soundfd, SNDCTL_DSP_SETFMT, &format);ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels); /*value = 16;ioctl(soundfd,SNDCTL_DSP_SAMPLESIZE,&value);value = 0;ioctl(soundfd,SNDCTL_DSP_STEREO,&value); */ } /* * 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 converts MAD's high-resolution PCM samples to 16 bits, then * writes them to standard output in little-endian, stereo-interleaved * format. */ static int decode(mp3_file *mp3fp); int main(int argc, 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(argv[1], "r")) == NULL){printf("can't open source file.\n");return 2;}fsta = ftell(mp3fp->fp);fseek(mp3fp->fp, 0, SEEK_END);fend = ftell(mp3fp->fp);flen = fend - fsta;fseek(mp3fp->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; } /* * 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 this 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 data's size*/int copy_size;mp3fp = (mp3_file *)data;if(mp3fp->fpos <= mp3fp->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(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 = 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);ret_code = MAD_FLOW_CONTINUE;}else{ret_code = MAD_FLOW_STOP;}return ret_code; } /* * The following utility routine performs simple rounding, clipping, and * scaling of MAD's 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 quality. 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 - 16);if(sample >= MAD_F_ONE)sample = MAD_F_ONE - 1;else if(sample < -MAD_F_ONE)sample = -MAD_F_ONE;return sample >> (MAD_F_FRACBITS + 1 - 16); } /* * This is the output callback function. It is called after each frame of * 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 *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->samples[0];right_ch = pcm->samples[1];/* update the sample rate of dsp*/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);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 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 offset %u\n",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 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 decoding) 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; }? ?編譯:gcc -o mp3player MP3player.c -lmad
? ?運行:./mp3player xxx.mp3
? ?至此,一個簡易MP3播放器就寫好了。
? ?程序已親自驗證,請放心閱覽。如有錯誤,歡迎批評指正。
? ?享受陽光,享受生活。愿與大家共同進步。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? --刀刀
轉(zhuǎn)載于:https://blog.51cto.com/weiyuqingcheng/1362179
總結(jié)
以上是生活随笔為你收集整理的Linux下基于Libmad库的MP3音乐播放器编写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: awk中$NF和NF的含义
- 下一篇: unix executable file