您的位置:首页 > 运维架构 > Linux

基于Linux下的开源wavplay播放器

2015-11-12 15:48 543 查看
转载自: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的缩写,每个W***E文件的头四个字节便是“RIFF”,W***E文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF W***E Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。如下图所示:





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

1):RIFF W***E Chunk



以'FIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段,为'W***E',表示是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文件格式进行解码,具体的部分代码如下:

[cpp] view
plaincopyprint?

/* $Id: wavfile.c,v 1.3 2009/11/30 15:02:31 ve3wwg Exp $

* Copyright: wavfile.c (c) Erik de Castro Lopo erikd@zip.com.au

*

* wavfile.c - Functions for reading and writing MS-Windoze .W*** files.

*

* This program is free software; you can redistribute it and/or modify it

* under the terms of the GNU General Public License as published by the

* Free Software Foundation.

*

* This program is distributed in the hope that it will be useful, but

* WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General

* Public License for more details (licensed by file COPYING or GPLv*).

*

* This code was originally written to manipulate Windoze .W*** files

* under i386 Linux (erikd@zip.com.au).

*

* ve3wwg@gmail.com

*/

static const char rcsid[] = "$Id: wavfile.c,v 1.3 2009/11/30 15:02:31 ve3wwg Exp $";



#include <stdio.h>

#include <errno.h>

#include <sys/types.h>

#include <unistd.h>

#include <string.h>



#include "wavplay.h"



#define BUFFERSIZE 1024

#define PCM_W***E_FORMAT 1



#define TRUE 1

#define FALSE 0



typedef struct

{ u_long dwSize ;

u_short wFormatTag ;

u_short wChannels ;

u_long dwSamplesPerSec ;

u_long dwAvgBytesPerSec ;

u_short wBlockAlign ;

u_short wBitsPerSample ;

} W***EFORMAT ;



typedef struct

{ char RiffID [4] ;

u_long RiffSize ;

char WaveID [4] ;

char FmtID [4] ;

u_long FmtSize ;

u_short wFormatTag ;

u_short nChannels ;

u_long nSamplesPerSec ;

u_long nAvgBytesPerSec ;

u_short nBlockAlign ;

u_short wBitsPerSample ;

char DataID [4] ;

u_long nDataBytes ;

} W***E_HEADER ;



/*=================================================================================================*/



char* findchunk (char* s1, char* s2, size_t n) ;



/*=================================================================================================*/





static W***E_HEADER waveheader =

{ { 'R', 'I', 'F', 'F' },

0,

{ 'W', 'A', 'V', 'E' },

{ 'f', 'm', 't', ' ' },

16, /* FmtSize*/

PCM_W***E_FORMAT, /* wFormatTag*/

0, /* nChannels*/

0,

0,

0,

0,

{ 'd', 'a', 't', 'a' },

0

} ; /* waveheader*/



static ErrFunc v_erf; /* wwg: Error reporting function */



/*

* Error reporting function for this source module:

*/

static void

err(const char *format,...) {

va_list ap;



if ( v_erf == NULL )

return; /* Only report error if we have function */

va_start(ap,format);

v_erf(format,ap); /* Use caller's supplied function */

va_end(ap);

}



int WaveWriteHeader (int wavefile, int channels, u_long samplerate, int sampbits, u_long samples, ErrFunc erf)

{ u_long databytes ;

u_short blockalign ;



v_erf = erf; /* wwg: Set error reporting function */



if ( wavefile < 0 ) {

err("Invalid file descriptor");

return WW_BADOUTPUTFILE ;

}



sampbits = (sampbits == 16) ? 16 : 8 ;



blockalign = ((sampbits == 16) ? 2 : 1) * channels ;

databytes = samples * (u_long) blockalign ;



waveheader.RiffSize = sizeof (W***E_HEADER) + databytes - 8 ;

waveheader.wFormatTag = PCM_W***E_FORMAT ;

waveheader.nChannels = channels ;

waveheader.nSamplesPerSec = samplerate ;

waveheader.nAvgBytesPerSec = samplerate * (u_long) blockalign ;

waveheader.nBlockAlign = blockalign ;

waveheader.wBitsPerSample = sampbits ;

waveheader.nDataBytes = databytes;



if (write (wavefile, &waveheader, sizeof (W***E_HEADER)) != sizeof (W***E_HEADER)) {

err("%s",strerror(errno)); /* wwg: report the error */

return WW_BADWRITEHEADER ;

}



return 0 ;

} ; /* WaveWriteHeader*/



int WaveReadHeader (int wavefile, int* channels, u_long* samplerate, int* samplebits, u_long* samples, u_long* datastart,ErrFunc erf)

