生活随笔
收集整理的這篇文章主要介紹了
基于libmad的MP3解码播放器
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? ? ? libmad:是一個(gè)開源的高精度mpeg音頻解碼庫,支持 MPEG-1(Layer I,?Layer II 和 LayerIII(也就是 MP3)。LIBMAD 提供 24-bit 的 PCM 輸出,完全是定點(diǎn)計(jì)算,非常適合沒有浮點(diǎn)支持的平臺(tái)上使用。使用 libmad 提供的一系列 API,就可以非常簡單地實(shí)現(xiàn) MP3 數(shù)據(jù)解碼工作。在 libmad 的源代碼文件目錄下的 mad.h 文件中,可以看到絕大部分該庫的數(shù)據(jù)結(jié)構(gòu)和 API 等。
? ? ?PCM編碼:即為脈沖代碼調(diào)制編碼。
PCM通過抽樣,量化,編碼三個(gè)步驟將連續(xù)的模擬信號轉(zhuǎn)換成數(shù)字編碼。
libmad中的主要數(shù)據(jù)結(jié)構(gòu):
| 主要數(shù)據(jù)結(jié)構(gòu) | 作用 |
| struct mad_stream | 存放解碼前的Bitstream數(shù)據(jù) |
| struct mad_synth | 存放解碼合成濾波后的PCM數(shù)據(jù) |
| struct mad_pcm | 定義了音頻的采樣率,聲道個(gè)數(shù)和PCM采樣數(shù)據(jù),用來初始化音頻 |
| struct mad_frame | 記錄MPEG幀解碼后PCM數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),其中的mad_header用來記錄MPEG幀的基本信息,比如MPEG層數(shù)、聲道模式、流比特率、采樣比特率。聲道模式包括單聲道、雙聲道、聯(lián)合立體混音道以及一般立體聲。 |
? ? ? MAD通過回調(diào)函數(shù)機(jī)制來實(shí)現(xiàn)解碼,每個(gè)回調(diào)函數(shù)會(huì)返回一個(gè)枚舉類型mad_flow,通過mad_flow可以控制解碼的過程。在未經(jīng)處理的情況下,MAD一般輸出32bit,以little endian格式存放在mad_fixed_t中的數(shù)據(jù)。但是大多數(shù)的聲卡并能支持輸出高達(dá)32bit精度的數(shù)據(jù),因而還必須對mad_fixed_t進(jìn)行量化,圓滑處理以及抖動(dòng),使到采樣信號降到16bit精度。MAD負(fù)責(zé)的只是解碼的過程,它工作過程是:從外部獲取輸入,逐幀解碼,在解碼的過程中返回信息,然后得到解碼結(jié)果。開發(fā)人員要手動(dòng)設(shè)置輸入輸出。
在libmad中提供了一個(gè)解碼源程序minimad.c,實(shí)現(xiàn)了將MP3文件解碼成pcm數(shù)據(jù),并將其數(shù)據(jù)顯示在終端上。
? ? ?現(xiàn)在就以該源碼程序?yàn)槔?#xff0c;來寫出我們自己的基于libmad的MP3播放器。
在我們打開我們的音頻程序之時(shí)同時(shí)也打開我們的音頻設(shè)備"/dev/dsp"。
?
static?int?sfd; ?if((sfd?=?open("/dev/dsp",?O_WRONLY))?<?0)? ?{ ?????printf("can?not?open?device!!!/n"); ?????return?1; ?}? ? ? 一般來說,我們的MP3文件都是立體音,有2個(gè)聲道,由于要把pcm采樣后并處理的數(shù)據(jù)放入一個(gè)char型的數(shù)組,而并行的左右聲道的每個(gè)采樣要在字符數(shù)組中處理成2個(gè),所以字符數(shù)組中的數(shù)據(jù)的個(gè)數(shù)應(yīng)該是pcm音頻采樣數(shù)的4倍。又因?yàn)榘炎笥衣暤赖臄?shù)據(jù)合在一個(gè)字符數(shù)組里串行處理,所以播放的速度應(yīng)該是pcm音頻采樣率的兩倍。
static?enum?mad_flow?output(void?*data, ??????????????struct?mad_header?const?*header,?struct?mad_pcm?*pcm) ?{ ?????unsigned?int?nchannels,?nsamples,?n; ?????mad_fixed_t?const?*left_ch,?*right_ch; ?????unsigned?char?Output[6912],?*OutputPtr; ?????int?fmt,?wrote,?speed; ??????nchannels?=?pcm->channels; ?????n?=?nsamples?=?pcm->length; ?????left_ch?=?pcm->samples[0]; ?????right_ch?=?pcm->samples[1]; ??????fmt?=?AFMT_S16_LE; ?????speed?=?pcm->samplerate?*?2;?????????ioctl(sfd,?SNDCTL_DSP_SPEED,?&(speed)); ?????ioctl(sfd,?SNDCTL_DSP_SETFMT,?&fmt); ?????ioctl(sfd,?SNDCTL_DSP_CHANNELS,?&(pcm->channels)); ?????OutputPtr?=?Output; ?????while?(nsamples--)?{ ?????signed?int?sample; ?????sample?=?scale(*left_ch++); ?????*(OutputPtr++)?=?sample?>>?0; ?????*(OutputPtr++)?=?sample?>>?8; ?????if?(nchannels?==?2)?{ ?????????sample?=?scale(*right_ch++); ?????????*(OutputPtr++)?=?sample?>>?0; ?????????*(OutputPtr++)?=?sample?>>?8; ?????} ?????} ?????n?*=?4;??????????????OutputPtr?=?Output; ?????while?(n)?{ ?????wrote?=?write(sfd,?OutputPtr,?n); ?????OutputPtr?+=?wrote; ?????n?-=?wrote; ?????} ?????OutputPtr?=?Output; ?????return?MAD_FLOW_CONTINUE; ?}?這樣就可以實(shí)現(xiàn)我們的播放器了.....
下面就以一個(gè)簡單的實(shí)例來說明問題:
?
#?include?<stdio.h> ?#?include?<stdlib.h> ?#?include?<unistd.h> ?#?include?<sys/stat.h> ?#?include?<sys/mman.h> ?#?include?<sys/soundcard.h> ?#?include?<sys/ioctl.h> ?#?include?<sys/fcntl.h> ?#?include?<sys/types.h> ?#?include?<mad.h> ?struct?buffer?{ ?????unsigned?char?const?*start; ?????unsigned?long?length; ?}; ?static?int?sfd;??????????static?int?decode(unsigned?char?const?*,?unsigned?long); ?int?main(int?argc,?char?*argv[]) ?{ ?????struct?stat?stat; ?????void?*fdm; ?????char?const?*file; ?????int?fd; ?????file?=?argv[1]; ?????fd?=?open(file,?O_RDONLY); ?????if?((sfd?=?open("/dev/dsp",?O_WRONLY))?<?0)?{ ?????printf("can?not?open?device!!!/n"); ?????return?5; ?????} ?????ioctl(sfd,?SNDCTL_DSP_SYNC,?0);??????if?(fstat(fd,?&stat)?==?-1?||?stat.st_size?==?0) ?????return?2; ?????fdm?=?mmap(0,?stat.st_size,?PROT_READ,?MAP_SHARED,?fd,?0); ?????if?(fdm?==?MAP_FAILED) ?????return?3; ?????decode(fdm,?stat.st_size); ?????if?(munmap(fdm,?stat.st_size)?==?-1) ?????return?4; ?????ioctl(sfd,?SNDCTL_DSP_RESET,?0); ?????close(sfd); ?????return?0; ?} ?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; ?} ??static?inline?signed?int?scale(mad_fixed_t?sample) ?{ ?????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); ?} ?static?enum?mad_flow?output(void?*data, ??????????????struct?mad_header?const?*header,?struct?mad_pcm?*pcm) ?{ ?????unsigned?int?nchannels,?nsamples,?n; ?????mad_fixed_t?const?*left_ch,?*right_ch; ?????unsigned?char?Output[6912],?*OutputPtr; ?????int?fmt,?wrote,?speed; ??????nchannels?=?pcm->channels; ?????n?=?nsamples?=?pcm->length; ?????left_ch?=?pcm->samples[0]; ?????right_ch?=?pcm->samples[1]; ??????fmt?=?AFMT_S16_LE; ?????speed?=?pcm->samplerate?*?2;?????????ioctl(sfd,?SNDCTL_DSP_SPEED,?&(speed)); ?????ioctl(sfd,?SNDCTL_DSP_SETFMT,?&fmt); ?????ioctl(sfd,?SNDCTL_DSP_CHANNELS,?&(pcm->channels)); ?????OutputPtr?=?Output; ?????while?(nsamples--)?{ ?????signed?int?sample; ?????sample?=?scale(*left_ch++); ?????*(OutputPtr++)?=?sample?>>?0; ?????*(OutputPtr++)?=?sample?>>?8; ?????if?(nchannels?==?2)?{ ?????????sample?=?scale(*right_ch++); ?????????*(OutputPtr++)?=?sample?>>?0; ?????????*(OutputPtr++)?=?sample?>>?8; ?????} ?????} ?????n?*=?4;??????????????OutputPtr?=?Output; ?????while?(n)?{ ?????wrote?=?write(sfd,?OutputPtr,?n); ?????OutputPtr?+=?wrote; ?????n?-=?wrote; ?????} ?????OutputPtr?=?Output; ?????return?MAD_FLOW_CONTINUE; ?} ??static?enum?mad_flow?error(void?*data, ?????????????struct?mad_stream?*stream,?struct?mad_frame?*frame) ?{ ?????return?MAD_FLOW_CONTINUE; ?} ??static?int?decode(unsigned?char?const?*start,?unsigned?long?length) ?{ ?????struct?buffer?buffer; ?????struct?mad_decoder?decoder; ?????int?result; ?????buffer.start?=?start; ?????buffer.length?=?length; ?????mad_decoder_init(&decoder,?&buffer,?input,?0,?0,?output,?error,?0); ?????mad_decoder_options(&decoder,?0); ?????result?=?mad_decoder_run(&decoder,?MAD_DECODER_MODE_SYNC); ?????mad_decoder_finish(&decoder); ?????return?result; ?} ? ?
轉(zhuǎn)載于:https://blog.51cto.com/yiluohuanghun/867922
總結(jié)
以上是生活随笔為你收集整理的基于libmad的MP3解码播放器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。