【音视频 | wav】wav音频文件格式详解——包含RIFF规范、完整的各个块解析、PCM转wav代码

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍wav音频格式🍭
😎金句分享😎:🍭子曰:父母在,不远游,游必有方。 ——《论语·里仁篇》。意思是,父母还健在时,就不要远离他们,如果一定要出远门,也必须告知自己所去的地方。🍭

文章未经允许,不许转载 !!!

目录

  • 🎄一、概述
  • 🎄二、RIFF 规范
    • ✨2.1 RIFF 介绍
    • ✨2.2 RIFF 文件结构
      • 🎈2.2.1 RIFF
      • 🎈2.2.2 LIST
    • ✨2.3 FourCC
  • 🎄三、wav 文件详解
    • ✨3.1 wav 文件结构
    • ✨3.2 wav 文件的编码格式
  • 🎄四、PCM 转 WAV 的C语言程序
  • 🎄五、总结


在这里插入图片描述

🎄一、概述

WAV全称是 Waveform Audio File Format,是一种常用的无损音频文件格式,它最初由微软和IBM于1991年共同开发,并成为Windows操作系统中音频文件的标准格式之一。从文件结构来讲,WAV文件格式是微软存储多媒体文件的RIFF规范的子集。本文将详细介绍WAV格式文件的文件结构。

WAV格式文件相对于其他音频文件格式具有以下特点:

  • 无损压缩:WAV文件采用无损压缩算法,不会丢失原始音频数据,能够保留音频的高质量。
  • 高音质:由于无损压缩技术的使用,WAV文件通常具有较高的音质和更好的还原性能。
  • 大文件大小:由于不进行任何压缩,WAV文件相对于其他压缩格式(如MP3)的文件大小较大,占用存储空间较多。
  • 支持多种采样率和位深度:WAV文件支持多种采样率和位深度,可以根据需求选择合适的参数进行录制或处理。
  • 广泛兼容性:WAV格式是一种通用的音频文件格式,几乎所有的音频软件和硬件设备都能够支持读取和播放WAV文件。

原文链接:https://blog.csdn.net/wkd_007/article/details/134125746
在这里插入图片描述

🎄二、RIFF 规范

WAV 文件采用RIFF规范来存储音频数据和相关元信息。这小节我们先了解RIFF规范。

✨2.1 RIFF 介绍

RIFF(Resource Interchange File Format)是一种通用的文件格式规范,最初由微软开发,用于在不同应用程序之间交换数据。它以分块的方式组织数据,每个块包含一个标识符和相应的数据内容。

能以RIFF格式存储的数据有:

  • .AVI:音频视频交错格式数据
  • .WAV:波形格式数据
  • .RDI:位图数据格式
  • .RMI:MIDI格式数据
  • .PAL:调色板格式
  • .RMN:多媒体电影
  • .ANI:动画光标
  • .BND:其他的RIFF文件

✨2.2 RIFF 文件结构

RIFF文件都是由一个或多个块(chunk)组成的,且第一个块必须是RIFF块。

常见的块有:RIFFLISTfmtdata,每个块都包含了Id(块标志)、Size(块大小)、data(块数据)。其中,RIFF块、LIST块可以包含其他子块。

🎈2.2.1 RIFF

RIFF规范的文件的第一个块必须是RIFF块,RIFF块前面12个字节是RIFF块描述,包含了块标志、块大小、块类型。接下去的数据就是子块(Subchunk),RIFF的块类型决定了有多少个子块,有哪些子块。
在这里插入图片描述

🎈2.2.2 LIST

LIST块可能比较少见,这里大概了解一下,下图是包含LIST块的RIFF文件,首先是RIFF文件必须的RIFF chunk,其数据域又包含有两个subchunk,其中一个subchunk的类型为LIST,该LIST chunk又包含了两个subchunk
在这里插入图片描述

✨2.3 FourCC

FourCC 全称为Four-Character Codes,是一个4字节32位的标识符,通常用来标识文件的数据格式。RIFF文件的块标志就是使用了 FourCC 。FourCC是4个ASCII字符,不足四个字符的则在最后补充空格(不是空字符)。比如,FourCC fmt,实际上是'f'、'm'、't'、' '

C语言中,可以用宏来生成FourCC:

#define MAKE_FOURCC(a,b,c,d) \
( ((uint32_t)d) | ( ((uint32_t)c) << 8 ) | ( ((uint32_t)b) << 16 ) | ( ((uint32_t)a) << 24 ) )

在这里插入图片描述

🎄三、wav 文件详解

✨3.1 wav 文件结构

WAV文件通常是一个RIFF文件,如果数据是没压缩的PCM,则整个文件可以看出 44个字节的文件头+音频数据 构成。如果是压缩的音频数据,接着看下面小节细说。