{ static W***EFORMAT waveformat ;

static char buffer [ BUFFERSIZE ] ; /* Function is not reentrant.*/

char* ptr ;

u_long databytes ;



v_erf = erf; /* wwg: Set error reporting function */



if (lseek (wavefile, 0L, SEEK_SET)) {

err("%s",strerror(errno)); /* wwg: Report error */

return WR_BADSEEK ;

}



read (wavefile, buffer, BUFFERSIZE) ;



if (findchunk (buffer, "RIFF", BUFFERSIZE) != buffer) {

err("Bad format: Cannot find RIFF file marker"); /* wwg: Report error */

return WR_BADRIFF ;

}



if (! findchunk (buffer, "W***E", BUFFERSIZE)) {

err("Bad format: Cannot find W***E file marker"); /* wwg: report error */

return WR_BADW***E ;

}



ptr = findchunk (buffer, "fmt ", BUFFERSIZE) ;



if (! ptr) {

err("Bad format: Cannot find 'fmt' file marker"); /* wwg: report error */

return WR_BADFORMAT ;

}



ptr += 4 ; /* Move past "fmt ".*/

memcpy (&waveformat, ptr, sizeof (W***EFORMAT)) ;



if (waveformat.dwSize < (sizeof (W***EFORMAT) - sizeof (u_long))) {

err("Bad format: Bad fmt size"); /* wwg: report error */

return WR_BADFORMATSIZE ;

}



if (waveformat.wFormatTag != PCM_W***E_FORMAT) {

err("Only supports PCM wave format"); /* wwg: report error */

return WR_NOTPCMFORMAT ;

}



ptr = findchunk (buffer, "data", BUFFERSIZE) ;



if (! ptr) {

err("Bad format: unable to find 'data' file marker"); /* wwg: report error */

return WR_NODATACHUNK ;

}



ptr += 4 ; /* Move past "data".*/

memcpy (&databytes, ptr, sizeof (u_long)) ;



/* Everything is now cool, so fill in output data.*/



*channels = waveformat.wChannels ;

*samplerate = waveformat.dwSamplesPerSec ;

*samplebits = waveformat.wBitsPerSample ;

*samples = databytes / waveformat.wBlockAlign ;



*datastart = ((u_long) (ptr + 4)) - ((u_long) (&(buffer[0]))) ;



if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {

err("Bad file format"); /* wwg: report error */

return WR_BADFORMATDATA ;

}



if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {

err("Bad file format"); /* wwg: report error */

return WR_BADFORMATDATA ;

}



return 0 ;

} ; /* WaveReadHeader*/



/*===========================================================================================*/



#if 0

char* WaveFileError (int errno)

{ switch (errno)

{ case WW_BADOUTPUTFILE : return "Bad output file.\n" ;

case WW_BADWRITEHEADER : return "Not able to write W*** header.\n" ;



case WR_BADALLOC : return "Not able to allocate memory.\n" ;

case WR_BADSEEK : return "fseek failed.\n" ;

case WR_BADRIFF : return "Not able to find 'RIFF' file marker.\n" ;

case WR_BADW***E : return "Not able to find 'W***E' file marker.\n" ;

case WR_BADFORMAT : return "Not able to find 'fmt ' file marker.\n" ;

case WR_BADFORMATSIZE : return "Format size incorrect.\n" ;

case WR_NOTPCMFORMAT : return "Not PCM format W*** file.\n" ;

case WR_NODATACHUNK : return "Not able to find 'data' file marker.\n" ;

case WR_BADFORMATDATA : return "Format data questionable.\n" ;

default : return "No error\n" ;

} ;

return NULL ;

} ; /* WaveFileError*/

#endif

/*===========================================================================================*/



char* findchunk (char* pstart, char* fourcc, size_t n)

{ char *pend ;

int k, test ;



pend = pstart + n ;



while (pstart < pend)

{ if (*pstart == *fourcc) /* found match for first char*/

{ test = TRUE ;

for (k = 1 ; fourcc [k] != 0 ; k++)

test = (test ? ( pstart [k] == fourcc [k] ) : FALSE) ;

if (test)

return pstart ;

} ; /* if*/

pstart ++ ;

} ; /* while lpstart*/



return NULL ;

} ; /* findchuck*/



/* $Source: /cvsroot/wavplay/code/wavfile.c,v $ */

具体的解码分析,俺就不分析了。不是很难的代码,至于其它部分的代码,就不贴出来了,可以自己去下载代码来分析,我下载的是1.5B版本,最新的是2.0版本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: