硬核音频系列(二)—— 音频文件编解码格式

音频压缩对比,手写 adpcm 解码器

Posted by Shao Guoji on August 4, 2019

在系列第二篇,会介绍一些关于音频数据存储、处理的内容,并回答上一篇末尾提出的两个问题:如何减小 PCM 格式数据的体积和管理这些数据。

音频数据的存储(wav PCM 格式)

我们不能直接在硬盘上保存 PCM 格式裸数据,就好比超市货架上的食品需要处理过才能上架,一块带血有毛的生肉耷拉在顾客面前,可不是件令人愉悦的事情。把食材加工、打包并贴上标签,这样才是一个合格的商品,同理,音频数据也需要进行加工打包,最终作为一个个文件摆放在我们电脑中。

编码格式、编解码器与容器

PCM 格式数据表示声音波形在某一时刻的真实值,能够被声卡和 DAC 直接“食用”。把这些 PCM 裸数据进行二次压缩编码,得到体积减小的音频数据,再附加一些属性信息(采样率位深通道数等),装进特制的容器中,成为可传播、处理、播放的单个音频文件。

在一个音频文件中,既有表示声音本身的音频数据(可以是 PCM 格式或经过二次编码),也有描述音频属性的一些元数据(Metadata),这类数据虽然不能被播放,却对播放起到重要辅助作用。对同一段声音使用不同编码格式编码,能得到不同的二进制音频数据,常见的编码格式有 PCM, MP3, AAC, FLAC 等。

图1 音频文件内容层次图

按照编码过程中是否损失声音信息,编码格式分为有损编码和无损编码格式,PCM 格式是无损编码,而有损编码为了压缩数据大小,并没有完整记录声音数据。MP3 编码丢弃某些人耳不敏感的频域,可大大降低文件体积,同时保证高音质。

编码后的音频数据不再表示波形采样值,因此不能直接输出播放,必须经过解码还原为最初的 PCM 形式,再发送给硬件播放。编解码器(codec)负责不同格式音频数据与 PCM 之间的编码和解码。各类编码格式数据,在解码后播放起来和 PCM 没有两样,PCM 是音频系统软硬件的桥梁

无论是 PCM 还是压缩后的音频,都需要通过容器封装,得到最终音频文件。在计算中所谓的封装,无非就是加头添尾,增加额外描述性数据,便于上层进一步处理。描述数据的数据也称为元数据(metadata),音频容器包含了音频数据、音频参数(采样率、位深通道数)、文件参数(大小)等,将文件划分成许多块区域,不同的容器格式规定了各类数据组织方式(大小顺序和位置),下图是 .wav 容器格式内的数据排布方式:

图2 WAV 容器格式

容器格式往往和文件后缀名对应,如 .wav、.m4a 等文件类型同时代表容器格式。

音频容器格式和编码格式是两个独立的概念,一种格式的音频数据能用多种容器封装,一种容器也能更换不同编码的数据。例如 MP3 编码数据可以用 WAV 或 MP3 容器封装,m4a 容器能封装 ALAC 或 AAC 两种编码,实际应用中要根据不同编码与容器特点,结合场景和系统情况选用搭配。

下面是一张不同音频格式的快速检索表:

图3 音频编码容器格式表

音频编码及文件容器是一个很庞大的知识领域,不同的标准下又有各种扩展和细分,限于篇幅,这里不做一一展开,有兴趣的读者可以看下这个维基词条:音频编码格式的比较 - 维基百科,自由的百科全书

音频压缩

音频编码的出现很大程度上是为了压缩文件体积,大文件除了占用存储空间,对传输带宽也是一笔不小的消耗,涉及到文件比特率的问题。

两个核心网页:

  1. https://wiki.multimedia.cx/index.php/Microsoft_ADPCM
  2. https://ffmpeg.org/doxygen/3.1/adpcm_8c_source.html

两个核心函数:

  1. adpcm_ms_expand_nibble();
  2. adpcm_decode_frame();

https://slideplayer.com/slide/7491471/

参考资料