基于Linux下的开源wavplay播放器

转载自:http://blog.csdn.net/wavemcu/article/details/8571396

       因为客户需要用到wav文件来测试播放我们的平台,而客户的应用程序,用在我们的平台上,会有一些问题,所以,我需要从网络上找开源的wav的播放器,终于在网络上找到了wavplay播放器.虽然是基于OSS架构的wav的播放器,不过没有关系,自己还是先来熟悉这个开源的代码吧, 最新的版本是2.0版本,源码的下载地址如下:

http://sourceforge.net/projects/wavplay/?source=dlp 节后抽个时间将其移植到ARM平台上去,这个小软件不管是用来测试,还是用来移植到实际的项目,对我们来说,都是很好的一个参考源码。你说是不?

一:wav文件格式 [引用网络,已做过修改]

      wave文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件的头四个字节便是“RIFF”,WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。如下图所示:

 

        其中除了Fact Chunk外,其他三个Chunk是必须的。每个Chunk有各自的ID,位于Chunk最开始位置,作为标示,而且均为4个字节。并且紧跟在ID后面的是Chunk大小(去除ID和Size所占的字节数后剩下的其他字节数目),4个字节表示,低字节表示数值低位,高字节表示数值高位。下面具体介绍各个Chunk内容。注意: 所有数值表示均为低字节表示低位,高字节表示高位。

1):RIFF WAVE Chunk

以'FIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段,为'WAVE',表示是wav文件。

2):Format Chunk

以'fmt '作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18,则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的附加信息。

3):Fact Chunk

Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。

4):Data Chunk

Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数,wav数据的bit位置可以分成以下几种形式:

二:wav文件格式解码

