PCM数据格式介绍

article/2025/9/30 19:22:29

目录

什么是PCM

Sampling(采样)

采样率(Sample rate)

Quantization(量化)

Encoding(编码)

PCM数据常用量化指标

PCM数据流

音量控制

采样率调整



什么是PCM


PCM全称Pulse-Code Modulation,翻译一下是脉冲调制编码。

其实大可以不用关心英文释义,之所以这么命名是因为一些历史原因。

在音视频中,PCM是一种用数字表示采样模拟信号的方法。

要将一段音频模拟信号转换为数字表示,包含如下三个步骤:

Sampling(采样)
Quantization(量化)
Coding(编码)
通常,我们可以通过一条曲线在坐标中显示连续的模拟信号,如下图所示:

在这里插入图片描述
为了更容易理解PCM,取其中一段来说明。

 

 

假设这表示一段一秒的音频模拟信号。

在这里插入图片描述


Sampling(采样)


Sampling(采样)处理,实际上就是让采样数据能够完全表示原始信号,且采样数据能够通过重构还原成原始信号的过程,如上图。

将采样后的图拿出来单独解释:

在这里插入图片描述
红色曲线:表示原始信号。
蓝色垂直线段:表示当前时间点对原始信号的一次采样。采样是一系列基于振幅(amplitude和相同时间间隔的样本。这也是为什么采样过程被称为PAM的原因。
PAM:(Pulse Amplitude Modulation)是一系列离散样本之的结果。


采样率(Sample rate)


每秒钟的样本数也被称之为采样率(Sample rate)。在Sampling图示案例中,采样率为每秒34次。意味着在一秒的时间内,原始信号被采样了34次(也就是蓝色垂直线段的数量)。

通常,采样率的单位用Hz表示,例如1Hz表示每秒钟对原始信号采样一次,1KHz表示每秒钟采样1000次。1MHz表示每秒钟采样1百万次。

根据场景的不同,采样率也有所不同,采样率越高,声音的还原程度越高,质量就越好,同时占用空间会变大。

例如:通话时的采样率为8KHz,常用的媒体采样率有44KHz,对于一些蓝光影片采样率高达1MHz。

Quantization(量化)


原始信号采样后,需要通过量化来描述采样数据的大小。如图:

在这里插入图片描述
量化处理过程,就是将时间连续的信号,处理成时间离散的信号,并用实数表示。这些实数将被转换为二进制数用于模拟信号的存储和传输。 

 

在图例中,如果说采样是画垂直线段的话,那么量化就是画水平线,用于衡量每次采样的数字指标。如图:在这里插入图片描述

 

图中,每条横线表示一个等级(level)

为了更好的描述量化过程,先来介绍一下bit-depth(位深):用来描述存储数字信号值的bit数。较常用的模拟信号位深有:

8-bit:2^8 = 256 levels,有256个等级可以用于衡量真实的模拟信号。
16-bit:2^16 = 65,536 levels,有65,536个等级可以用于衡量真实的模拟信号。
24-bit:2^24 = 16,666,216 levels,有16,666,216个等级可以用于衡量真实的模拟信号。
显而易见,位深越大,对模拟信号的描述将越真实,对声音的描述更加准确。

在当前例子中,如果用为8-bit位深来描述的话,就如下图所示:

在这里插入图片描述 

量化的过程就是将一个平顶样本四舍五入到一个可用最近level描述的过程。如图中黑色加粗梯形折线。量化过程中,我们将尽量让每个采样和一个level匹配,因为每个level都是表示一个bit值。

图中,第9次采样的平顶样本对应的level用十进制表示为255,也就是二进制的1111 1111。

Encoding(编码)

在这里插入图片描述
在编码这一步,我们会将时间线上的每个sample数据转化为对应的二进制数据。

采样数据经过编码后产生的二进制数据,就是PCM数据。PCM数据可以直接存储在介质上,也可以在经过编解码处理后进行存储或传输。

PCM数据常用量化指标


采样率(Sample rate):每秒钟采样多少次,以Hz为单位。详见:**采样率(Sample rate)**一节。

位深度(Bit-depth):表示用多少个二进制位来描述采样数据,一般为16bit。详见:**Quantization(量化)**一节。

字节序:表示音频PCM数据存储的字节序是大端存储(big-endian)还是小端存储(little-endian),为了数据处理效率的高效,通常为小端存储。

声道数(channel number):当前PCM文件中包含的声道数,是单声道(mono)、双声道(stereo)?此外还有5.1声道等。

采样数据是否有符号(Sign):要表达的就是字面上的意思,需要注意的是,使用有符号的采样数据不能用无符号的方式播放。

以FFmpeg中常见的PCM数据格式s16le为例:它描述的是有符号16位小端PCM数据

s表示有符号,16表示位深,le表示小端存储。

PCM数据流


对于PCM数据都是一些图像化的描述,那么一段PCM格式的数据流怎么表示的呢?

以8-bit有符号为例,长得像这样:

+---------+-----------+-----------+----binary 	| 0010 0000 | 1010 0000 | ...decimal	| 32        | -96       | ...
+---------+-----------+-----------+----  


每个分割符"|"分割字节。因为是8-bit有符号表示的采样数据,所以采样的范围为-128~128

图示中表示的是两个连续采样数据的二进制和十进制表示的值。

如果我们有一个PCM文件,在代码中,我们可以通过以下方式来读取这样的PCM数据流(Stream)。

FILE *file
int8_t *buffer;
file = fopen("PCM file path");
buffer = malloc(fileSize);
fread(buffer, sizeof(int8_t), fileSize / sizeof(int8_t), file);


伪代码仅仅表示一种加载方式。但在代码中,一开始就将整个文件加载到了内存中,这是不对的。因为我们的音频数据量往往会比较大,一次性全部加载增加了内存负担,而且并不必要。

通常我们会为buffer分配一个固定的长度,例如2048字节,通过循环的方式一边从文件中加载PCM数据,一边播放。

加载好PCM数据后,需要送到音频设备驱动程序中播放,这时我们应该能听到声音。与PCM数数据一同到达驱动程序的通常还有采样率(sample rate),用来告诉驱动每秒钟应该播放多少个采样数据。如果传递给驱动程序的采样率大于PCM实际采样率,那么声音的播放速度将比实际速度快,反之亦然。

OK,对于PCM数据流的存储而言,上面仅仅只是单声道。对于多声道的PCM数据而言,通常会交错排列,就像这样:

+---------+-----------+-----------+-----------+-----------+----FL 	|     FR    |     FL 	  |     FR    |     FL 	  |    
+---------+-----------+-----------+-----------+-----------+----


对于8-bit有符号的PCM数据而言,上图表示第一个字节存放第一个左声道数据(FL),第二个字节放第一个右声道数据(FL),第三个字节放第二个左声道数据(FL)

不同的驱动程序对于多声道数据的排列方式可能稍有区别,下面是常用的声道排列地图:

2:  FL FR                       (stereo)
3:  FL FR LFE                   (2.1 surround)
4:  FL FR BL BR                 (quad)
5:  FL FR FC BL BR              (quad + center)
6:  FL FR FC LFE SL SR          (5.1 surround - last two can also be BL BR)
7:  FL FR FC LFE BC SL SR       (6.1 surround)
8:  FL FR FC LFE BL BR SL SR    (7.1 surround)


音量控制


音量的表示实际上就是量化过程中每个采样数据的level值,只要适当的增大或者缩小采样的level就可以达到更改音量的目的。

但需要说明的是,并是不将level值*2就能得到两倍于原声音的音量。

因为如下两个原因:

  • 数据溢出:我们都知道每个采样数据的取值范围是有限制的,例如一个signed 8-bit样本,取值范围为-128~128,值为125时,放大两倍后的值为250,超过了可描述的范围,此时发生了数据溢出。这个时候就需要我们做策略性的裁剪处理,使放大后的值符合当前格式的取值区间。

如下伪代码描述了signed 8-bit格式的声音放大两倍的裁剪处理:

int16_t pcm[1024] = read in some pcm data;
int32_t pcmval;
for (ctr = 0; ctr < 1024; ctr++) {pcmval = pcm[ctr] * 2;if (pcmval < 128 && pcmval > -128) {pcm[ctr] = pcmval} else if (pcmval > 128) {pcm[ctr] = 128;} else if (pcmval < -128) {pcm[ctr] = -128;}
}

  • 对数描述:平时表示声音强度我们都是用分贝(db)作单位的,声学领域中,分贝的定义是声源功率与基准声功率比值的对数乘以10的数值。根据人耳的心理声学模型,人耳对声音感知程度是对数关系,而不是线性关系。人类的听觉反应是基于声音的相对变化而非绝对的变化。对数标度正好能模仿人类耳朵对声音的反应。所以用分贝作单位描述声音强度更符合人类对声音强度的感知。前面我们直接将声音乘以某个值,也就是线性调节,调节音量时会感觉到刚开始音量变化很快,后面调的话好像都没啥变化,使用对数关系调节音量的话声音听起来就会均匀增大。

如下图所示,横轴表示音量调节滑块,纵坐标表示人耳感知到的音量,图中取了两块横轴变化相同的区域,音量滑块滑动变化一样,但是人耳感觉到的音量变化是不一样的,在左侧也就是较安静的地方,感觉到音量变化大,在右侧声音较大区域人耳感觉到的音量变化较小。

在这里插入图片描述
这就需要对音量值的乘数系数合理取值。

采样率调整


采样率的定义为:每秒钟采样次数。而降低增加采样率只需要以固定的频率复制或者丢弃采样数据即可。

如10Hz表示每秒钟采样10次,我们只需要将2*n(n为从0开始的值)处的采样数据舍弃,就可以得到10/2 = 5Hz的采样数据。
————————————————
版权声明:本文为CSDN博主「SuperDali」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_25333681/article/details/90682989


http://chatgpt.dhexx.cn/article/ed2LIuBM.shtml

相关文章

PCM音频数据格式介绍

1. What is PCM? PCM(Pulse-code-modulation)是模拟信号以固定的采样频率转换成数字信号后的表现形式。 Sample Rate : 采样频率单位为&#xff1a;Hz。采样频率越高&#xff0c;音频质量越好&#xff0c;占用空间也越大。 Sign : 音频数据是否是有符号的。通常情况下都是有…

单调栈图文详解(附Java模板)

啥是"单调栈"&#xff0c;它能解决什么样的问题&#xff1f; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 数据结构与算法专栏的文章图文并茂&#x1f995;生动形象&#…

算法之单调栈常见题目

什么时候需要使用单调栈&#xff1f; 通常是一维数组&#xff0c;要寻找任意一个右边或者左边第一个比自己大或小的元素的位置&#xff0c;此时我们就想到可以使用单调栈了。 单调栈的本质是空间换时间&#xff0c;因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高…

单调栈及单调栈的应用

什么是单调栈 单调递增栈&#xff1a;单调递增栈就是从栈底到栈顶数据是从大到小单调递减栈&#xff1a;单调递减栈就是从栈底到栈顶数据是从小到大 解决那类问题 要知道单调栈的适用于解决什么样的问题&#xff0c;我们首先需要知道单调栈的作用。单调栈分为单调递增栈和单调…

理解单调栈与单调队列

单调栈 单调栈&#xff1a;栈内的元素按照某种方式排序下单调递增或单调递减&#xff0c;如果新入栈的元素破坏的单调性&#xff0c;就弹出栈内元素&#xff0c;直到满足单调性。 单调栈分为单调递增栈和单调递减栈&#xff1a; 单调递增栈&#xff1a;栈中数据入栈或出栈的…

【栈 单调栈】浅谈单调栈与单调栈的理解

单调栈 定义&#xff1a; 单调栈&#xff0c;顾名思义&#xff0c;是栈内元素保持一定单调性&#xff08;单调递增或单调递减&#xff09;的栈。这里的单调递增或递减是指的从栈顶到栈底单调递增或递减。既然是栈&#xff0c;就满足后进先出的特点。与之相对应的是单调队列。 …

单调栈(一)

单调栈基本概念及实现 方案1&#xff1a;对于每一个数&#xff0c;遍历其左右位置&#xff0c;时间复杂度为O(N^2) 方案2&#xff1a;单调栈&#xff0c;每个元素入栈一次出栈一次&#xff0c;时间复杂度为O(N) &#xff08;一&#xff09;数组中没有重复值 示例&#xff1a;[…

第九章:单调栈与单调队列

单调栈与单调队列 一、单调栈1、什么是单调栈&#xff1f;2、单调栈的模板&#xff08;1&#xff09;问题&#xff1a;&#xff08;2&#xff09;分析&#xff1a; 二、单调队列1、什么是单调队列2、单调队列模板&#xff08;1&#xff09;问题&#xff08;2&#xff09;分析 一…

单调栈算法详解

单调栈算法详解 单调栈使用模板 stack<int> st; //此处一般需要给数组最后添加结束标志符&#xff0c;具体下面例题会有详细讲解 for (遍历这个数组){if (栈空 || 栈顶元素大于等于当前比较元素){入栈;}else{while (栈不为空 && 栈顶元素小于当前元素){栈顶元素…

单调队列和单调栈详解

这里是我的blog&#xff1a;有更多算法分享。排版可能也会更好看一点v https://endlesslethe.com/monotone-queue-and-stack-tutorial.html 前言 单调栈和单调队列算是栈和队列的高级应用吧&#xff0c;在公司面试中应该是不怎么会出现的&#xff08;除非算法岗&#xff1f;…

什么是单调栈

什么是单调栈 单调栈就是单调递增或者单调递减的栈&#xff0c;也就是栈底到栈顶递增或递减&#xff0c;根据单调栈的的这种结构&#xff0c;可以很容易想到运用单调栈可以很容易的把O(n)的时间复杂度优化到O(n),如果使用数组的话&#xff0c;相对的空间复杂度也不会太高 示例 …

Java实现之单调栈

目录 一.单调栈 二.每日温度 1.题目描述 2.问题分析 3.代码实现 三.下一个更大元素 I 1.题目描述 2.问题分析 3.代码实现 四.下一个更大元素 II 1.题目描述 2.问题分析 3.代码实现 一.单调栈 通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自…

[数据结构]单调栈

单调栈 这是笔者的第一篇博客&#xff0c;由于笔者自身水平的限制。用词可能不够准确&#xff0c;句子不太通顺&#xff0c;代码水平可能也不太行&#xff0c;敬请指出&#xff0c;感激不尽&#xff01; 我们都知道栈&#xff08;Stack&#xff09;是一种先入后出的数据结构&am…

单调栈和单调队列

本文摘自博客&#xff0c;欢迎前往博客以获得更好的体验。 单调栈 从名字上就听的出来&#xff0c;单调栈中存放的数据应该是严格单调有序的&#xff0c;具有以下两个性质。 满足从栈顶到栈底的元素具有严格的单调递增或单调递减性&#xff1b;满足栈的后进先出特性&#xff…

数据结构之单调栈(含代码实现)

目录 1.单调栈的基本概念 &#xff1a; 2.单调栈的应用 2.1单调栈 2.2单调栈进阶 2.3最大矩形面积 2.4最大矩形 2.5统计全为1的子矩阵数量 ​ 1.单调栈的基本概念 &#xff1a; 相信大家对栈都非常的熟悉&#xff1f;栈有一个非常鲜明的特点&#xff1a;先进后出 而所谓 单调栈…

C++之单调栈

单调栈的性质 单调栈是一种特殊的栈&#xff0c;特殊之处在于栈内的元素都保持一个单调性。 假设下图是一个栈内元素的排列情况(单调递增的栈)&#xff1a; 此时插入情况有两种&#xff1a; &#xff08;1&#xff09;插入元素大于栈顶元素&#xff1a; 因为7 > 6&#xf…

单调栈以及单调栈的应用

文章目录 单调栈的概念单调栈的应用CD101 单调栈结构&#xff08;无重复值&#xff09;CD188 单调栈结构(有重复值)496. 下一个更大元素 I739. 每日温度1856. 子数组最小乘积的最大值84. 柱状图中最大的矩形85. 最大矩形1504. 统计全 1 子矩形907. 子数组的最小值之和1307 验证…

单调栈完全解析

目录 单调栈的应用场景 为什么要使用单调栈&#xff1f; 单调栈作用的基本过程 单调栈的实现方式 栈里面的元素存放数字下标&#xff08;无重复元素&#xff09; 栈里面的元素存放数字下标组成的链表 &#xff08;有重复元素&#xff09; 单调栈的应用题目 直方图类型 …

单调栈与单调队列

文章目录 单调栈与单调队列一、单调栈1.单调递增栈2.单调递减栈总结 二、单调队列(单调双端队列) 单调栈与单调队列总结&#xff1a; 单调栈与单调队列 单调栈就是栈内元素满足单调性的栈结构。此处的单调性分为单调递增与单调递减 如何维护一个单调栈&#xff1a; 单调递增栈…

详解单调栈算法

前言 嘿&#xff01;彩蛋&#xff01;感觉有帮助就三连呗&#xff01; 如果你对这篇文章可感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 栈属于基础数据结构之一&#xff0c;基础到仅用「后进…