wav音频文件头解析
wav概述
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource
Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT
A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几! WAV打开工具是WINDOWS的媒体播放器。
通常使用三个参数来表示声音,量化位数,取样频率和采样点振幅。量化位数分为8位,16位,24位三种,声道有单声道和立体声之分,单声道振幅数据为n*1矩阵点,立体声为n*2矩阵点,取样频率一般有11025Hz(11kHz)
,22050Hz(22kHz)和44100Hz(44kHz) 三种,不过尽管音质出色,但在压缩后的文件体积过大!相对其他音频格式而言是一个缺点,其文件大小的计算方式为:WAV格式文件所占容量(B)
= (取样频率 X量化位数X 声道) X 时间 / 8 (字节=
8bit) 每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。
支持WAV设计的手机主要为智能手机,如索尼爱立信P910和诺基亚N90以及采用Windows Moblie的多普达等手机还有微软Windows
Phone系列手机,而其它一些非智能手机的产品,如果宣传支持WAV格式则多半属于只是支持单声道的。
格式解析
WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。
整个头长度44byte.
标志符(RIFF) |
余下所有数据的长度 |
格式类型("WAVE") |
"fmt" |
PCMWAVEFORMAT的长度 |
PCMWAVEFORMAT |
"data" |
声音数据大小 |
声音数据 |
wav头结构体定义
- /* RIFF WAVE file struct.
- * For details see WAVE file format documentation
- * (for example at <a href="http://www.wotsit.org)." target="_blank">http://www.wotsit.org).</a> */
- typedef struct WAV_HEADER_S
- {
- char riffType[4]; //4byte,资源交换文件标志:RIFF
- unsigned int riffSize; //4byte,从下个地址到文件结尾的总字节数
- char waveType[4]; //4byte,wav文件标志:WAVE
- char formatType[4]; //4byte,波形文件标志:FMT(最后一位空格符)
- unsigned int formatSize; //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
- unsigned short compressionCode;//2byte,格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
- unsigned short numChannels; //2byte,通道数
- unsigned int sampleRate; //4byte,采样率
- unsigned int bytesPerSecond; //4byte,传输速率
- unsigned short blockAlign; //2byte,数据块的对齐,即DATA数据块长度
- unsigned short bitsPerSample; //2byte,采样精度-PCM位宽
- char dataType[4]; //4byte,数据标志:data
- unsigned int dataSize; //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
- }WAV_HEADER;
头解析程序示例
wav.h
#ifndef __WAV_H__
#define __WAV_H__ #define debug(fmt...) do \
{ \
printf("[%s::%d] ", __func__, __LINE__);\
printf(fmt); \
}while() /* RIFF WAVE file struct.
* For details see WAVE file format documentation
* (for example at <a href="http://www.wotsit.org)." target="_blank">http://www.wotsit.org).</a> */
typedef struct WAV_HEADER_S
{
char riffType[]; //4byte,资源交换文件标志:RIFF
unsigned int riffSize; //4byte,从下个地址到文件结尾的总字节数
char waveType[]; //4byte,wave文件标志:WAVE
char formatType[]; //4byte,波形文件标志:FMT
unsigned int formatSize; //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
unsigned short compressionCode;//2byte,编码格式(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
unsigned short numChannels; //2byte,通道数
unsigned int sampleRate; //4byte,采样率
unsigned int bytesPerSecond; //4byte,传输速率
unsigned short blockAlign; //2byte,数据块的对齐
unsigned short bitsPerSample; //2byte,采样精度
char dataType[]; //4byte,数据标志:data
unsigned int dataSize; //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
}WAV_HEADER; typedef struct WAV_INFO_S
{
WAV_HEADER header;
FILE *fp;
unsigned int channelMask;
}WAV_INFO; #endif
wav.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wav.h" /* func : endian judge
* return : 0-big-endian othes-little-endian
*/
int IS_LITTLE_ENDIAN(void)
{
int __dummy = 1;
return ( *( (unsigned char*)(&(__dummy) ) ) );
} unsigned int readHeader(void *dst, signed int size, signed int nmemb, FILE *fp)
{
unsigned int n, s0, s1, err;
unsigned char tmp, *ptr; if ((err = fread(dst, size, nmemb, fp)) != nmemb)
{
return err;
}
if (!IS_LITTLE_ENDIAN() && size > 1)
{
//debug("big-endian \n");
ptr = (unsigned char*)dst;
for (n=0; n<nmemb; n++)
{
for (s0=0, s1=size-1; s0 < s1; s0++, s1--)
{
tmp = ptr[s0];
ptr[s0] = ptr[s1];
ptr[s1] = tmp;
}
ptr += size;
}
}
else
{
//debug("little-endian \n");
} return err;
} void dumpWavInfo(WAV_INFO wavInfo)
{
debug("compressionCode:%d \n",wavInfo.header.compressionCode);
debug("numChannels:%d \n",wavInfo.header.numChannels);
debug("sampleRate:%d \n",wavInfo.header.sampleRate);
debug("bytesPerSecond:%d \n",wavInfo.header.bytesPerSecond);
debug("blockAlign:%d \n",wavInfo.header.blockAlign);
debug("bitsPerSample:%d \n",wavInfo.header.bitsPerSample); } int wavInputOpen(WAV_INFO *pWav, const char *filename)
{
signed int offset;
WAV_INFO *wav = pWav ; if (wav == NULL)
{
debug("Unable to allocate WAV struct.\n");
goto error;
}
wav->fp = fopen(filename, "rb");
if (wav->fp == NULL)
{
debug("Unable to open wav file. %s\n", filename);
goto error;
} /* RIFF标志符判断 */
if (fread(&(wav->header.riffType), 1, 4, wav->fp) != 4)
{
debug("couldn't read RIFF_ID\n");
goto error; /* bad error "couldn't read RIFF_ID" */
}
if (strncmp("RIFF", wav->header.riffType, 4))
{
debug("RIFF descriptor not found.\n") ;
goto error;
}
debug("Find RIFF \n"); /* Read RIFF size. Ignored. */
readHeader(&(wav->header.riffSize), 4, 1, wav->fp);
debug("wav->header.riffSize:%d \n",wav->header.riffSize); /* WAVE标志符判断 */
if (fread(&wav->header.waveType, 1, 4, wav->fp) !=4)
{
debug("couldn't read format\n");
goto error; /* bad error "couldn't read format" */
}
if (strncmp("WAVE", wav->header.waveType, 4))
{
debug("WAVE chunk ID not found.\n") ;
goto error;
}
debug("Find WAVE \n"); /* fmt标志符判断 */
if (fread(&(wav->header.formatType), 1, 4, wav->fp) != 4)
{
debug("couldn't read format_ID\n");
goto error; /* bad error "couldn't read format_ID" */
}
if (strncmp("fmt", wav->header.formatType, 3))
{
debug("fmt chunk format not found.\n") ;
goto error;
}
debug("Find fmt \n"); readHeader(&wav->header.formatSize, 4, 1, wav->fp); // Ignored
debug("wav->header.formatSize:%d \n",wav->header.formatSize); /* read info */
readHeader(&(wav->header.compressionCode), 2, 1, wav->fp);
readHeader(&(wav->header.numChannels), 2, 1, wav->fp);
readHeader(&(wav->header.sampleRate), 4, 1, wav->fp);
readHeader(&(wav->header.bytesPerSecond), 4, 1, wav->fp);
readHeader(&(wav->header.blockAlign), 2, 1, wav->fp);
readHeader(&(wav->header.bitsPerSample), 2, 1, wav->fp); offset = wav->header.formatSize - 16; /* Wav format extensible */
if (wav->header.compressionCode == 0xFFFE)
{
static const unsigned char guidPCM[16] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
};
unsigned short extraFormatBytes, validBitsPerSample;
unsigned char guid[16];
signed int i; /* read extra bytes */
readHeader(&(extraFormatBytes), 2, 1, wav->fp);
offset -= 2; if (extraFormatBytes >= 22)
{
readHeader(&(validBitsPerSample), 2, 1, wav->fp);
readHeader(&(wav->channelMask), 4, 1, wav->fp);
readHeader(&(guid), 16, 1, wav->fp); /* check for PCM GUID */
for (i = 0; i < 16; i++) if (guid[i] != guidPCM[i]) break;
if (i == 16) wav->header.compressionCode = 0x01; offset -= 22;
}
}
debug("wav->header.compressionCode:%d \n",wav->header.compressionCode); /* Skip rest of fmt header if any. */
for (;offset > 0; offset--)
{
fread(&wav->header.formatSize, 1, 1, wav->fp);
} #if 1
do
{
/* Read data chunk ID */
if (fread(wav->header.dataType, 1, 4, wav->fp) != 4)
{
debug("Unable to read data chunk ID.\n");
free(wav);
goto error;
}
/* Read chunk length. */
readHeader(&offset, 4, 1, wav->fp); /* Check for data chunk signature. */
if (strncmp("data", wav->header.dataType, 4) == 0)
{
debug("Find data \n");
wav->header.dataSize = offset;
break;
} /* Jump over non data chunk. */
for (;offset > 0; offset--)
{
fread(&(wav->header.dataSize), 1, 1, wav->fp);
}
} while (!feof(wav->fp));
debug("wav->header.dataSize:%d \n",wav->header.dataSize);
#endif /* return success */
return 0; /* Error path */
error:
if (wav)
{
if (wav->fp)
{
fclose(wav->fp);
wav->fp = NULL;
}
//free(wav);
}
return -1;
} #if 0
int main(int argc,char **argv) {
WAV_INFO wavInfo;
char fileName[128];
if(argc<2 || strlen(&argv[1][0])>=sizeof(fileName))
{
debug("argument error !!! \n");
return -1 ;
}
debug("size : %d \n",sizeof(WAV_HEADER));
strcpy(fileName,argv[1]);
wavInputOpen(&wavInfo, fileName);
return 0;
}
#endif
附:FIFF文件知识点
1. 简介RIFF全称为资源互换文件格式(ResourcesInterchange FileFormat),RIFF文件是windows环境下大部分多媒体文件遵循的一种文件结构,RIFF文件所包含的数据类型由该文件的扩展名来标识,能以RIFF文件存储的数据包括:音频视频交错格式数据(.AVI)
波形格式数据(.WAV) 位图格式数据(.RDI) MIDI格式数据(.RMI)调色板格式(.PAL)多媒体电影(.RMN)动画光标(.ANI)其它RIFF文件(.BND)
2. CHUNK
chunk是组成RIFF文件的基本单元,它的基本结构如下:
struct chunk{
u32 id; /* 块标志 */
u32 size; /* 块大小 */
u8 dat[size]; /* 块内容 */
};
id 由4个ASCII字符组成,用以识别块中所包含的数据。如:'RIFF','LIST','fmt','data','WAV','AVI'等等,由于这种文件结构最初是由Microsoft和IBM为PC机所定义,RIFF文件是按照little-endian[2] 字节顺序写入的。
size(块大小) 是存储在data域中数据的长度,id与size域的大小则不包括在该值内。
dat(块内容) 中所包含的数据是以字(WORD)为单位排列的,如果该数据结构长度是奇数,则在最后添加一个空(NULL)字节。
chunk块中有且仅有两种类型块:'RIFF'和'LIST'类型可以包含其他块,而其它块仅能含有数据。
'RIFF'和'LIST'类型的chunk结构如下
structchunk{
u32 id; /* 块标志 */
u32 size; /* 块大小 */
/*此时的dat = type + restdat */
u32 type ; /* 类型 */
u8 restdat[size] /* dat中除type4个字节后剩余的数据*/
};
可以看出,'RIFF'和'LIST'也是chunk,只是它的dat由两部分组成type和restdat。
type,由4个ASCII字符组成,代表RIFF文件的类型,如'WAV','AVI ';或者'LIST'块的类型,如avi文件中的列表'hdrl','movi'。
restdat,dat中除type4个字节后剩余的数据,包括块内容,包含若干chunk和'LIST'
2.1 FOURCC 一个FOURCC(fourcharacter
code)是一个占4个字节的数据,一般表示4个ASCII字符。在RIFF文件格式中,FOURCC非常普遍,structchunk
中的id成员,'LIST','RIFF'的type成员,起始标识等信息都是用FOURCC表示的。FOURCC一般是四个字符,如'abcd'这样的形式,也可以三个字符包含一个空格,如'abc'这样的形式。
RIFF文件的FileData部分由若干个'LIST'和chunk组成,而'LIST'的ListData又可以由若干个'LIST'和chunk组成,即'LIST'是可以嵌套的。
'RIFF',FileType,'LIST',ListType,ChunkID都是FOURCC,即使用4字节的ASIIC字符标识类型。
FileSize,ListSize,ChunkSize为little-endian32-bit正整数,表示Type(只有'RIFF','LIST'chunk有Type)+Data一起的大小,注意它是little-endian表示,如:0x00123456,存储地址由低到高,在little-endian系统中的存储表示为0x56341200(字节由低位到高位存储),而在big-endian为0x00123456(字节由高位到低位存储)。32bit整数0x00123456存储地址低--------->;高little-endian(字节由低位到高位存储)56341200big-endian(字节由高位到低位存储)00123456
wav音频文件头解析的更多相关文章
- 解析WAV音频文件----》生成WAV音频文件头
前言:请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i WAV音频文件介绍: WAV文件是在PC机平台上很常见的.最经典的多媒体音频文件,最早于1991年8月出现在Windows3.1操作系统 ...
- DEX文件解析---1、dex文件头解析
DEX文件解析---1.dex文件头解析 一.dex文件 dex文件是Android平台上可执行文件的一种文件类型.它的文件格式可以下面这张图概括: dex文件头一般固定为0x70个字 ...
- JPEG解码——(3)文件头解析
与具体的编码数据空间相比,jpeg文件头占据非常小乃至可以忽略不计的大小. 仍然拿JPEG解码--(1)JPEG文件格式概览中的<animal park>这张图片来举例,从跳过SOS(FF ...
- S3C2416裸机开发系列19_Fatfs播放录像wav音频文件
S3C2416裸机开发系列19 Fatfs播放录像wav音频文件 国际象棋男孩 1048272975 多媒体资源,一般都是以文件的形式存储在固化存储器中.Fatfs所支持的fat32为windo ...
- 常用文件的文件头(附JAVA测试类)
1. MIDI (mid),文件头:4D546864 2. JPEG (jpg),文件头:FFD8FF 3. PNG (png),文件头:89504E47 4. GIF (gif),文件头:47494 ...
- 【CTF杂项】常见文件文件头文件尾格式总结及各类文件头
文件头文件尾总结 JPEG (jpg), 文件头:FFD8FF 文件尾:FF D9PNG (png), 文件头:89504E47 文件尾:AE 42 60 82GIF (gif), 文件头:47494 ...
- 【杂项】各类文件头结合winhex使用-转载
———常用文件头——— JPEG (jpg),文件头:FFD8FFE1 PNG (png),文件头:89504E47 (0D0A1A0A) GIF (gif),文件头:47494638 ZIP Arc ...
- 音频文件解析(一):WAV格式文件头部解析
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 文 ...
- wav音频文件格式解析【个人笔记】(自用)
1. WAV格式 wav是微软开发的一种音频文件格式,注意,wav文件格式是无损音频文件格式,相对于其他音频格式文件数据是没有经过压缩的,通常文件也相对比较大些.. 支持多种音频数字,取样频率和声道, ...
随机推荐
- pycharm上传代码到码云错误现象用户密码
>>出现此时错误说明在pycharm>git登录用户名或密码是错误的(必须填成是自己注册的码云邮箱和密码 不允许出现中文)并且无法在当前修改用户名或密码 >>接下来打开电 ...
- 多核服务器的JVM优化选项(转载)
原文链接 现在多核CPU是主流.利用多核技术,可以有效发挥硬件的能力,提升吞吐量,对于Java程序,可以实现并发垃圾收集.但是Java利用多核技术也带来了一些问题,主要是多线程共享内存引起了.目前内存 ...
- mc
Description 小C在MC里有n个牧场,自西向东呈一字形排列(自西向东用1-n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站, 每个牧场上只能建立一个控制站,每个控 ...
- Maven设置代理
很多时候电信的网络对于出国不太稳定,针对一些库下载速度比较慢,所以在使用SSR出国时配置maven使用是一种不错的选择.当然,还有另一种选择,就是使用国内的镜像库. 操作步骤: 1.打开{M2_HOM ...
- python--文件处理1
1. 读取文件 方法: all_the_text = open('thefile.txt').read() 但是为了安全起见还是给打开的文件对象指定一个名字,这样在完成之后可以迅速关掉,防止无 ...
- 邁向IT專家成功之路的三十則鐵律 鐵律二十九 IT人富足之道-信仰
天地自然的循環法則,讓每一個人都必須經歷生.老.病.死.喜.怒.哀.樂,然而至始至終無盡的煩惱總是遠多於快樂,因此筆者深信每一個人在一生當中,都必須要有適合自己的正確信仰,他可以在你無法以物質力量來解 ...
- docker run 报错——WARNING: IPv4 forwarding is disabled. Networking will not work.
执行 docker run 时遇到如下WARNING: [root@etcd1 volumes]# docker run -d -p 8080:80 -v /tmp/test_mount http ...
- 【GitHub】删除GitHub上的文件
想要删除已经提交上GitHub上的文件, 删除之后,如果这个文件夹下没有文件了,这个文件夹也会被删除! 并且在它的上层文件夹后面 有提示删除了这个文件的信息!!
- xpath的匹配规则
starts-with 匹配一个属性开始位置的关键字 contains 匹配一个属性值中包含的字符串 text() 匹配的是显示文本信息,此处也可以用来做定位用 i.e. //input[starts ...
- C#开发ActiveX控件,.NET开发OCX控件案例 【转】
http://xiaochen.2003.4.blog.163.com/blog/static/480409672012530227678/ 讲下什么是ActiveX控件,到底有什么作用?在网页中又如 ...