具体的代码,可以仔细研究wavplay的源码中的wavfile.c和wavfile.h文件,这两个文件主要是对wav文件格式进行解码,具体的部分代码如下:

  1. /* $Id: wavfile.c,v 1.3 2009/11/30 15:02:31 ve3wwg Exp $ 
  2.  * Copyright: wavfile.c (c) Erik de Castro Lopo  erikd@zip.com.au 
  3.  * 
  4.  * wavfile.c - Functions for reading and writing MS-Windoze .WAV files. 
  5.  * 
  6.  * This  program is free software; you can redistribute it and/or modify it 
  7.  * under the  terms  of  the GNU General Public License as published by the 
  8.  * Free Software Foundation. 
  9.  *  
  10.  * This  program  is  distributed  in  the hope that it will be useful, but 
  11.  * WITHOUT   ANY   WARRANTY;   without   even  the   implied   warranty  of 
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
  13.  * Public License for more details (licensed by file COPYING or GPLv*). 
  14.  *  
  15.  * This code was originally written to manipulate Windoze .WAV files 
  16.  * under i386 Linux (erikd@zip.com.au). 
  17.  * 
  18.  * ve3wwg@gmail.com 
  19.  */   
  20. static const char rcsid[] = "$Id: wavfile.c,v 1.3 2009/11/30 15:02:31 ve3wwg Exp $";  
  21.   
  22. #include    <stdio.h>  
  23. #include    <errno.h>  
  24. #include    <sys/types.h>  
  25. #include    <unistd.h>  
  26. #include    <string.h>  
  27.   
  28. #include "wavplay.h"  
  29.   
  30. #define     BUFFERSIZE          1024  
  31. #define     PCM_WAVE_FORMAT     1  
  32.   
  33. #define     TRUE            1  
  34. #define     FALSE           0  
  35.   
  36. typedef  struct  
  37. {   u_long     dwSize ;  
  38.     u_short    wFormatTag ;  
  39.     u_short    wChannels ;  
  40.     u_long     dwSamplesPerSec ;  
  41.     u_long     dwAvgBytesPerSec ;  
  42.     u_short    wBlockAlign ;  
  43.     u_short    wBitsPerSample ;  
  44. } WAVEFORMAT ;  
  45.   
  46. typedef  struct  
  47. {   char        RiffID [4] ;  
  48.     u_long      RiffSize ;  
  49.     char        WaveID [4] ;  
  50.     char        FmtID  [4] ;  
  51.     u_long      FmtSize ;  
  52.     u_short     wFormatTag ;  
  53.     u_short     nChannels ;  
  54.     u_long      nSamplesPerSec ;  
  55.     u_long      nAvgBytesPerSec ;  
  56.     u_short     nBlockAlign ;  
  57.     u_short     wBitsPerSample ;  
  58.     char        DataID [4] ;  
  59.     u_long      nDataBytes ;  
  60. } WAVE_HEADER ;  
  61.   
  62. /*=================================================================================================*/  
  63.   
  64. char*  findchunk (char* s1, char* s2, size_t n) ;  
  65.   
  66. /*=================================================================================================*/  
  67.   
  68.   
  69. static  WAVE_HEADER  waveheader =  
  70. {   { 'R''I''F''F' },  
  71.         0,  
  72.     { 'W''A''V''E' },  
  73.     { 'f''m''t'' ' },  
  74.         16,                             /* FmtSize*/  
  75.         PCM_WAVE_FORMAT,                        /* wFormatTag*/  
  76.         0,                              /* nChannels*/  
  77.         0,  
  78.         0,  
  79.         0,  
  80.         0,  
  81.     { 'd''a''t''a' },  
  82.         0  
  83. } ; /* waveheader*/  
  84.   
  85. static ErrFunc v_erf;               /* wwg: Error reporting function */  
  86.   
  87. /* 
  88.  * Error reporting function for this source module: 
  89.  */  
  90. static void  
  91. err(const char *format,...) {  
  92.     va_list ap;  
  93.   
  94.     if ( v_erf == NULL )  
  95.         return;             /* Only report error if we have function */  
  96.     va_start(ap,format);  
  97.     v_erf(format,ap);           /* Use caller's supplied function */  
  98.     va_end(ap);  
  99. }  
  100.   
  101. int  WaveWriteHeader (int wavefile, int channels, u_long samplerate, int sampbits, u_long samples, ErrFunc erf)  
  102. {   u_long      databytes ;  
  103.     u_short     blockalign ;  
  104.   
  105.     v_erf = erf;                /* wwg: Set error reporting function */  
  106.   
  107.     if ( wavefile < 0 ) {  
  108.         err("Invalid file descriptor");  
  109.         return WW_BADOUTPUTFILE ;  
  110.     }  
  111.   
  112.     sampbits   = (sampbits == 16) ? 16 : 8 ;  
  113.   
  114.     blockalign = ((sampbits == 16) ? 2 : 1) * channels ;  
  115.     databytes  = samples * (u_long) blockalign ;  
  116.   
  117.     waveheader.RiffSize        = sizeof (WAVE_HEADER) + databytes - 8 ;  
  118.     waveheader.wFormatTag      = PCM_WAVE_FORMAT ;  
  119.     waveheader.nChannels       = channels ;  
  120.     waveheader.nSamplesPerSec  = samplerate ;  
  121.     waveheader.nAvgBytesPerSec = samplerate * (u_long) blockalign ;  
  122.     waveheader.nBlockAlign     = blockalign ;  
  123.     waveheader.wBitsPerSample  = sampbits ;  
  124.     waveheader.nDataBytes      = databytes;  
  125.   
  126.     if (write (wavefile, &waveheader, sizeof (WAVE_HEADER)) != sizeof (WAVE_HEADER)) {  
  127.         err("%s",strerror(errno));  /* wwg: report the error */  
  128.         return  WW_BADWRITEHEADER ;  
  129.     }  
  130.   
  131.   return 0 ;  
  132. } ; /* WaveWriteHeader*/  
  133.   
  134. int  WaveReadHeader  (int wavefile, int* channels, u_long* samplerate, int* samplebits, u_long* samples, u_long* datastart,ErrFunc erf)  
  135. {   static  WAVEFORMAT  waveformat ;  
  136.     static  char   buffer [ BUFFERSIZE ] ;      /* Function is not reentrant.*/  
  137.     char*   ptr ;  
  138.     u_long  databytes ;  
  139.   
  140.     v_erf = erf;                    /* wwg: Set error reporting function */  
  141.   
  142.     if (lseek (wavefile, 0L, SEEK_SET)) {  
  143.         err("%s",strerror(errno));      /* wwg: Report error */  
  144.         return  WR_BADSEEK ;  
  145.     }  
  146.   
  147.     read (wavefile, buffer, BUFFERSIZE) ;  
  148.   
  149.     if (findchunk (buffer, "RIFF", BUFFERSIZE) != buffer) {  
  150.         err("Bad format: Cannot find RIFF file marker");    /* wwg: Report error */  
  151.         return  WR_BADRIFF ;  
  152.     }  
  153.   
  154.     if (! findchunk (buffer, "WAVE", BUFFERSIZE)) {  
  155.         err("Bad format: Cannot find WAVE file marker");    /* wwg: report error */  
  156.         return  WR_BADWAVE ;  
  157.     }  
  158.   
  159.     ptr = findchunk (buffer, "fmt ", BUFFERSIZE) ;  
  160.   
  161.     if (! ptr) {  
  162.         err("Bad format: Cannot find 'fmt' file marker");   /* wwg: report error */  
  163.         return  WR_BADFORMAT ;  
  164.     }  
  165.   
  166.     ptr += 4 ;  /* Move past "fmt ".*/  
  167.     memcpy (&waveformat, ptr, sizeof (WAVEFORMAT)) ;  
  168.   
  169.     if (waveformat.dwSize < (sizeof (WAVEFORMAT) - sizeof (u_long))) {  
  170.         err("Bad format: Bad fmt size");            /* wwg: report error */  
  171.         return  WR_BADFORMATSIZE ;  
  172.     }  
  173.   
  174.     if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {  
  175.         err("Only supports PCM wave format");           /* wwg: report error */  
  176.         return  WR_NOTPCMFORMAT ;  
  177.     }  
  178.   
  179.     ptr = findchunk (buffer, "data", BUFFERSIZE) ;  
  180.   
  181.     if (! ptr) {  
  182.         err("Bad format: unable to find 'data' file marker");   /* wwg: report error */  
  183.         return  WR_NODATACHUNK ;  
  184.     }  
  185.   
  186.     ptr += 4 ;  /* Move past "data".*/  
  187.     memcpy (&databytes, ptr, sizeof (u_long)) ;  
  188.   
  189.     /* Everything is now cool, so fill in output data.*/  
  190.   
  191.     *channels   = waveformat.wChannels ;  
  192.     *samplerate = waveformat.dwSamplesPerSec ;  
  193.     *samplebits = waveformat.wBitsPerSample ;  
  194.     *samples    = databytes / waveformat.wBlockAlign ;  
  195.       
  196.     *datastart  = ((u_long) (ptr + 4)) - ((u_long) (&(buffer[0]))) ;  
  197.   
  198.     if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {  
  199.         err("Bad file format");         /* wwg: report error */  
  200.         return  WR_BADFORMATDATA ;  
  201.     }  
  202.   
  203.     if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {  
  204.         err("Bad file format");         /* wwg: report error */  
  205.         return  WR_BADFORMATDATA ;  
  206.     }  
  207.   
  208.   return  0 ;  
  209. } ; /* WaveReadHeader*/  
  210.   
  211. /*===========================================================================================*/  
  212.   
  213. #if 0  
  214. char*  WaveFileError (int  errno)  
  215. {   switch (errno)  
  216.     {   case    WW_BADOUTPUTFILE    : return "Bad output file.\n" ;  
  217.         case    WW_BADWRITEHEADER   : return "Not able to write WAV header.\n" ;  
  218.           
  219.         case    WR_BADALLOC         : return "Not able to allocate memory.\n" ;  
  220.         case    WR_BADSEEK          : return "fseek failed.\n" ;  
  221.         case    WR_BADRIFF          : return "Not able to find 'RIFF' file marker.\n" ;  
  222.         case    WR_BADWAVE          : return "Not able to find 'WAVE' file marker.\n" ;  
  223.         case    WR_BADFORMAT        : return "Not able to find 'fmt ' file marker.\n" ;  
  224.         case    WR_BADFORMATSIZE    : return "Format size incorrect.\n" ;  
  225.         case    WR_NOTPCMFORMAT     : return "Not PCM format WAV file.\n" ;  
  226.         case    WR_NODATACHUNK      : return "Not able to find 'data' file marker.\n" ;  
  227.         case    WR_BADFORMATDATA    : return "Format data questionable.\n" ;  
  228.         default                     :  return "No error\n" ;  
  229.     } ;  
  230.     return  NULL ;    
  231. } ; /* WaveFileError*/  
  232. #endif  
  233. /*===========================================================================================*/  
  234.   
  235. char* findchunk  (char* pstart, char* fourcc, size_t n)  
  236. {   char    *pend ;  
  237.     int     k, test ;  
  238.   
  239.     pend = pstart + n ;  
  240.   
  241.     while (pstart < pend)  
  242.     {   if (*pstart == *fourcc)       /* found match for first char*/  
  243.         {   test = TRUE ;  
  244.             for (k = 1 ; fourcc [k] != 0 ; k++)  
  245.                 test = (test ? ( pstart [k] == fourcc [k] ) : FALSE) ;  
  246.             if (test)  
  247.                 return  pstart ;  
  248.             } ; /* if*/  
  249.         pstart ++ ;  
  250.         } ; /* while lpstart*/  
  251.   
  252.     return  NULL ;  
  253. } ; /* findchuck*/  
  254.   
  255. /* $Source: /cvsroot/wavplay/code/wavfile.c,v $ */  


具体的解码分析,俺就不分析了。不是很难的代码,至于其它部分的代码,就不贴出来了,可以自己去下载代码来分析,我下载的是1.5B版本,最新的是2.0版本。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值