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

news/2025/2/22 5:16:25/

😁博客主页😁:🚀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_HEADERmemcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));                    memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));  fseek(fpout,sizeof(WAVE_HEADER),1); //WAVE_FMTpcmFMT.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.ppmy.cn/news/1189556.html

相关文章

Webpack构建慢如蜗牛?提升开发效率的速度优化秘籍!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、背…

窗口命令怎么查看正在运行的jar包并杀死该进程

要查看正在运行的 JAR 包&#xff0c;可以使用 jps 命令&#xff08;Java Virtual Machine Process Status Tool&#xff09;来列出当前正在运行的 Java 进程&#xff0c;并找到相关的 JAR 包。下面是具体的步骤&#xff1a; 1.打开命令提示符或终端窗口。 2.运行以下命令来查…

算法升级之路(六)

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]] 解题思路&…

尚硅谷-kubernetes

目录 一、kubernetes概述1、kubernetes基本介绍**2、kubernetes 功能和架构** 一、kubernetes概述 1、kubernetes基本介绍 kubernetes&#xff0c;简称 K8s&#xff0c;是用 8 代替 8 个字符“ubernete”而成的缩写 kubernetes是一个开源的&#xff0c;用于管理云平台中多个…

Android---StartActivity启动过程

在手机桌面应用中点击某一个 icon 之后&#xff0c;最终是通过 startActivity 去打开某一个 Activity 页面。我们知道&#xff0c;Android 中的一个 APP 就相当于一个进程。所以&#xff0c;startActivity 操作中还需要判断&#xff0c;目标 Activity 的进程是否已经创建。如果…

项目进度管理-关键路径法介绍及计算例题

什么是关键路径法 关键路径法(Critical Path Method,CPM)是一种用于项目进度管理的技术,它用于确定项目中的关键路径和关键活动。关键路径指的是项目中的一组活动,它们的延误会导致整个项目的延误,这些活动是项目完成所需时间的主要瓶颈。CPM 有以下关键要点: 活动定义…

JVM虚拟机:堆结构的逻辑分区

堆内存的逻辑分区 堆内存的逻辑分区如下所示: 堆内存中分为新生代和老年代,二者空间大小1:3。在新生代里面分为两类区域(eden、survivor),三个区域(eden、survivor、survivor),三个区大小比例为8:1:1。 对象存放的位置 栈 当我们new一个对象的时候,首先会将对象…

node学习之包管理器

一、概念介绍 **1.1 包是什么 ** 『包』英文单词是 package &#xff0c;代表了一组特定功能的源码集合 **1.2 包管理工具 ** 管理『包』的应用软件&#xff0c;可以对「包」进行 下载安装 &#xff0c; 更新 &#xff0c; 删除 &#xff0c; 上传 等操作 借助包管理工具&…