音视频入门基础:WAV专题(2)——WAV格式简介

注:本文有部分内容引用了维基百科:https://zh.wikipedia.org/wiki/WAV

一、引言

Waveform Audio File Format(缩写WAVE或WAV)是微软与IBM公司所开发在个人电脑存储音频流的编码格式,在Windows平台的应用软件受到广泛的支持。此格式属于资源交换文件格式(RIFF)的应用之一(关于RIFF格式可以上微软的官网了解:https://learn.microsoft.com/zh-cn/windows/win32/xaudio2/resource-interchange-file-format--riff-)。WAV音频文件通常会将采用脉冲编码调制(音频压缩编码格式为PCM)的音频存储在区块中。由于此音频格式未经过压缩,所以在音质方面不会出现失真的情况,但文件的体积较大。

WAV格式的官方文档可以从https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html 下载:

二、WAV文件的Header

WAV文件遵守RIFF格式的规则,文件最前面的数据为文件头(header),使音频播放器能够简单掌握文件的基本信息。注意:文件头不一定为固定的44字节,由是否存在扩展块和是否存在可选区块决定。文件头中的内容以区块(chunk)为最小单位(注意:是子区块包含区块),每一区块长度为4字节,而区块之上则由子区块包裹,每一子区块长度不受限制,但须在前头先声明标签及长度(单位为字节)。文件头的前3个区块记录文件格式及长度;接着第一个子区块(标签为"fmt",被称为“Format chunk”)包含多个区块,记录声道数量、采样率等信息;另外一个子区块(标签为"data",被称为“Data chunk”)才包含真正的音频资料(或者说音频数据),长度则视音频长度而定。内容如下表所示。须注意的是,每个区块的字节序不尽相同(也就是说有些区块按照大端字节序存贮,有些按照小端字节序存贮),而音频数据本身则是采用小端字节序:

注:

1.上图描述有误,“位元(组)率”实际应为“=声道数 * 采样频率 * 量化位数 / 8”(图片中漏乘了声道数量),它代表每秒钟数据的字节数。

2.上图仅仅列出了WAV文件Header中必须包含的区块。Format chunk和Data chunk是必须的。但实际Header中还可能存在可选区块,Format chunk中也可能包含扩展块。

3.上图中“总区块大小”的描述有误,其区块内容不一定为“N+36”。

三、WAV文件实例分析

用notepad++打开《音视频入门基础:WAV专题(1)——使用FFmpeg命令生成WAV音频文件》中生成的WAV文件,下图红框中的数据为文件头(header):

(一)WAV Header中的前3个区块

第0到3字节为WAV Header中的第一个区块:“区块编号”,内容为“RIFF”或“RIFX”。“RIFF”指定该文件中真正的音频数据按照小端字节序存贮,“RIFX”指定该文件中真正的音频数据按照大端字节序存贮。下图中的值为“RIFF”,表示该文件遵守RIFF格式的规则,音频数据按照小端字节序存贮:

第4到7字节为WAV Header中的第二个区块:“总区块大小”,值等于:该WAV文件所有区块减去“”区块编号和“总区块大小”所占的字节数,即“该WAV文件所有区块所占空间 - 8”,单位为字节。由于该区块是小端字节序,所以下图中的总区块大小为0x03184846,也就是十进制的51923014,表示总区块大小为51923014字节:

第8到11字节为WAV Header中的第三个区块:“档案格式”,内容固定为“WAVE”,表示该文件为WAVE / WAV格式的文件:

(二)WAV Header中的子区块:Format chunk

第12到15字节为“子区块1标签”,内容固定为“fmt ”,表示这是第一个子区块的开头,该子区块被称为Format chunk,记录声道数量、采样率等信息:

第16到19字节为“子区块1大小”,单位为字节。如果子区块1中无扩展块,值为16,子区块1中有扩展块,值为“16 + 2字节扩展块长度 + 扩展块内容”。当WAV文件中的音频数据使用的不是PCM压缩编码格式时,Format chunk中就会有扩展块。下图中的值为0x10(小端字节序),也就是十进制的16(字节),所以该wav文件的Format chunk中无扩展块:

“子区块1大小”就是下图红框中的区块加起来的总大小。也就是子区块1中,去掉“子区块1标签”和“子区块1大小”这两个区块后的总大小:

第20到21字节为“音讯格式”,也就是所谓的音频压缩编码格式,值一般为0x01(小端字节序),表示音频压缩编码格式为PCM:

第22到23字节为声道数量。值为1是单声道,为2则是双声道(立体声)。下图中的值为0x02(小端字节序),表示音频为双声道:

第24到27字节为“取样频率”,也就是音频的采样频率,单位为Hz。下图中的值为0xAC44(小端字节序),换算成10进制就是44100,表示音频的采样频率为44100Hz:

第28到31字节为“位元(组)率”,即音频的码率(单位为byte per second,音频每秒播放的字节数)。其值为:声道数 * 采样频率 * 采样位数 / 8。下图中的值为0x02B110(小端字节序),也就是10进制的176400,表示音频的码率为176400Byte/s。可以计算出来:176400 = 2 * 44100 * 16 / 8,符合上述计算公式:

第32到33字节为“区块对齐”,即每个采样点所需的字节数,其值为:声道数 * 采样位数 / 8。下图中的值为0x04(小端字节序),换算成10进制就是4。 4 = 2 * 16 / 8,符合上述计算公式:

第34到35字节为“位元深度”,即采样位数。下图中的值为0x10(小端字节序),换算成10进制就是16,表示音频的采样位数是16位:

由于我们上述读取到的“子区块1大小”为16字节。所以至此“子区块1”读取结束。后面的内容为另外一个子区块的。

(三)WAV Header中的可选区块

WAV文件的Header中还可能包含一些可选的区块,如:Fact chunk、Cue points chunk、Playlist chunk、Associated data list chunk等。这些区块在WAV文件中不是必须的,WAV文件的Header中可能存在、也可能不存在这些区块。list chunk是其中一种可选区块,包含关于版权、作者、文件工程师和其他类似文本的信息。由于我们演示的这个WAV文件是通过FFmpeg生成的,FFmpeg在它的Header中加入了list chunk。

从该WAV文件的第36到39字节中读取到了“子区块1”后面区块的标签:“LIST”,表示这是list chunk的开头:

WAV文件遵守RIFF格式的规则,根据微软官方对RIFF格式的描述:https://learn.microsoft.com/zh-cn/windows/win32/xaudio2/resource-interchange-file-format--riff-

我们可以知道chunkSize(区块大小)是一个4字节值。所以下图红框中,也就是该WAV文件的第40到43字节为list chunk这个子区块的大小,下图中的值为0x1A(小端字节序),换算成10进制就是26,表示子区块list chunk中,去掉“list chunk标签”和“list chunk大小”这两个区块后的总大小是26字节:

所以据此,我们可以推断出list chunk中去掉“list chunk标签”和“list chunk大小”后的有效数据的范围是从该WAV文件的第44字节到第69字节:

至此该子区块(list chunk)读取结束。后面的内容为另外一个子区块的。

(四)WAV Header中的子区块:Data chunk

从该WAV文件的第70到73字节中读取到了“子区块list chunk”后面区块的标签:“data”,表示这是Data chunk的开头,该子区块存放真正的音频数据:

第74到77字节为“子区块Data chunk的大小”,单位为字节。下图中的值为0x03184800(小端字节序),换算成十进制是51922944,表示该WAV文件中存放的真正的音频数据的大小为51922944字节。由上述第20到21字节中的“音讯格式”,我们可以知道该WAV文件中音频的压缩编码格式为PCM。所以该WAV文件中PCM音频数据的大小为51922944字节。该值 = (采样频率*采样位数*声道)*时间 / 8(单位:字节数)。我们把实际数据带入该公式:51922944  ≈ (44100 * 16 * 2) * 294 / 8,可以看到是符合该公式的。“约等于”是因为该WAV文件的总时长不是正好的294秒:

“子区块Data chunk的大小”占用的空间为4字节,所以WAV存放真正的音频数据的极限是2 ^ 32 = 4294967296字节,也就是说它最多只能容纳4GB的音频流信息,这是Wave作为32bit时代产物的局限性。要想存贮超过4G的音频数据,可以使用WAVE 64位扩展格式Wave64。

从第78字节开始存放的就是真正的音频数据了。从上面我们可以知道该WAV文件的Header为从第0到第77字节,也就是说它的Header占78字节。我们在Windows系统中通过“属性”查看该WAV文件的大小,可以看到是51923022 字节。51923022 =  51922944(PCM音频数据的大小) + 78(Header的大小)。可以看出来,数值是完全符合的:

四、删除WAV文件头测试

由上面我们可以知道该WAV文件的Header为从第0到第77字节,所以删掉该文件头以后WAV文件能不能播放呢?我们做一个测试:

备份WAV文件。在notepad++中删掉该WAV文件的Header:


 

然后发现用vlc打开没反应。也就是说无法打开了:

从上面我们可以知道该WAV文件的第20到21字节值为0x01,表示音频压缩编码格式为PCM。所以去掉WAV Header后,剩下的数据就是PCM音频数据。我们可以按照《音视频入门基础:PCM专题(3)——使用Audacity工具分析PCM音频文件》,通过导入PCM音频文件的方法,来打开去掉Header后的WAV文件:

果然可以成功打开播放:

五、Wave64格式

想存贮超过4G的音频数据,可以使用WAVE 64位扩展格式Wave64,具体可以参考:《什么是Wave64和RF64?》、《F64 | MBWF | WAV 64-bit | Learn, Get Free Samples Now》

六、总结

1.WAV的文件头不一定为固定的44字节,由是否存在扩展块和是否存在可选区块决定。所以如果不通过第三方库,自己写解析WAV文件的程序时要注意这一点。

2.WAV文件头包含了音频采样频率、采样位数、声道数信息。而WAV文件遵守RIFF格式的规则,RIFF规定了符号和字节序。所以播放器可以根据这些信息播放WAV文件。同样的,即使去掉了WAV Header,只要我们播放时指定了这五个参数(这五个参数可以参考:《音视频入门基础:PCM专题(1)——使用FFmpeg命令生成PCM音频文件并播放》),而我们又同时知道了它的音频压缩编码方式,我们就能播放该音频文件。

3.WAV是文件格式。PCM是音频压缩编码格式。WAV文件中的音频压缩编码格式一般是PCM,但也可以是其它。

4.WAV文件只能容纳4GB的音频流信息,要想存贮超过4G的音频数据,可以使用WAVE 64位扩展格式Wave64。

七、参考

维基百科:http://​https://zh.wikipedia.org/wiki/WAV​

https://docs.fileformat.com/audio/wav/

《WAV文件格式详解》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/50678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI/机器学习(计算机视觉/NLP)方向面试复习3

1. Pooling 有哪些方式?pytorch的实现? Pooling可以分成:最大池化,平均池化,全局平均池化,随机池化,空间金字塔池化。 1. 最大池化(Max Pooling) 最大池化是最常用的池…

union的特性和大小端

一、union在c和c语言中的特性 1.共享内存空间:union的所有成员共享同一块内存空间。意味着在同一时刻,union 只能存储其成员 中的一个值。当你修改了union中的一个成员,那么其它成员的值也会被改变,因为它们实际上都是指向同一块…

JS逆向高级爬虫

JS逆向高级爬虫 JS逆向的目的是通过运行本地JS的文件或者代码,以实现脱离他的网站和浏览器,并且还能拿到和浏览器加密一样的效果。 10.1、编码算法 【1】摘要算法:一切从MD5开始 MD5是一个非常常见的摘要(hash)逻辑. 其特点就是小巧. 速度快. 极难被破解. 所以,…

skywalking docker部署

skywalking-oap # 拉取skywalking-oap镜像 docker pull apache/skywalking-oap-server:9.7.0# 启动容器 docker run --name oap \ -d \ -p 11800:11800 \ -p 12800:12800 \ apache/skywalking-oap-server:9.7.0skywalking-ui # 摘取skywalking-ui镜像 docker pull apache/sky…

大屏使用技巧——如何实现数据分发

当多个组件需共用同一数据源时,为了减少重复请求,需要进行数据分发。那如何实现接一次数据就能让多个组件映射同一数据源中的不同数据字段呢? 实现思路 目标组件的静态数据中添加标记字段,数据过滤器内通过 data 参数获取到对应…

加密micropython写的程序为.mpy的方法

2024年7月26日 用虚拟机安装一个Linux,本例为CentOS7的Linux系统。 1.保证Linux能够连接网络。 2.进入root用户,使用下面的命令行安装gcc编译器: yum install gcc 3.安装完成后,查看gcc是否安装成功,用下面的命令…

家政项目小程序的设计

管理员账户功能包括:系统首页,个人中心,用户管理,家政人员管理,家政服务管理,咨询信息管理,咨询服务管理,家政预约管理,留言板管理,系统管理 微信端账号功能…

前端开发知识-vue

大括号里边放键值对,即是一个对象。 一、vue可以简化前端javascript的操作。 主要特点是可以实现视图、数据的双向绑定。 使用vue主要分为三个步骤: 1.javascript中引入vue.js 可以src中可以是vue的网址,也可以是本地下载。 2.在javasc…

C#中的泛型约束:如何利用泛型约束来提高代码的类型安全性和灵活性?

泛型约束是指可以对泛型类型参数进行限制,只允许特定类型或满足特定条件的类型作为泛型参数。使用泛型约束可以提高代码的类型安全性和灵活性,以下是一些常见的泛型约束及其作用: 类型约束(class constraint)&#xff…

FastAPI(七十九)实战开发《在线课程学习系统》接口开发-- 加入课程和退出课程

源码见:"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 加入课程 我们先看下加入课程 1.是否登录 2.课程是否存在 3.是否已经存在 4.添加 首先实现逻辑 def get_student_course(db: Session, course: int…

C++——QT:保姆级教程,从下载到安装到用QT写出第一个程序

登录官网,在官网选择合适的qt版本进行下载 这里选择5.12.9版本 点击exe文件下载,因为服务器在国外,国内不支持,所以可以从我的网盘下载 链接: https://pan.baidu.com/s/1XMILFS1uHTenH3mH_VlPLw 提取码: 1567 --来自百度网盘超级…

Github使用技巧

(1)基本操作: Github 点击绿色按键Code 复制地址,打开自己本地想要保存的文件夹,右键,Git Bach Here git clone 地址 --下载☆star:可以衡量该程序的热度和知名度README.md 是使用一个项目前必须要阅…

本地部署Graphhopper路径规划服务(graphhopper.sh启动版)

文章目录 文章参考源码获取一、配置Java环境变量二、配置Maven环境变量三、构建graphhopper步骤1. 下载数据2. 配置graphhopper配置文件config-example.yml3. 在项目中启动命令行执行./graphhopper.sh build3.1|、遇到的问题3.1.1、pom.xml中front-maven-plugin-无法下载npm6.1…

使用 nmcli 管理网络连接

nmcli 是 NetworkManager 的命令行工具,它提供了一种方便的方式来管理网络连接、查看网络状态以及进行网络配置。无论你是在服务器环境中,还是在没有图形界面的桌面系统中,nmcli 都是一个强大的网络管理工具。本文将介绍 nmcli 的基础用法及一…

【python代码不需要额外的操作就能交换两个变量的值】

看到一个案例,想着用Python代码实现一下,不需要额外的操作就能交换两个变量的值 def swap(a, b):return b, a a, b -1, 14 swap(a, b) # (14, -1) spread([1,2,3,[4,5,6],[7],8,9]) # [1,2,3,4,5,6,7,8,9]在Python中,确实存在一种非常简洁的…

JavaScript 的奇技淫巧

JavaScript 作为一门动态语言,拥有丰富的特性和灵活性。这使得开发者们能够编写出既强大又高效的代码。然而,在某些情况下,为了追求代码的精简或性能优化,开发者可能会采用一些非传统的技巧。接下来,我们一起探索一些这…

土耳其云手机提升TikTok电商效率

在数字化飞速发展的今天,TikTok不仅是一个社交平台,更是一个巨大的电商市场。随着TikTok电商功能在全球范围内的扩展,土耳其的商家和内容创作者正面临着前所未有的机遇。本文将详细介绍土耳其云手机怎样帮助商家抓住机遇,实现业务…

项目都做完了,领导要求国际化????--JAVA后端篇

springboot项目国际化相信各位小伙伴都会,很简单,但是怎么项目都做完了,领导却要求国际化文件就很头疼了 国际化的SpringBoot代码: 第一步:创建工具类 /*** 获取i18n资源文件** author bims*/ public class Message…

MATLAB怎么实现多条曲线共用一个图例

y1 sin(x); y2 3*sin(x); y3 cos(x); y4 3*cos(x); 例子:如果我们有4条曲线,分布是cos类和sin类,我们的图例就想区分是cos类还是sin类。 第一步(关键步骤) 我们要把我们所需要的类别曲线先画一遍, …

实现文档的自动化发布与跨平台阅读

在当今的软件开发领域,文档作为代码之外的重要资产,其管理和发布同样需要高效和自动化。 利用Git进行版本控制,通过GitBook和Typora发布文档,并与GitLab CI/CD工具集成,以实现文档在多种设备上的流畅阅读体验。 一、…