基於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中的主要數據結構:ide

主要數據結構 做用
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"。spa

 

  
  
           
  
  
  1. static int sfd;  
  2. if((sfd = open("/dev/dsp", O_WRONLY)) < 0)   
  3. {  
  4.     printf("can not open device!!!/n");  
  5.     return 1;  

    通常來講,咱們的MP3文件都是立體音,有2個聲道,因爲要把pcm採樣後並處理的數據放入一個char型的數組,而並行的左右聲道的每一個採樣要在字符數組中處理成2個,因此字符數組中的數據的個數應該是pcm音頻採樣數的4倍。又由於把左右聲道的數據合在一個字符數組裏串行處理,因此播放的速度應該是pcm音頻採樣率的兩倍。code

  
  
           
  
  
  1. static 
  2. enum mad_flow output(void *data,  
  3.              struct mad_header const *header, struct mad_pcm *pcm)  
  4. {  
  5.     unsigned int nchannels, nsamples, n;  
  6.     mad_fixed_t const *left_ch, *right_ch;  
  7.     unsigned char Output[6912], *OutputPtr;  
  8.     int fmt, wrote, speed;  
  9.  
  10.     nchannels = pcm->channels;  
  11.     n = nsamples = pcm->length;  
  12.     left_ch = pcm->samples[0];  
  13.     right_ch = pcm->samples[1];  
  14.  
  15.     fmt = AFMT_S16_LE;  
  16.     speed = pcm->samplerate * 2;    /*播放速度是採樣率的兩倍 */ 
  17.     ioctl(sfd, SNDCTL_DSP_SPEED, &(speed));  
  18.     ioctl(sfd, SNDCTL_DSP_SETFMT, &fmt);  
  19.     ioctl(sfd, SNDCTL_DSP_CHANNELS, &(pcm->channels));  
  20.     OutputPtr = Output;  
  21.     while (nsamples--) {  
  22.     signed int sample;  
  23.     sample = scale(*left_ch++);  
  24.     *(OutputPtr++) = sample >> 0;  
  25.     *(OutputPtr++) = sample >> 8;  
  26.     if (nchannels == 2) {  
  27.         sample = scale(*right_ch++);  
  28.         *(OutputPtr++) = sample >> 0;  
  29.         *(OutputPtr++) = sample >> 8;  
  30.     }  
  31.     }  
  32.     n *= 4;         /*數據長度爲pcm音頻採樣的4倍 */ 
  33.     OutputPtr = Output;  
  34.     while (n) {  
  35.     wrote = write(sfd, OutputPtr, n);  
  36.     OutputPtr += wrote;  
  37.     n -= wrote;  
  38.     }  
  39.     OutputPtr = Output;  
  40.     return MAD_FLOW_CONTINUE;  
這樣就能夠實現咱們的播放器了.....

下面就以一個簡單的實例來講明問題:ci

 

  
  
           
  
  
  1. # include <stdio.h>  
  2. # include <stdlib.h>  
  3. # include <unistd.h>  
  4. # include <sys/stat.h>  
  5. # include <sys/mman.h>  
  6. # include <sys/soundcard.h>  
  7. # include <sys/ioctl.h>  
  8. # include <sys/fcntl.h>  
  9. # include <sys/types.h>  
  10. # include <mad.h>  
  11. struct buffer {  
  12.     unsigned char const *start;  
  13.     unsigned long length;  
  14. };  
  15. static int sfd;         /*聲音設備的描述符 */ 
  16. static int decode(unsigned char const *, unsigned long);  
  17. int main(int argc, char *argv[])  
  18. {  
  19.     struct stat stat;  
  20.     void *fdm;  
  21.     char const *file;  
  22.     int fd;  
  23.     file = argv[1];  
  24.     fd = open(file, O_RDONLY);  
  25.     if ((sfd = open("/dev/dsp", O_WRONLY)) < 0) {  
  26.     printf("can not open device!!!/n");  
  27.     return 5;  
  28.     }  
  29.     ioctl(sfd, SNDCTL_DSP_SYNC, 0); /*此句能夠不要 */ 
  30.     if (fstat(fd, &stat) == -1 || stat.st_size == 0)  
  31.     return 2;  
  32.     fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);  
  33.     if (fdm == MAP_FAILED)  
  34.     return 3;  
  35.     decode(fdm, stat.st_size);  
  36.     if (munmap(fdm, stat.st_size) == -1)  
  37.     return 4;  
  38.     ioctl(sfd, SNDCTL_DSP_RESET, 0);  
  39.     close(sfd);  
  40.     return 0;  
  41. }  
  42. static 
  43. enum mad_flow input(void *data, struct mad_stream *stream)  
  44. {  
  45.     struct buffer *buffer = data;  
  46.     if (!buffer->length)  
  47.     return MAD_FLOW_STOP;  
  48.     mad_stream_buffer(stream, buffer->start, buffer->length);  
  49.     buffer->length = 0;  
  50.     return MAD_FLOW_CONTINUE;  
  51. }  
  52. /*這一段是處理採樣後的pcm音頻 */ 
  53. static inline signed int scale(mad_fixed_t sample)  
  54. {  
  55.     sample += (1L << (MAD_F_FRACBITS - 16));  
  56.     if (sample >= MAD_F_ONE)  
  57.     sample = MAD_F_ONE - 1;  
  58.     else if (sample < -MAD_F_ONE)  
  59.     sample = -MAD_F_ONE;  
  60.     return sample >> (MAD_F_FRACBITS + 1 - 16);  
  61. }  
  62. static 
  63. enum mad_flow output(void *data,  
  64.              struct mad_header const *header, struct mad_pcm *pcm)  
  65. {  
  66.     unsigned int nchannels, nsamples, n;  
  67.     mad_fixed_t const *left_ch, *right_ch;  
  68.     unsigned char Output[6912], *OutputPtr;  
  69.     int fmt, wrote, speed;  
  70.  
  71.     nchannels = pcm->channels;  
  72.     n = nsamples = pcm->length;  
  73.     left_ch = pcm->samples[0];  
  74.     right_ch = pcm->samples[1];  
  75.  
  76.     fmt = AFMT_S16_LE;  
  77.     speed = pcm->samplerate * 2;    /*播放速度是採樣率的兩倍 */ 
  78.     ioctl(sfd, SNDCTL_DSP_SPEED, &(speed));  
  79.     ioctl(sfd, SNDCTL_DSP_SETFMT, &fmt);  
  80.     ioctl(sfd, SNDCTL_DSP_CHANNELS, &(pcm->channels));  
  81.     OutputPtr = Output;  
  82.     while (nsamples--) {  
  83.     signed int sample;  
  84.     sample = scale(*left_ch++);  
  85.     *(OutputPtr++) = sample >> 0;  
  86.     *(OutputPtr++) = sample >> 8;  
  87.     if (nchannels == 2) {  
  88.         sample = scale(*right_ch++);  
  89.         *(OutputPtr++) = sample >> 0;  
  90.         *(OutputPtr++) = sample >> 8;  
  91.     }  
  92.     }  
  93.     n *= 4;         /*數據長度爲pcm音頻採樣的4倍 */ 
  94.     OutputPtr = Output;  
  95.     while (n) {  
  96.     wrote = write(sfd, OutputPtr, n);  
  97.     OutputPtr += wrote;  
  98.     n -= wrote;  
  99.     }  
  100.     OutputPtr = Output;  
  101.     return MAD_FLOW_CONTINUE;  
  102. }  
  103.  
  104. static 
  105. enum mad_flow error(void *data,  
  106.             struct mad_stream *stream, struct mad_frame *frame)  
  107. {  
  108.     return MAD_FLOW_CONTINUE;  
  109. }  
  110.  
  111. static 
  112. int decode(unsigned char const *start, unsigned long length)  
  113. {  
  114.     struct buffer buffer;  
  115.     struct mad_decoder decoder;  
  116.     int result;  
  117.     buffer.start = start;  
  118.     buffer.length = length;  
  119.     mad_decoder_init(&decoder, &buffer, input, 0, 0, output, error, 0);  
  120.     mad_decoder_options(&decoder, 0);  
  121.     result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);  
  122.     mad_decoder_finish(&decoder);  
  123.     return result;  
  124. }  
相關文章
相關標籤/搜索