wav文件(PCM数据)分为三个部分,如下图:

  • RIFF块描述(下图紫色部分);
  • 指定数据格式的子块——fmt块(下图绿色部分)、
  • 包含实际样本数据的子块——data块(下图砖红色部分)。

在这里插入图片描述
下面是各个块详细的解释,有些块在pcm数据中是用不到的:

  • RIFF块描述:
    • 1、ChunkID:包含ASCII格式的字母RIFF
    • 2、ChunkSize:这个数值ChunkSize后面所有数据的大小。可以是整个文件的大小减去8个字节;也可以是36+SubChunk2Size;还可以是4 + (8+SubChunk1Size) + (8+SubChunk2Size)
    • 3、Format:包含字母WAVE

  • fmt块:
    • Subchunk1ID:包含字母fmt,表示fmt块;
    • Subchunk1Size:这个数值是Subchunk1Size后所有fmt块数据的大小,对于PCM数据来说,这个值固定为16;
    • AudioFormat:如果音频数据是PCM,这个值为 11 以外的值表示一些压缩形式;
    • NumChannels:声道数,Mono = 1, Stereo = 2 等等;
    • SampleRate:采样率,8000,44100,48000 等;
    • ByteRate:每秒的字节数,采样率 * 声道数 * 样本位数 / 8
    • BlockAlign:每个声道取一个样本的字节数之和,声道数 * 样本位数 / 8
    • BitsPerSample:样本位数,每个样本占用的bit位个数。8bit、16bit 等等。
    • ExtraParamSize:拓展参数大小,如果是PCM,则不存在;
    • ExtraParams:拓展参数数据;

  • fact块 (可选),如果是没压缩的PCM,则没有这个块
    • id:FOURCC 值为 'f' 'a' 'c' 't',4个字节
    • size:数据域的长度,4个字节(最小值为4)
    • Data:采样总数 4字节

  • data块:
    • Subchunk2ID:包含字母data,表示data块;
    • Subchunk2Size:这个数值是Subchunk2Size后所有数据的字节数,也就是实际音频数据的总字节数。
    • Data:实际的音频数据;

✨3.2 wav 文件的编码格式

大部分的wav文件的编码格式都是PCM的,但也存在其他编码格式,不同的编码格式,其文件结构会有区别,下表列出了常见编码格式和wav文件结构的区别:

格式编码格式名称fmt块长度fact 块
0x01PCM / 非压缩格式16
0x02Microsoft ADPCM18
0x03IEEE float18
0x06ITU G.711 a-law18
0x07ITU G.711 μ-law18
0x031GSM 6.1020
0x040ITU G.721 ADPCM
0xFFFE见子格式块中的编码格式40

在这里插入图片描述

🎄四、PCM 转 WAV 的C语言程序

// pcm2wac.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * Convert PCM16LE raw data to WAVE format
 * @param pcmpath      Input PCM file.
 * @param channels     Channel number of PCM file.
 * @param sample_rate  Sample rate of PCM file.
 * @param wavepath     Output WAVE file.
 */
int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
 
	typedef struct WAVE_HEADER{  
		char         fccID[4];        
		unsigned   int    dwSize;            
		char         fccType[4];    
	}WAVE_HEADER;  
 
	typedef struct WAVE_FMT{  
		char         fccID[4];        
		unsigned   int       dwSize;            
		unsigned   short     wFormatTag;    
		unsigned   short     wChannels;  
		unsigned   int       dwSamplesPerSec;  
		unsigned   int       dwAvgBytesPerSec;  
		unsigned   short     wBlockAlign;  
		unsigned   short     uiBitsPerSample;  
	}WAVE_FMT;  
 
	typedef struct WAVE_DATA{  
		char       fccID[4];          
		unsigned int dwSize;              
	}WAVE_DATA;  
 
 
	if(channels==0||sample_rate==0){
		channels = 2;
		sample_rate = 44100;
	}
	int bits = 16;
 
    WAVE_HEADER   pcmHEADER;  
    WAVE_FMT   pcmFMT;  
    WAVE_DATA   pcmDATA;  
 
    unsigned   short   m_pcmData;
    FILE   *fp,*fpout;  
 
	fp=fopen(pcmpath, "rb");
    if(fp == NULL) {  
        printf("open pcm file error\n");
        return -1;  
    }
	fpout=fopen(wavepath,   "wb+");
    if(fpout == NULL) {    
        printf("create wav file error\n");  
        return -1; 
    }        
	//WAVE_HEADER
    memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));                    
    memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));  
    fseek(fpout,sizeof(WAVE_HEADER),1); 
	//WAVE_FMT
    pcmFMT.dwSamplesPerSec=sample_rate;  
    pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*sizeof(m_pcmData);  
    pcmFMT.uiBitsPerSample=bits;
    memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));  
    pcmFMT.dwSize=16;  
    pcmFMT.wBlockAlign=2;  
    pcmFMT.wChannels=channels;  
    pcmFMT.wFormatTag=1;  
 
    fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout); 
 
    //WAVE_DATA;
    memcpy(pcmDATA.fccID,"data",strlen("data"));  
    pcmDATA.dwSize=0;
    fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
 
    fread(&m_pcmData,sizeof(unsigned short),1,fp);
    while(!feof(fp)){  
        pcmDATA.dwSize+=2;
        fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
        fread(&m_pcmData,sizeof(unsigned short),1,fp);
    }  
 
    pcmHEADER.dwSize=44+pcmDATA.dwSize;
 
    rewind(fpout);
    fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
    fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
    fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
	
	fclose(fp);
    fclose(fpout);
 
    return 0;
}

