wav文件格式解析

本文将详细分析不同格式的wav文件。


简介

wavwave(下文统称为wav), 该文件格式是由微软开发的用于音频数字存储的标准,可应用于WindowsLinuxMacOS等多种操作系统,文件扩展名为.wav,是waveform的简写。

wav文件结构

Windows下,大部分多媒体文件都遵循RIFFResource Interchange File Format,资源互换文件格式)格式来存储数据。

RIFF文件的基本存储单位称为块(chunk),一个遵循RIFF格式的文件由若干个chunk组成,每个chunk又由块标识、块长度和块数据三部分构成,其基本结构见表1

Field Size(bytes) Type
块标识 4 S8 *
块长度 4 U32
块数据 S8 *

表1 chunk基本结构

  • 块标识:用于标识块中的数据,由4ASCII字符组成,如不满4个字符则在右边以空格充填,如:RIFFLISTfmtdata等;
  • 块长度:用于标识块数据域中的数据长度,块标识域和块长度域不包括在其中,所以一个chunk的实际长度为该值加8;
  • 块数据:存储块数据,若数据长度为奇数,则在最后添加一个NULL

特别需要注意的是,RIFF格式规定只有块标识为RIFFLIST的块可以含有子块(subChunk),而其它块只可以包含数据。块标识为RIFFLIST的块的结构与表1大致相同,只不过其块数据域分为两部分:

  • type:由4ASCII字符组成,代表RIFF文件的类型,如WAVEAVI,或者代表LIST块的类型,如avi文件中的列表hdrlmovi
  • data:实际的块内容,包含若干subChunk

wav文件是非常简单的一种RIFF文件,其本身就是由一个块标识为RIFFchunk和多个subChunk组成的一个chunk,其组成如下:

  • RIFF chunk:主块,必选,块标识为RIFF,说明这是一个RIFF文件,RIFF文件的第一个块标识必须是RIFF
  • Format chunk:子块,必选,块标识为fmt,用于存储文件的一些参数信息,比如采样率、通道数和编码格式等;
  • Fact chunk:子块,可选,块标识为fact,基于压缩编码的wav文件必须含有fact块;
  • List chunk:子块,可选,块标识为LIST,用于记录文件版权和创建时间信息;
  • Data chunk:子块,必选,块标识为data,用于存储音频数据;

目前业界标准的wav文件仅由RIFF chunkFormat chunkData chunk组成:
标准wav文件格式

wav文件头格式

wav文件从数据类型上看,主要由文件头和数据体两部分组成:

  • 文件头:由RIFF chunkFormat chunkList chunkFact chunk等组成,用于存储一些文件信息;
  • 数据体:由Data chunk组成,用于存储音频数据;

标准格式

标准的wav文件头仅由RIFF chunkFormat chunk组成,长度为44个字节,格式见表2

file offset(bytes) Field name Field size(bytes) type endian description
0 Chunk ID 4 S8 * big “RIFF”,表明为RIFF文件
4 Chunk Size 4 U32 little 除了RIFF及自己之外,整个文件的长度,即文件总字节数减去8字节
8 Format 4 S8 * big “WAVE”,表明为wav格式
12 Subchunk1 ID 4 S8 * big “fmt “
16 Subchunk1 Size 4 U32 little 表示fmt数据块即subchunk1除了Subchunk1 ID和Subchunk1 Size之后剩下的长度,一般为16, 大于16表示存在扩展区域,可选值为16、18、20、40等
20 AudioFormat 2 U16 little 编码格式,即压缩格式,0x01表示pcm格式,无压缩,参见表3
22 NumChannels 2 U16 little 音频通道数,单声道为1,立体声或双声道为2
24 SampleRate 4 U32 little 采样频率,每个通道单位时间采样次数,可选值为16000kHz和44100kHz等
28 ByteRate 4 U32 little 数据传输速率,可用此估算缓冲区长度,ByteRate = SampleRate NumChannels (BitsPerSample / 8)
32 BlockAlign 2 U16 little 采样一次的字节数,即一帧的字节数,表示块对齐的内容(数据块的调整数),播放软件一次处理多少个该长度的字节数据,以便将其用于缓冲区的调整,BlockAlign = NumChannels * (BitsPerSample / 8)
34 BitsPerSample 2 U16 little 采样位宽,即每个采样点的bit数,可选值8、16或32等
36 Subchunk2 ID 4 S8 * big “data”
40 Subchunk2 Size 4 U32 little 音频数据的总长度,即文件总字节数减去wav文件头的长度
44 Data little 音频数据

