语音文件的格式、字节计算、PCM头信息 2019-04-26
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了语音文件的格式、字节计算、PCM头信息 2019-04-26相关的知识,希望对你有一定的参考价值。
参考技术A PCM我们在音频处理的时候经常会接触到 PCM 数据:它是模拟音频信号经 模数转换 (A/D变换)直接形成的 二进制序列 ,该文件 没有附加的文件头 和 文件结束 标志。
声音本身是模拟信号,而计算机只能识别数字信号,要在计算机中处理声音,就需要将声音数字化,这个过程叫经模数转换(A/D变换)。最常见的方式是透过脉冲编码调制PCM (Pulse Code Modulation) 。
运作原理如下:首先我们考虑声音经过麦克风,转换成一连串电压变化的信号,如下图所示。这张图的横座标为秒,纵座标为电压大小。
要将这样的信号转为 PCM 时,需要将声音量化,我们一般从如下几个维度描述一段声音:
采样频率: 即取样频率,指每秒钟取得声音样本的次数。采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多。由于人耳的分辨率很有限,太高的频率并不能分辨出来。在16位声卡中有22KHz、44KHz等几级,其中,22KHz相当于普通FM广播的音质,44KHz已相当于CD音质了,目前的常用采样频率都不超过48KHz。
采样位数: 即采样值或取样值(就是将采样样本幅度量化)。它是用来衡量声音波动变化的一个参数,也可以说是声卡的分辨率。它的数值越大,分辨率也就越高,所发出声音的能力越强。
声道数: 很好理解,有单声道和立体声之分,单声道的声音只能使用一个喇叭发声(有的也处理成两个喇叭输出同一个声道的声音),立体声的PCM 可以使两个喇叭都发声(一般左右声道有分工) ,更能感受到空间效果。
时长: 采样的时长
下面再用图解来看看采样位数和采样频率的概念。让我们来看看这几幅图。
图中的黑色曲线表示的是PCM 文件录制的自然界的声波,
红色曲线表示的是PCM 文件输出的声波,
这个图中,采样点是离散的,每一个点对应pcm一个单元的数据。
采样频率越高,x轴采样点就越密集,声音越接近原始数据
采样位数越高,y轴采样点就越密集,声音越接近原始数据
采样频率单位为Hz,表示每秒采样的次数:
一般有11025HZ(11KHz)、22050HZ(22KHz)、44100Hz(44KHz)三种。
采样位数单位为bit(位),一般有 8bit 和 16bit 。8bit 表示用 8bit 空间量化某时刻的声音,这一点基本是和图片用r、g、b三单位共 24bit 量化颜色一样。
综上所述,我们可以得到pcm文件的体积计算公式(这里我们把 采样位数/8 是因为电脑上是将bit转化为byte):
存储量 = (采样频率 × 采样位数/8) × 声道 × 时间.
例如,数字激光唱盘(CD-DA,红皮书标准)的标准采样频率为44.l kHz,采样数位为16 位,立体声(2声道),可以几乎无失真地播出频率高达22 kHz的声音,这也是人类所能听到的最高频率声音。激光唱盘一分钟音乐需要的存储量为:
(44.1*1000* l6 *2)*60/8=10,584,000(字节)=10.584 M Bytes
这个数值就是 PCM 声音文件在硬盘中所占磁盘空间的存储量。
数据以 二进制序列 储存在文件里
双声道音频的存储方式是LRLRLRLR,16bit音频是每个声道都是16bit(2字节)么?PCM是interleaved的方式存储,具体存储的时候还有小端(little endian)和 (big endian)的问题,一般的存储是小端的,也就是2字节,低位在前,高位在后一个采样点16位是0x 1234 存储的时候是 0x34 和 0x12 , 如果是大端就反过来。
一个单声道的pcm无头音频1M ,转成 双声道就变成2M了,就算是有一条声道没信息(或者微弱信号噪声),但是 转成双声道的时候就算是静音,数据大小是0x0000他也是要占着位数的,所以不管怎样,只要是双声道就会变成2倍大小。
前面也介绍到了,PCM 数据本身只是一个 裸码流 ,它是由 声道、采样位数、采样频率、时长 共同决定的,因此我们至少要知道其中的三个才能将 PCM 所代表的数据提取出来。
因此,纯PCM数据是无法播放的,因此还需要一段 描述数据 。计算机系统中的一个比较常见的做法是将 pcm码流和描述信息封装在一起 ,形成一个音频文件。这样就可以直接播放了。
一种常见的方式是使用wav格式定义的规范将pcm码流和描述信息封装起来。 查看 pcm 和对应wav文件的 hex(16进制)文件,可以发现,wav文件只是在pcm文件的开头多了44字节 ,来表征其声道数、采样频率和采样位数等信息。 这个其实和bmp非常类似。
WAV、G729、G723 、MP3 等音频格式都是8k 16bit wav音频经过压缩的格式。
由于厂商众多、 很多音频格式 应运而生,比如nice公司出品的 nmf 其实音频,其实就是一个经过多层再包装的g729;vox 格式是华为公司出品的音频。
vox 格式是华为的格式、他的后缀一种是 V3 的,直接把后缀改成vox就可以听;还有一种后缀就是vox。
vox格式因为本身是没有头信息的看不到,所以不知道采样率不能转码、这时候用 cooledit 打开听一下,选择8k的采样率打开如果语速很快音频实际是6k;如果选择6k的采样率打开如果语速很快音频实际是8k。现在 得知采样率之后就可以用工具转码,下面会说到工具ffmpeg以及他的轻量版sox。
G729以10字节作为一个解码单元,G729转码时先把头去掉再转。
G729是十六倍压缩。8k 16bit 8kb/s (正常是128kb/s 压缩16倍)
和g729一样是16倍压缩,但是由于压缩算法不一样,G729的频谱是光滑的、而MP3音频的损失很多。是最差的一种音频格式。
8k 8bit stereo 128kb/s音频格式,应该是非压缩的格式
首先音频格式之间转码,比如g729 转 mp3 流程是g729->8k、16bit wav -> mp3,都是要先经过wav的。
一般会内置的轻量级ffmpeg工具。
sox 1.wav 2.wav 3.wav 1_2_3.wav
hexdump -Cv in.wav | less
标准音频的头字节是44位
查看音频字节信息是:hexdump -C in.wav
看红色部分
其中音频大小可以在第 40-43 位(从0位开始)倒着看是音频大小: 0x 00 02 53 a0
转换成 十进制 是152480 加上 标准头字节 44 是152524字节
查看音频的 文件大小 是 152524字节 与计算结果吻合
其实看4-7位也行,4-7位查看下来是152516字节
152516+8=152524字节其实这个152516就是除了头字节的八个字节后面的字节数
看蓝色部分
第 24-25 位是 0x 40 1f = 8k 这个位置标记的是音频的采样率大小标准音频的头字节是44位
一个裸的PCM格式音频数据,如果不带头信息,不知道其采样率等相关信息,就无法用播放器播放出来。下面是默认的头信息格式:
//音频头部格式
struct wave_pcm_hdr
char riff[4]; // = "RIFF"
SR_DWORD size_8; // = FileSize - 8
char wave[4]; // = "WAVE"
char fmt[4]; // = "fmt "
SR_DWORD dwFmtSize; // = 下一个结构体的大小 : 16
SR_WORD format_tag; // = PCM : 1
SR_WORD channels; // = 通道数 : 1
SR_DWORD samples_per_sec; // = 采样率 : 8000 | 6000 | 11025 | 16000
SR_DWORD avg_bytes_per_sec; // = 每秒字节数 : dwSamplesPerSec *wBitsPerSample / 8
SR_WORD block_align; // = 每采样点字节数 : wBitsPerSample / 8
SR_WORD bits_per_sample; // = 量化比特数: 8 | 16
char data[4]; // = "data";
SR_DWORD data_size; // = 纯数据长度 : FileSize - 44
;
//默认音频头部数据
struct wave_pcm_hdr default_pcmwavhdr =
'R', 'I', 'F', 'F' ,
0,
'W', 'A', 'V', 'E',
'f', 'm', 't', ' ',
16,
1,
1,
16000,
32000,
2,
16,
'd', 'a', 't', 'a',
0
;
PCM 音频到文件
【中文标题】PCM 音频到文件【英文标题】:PCM Audio to File 【发布时间】:2019-09-24 00:14:59 【问题描述】:我想在 Discord 语音频道中录制音频并使用 Discord Bot 将其保存到文件中。
我每 20 毫秒接收一次音频,作为 pcm 编码的字节 [],我想将其保存到文件中。 MP3 是首选,但我对 ogg 等其他文件格式也没有问题(它可能更容易)。
我正在使用 JDA 版本 4.ALPHA.0_82
并且我还包括 lavaplayer 版本 1.3.17
用于其他功能。如果这些库足够的话会很有帮助,但如果我必须包含更多库也没问题。
【问题讨论】:
我将 PCM 转储到一个文件中,然后通过 discord 将其发回以听到它。当然,这些文件很大,但它可以工作:^) 另请注意,JDA 为您提供 PCM 数据,而不是作品(除非他们在 v4 中更改了某些内容) 我想到了同样的方法,难道没有一种简单的方法可以将其保存为压缩音频格式吗? 我曾经被告知要通过 ffmpeg 进行管道传输。我假设你想要一个跨平台/独立的解决方案 【参考方案1】:This question 解释了如何将 pcm 转换为 wav。
我通过覆盖方法 AudioReceiveHandler#handleCombinedAudio
将 Discord 音频复制到 List<byte[]>
:
private List<byte[]> rescievedBytes=new ArrayList<>();
@Override
public void handleCombinedAudio(CombinedAudio combinedAudio)
try
rescievedBytes.add(combinedAudio.getAudioData(VOLUME));
catch (OutOfMemoryError e)
//close connection
之后,我将List
复制到byte[]
并创建了wav
文件。
try
int size=0;
for (byte[] bs : rescievedBytes)
size+=bs.length;
byte[] decodedData=new byte[size];
int i=0;
for (byte[] bs : rescievedBytes)
for (int j = 0; j < bs.length; j++)
decodedData[i++]=bs[j];
getWavFile(getNextFile(), decodedData);
catch (IOException|OutOfMemoryError e)
e.printStackTrace();
private void getWavFile(File outFile, byte[] decodedData) throws IOException
AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(
decodedData), format, decodedData.length), AudioFileFormat.Type.WAVE, outFile);
如果恢复的音频太大 (OutOfMemoryError
),转换将中止。
【讨论】:
你忘了增加 i。 为什么不使用AudioReceiveHandler提供的格式?以上是关于语音文件的格式、字节计算、PCM头信息 2019-04-26的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向ELF 文件格式 ( ELF 文件当前版本号 | 操作系统 ABI 信息 | ABI 版本 | 文件头校验 | 文件头长度信息 )