int main()
{
	simplest_pcm16le_to_wave("48000Hz-s16le-2ch-ChengDu.pcm",2,48000,"output_nocturne.wav");
	return 0;
}

代码来自:https://blog.csdn.net/leixiaohua1020/article/details/50534316

在这里插入图片描述

🎄五、总结

本文详细介绍wav音频文件的结构,包含RIFF规范、完整的各个块解析、以及提供了pcm转wav的C语言代码。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考资料:
WAVE PCM soundfile format
视音频数据处理入门:PCM音频采样数据处理
wav头文件解析
RIFF和WAVE音频文件格式
音频——WAV 格式详解
https://blog.csdn.net/jackailson/article/details/105183413

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Node学习笔记之跨域

1.跨域是什么&#xff1f; 跨域&#xff0c;是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript实施的安全限制。 同源策略限制了一下行为&#xff1a; Cookie无法读取DOM 和 JS 对象无法获取Ajax请求发送不出去 同源是指&#…

LuaHttp库写的一个简单的爬虫

LuaHttp库是一个基于Lua语言的HTTP客户端库&#xff0c;可以用于爬取网站数据。与Python的Scrapy框架类似&#xff0c;LuaHttp库也可以实现网站数据的抓取&#xff0c;并且可以将抓取到的数据保存到数据库中。不过需要注意的是&#xff0c;LuaHttp库并不像Scrapy框架那样具有完…

CN考研真题知识点二轮归纳(5)

本轮的最后一贴&#xff0c;真题中涉及计网的部分彻底总结完&#xff01;后期的3轮总结可能会上一些大题&#xff0c;比如路由转发、子网划分什么的&#xff0c;以及重点的背诵内容~ 上期目录&#xff1a; CN考研真题知识点二轮归纳&#xff08;4&#xff09;https://jslhyh32…

【Linux】安装使用Nginx负载均衡,并且部署前端项目

目录 一、Nginx概述 1. 什么 2. 背景 3. 作用 二、Nginx负载均衡 1. 讲述 2. 使用 1. 下载 2. 安装 3. 负载均衡 三、前端部署 1. 准备 2. 部署 一、Nginx概述 1. 什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它具有轻量级、高并发、低内存消耗的…

Classifier-Free Guidance

1.为什么需要分类引导 顾名思义&#xff0c;在原来扩散模型的基础上加上一个引导&#xff0c;让扩散模型朝着我们想要的方向去生成图像 从上图可以了解到生成下一张图像是有分类器参与的 无分类器就是这种形式要参与下一张图像的生成

SQL面试

#(1)请写出要查询员工J开头的名字其工号(EMPNO)及部门名称(DEPTNA)的 SQL语句SELECT e.emp,e.name,d.deptna FROM emp e left join dept d on d.deptno e.deptno where e.name like J%#(2)请写出要查询 Kevin 所在部门的部门代号(DEPTNO)及部门名称(DEPTNA)的 SQL 语句SELECT e…

【PCIe 5.0 - 10】Memory, I/O, and Configuration Request 规则

下列规则适用于所有 Memory, I/O, Configuration Requests&#xff0c;以下是针对各类请求的附加规则。 除通用 header 字段外&#xff0c;所有 Memory, I/O, 和 Configuration Requests 还包括以下字段&#xff1a; Requester ID[15:0] 和 Tag[9:0]&#xff0c;组成 Transact…

不是我吹牛逼,这绝对是去掉 if...else 最佳的文章

我相信小伙伴一定看过多篇怎么去掉 if…else 的文章&#xff0c;也知道大家都很有心得&#xff0c;知道多种方法来去掉 if…else &#xff0c;比如 Option&#xff0c;策略模式等等&#xff0c;但我相信大明哥这篇文章绝对是最全&#xff0c;最完备怎么去掉 if…else 的文章&am…

