Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1154787
  • 博文数量: 221
  • 博客积分: 10152
  • 博客等级: 上将
  • 技术积分: 1518
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-22 10:42
文章分类

全部博文(221)

文章存档

2018年(1)

2015年(6)

2014年(3)

2013年(4)

2012年(1)

2011年(5)

2010年(14)

2009年(10)

2008年(28)

2007年(33)

2006年(114)

2005年(2)

我的朋友

分类: LINUX

2014-10-28 15:06:19

WAV文件播放

(2012-12-12 19:56:09)
标签:

android

wav

分类: Android机制
wav文件分为三步分:
1:头,占固定的12个字节;
2:中间是部分是一个fmt的chunk,记录了channel,mask,samplerate等信息;
3:最后是一个data的chunk,包含编码后的数据。

如下图所示:
WAV文件播放

下面具体分析每一块的内容

一:header包含的12字节的含义
组织结构图如下:
WAV文件播放
前四个字节后后四个字节是固定的字段,用来作为WAV文件的标识符,在用循环调用sniff解析文件类型的时候,读取的就是这前后各四个字节,代码如下:
bool SniffWAV(
        const sp &source, String8 *mimeType, float *confidence,
        sp *) {
    char header[12];
    if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
        return false;
    }
    if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
        return false;
    }
    *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
    *confidence = 0.3f;
    return true;
}
中间的四个字节表示整个wav文件的长度,即totalSize

二:fmt chunk的组织结构
这里只分析一般的wav的fmt结构,至于扩展的类似分析,一般的wav文件的fmt chunk占16个字节,主要用来保存一下内容:
mWaveFormat = U16_LE_AT(formatSpec);
    enum {
    WAVE_FORMAT_PCM        = 0x0001,
    WAVE_FORMAT_ALAW       = 0x0006,
    WAVE_FORMAT_MULAW      = 0x0007,
    WAVE_FORMAT_EXTENSIBLE = 0xFFFE
    };

mNumChannels = U16_LE_AT(&formatSpec[2]); 声音通道数

mSampleRate = U32_LE_AT(&formatSpec[4]);码率

mSampleRate = U32_LE_AT(&formatSpec[4]);每个sample中包含的bit数目

上面类似于U32_LE_AT这种函数都是大小端转换的函数,简单说就是调换字节顺序,前面的blog中有分析。

组织结构如下:
WAV文件播放

                  前面的变量代表保存的信息,后面的数字代表占用几个字节

三: data chunk 保存多媒体数据的部分,解码播放读取源数据就是从这里开始从前往后读取
前四个字节表明chunk的类型,紧跟着字节表明这个chunk的大小,后面剩下的字节为多媒体数据
WAV文件播放

其中获取到多媒体数据的长度后,加上fmt里面获取的信息,就可以计算这个音频文件的时长,计算公式如下:

WAV文件播放

四:补充1
解析完成之后,会将游标mOffset设置到Audio data的位置,这样下次读取数据的时候就可以跳过一些头字节,读取音频数据了;

五:补充2
这里计算文件总长度和计算data类型的chunk的时候是根据具体的chunk的header中的后四个字节读出来的,一般情况下不会有问题,如果遇到 正常编码后长度为5M的文件,被某个软件截取了前面的1M,但是并没有去改那几个字节的数据,这样会导致通过头信息计算出来的文件的长度和播放时长会和实 际情况严重不符,遇到这种情况,就需要采用其他方式来计算文件的长度了,如:
              int fileLength = lseek(fd, 0, SEEK_END);
 多媒体数据部分的长度为
              mDataSize = fileLength - 12 - 8 - 16 - 8;
12 表示文件头,8为fmt的头,16为fmt的chunkSize,8为data的头

综合考虑两种情况的代码如下:
                mDataOffset = offset;
                mDataSize = chunkSize;
                int fileLength = lseek(fd, 0, SEEK_END);
                if(fileLength - 12 - 8 - 16 - 8 < mDataSize)
                    mDataSize = fileLength - 12 - 8 - 16 - 8;

这样计算出来的音频文件的播放时长就不会有问题了。
阅读(1085) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~