基于Linux下的开源wavplay播放器

2019-07-12 20:18发布

***************************************************************************************************************************
作者:EasyWave                                                                                 时间:2013.02.05
类别:Linux 应用之wavplay播放器                                                      声明:转载,请保留链接 注意:如有错误,欢迎指正。这些是我学习的日志文章...... ***************************************************************************************************************************        因为客户需要用到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文件格式进行解码,具体的部分代码如下: /* $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 .WAV 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 .WAV 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 #include #include #include #include #include "wavplay.h" #define BUFFERSIZE 1024 #define PCM_WAVE_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 ; } WAVEFORMAT ; 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 ; } WAVE_HEADER ; /*=================================================================================================*/ char* findchunk (char* s1, char* s2, size_t n) ; /*=================================================================================================*/ static WAVE_HEADER waveheader = { { 'R', 'I', 'F', 'F' }, 0, { 'W', 'A', 'V', 'E' }, { 'f', 'm', 't', ' ' }, 16, /* FmtSize*/ PCM_WAVE_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 (WAVE_HEADER) + databytes - 8 ; waveheader.wFormatTag = PCM_WAVE_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 (WAVE_HEADER)) != sizeof (WAVE_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 WAVEFORMAT 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, "WAVE", BUFFERSIZE)) { err("Bad format: Cannot find WAVE file marker"); /* wwg: report error */ return WR_BADWAVE ; } 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 (WAVEFORMAT)) ; if (waveformat.dwSize < (sizeof (WAVEFORMAT) - sizeof (u_long))) { err("Bad format: Bad fmt size"); /* wwg: report error */ return WR_BADFORMATSIZE ; } if (waveformat.wFormatTag != PCM_WAVE_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. " ; case WW_BADWRITEHEADER : return "Not able to write WAV header. " ; case WR_BADALLOC : return "Not able to allocate memory. " ; case WR_BADSEEK : return "fseek failed. " ; case WR_BADRIFF : return "Not able to find 'RIFF' file marker. " ; case WR_BADWAVE : return "Not able to find 'WAVE' file marker. " ; case WR_BADFORMAT : return "Not able to find 'fmt ' file marker. " ; case WR_BADFORMATSIZE : return "Format size incorrect. " ; case WR_NOTPCMFORMAT : return "Not PCM format WAV file. " ; case WR_NODATACHUNK : return "Not able to find 'data' file marker. " ; case WR_BADFORMATDATA : return "Format data questionable. " ; default : return "No error " ; } ; 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版本。