微信小程序导入js使用时候报错

我是引入weapp库时候&#xff0c;导入js会报错。 需要在小程序开发工具里面配置 就可以了。

YOLOv5:修改backbone为MobileOne

YOLOv5&#xff1a;修改backbone为MobileOne 前言前提条件相关介绍MobileOneYOLOv5修改backbone为MobileOne修改common.py修改yolo.py修改yolov5.yaml配置 参考 前言 记录在YOLOv5修改backbone操作&#xff0c;方便自己查阅。由于本人水平有限&#xff0c;难免出现错漏&#xf…

Redis之持久化(RDB和AOF)

文章目录 前言一、RDB1.介绍2.redis.config有关配置3.触发4.恢复5.优缺点 二、AOF1.介绍2.redis.config配置3.启动4.恢复5.重写6.优缺点 总结 前言 Redis 是内存数据库&#xff0c;即数据存储在内存。 如果不将内存中的数据保存到磁盘&#xff0c;一旦服务器进程退出&#xff…

Spring Cloud之Docker的学习【详细】

目录 Docker 项目部署问题 总结 镜像与容器 Docker的安装 Docker基本操作 镜像相关命令 拉取镜像 镜像保存 删除镜像 镜像加载 容器相关命令 删除容器 数据卷 数据卷命令 数据挂载 自定义镜像 Dockerfile 案例 Docker-Compose Compose文件 Docker-Compos…

数据结构与算法C语言版学习笔记(1)-绪论

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、数据结构的研究内容二、基本概念与术语1.数据与数据元素2.数据结构逻辑结构的种类存储结构的种类 三、算法1.什么是算法&#xff1f;算法的描述2.一个算法要具备…

【VR开发】【Unity】【VRTK】1-无代码VRVR开发介绍

本篇开始精简讲解VRTK相关的知识。 VRTK是基于Unity的一套提供无代码VR开发的插件,这套插件开源,可商用,集合了目前可能的VR体验组件,可以让不会C#编程但想要开发VR体验的人在不写一行代码的前提下开发出心仪的VR作品。 这套组件问世后也很受欢迎,目前已经进化到了第四代…

Java 算法篇-深入了解二分查找法

&#x1f525;博客主页&#xff1a; 小扳_-CSDN博客 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 1.0 二分查找法的说明 2.0 二分查找实现的多种版本 2.1 二分查找的基础版本 2.2 二分查找的改动版本 2.3 二分查找的平衡版本 2.4 二分查找的官方版本 3.0 二分查找的应用 1…

【Linux系统学习】系统编程开发工具编译器gcc/g++使用

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统学习 目录 前言 Linux系统下安装gcc和g gcc和g的不同 gcc/g的使用 gcc/g选项 预处理 头文件的展开 宏替换 注释的删除 条件的编译 编译 汇编 链接 系统库 库的分类 库的安装 库的…

[计算机提升] Windows系统软件:娱乐类

3.3 系统软件&#xff1a;娱乐类 3.3.1 Windows Media Player&#xff1a;dvdplay Windows Media Player是Windows操作系统自带的多媒体播放软件&#xff0c;用于播放和管理电脑中的音频和视频文件。它提供了以下功能&#xff1a; 播放音频和视频文件&#xff1a;Windows Med…

基于ThinkPHP+MySQL实现的通用的PHP网站后台管理系统

caozha-admin 后台管理框架 1.8.3 caozha-admin是一个通用的PHP网站后台管理框架&#xff0c;基于开源的ThinkPHP开发&#xff0c;特点&#xff1a;易上手&#xff0c;零门槛&#xff0c;界面清爽极简&#xff0c;极便于二次开发。 基础功能 1、系统设置 2、管理员管理 3、…

搭建ELK+Filebead+zookeeper+kafka实验

一、ELKFilebeatkafkazookeeper架构 架构图分别演示 第一层&#xff1a;数据采集层 数据采集层位于最左边的业务服务集群上&#xff0c;在每个业务服务器上面安装了filebead做日志收集&#xff0c;然后把采集到的原始日志发送到kafkazookeeper集群上。 第二层&#xff1a;消…

vue3中,使用html2canvas截图包含视频、图片、文字的区域

需求&#xff1a;将页面中指定区域进行截图&#xff0c;区域中包含了图片、文字、视频。 第一步&#xff0c;先安装 npm install html2canvas第二步&#xff0c;在页面引入&#xff1a; import html2canvas from html2canvas;第三步&#xff0c;页面使用&#xff1a; 1&…
最新文章