10_PCM转WAV
播放器是无法直接播放PCM的,因为播放器并不知道PCM的采样率、声道数、位深度等参数。当PCM转成某种特定的音频文件格式后(比如转成WAV),就能够被播放器识别播放了。
本文通过2种方式(命令行、编程)演示一下:如何将PCM转成WAV。
WAV文件格式
在进行PCM转WAV之前,先再来认识一下WAV的文件格式。
- WAV、AVI文件都是基于RIFF标准的文件格式
- RIFF(Resource Interchange File Format,资源交换文件格式)由Microsoft和IBM提出
- 所以WAV、AVI文件的最前面4个字节都是RIFF四个字符
WAV 文件标准格式如下:**

我们用一个数据格式使用十六进制展示的大小为 72 字节 WAVE 格式文件举例:

下面来一张通俗易懂的图:

每一个chunk(数据块)都由3部分组成:
- id:chunk的标识
- data size:chunk的数据部分大小,字节为单位
- data,chunk的数据部分
整个WAV文件是一个RIFF chunk,它的data由3部分组成:
- format:文件类型
- fmt chunk
- 音频参数相关的chunk
- 它的data里面有采样率、声道数、位深度等参数信息
- data chunk
- 音频数据相关的chunk
- 它的data就是真正的音频数据(比如PCM数据)
RIFF chunk除去data chunk的data(音频数据)后,剩下的内容可以称为:WAV文件头,一般是44字节。
命令行
通过下面的命令可以将PCM转成WAV。
// ffmpeg 输入文件参数 -i 输入文件 输出文件参数 输出文件
ffmpeg -ar 44100 -ac 2 -f s16le -i out.pcm out.wav
需要注意的是:上面命令生成的WAV文件头有78字节。对比44字节的文件头,它多增加了一个34字节大小的LIST chunk。
关于LIST chunk的参考资料:
加上一个输出文件参数-bitexact可以去掉LIST Chunk。
ffmpeg -ar 44100 -ac 2 -f s16le -i out.pcm -bitexact out2.wav
编程
在PCM数据的前面插入一个44字节的WAV文件头,就可以将PCM转成WAV。
WAV的文件头结构
WAV的文件头结构大概如下所示:
#define AUDIO_FORMAT_PCM 1
#define AUDIO_FORMAT_FLOAT 3
// WAV文件头(44字节)
typedef struct {
// RIFF chunk的id
uint8_t riffChunkId[4] = {'R', 'I', 'F', 'F'};
// RIFF chunk的data大小,即文件总长度减去8字节
uint32_t riffChunkDataSize;
// "WAVE"
uint8_t format[4] = {'W', 'A', 'V', 'E'};
/* fmt chunk */
// fmt chunk的id
uint8_t fmtChunkId[4] = {'f', 'm', 't', ' '};
// fmt chunk的data大小:存储PCM数据时,是16
uint32_t fmtChunkDataSize = 16;
// 音频编码,1表示PCM,3表示Floating Point
uint16_t audioFormat = AUDIO_FORMAT_PCM;
// 声道数
uint16_t numChannels;
// 采样率
uint32_t sampleRate;
// 字节率 = sampleRate * blockAlign
uint32_t byteRate;
// 一个样本的字节数 = bitsPerSample * numChannels >> 3
uint16_t blockAlign;
// 位深度
uint16_t bitsPerSample;
/* data chunk */
// data chunk的id
uint8_t dataChunkId[4] = {'d', 'a', 't', 'a'};
// data chunk的data大小:音频数据的总长度,即文件总长度减去文件头的长度(一般是44)
uint32_t dataChunkDataSize;
} WAVHeader;
PCM转WAV核心实现
封装到了FFmpegUtil类的pcm2wav方法中。
#include <QFile>
#include <QDebug>
class FFmpegUtil {
public:
FFmpegUtil();
static void pcm2wav(WAVHeader &header,
const char *pcmFilename,
const char *wavFilename);
};
void FFmpegUtil::pcm2wav(WAVHeader &header,
const char *pcmFilename,
const char *wavFilename) {
header.blockAlign = header.bitsPerSample * header.numChannels >> 3;
header.byteRate = header.sampleRate * header.blockAlign;
// 打开pcm文件
QFile pcmFile(pcmFilename);
if (!pcmFile.open(QFile::ReadOnly)) {
qDebug() << "文件打开失败" << pcmFilename;
return;
}
header.dataChunkDataSize = pcmFile.size();
header.riffChunkDataSize = header.dataChunkDataSize
+ sizeof (WAVHeader)
- sizeof (header.riffChunkId)
- sizeof (header.riffChunkDataSize);
// 打开wav文件
QFile wavFile(wavFilename);
if (!wavFile.open(QFile::WriteOnly)) {
qDebug() << "文件打开失败" << wavFilename;
pcmFile.close();
return;
}
// 写入头部
wavFile.write((const char *) &header, sizeof (WAVHeader));
// 写入pcm数据
char buf[1024];
int size;
while ((size = pcmFile.read(buf, sizeof (buf))) > 0) {
wavFile.write(buf, size);
}
// 关闭文件
pcmFile.close();
wavFile.close();
}
调用函数
// 封装WAV的头部
WAVHeader header;
header.numChannels = 2;
header.sampleRate = 44100;
header.bitsPerSample = 16;
header.audioFormat = 1;
// 调用函数
FFmpegUtil::pcm2wav(header, "F:/in.pcm", "F:/out.wav");
10_PCM转WAV的更多相关文章
- C++标准库实现WAV文件读写
在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库. WAV文件结构 ...
- iOS 使用EZAudio库生成wav出错的情况
使用EZAudio库 录M4A格式可以参考该库例子中的代码. 录wav格式得改下源码.看下面的代码 AVAudioSession *session = [AVAudioSession sharedIn ...
- C#播放wav文件
C#使用HWQPlayer类播放wav文件 类的代码: using System.IO; using System.Runtime.InteropServices; namespace HoverTr ...
- WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
刚好最近接触了一些DirectSound,就写了一个小程序练练手,可以用来添加播放基本的wav和mp3音频文件的播放器.界面只是简单的GDI,dxsdk只使用了DirectSound8相关的接口. D ...
- ffmpeg常用转换命令,支持WAV转AMR
音频转换: 1.转换amr到mp3: ffmpeg -i shenhuxi.amr amr2mp3.mp3 2.转换amr到wav: ffmpeg -acodec libamr_nb -i shenh ...
- wince mobile环境下播放WAV声音
[DllImport("coredll", EntryPoint = "PlaySound")] public static extern i ...
- 音频文件解析(二):WAV格式文件波形绘制
解析WAV头部信息后,接下来就可以根据相关参数和DATA块数据绘制波形. 1.重新编码(转换为8bits,单声道数据) Public Function GetFormatData(ByVal pDat ...
- 音频文件解析(一):WAV格式文件头部解析
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 文 ...
- python 播放 wav 文件
未使用其他库, 只是使用 pywin32 调用系统底层 API 播放 wav 文件. # Our raison d'etre - playing sounds import pywintypes im ...
- FreeSWITCH无法读取wav文件
错误日志如下: -- :: Invalid file format [wav] /suite-espanola-op--leyenda.wav]! -- :: Can't open /usr/loca ...
随机推荐
- typescript json 转 bean
3个文件: 1.UserInfoGetResponse.ts class UserInfoGetResponse{ private userId: number; private userName: ...
- ClickHouse-tgz安装步骤
一.什么是clickhouse ClickHouse是开源的列式存储数据库(DBMS),主要用于在线处理查询(OLAP),能够使用SQL查询实时生成数据分析报告. 下面介绍下安装clickhouse. ...
- 《Learning from Context or Names?An Empirical Study on Neural Relation Extraction》论文阅读笔记
代码 原文地址 预备知识: 1.什么是对比学习? 对比学习是一种机器学习范例,将未标记的数据点相互并列,以教导模型哪些点相似,哪些点不同. 也就是说,顾名思义,样本相互对比,属于同一分布的样本在嵌入空 ...
- Unicode编码的魅力:跨语言交流的桥梁
引言: Unicode编码是一种用于表示世界上所有字符的标准编码方式.它解决了字符集兼容性和多语言文本处理的难题,成为实现全球化软件的关键技术.本文将深入探讨Unicode编码的优点与缺点,并介绍它在 ...
- Python_json类方法
Python_json类方法 import requests import json headers = { "User-Agent": "Mozilla/5.0 (Li ...
- 【JS】一个思路搞定三道Promise并发编程题,手摸手教你实现一个Promise限制器
壹 ❀ 引 之前在整理手写Promise相关资料时,在文章推荐区碰巧看到了一道手写Promise并发控制调度器的笔试题(大厂可能爱考),结果今天同事又正好问了我一个关于Promise调度处理的场景问题 ...
- NC25005 [USACO 2008 Ope S]Clear And Present Danger
题目链接 题目 题目描述 Farmer John is on a boat seeking fabled treasure on one of the N (1 <= N <= 100) ...
- Smartctrl 命令使用说明
一.smartctl工具简介 Smartmontools是一种硬盘检测工具,通过控制和管理硬盘的SMART(Self Monitoring Analysis and Reporting Techno ...
- IntersectionObserver对象
IntersectionObserver对象 IntersectionObserver对象,从属于Intersection Observer API,提供了一种异步观察目标元素与其祖先元素或顶级文档视 ...
- performance schema 性能模式
1.performance_schema简介 MySQL的performance schema 用于监控MySQL server在一个较低级别的运行过程中的资源消耗.资源等待等情况.performan ...