日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于libmad的MP3解码播放器

發(fā)布時(shí)間:2025/1/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于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;?????????/*數(shù)據(jù)長度為pcm音頻采樣的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;?????????/*聲音設(shè)備的描述符?*/?
  • 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; ?
  • } ?
  • /*這一段是處理采樣后的pcm音頻?*/?
  • 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;?????????/*數(shù)據(jù)長度為pcm音頻采樣的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ò),歡迎將生活随笔推薦給好友。