格式说明
wav是一种无损的音频文件格式。所有的WAV都有一个文件头,包含了这个音频的编码参数。wav对音频流的编码没有硬性规定,除了PCM之外,还有几乎所有支持ACM规范的编码都可以为WAV的音频流进行编码。
对PCM数据来说,加上wav文件头就变成了wav格式。
不同格式的数据,wav文件头的格式也略有不同,标准PCM数据的wav文件头是44字节,而ulaw或alaw的文件头会多一个区块,占58字节。
PCM数据对应的WAV文件头:
区块名
bytes
端序
内容
说明
ChunkID
4
大
"RIFF"
ChunkSzie
4
小
N+sizeof(head)-8
N是音频数据的长度
Format
4
大
"WAVE"
Subchunk1ID
4
大
"fmt "
fmt加空格
Subchunk1IDsize
4
小
16or18
AudioFormat
2
小
音频格式
PCM: 0x01;a-law: 0x06;u-law: 0x07
NumChannels
2
小
通道数
单声道:1,立体声:2
SampleRate
4
小
采样频率Hz
ByteRate
4
小
SampleRate * NumChannels * BitsPerSample/8
BlockAlign
2
小
NumChannels * BitsPerSample/8
BitPerSample
2or4
小
8bits=8, 16bits=16
采样位深
是压缩编码数据时占4字节,正常编码数据占2字节
factchunkID
4
大
"fact"
压缩编码的数据需要这个块,否则不需要
factchunkIDsize
4
小
4
factData
4
小
可以是音频数据长度
Subchunk2ID
4
大
"data"
Subchunk2IDsize
4
小
N
音频数据的长度
data
N
小
十六进制文件说明
原始数据
52 49 46 46 0e 82 01 00 57 41 56 45 66 6d 74
20 10 00 00 00 01 00 01 00 80 3e 00 00 00 7d
00 00 02 00 10 00 64 61 74 61 ea 81 01 00 a3
ff a3 ff a5 ff a7 ff a8 ff
数据分析
52 49 46 46:对应的 ASCII 字符为:RIFF
0e 82 01 00:ChunkSize,对应的十六进制是 0x1820e=98830 +8 和上面的文件大小一致
57 41 56 45:对应的 ASCII 字符为 WAVE
66 6d 74 20:对应的 ASCII 字符为 fmt
10 00 00 00:FmtSize 0x10=16 代表PCM编码方式
01 00:对应为1,代表PCM编码方式
01 00:通道个数,通道数为1
80 3e 00 00:采样频率 0x3e80=16000=16KHz
00 7d 00 00:每秒所需的字节数,转化为十六进制为: 0x7d00=32000 通过此值可以计算该音频的时长:98838/32000 = 3s
02 00:数据对齐单位
10 00:采样位数 0x10=16
64 61 74 61:对应的 ASCII 字符为 data
ea 81 01 00:对应该音频的raw数据的大小
代码解析格式头
//WAVE文件一般有四种块,它们依次是:RIFF块、格式块、附加块(可选),数据块
#pragma pack(1)
typedef struct {
//RIFF块
uint8_t riffID[4]; //RIFF标识
uint32_t fileSize; //文件大小
uint8_t fccType[4]; //WAVE标志
//fmt块
uint8_t fmtID[4]; //fmt
uint32_t ckLen; //块大小 pcm-0x10;ulaw-0x12;alaw-0x12
uint16_t wFormatTag; //音频格式 pcm-0x01;ulaw-0x07;alaw-0x06
uint16_t nChannels; //采样声道数
uint32_t nSamplesPerSec; //采样率
uint32_t nAvgBytesPerSec; //每秒字节数 采样率*采样精度/8(字节位数)
uint16_t cbSize;
uint32_t bPerSample; //每个采样位数,量化数(pcm为2byte)
//fact块,压缩编码须有该块
uint8_t factID[4]; //fact
uint32_t factSzie; //4
uint32_t factData;
//data块
uint8_t wdid[4]; //data 标志
uint32_t wdSize; //块大小
} WAVFILEHEADER;
//0x3A(58)字节
//针对ulaw和alaw,未经压缩的原始pcm对应的wav文件头有所不同
#pragma pack()
void TestWAVFile()
{
int nWaveHeaderLen = sizeof(WAVFILEHEADER);
FILE *fp = fopen("F:/ffmpeg/audio/7221/libg7221-master/test-data/local/short_wb_voice.wav", "rb+");
if (fp == NULL)
{
std::cout << "打开文件失败" << std::endl;
return;
}
char *pWavBuffer = (char *)calloc(nWaveHeaderLen, sizeof(char));
if (fread(pWavBuffer, 1, nWaveHeaderLen, fp) != nWaveHeaderLen)
{
std::cout << "读取文件失败" << std::endl;
return;
}
WAVFILEHEADER *pWavHeader = (WAVFILEHEADER *)pWavBuffer;
return;
}
参考
wav文件格式分析与详解 - nigaopeng - 博客园 (cnblogs.com)