WAV 文件格式解析
概述
wav 文件支持多種不同的比特率、采樣率、多聲道音頻。
WAV 文件格式是 Microsoft 的 RIFF 規(guī)范的一個(gè)子集,用于存儲(chǔ)多媒體文件。RIFF(resource interchange file format 資源互換文件格式,以 chunk(塊) 為單位組織文件)格式文件。在 windows 上,大部分多媒體文件都是 RIFF 文件。wav 文件由若干個(gè) RIFF chunk 構(gòu)成,分別為: RIFF WAVE Chunk,F(xiàn)ormat Chunk,F(xiàn)act Chunk(可選),Data Chunk。另外,文件中還可能包含一些可選的區(qū)塊,如:Fact chunk、Cue points chunk、Playlist chunk、Associated data list chunk 等。具體格式如下:
塊解析
wav 文件都是由 chunk 組成,chunk 的格式如下
size | 內(nèi)容 | 含義 |
---|---|---|
4 bytes | ID | 如:RIFF,fmt,data |
4 bytes | chund size | 如標(biāo)準(zhǔn)的 fmt chunk 為 16 字節(jié) |
N bytes | data | chunk 的內(nèi)容 |
RIFF chunk
typedef struct
{
char ChunkID[4]; //'R','I','F','F'
unsigned int ChunkSize;
char Format[4]; //'W','A','V','E'
}riff_chunk;
size | 內(nèi)容 | 含義 |
---|---|---|
4 bytes | ChunkID | RIFF |
4 bytes | ChunkSize | 從下一個(gè)字段首地址開始到文件末尾的總字節(jié)數(shù)。該字段的數(shù)值加 8 為當(dāng)前文件的實(shí)際長度 |
4 bytes | Format | WAVE |
其中 ChunkSize 代表的是整個(gè) file_size 的大小減去 ChunkID 和 ChunkSize 的大小,即 file_size=ChunkSize+8。
fmt chunk
typedef struct
{
char FmtID[4];
unsigned int FmtSize;
unsigned short FmtTag;
unsigned short FmtChannels;
unsigned int SampleRate;
unsigned int ByteRate;
unsigned short BlockAilgn;
unsigned short BitsPerSample;
}fmt_chunk;
size | 內(nèi)容 | 含義 |
---|---|---|
4 bytes | FmtID | fmt |
4 bytes | FmtSize | fmt chunk 的大小,一般有 16/18/20/22/40 字節(jié) (也有超過 40 字節(jié)的情況,如果不知道后面部分的含義,直接跳過即可),超過 16 字節(jié)部分為擴(kuò)展塊 |
2 bytes | FmtTag | 編碼格式代碼,其值見下 常見編碼格式 表,如果上述取值為 16,則此值通常為 1,代表該音頻的編碼方式是 PCM 編碼 |
2 bytes | FmtChannels | 聲道數(shù)目,1 代表單聲道,2 代表雙聲道 |
4 bytes | SampleRate | 采樣頻率,8/11.025/12/16/22.05/24/32/44.1/48/64/88.2/96/176.4/192 kHZ |
4 bytes | ByteRate | 傳輸速率,每秒的字節(jié)數(shù),計(jì)算公式為:SampleRate * FmtChannels * BitsPerSample/8 |
2 bytes | BlockAilgn | 塊對(duì)齊,告知播放軟件一次性需處理多少字節(jié),公式為: BitsPerSample*FmtChannels/8 |
2 bytes | BitsPerSample | 采樣位數(shù),一般有8/16/24/32/64,值越大,對(duì)聲音的還原度越高 |
常見編碼格式
格式編碼 | 格式名稱 | fmt 塊長度 | fact 塊 |
---|---|---|---|
0x01 | PCM / 非壓縮格式 | 16 | |
0x02 | Microsoft ADPCM | 18 | √ |
0x03 | IEEE float | 18 | √ |
0x06 | ITU G.711 a-law | 18 | √ |
0x07 | ITU G.711 μ-law | 18 | √ |
0x031 | GSM 6.10 | 20 | √ |
0x040 | ITU G.721 ADPCM | √ | |
0xFFFE | 見子格式塊中的編碼格式 | 40 |
data chunk
struct DATA_CHUNK
{
char DataID[4]; //'d','a','t','a'
unsigned int DataSize;
};
size | 內(nèi)容 | 含義 |
---|---|---|
4 bytes | DataID | data |
4 bytes | DataSize | 原始音頻數(shù)據(jù)的大小 |
示例分析
Linux 平臺(tái)下使用 mediainfo 分析 wav 文件
安裝
sudo apt-get install mediainfo
解析
執(zhí)行命令:mediainfo test.wav
General
Complete name : test.wav
Format : Wave
File size : 1.35 MiB
Duration : 8 s 0 ms
Overall bit rate mode : Constant
Overall bit rate : 1 411 kb/s
Audio
Format : PCM
Format settings : Little / Signed
Codec ID : 1
Duration : 8 s 0 ms
Bit rate mode : Constant
Bit rate : 1 411.2 kb/s
Channel(s) : 2 channels
Sampling rate : 44.1 kHz
Bit depth : 16 bits
Stream size : 1.35 MiB (100%)
查看文件大小文章來源:http://www.zghlxwxcb.cn/news/detail-401477.html
ls test.wav -l
-rw-rw-r-- 1 tyustli tyustli 1411248 7月 29 15:03 test.wav
hd
工具查看原始數(shù)據(jù)文章來源地址http://www.zghlxwxcb.cn/news/detail-401477.html
hd test.wav -n 128
00000000 52 49 46 46 a8 88 15 00 57 41 56 45 66 6d 74 20 |RIFF....WAVEfmt |
00000010 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 |........D.......|
00000020 04 00 10 00 64 61 74 61 84 88 15 00 0e fc fa fe |....data........|
00000030 6c fb 8a fe c2 fa 19 fe 1e fa b5 fd 85 f9 64 fd |l.............d.|
00000040 f5 f8 20 fd 73 f8 df fc 09 f8 92 fc bb f7 28 fc |.. .s.........(.|
00000050 83 f7 9d fb 5f f7 fe fa 46 f7 55 fa 2e f7 a3 f9 |...._...F.U.....|
00000060 23 f7 fa f8 36 f7 6b f8 57 f7 ef f7 84 f7 83 f7 |#...6.k.W.......|
00000070 c7 f7 2d f7 1e f8 eb f6 88 f8 c3 f6 0b f9 c5 f6 |..-.............|
- 52 49 46 46:對(duì)應(yīng)的 ASCII 字符為:RIFF
- a8 88 15 00:ChunkSize,對(duì)應(yīng)的十六進(jìn)制是 0x1588a8=1411240 +8 和上面的文件大小一致
- 57 41 56 45:對(duì)應(yīng)的 ASCII 字符為 WAVE
- 66 6d 74 20:對(duì)應(yīng)的 ASCII 字符為 fmt
- 10 00 00 00:FmtSize 0x10=16 代表PCM編碼方式
- 01 00:對(duì)應(yīng)為1,代表PCM編碼方式
- 02 00:通道個(gè)數(shù),通道數(shù)為2
- 44 ac 00 00:采樣頻率 0xac44=44100=44.1KHz
- 10 b1 02 00:每秒所需的字節(jié)數(shù),轉(zhuǎn)化為十六進(jìn)制為: 0x2b110=176400 通過此值可以計(jì)算該音頻的時(shí)長:1411240/176400 = 8s
- 04 00:數(shù)據(jù)對(duì)齊單位
- 10 00:采樣位數(shù) 0x10=16
- 64 61 74 61:對(duì)應(yīng)的 ASCII 字符為 data
- 84 88 15 00:對(duì)應(yīng)該音頻的raw數(shù)據(jù)的大小,轉(zhuǎn)化為十六進(jìn)制為 0x158884=1411204,此值等于 1411248-44
代碼解析
/*
* Change Logs:
* Date Author Notes
* 2022-08-26 tyustli first version
*/
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
typedef struct {
char ChunkID[4]; //'R','I','F','F'
unsigned int ChunkSize;
char Format[4]; //'W','A','V','E'
} riff_chunk;
typedef struct {
char FmtID[4];
unsigned int FmtSize;
unsigned short FmtTag;
unsigned short FmtChannels;
unsigned int SampleRate;
unsigned int ByteRate;
unsigned short BlockAilgn;
unsigned short BitsPerSample;
} fmt_chunk;
typedef struct {
char DataID[4]; //'d','a','t','a'
unsigned int DataSize;
} data_chunk;
typedef struct {
riff_chunk riff_region;
fmt_chunk fmt_region;
data_chunk data_region;
} wav_struct;
static void *map_file(const char *path);
static void data_dump(wav_struct *data);
int main(int argc, char *argv[]) {
assert(sizeof(wav_struct) == 44); /* defensive */
if (argc < 2) {
printf("usage: %s file_path\r\n", argv[0]);
exit(-1);
}
/* map file */
wav_struct *map_data = map_file(argv[1]);
/* data dump */
data_dump(map_data);
/* munmap file */
munmap(map_data, map_data->riff_region.ChunkSize + 8);
return 1;
}
static void *map_file(const char *path) {
assert(path != NULL);
int fd = open(path, O_RDWR);
if (fd == -1) {
goto __release;
}
#if 0
off_t size = lseek(fd, 0, SEEK_END);
if (size == -1) {
goto __release;
}
#endif
/* get file size */
struct stat stat;
int ret = fstat(fd, &stat);
if (ret == -1) {
goto __release;
}
size_t size = stat.st_size;
/* map file */
void *file_data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if(file_data == (void *)-1) {
goto __release;
}
close(fd);
return file_data;
/* error handle */
__release:
perror("map file");
if (fd > 0) {
close(fd);
}
exit(1);
}
static void data_dump(wav_struct *data) {
/* riff chunkid */
printf("riff chunk id :");
for(int i = 0; i < 4; i++) {
printf("%c", data->riff_region.ChunkID[i]);
}
printf("\r\n");
/* file size */
printf("wav file size :%d\r\n", data->riff_region.ChunkSize + 8);
/* riff Format */
printf("riff format id :");
for(int i = 0; i < 4; i++) {
printf("%c", data->riff_region.Format[i]);
}
printf("\r\n");
/* fmt chunkid */
printf("fmt chunk id :");
for(int i = 0; i < 4; i++) {
printf("%c", data->fmt_region.FmtID[i]);
}
printf("\r\n");
printf("FmtChannels :%d(1 單聲道, 2 雙聲道)\r\n", data->fmt_region.FmtChannels);
printf("FmtTag :%d(1 PCM 編碼)\r\n", data->fmt_region.FmtTag);
printf("SampleRate :%d\r\n", data->fmt_region.SampleRate);
printf("ByteRate :%d\r\n", data->fmt_region.ByteRate);
printf("BitsPerSample :%d\r\n", data->fmt_region.BitsPerSample);
/* data chunkid */
printf("fmt chunk id :");
for(int i = 0; i < 4; i++) {
printf("%c", data->data_region.DataID[i]);
}
printf("\r\n");
}
/**
* 編譯:gcc wav_parse.c
* 運(yùn)行:./a.out sample.wav
* 結(jié)果:
* riff chunk id :RIFF
* wav file size :497904
* riff format id :WAVE
* fmt chunk id :fmt
* FmtChannels :2(1 單聲道, 2 雙聲道)
* FmtTag :1(1 PCM 編碼)
* SampleRate :44100
* ByteRate :176400
* BitsPerSample :16
* fmt chunk id :data
*
*/
/*************** end of file ***************/
到了這里,關(guān)于【音頻】WAV 格式詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!