PCM, WAV, MP3格式解析

698 阅读2分钟

PCM

音频原始数据格式PCM(纯音频数据)

存储格式解析

了解PCM存在单、双信道8位、16位等采样率,其他基本就是纯音频数据流。(小端模式) image.png

大小分析

  1. 采样大小: 一个采样用多少bit存放,通常是16bit
  2. 采样率: 每秒采样的频率, 一般有8k, 16k, 32, 44.1k, 48k(接近原声)
  3. 声道数: 单声道,双声道,立体声(多声道)

原始音频数据的大小 = 采样大小 * 采样率 * 声道数 * 时间

js获取方式

使用MediaRecorderAPI可以使用设备麦克风录制音频,得到PCM数据

if (navigator.mediaDevices) {

    const constraints = { audio: true };

    navigator.mediaDevices.getUserMedia(constraints)
        .then((stream) => {

            // 传对应的mimeType
            this.mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm; codecs=pcm" });

            this.mediaRecorder.ondataavailable = async (e) => {
                // e.data就是录制的PCM数据
                console.log(e.data)
            }
        })
        .catch((err) => {
            this.$message.warning("浏览器不支持媒体操作" + err);
        })
}

image.png

WAV

WAV其实就是带了一些数据头(44字节)的PCM数据,可以使用类似哈夫曼之类的无损压缩。

WAV结构分析

头部树数据分析

image.png

typedef struct {
    char          ChunkID[4]; //内容为"RIFF"
    unsigned long ChunkSize;  //存储文件的字节数(不包含ChunkID和ChunkSize这8个字节)
    char          Format[4];  //内容为"WAVE“
} WAVE_HEADER;
 
typedef struct {
   char           Subchunk1ID[4]; //内容为"fmt"
   unsigned long  Subchunk1Size;  //存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节)
   unsigned short AudioFormat;    //存储音频文件的编码格式,例如若为PCM则其存储值为1。
   unsigned short NumChannels;    //声道数,单声道(Mono)值为1,双声道(Stereo)值为2,等等
   unsigned long  SampleRate;     //采样率,如8k,44.1k等
   unsigned long  ByteRate;       //每秒存储的bit数,其值 = SampleRate * NumChannels * BitsPerSample / 8
   unsigned short BlockAlign;     //块对齐大小,其值 = NumChannels * BitsPerSample / 8
   unsigned short BitsPerSample;  //每个采样点的bit数,一般为8,16,32等。
} WAVE_FMT;
 
typedef struct {
   char          Subchunk2ID[4]; //内容为“data”
   unsigned long Subchunk2Size;  //接下来的正式的数据部分的字节数,其值 = NumSamples * NumChannels * BitsPerSample / 8
} WAVE_DATA;

image.png (图片 摘取自 zhuanlan.zhihu.com/p/512791706…

自己生成一段WAV数据,使用DataView分析,确实和上面的数据一致

image.png

js获取方式

既然知道WAV就比PCM数据多一个头部,那么就一一添加就好。

使用audiobuffer-to-wavPCM转为WAV,使用方式很简单,根据npmjs上的说明就行。

可以看看他的源码:

image.png 也就是在给PCM添加上了对应的头部信息

MP3

MP3为有损编码方式,去除了部分数据,体积比无损压缩的WAV更小。

js获取方式

使用lamejs,将WAV转成MP3。按照官网提供的转化案例复制过来就行,单声道(MONO)和立体声(stereo)都有。有一定的计算耗时,可以使用worker处理。