生活随笔
收集整理的這篇文章主要介紹了
基于libmad的MP3解码播放器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? libmad:是一個開源的高精度mpeg音頻解碼庫,支持 MPEG-1(Layer I,?Layer II 和 LayerIII(也就是 MP3)。LIBMAD 提供 24-bit 的 PCM 輸出,完全是定點計算,非常適合沒有浮點支持的平臺上使用。使用 libmad 提供的一系列 API,就可以非常簡單地實現 MP3 數據解碼工作。在 libmad 的源代碼文件目錄下的 mad.h 文件中,可以看到絕大部分該庫的數據結構和 API 等。
? ? ?PCM編碼:即為脈沖代碼調制編碼。
PCM通過抽樣,量化,編碼三個步驟將連續的模擬信號轉換成數字編碼。
libmad中的主要數據結構:
| 主要數據結構 | 作用 |
| struct mad_stream | 存放解碼前的Bitstream數據 |
| struct mad_synth | 存放解碼合成濾波后的PCM數據 |
| struct mad_pcm | 定義了音頻的采樣率,聲道個數和PCM采樣數據,用來初始化音頻 |
| struct mad_frame | 記錄MPEG幀解碼后PCM數據的數據結構,其中的mad_header用來記錄MPEG幀的基本信息,比如MPEG層數、聲道模式、流比特率、采樣比特率。聲道模式包括單聲道、雙聲道、聯合立體混音道以及一般立體聲。 |
? ? ? MAD通過回調函數機制來實現解碼,每個回調函數會返回一個枚舉類型mad_flow,通過mad_flow可以控制解碼的過程。在未經處理的情況下,MAD一般輸出32bit,以little endian格式存放在mad_fixed_t中的數據。但是大多數的聲卡并能支持輸出高達32bit精度的數據,因而還必須對mad_fixed_t進行量化,圓滑處理以及抖動,使到采樣信號降到16bit精度。MAD負責的只是解碼的過程,它工作過程是:從外部獲取輸入,逐幀解碼,在解碼的過程中返回信息,然后得到解碼結果。開發人員要手動設置輸入輸出。
在libmad中提供了一個解碼源程序minimad.c,實現了將MP3文件解碼成pcm數據,并將其數據顯示在終端上。
? ? ?現在就以該源碼程序為例,來寫出我們自己的基于libmad的MP3播放器。
在我們打開我們的音頻程序之時同時也打開我們的音頻設備"/dev/dsp"。
?
static?int?sfd; ?if((sfd?=?open("/dev/dsp",?O_WRONLY))?<?0)? ?{ ?????printf("can?not?open?device!!!/n"); ?????return?1; ?}? ? ? 一般來說,我們的MP3文件都是立體音,有2個聲道,由于要把pcm采樣后并處理的數據放入一個char型的數組,而并行的左右聲道的每個采樣要在字符數組中處理成2個,所以字符數組中的數據的個數應該是pcm音頻采樣數的4倍。又因為把左右聲道的數據合在一個字符數組里串行處理,所以播放的速度應該是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; ?}?這樣就可以實現我們的播放器了.....
下面就以一個簡單的實例來說明問題:
?
#?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; ?} ? ?
轉載于:https://blog.51cto.com/yiluohuanghun/867922
總結
以上是生活随笔為你收集整理的基于libmad的MP3解码播放器的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。