发布于 

音视频编程: 简单分析 WAV 文件

最近在看人工智能相关的知识,无意中发现了一个巨牛的 人工智能教程,分享一下给大家。

教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点 这里 可以直接看教程。


这篇分享是下篇 音视频编程: iOS 使用 faad2 的预备知识, 如果要解码 WAV 文件, 首先需要了解一下 WAV 音频文件的格式。

今天说的是 线性 PCM 对应的 WAV 格式的数据。

PCM 的种类

  • 线性化 PCM
  • A律量化的 PCM
  • U律量化的 PCM
  • AD PCM
  • GSM

该系列博文:

WAV 简介

WAV 只是该音频文件的后缀名, 其完整名称缩写是 WAVE,WAVE(Waveform Audio File Format), 采用RIFF(Resource Interchange File Format)文件格式结构。

WAV 格式的音频文件通常用来保存 PCM 格式的原始音频数据,通常被称之为无损音频。

WAV 音频文件, 粗略来说是 WAV 数据头 + PCM 数据组成的. 裸数据 PCM 外面包了一层文件头,WAV 实质为一个 RIFF 文件.

WAV 数据头

关于 WAV 音频文件的数据头定义如下图所示:

1

最前面的4个字节用来标示是 RIFF 字符串。

可以看出, 一般的 WAV 文件的数据头为 44 个字节, 其后面跟的是 PCM 数据。

分析 WAV 数据头

使用 hexdump 来看一下 WAV 文件的数据头。

在当前路径下, 有个 wav 格式的音频文件 m.wav, 使用 hexdump 分析一下.

1
hexdump -n 44 m.wav

2

其中, -n 44 表示查看前 44 个字节.

按字节分组的图, 如下所示:
2

1
52 49 46 46

分别是 RIFF 的 ASCII 码.

跟在 RIFF 后面的四个字节是文件的大小信息, 我们先使用 ls 命令看一下该文件的大小。

1
ls -al

输出文件大小为(字节数): 1080808

1
staff  1080808 Jan 25 15:44 m.wav

RIFF 后面的四个字节分别是: e0 7d 10 00, 由于该存储使用了小端序(Little-Endian 存储,也就是说对其中的数据,低位字节在前,高位字节在后), 所以16进制表示为: 0x00107de0, 对应的字节大小是 1080808.

上面说到, 线性 PCM, 其实在该文件头中, 第17到第第22个字节(上图红色的5和6组合)标示了 PCM 的类型, 即:

1
10 00 00 00 01 00 

其他类型的 PCM 类型定义为:

A律量化的PCM: 12 00 00 0006 00
U律量化的PCM: 12 00 00 00 07 00
AD PCM: 32 00 00 00 02 00
GSM: 14 00 00 00 31 00

最后4个字节表示真正 PCM 数据的文件大小, 即: 0x00107dbc, 其10进制大小为: 1080764, 用总文件大小减去 1080764, 就是文件头的大小, 如下:

1
1080808 - 1080764 = 44

其他对应的数据, 大家可以对照表自行分析。

定义数据头

数据类型

  • char 占用 1 个字节
  • uint32_t 占用 4 个字节
  • uint16_t 占用 2 个字节

这里使用结构体定义 WAV 文件头, 其定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct MZWavAudioFileHeader
{
char riff[4]; // 字符串 "RIFF"
uint32_t totalLength; // 文件总大小, 包括PCM 数据大小和该文件头大小
char wave[4]; // 字符串 "WAVE"
char fmt[4]; // 字符串 "fmt "
uint32_t format; // WAV 头大小, 固定为值 16
uint16_t pcm; // PCM 编码方式, 固定值为 1
uint16_t channels; // 声道数量, 为 2
uint32_t frequency; // 采样频率
uint32_t bytes_per_second; // 每秒字节数(码率), 其值=采样率x通道数x位深度/8
uint16_t bytes_by_capture; // 采样块大小
uint16_t bits_per_sample; // 采样点大小, 这里是 16 位
char data[4]; // 字符串 "data"
uint32_t bytes_in_pcmdata; // pcm 数据长度
};

可以使用下面代码来计算该结构体所占的字节数(结果是44):

1
int wav_header_size = sizeof(struct MZWavAudioFileHeader);

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

veryitman