表2 标准的wav文件头格式

通过wav文件头信息,我们可以计算出音频时长:

1
音频时长(s) = Subchunk2 Size / ByteRate

压缩编码格式

wav文件几乎支持所有ACM规范的编码格式,其信息存储在wav文件头偏移2021两个字节中,常见的压缩编码格式见表3

格式代码 格式名称 Format chunk 长度 是否有Fact chunk
0 (0x0000) unknown unknown unknown
1 (0x0001) PCM/uncompressed 16
2 (0x0002) Microsoft ADPCM 18
3(0x0003) IEEE float 18
6 (0x0006) ITU G.711 a-law 18
7 (0x0007) ITU G.711 µ-law 18
17 (0x0011) IMA ADPCM unknown unknown
20 (0x0016) ITU G.723 ADPCM (Yamaha) unknown unknown
49 (0x0031) GSM 6.10 20
64 (0x0040) ITU G.721 ADPCM unknown
80 (0x0050) MPEG unknown unknown
65,534 (0xFFFE) 扩展格式标识 40 unknown
65,536 (0xFFFF) Experimental unknown unknown

表3 常见的压缩编码格式

扩展格式

当然,也不是所有的wav文件头都是44个字节的,比如通过FFmpge编码而来的wav文件头通常大于44个字节,目前比较常见的wav文件头长度有44字节、46字节、58字节和98字节。

Format chunk扩展

wav文件采用非PCM编码即压缩格式时,会扩展Format chunk,在其之后扩充了一个数据结构,见表4

file offset(bytes) Field name Field size(bytes) type description
24 extand size 2 U16 除其自身外的扩展区域长度
26 extand area 包含扩展的格式信息,其长度取决于压缩编码类型。当某种编码格式(如ITU G.711 a-law)使扩展区的长度为0时,该字段还必须保留,只是长度字段的数值为0。

表4 标准Format chunk扩展格式

由此可以得出,如果Subchunk1 Size等于0x10(16),表示不包含Format chunk扩展,wav文件头长度为44字节;如果大于0x10(16),则包含Format chunk扩展,扩展长度的最小值为18(16+2),此时wav文件头大于44字节。

当编码格式代码为0xFFFE时,Format chunk扩展长度为24字节,格式见表5

file offset(bytes) Field name Field size(bytes) type description
24 扩展区长度 2 U16 值为22
26 有效采样位数 2 U16 最大值为 每个采样字节数 * 8
28 扬声器位置 4 U32 声道号与扬声器位置映射的二进制掩码
32 编码格式 2 U16 真正的编码格式代码
34 14 值为{\x00, \x00, \x00, \x00, \x10, \x00, \x80, \x00, \x00, \xAA, \x00, \x38, \x9B, \x71}

表5 编码为0xFFFE的Format chunk扩展格式

Fact chunk

采用压缩编码(修订版Rev.3以后出现的编码格式)的wav文件必定有含有Fact chunk,其结构符合标准chunk结构,参见表1

Fact chunk的块标识符为”fact“,块长度至少为4个字节,目前其只有一个块数据内容,即每个声道采样总数,或采样帧总数。该值等于Subchunk2 Size / BlockAlign

值得注意的是,在实测中发现,将压缩编码格式文件转换成PCM编码格式后,原Fact chunk仍然存在。

wav文件动态解析库

wav文件格式是一种极其简单的文件格式,如果对其结构足够熟悉,完全可以通过代码正确读写,从而免去引入一些复杂的中间库,降低复杂度,提高工作效率。

这里提供了一个wav文件动态解析库,欢迎使用。

Reference


Author

微信公众号同步更新,微信搜索"AnSwEr不是答案"或者扫描二维码,即可订阅。
AnSwEr(Weijie Yuan) wechat