数据格式

Android 在内部使用多种音频数据格式,并在公共 API、文件格式硬件抽象层 (HAL) 中公布了其中的一部分。

属性

音频数据格式按其属性进行分类:

压缩
未压缩无损压缩有损压缩。PCM 是最常见的未压缩音频格式。FLAC 是一种无损压缩格式,而 MP3 和 AAC 是有损压缩格式。
位深
每个音频样本的有效位数量。
容器大小
用于存储或传输样本的位数。通常与位深相同,但是有时会为了对齐而分配额外的填充位。例如,一个 24 位样本可以包含在一个 32 位字中。
对齐方式
如果容器大小与位深完全相同,该表示法被称为“打包”。否则,表示法为“解包”。样本的有效位通常与容器的最左(最高有效)或最右(最低有效)位对齐。通常只有当位深不是 2 的幂时,才使用术语“打包”和“解包”。
符号性
样本是有符号,还是无符号。
表示法
定点数或浮点数(见下文)。

定点数表示法

定点数是未压缩 PCM 音频数据的最常见表示法,特别是对于硬件接口。

定点数在小数点前后具有固定(恒定)位数。我们所有的表示法都使用基数 2,因此我们用“位”代替“位数”,用“二进制点”或简单的“点”代替“小数点”。点左边的位是整数部分,点右边的位是小数部分

我们之所以用“整数 PCM”的说法,是因为定点数值通常作为整数值进行存储和操作。隐含的解释就是定点数。

我们对所有有符号的定点数表示法使用二进制补码,因此下列表达式中的所有值都以 LSB 为单位:

|largest negative value| = |largest positive value| + 1

Q 和 U 标记

有各种标记用于整数中的定点数表示法。我们使用 Q 标记:Qm.n 表示 m 个整数位,n 个小数位。“Q”计为一位,尽管值以二进制补码表示。总位数为 m + n + 1。

Um.n 用于无符号数:m 个整数位和 n 个小数位,并且“U”计为零位。总位数为 m + n。

整数部分可以在最终结果中使用,也可以临时使用。在后一种情况下,构成整数部分的位称为“保护位”。保护位允许中间计算溢出,只要最终值在某个范围内或者可以限制在该范围内。请注意,定点数保护位位于左侧,而用于减少舍入误差的浮点数单元保护位位于右侧。

浮点数表示法

浮点数是定点数的替代方案,其中点的位置可以变化。浮点数的主要优点包括:

  • 余量动态范围更大;在中间计算过程中,浮点数运算容许超出标称范围,并且只在最后限制值
  • 支持特殊值,如无穷数和 NaN
  • 在许多情况下更易于使用

过去,浮点数运算比整数或定点数运算慢,但现在只要控制流决策不是基于计算的值,浮点数运算的速度通常会更快。

Android 音频格式

主要的 Android 音频格式如下表所列:

标记
属性 Q0.15 Q0.7 1 Q0.23 Q0.31 浮点数
容器
16 8 24 或 32 2 32 32
有效位
(包括符号)
16 8 24 24 或 32 2 25 3
余量
(以 dB 为单位)
0 0 0 0 126 4
动态范围
(以 dB 为单位)
90 42 138 138 到 186 900 5

上述所有定点数格式的标称范围均为 -1.0 至 +1.0 减去一个 LSB。由于采用二进制补码表示法的缘故,负值要比正值多一个。

脚注:

  1. 以上所有格式表示的是有符号的样本值。8 位格式通常称为“无符号”,但实际上是偏差为 0.10000000 的有符号值。
  2. Q0.23 可以打包成 24 位(三个 8 位字节,采用小端字节序),或者解包成 32 位。如果解包,则有效位向右对齐到 LSB,以符号扩展填充到 MSB (Q8.23);或向左对齐到 MSB,以零填充到 LSB (Q0.31)。理论上,Q0.31 最多允许 32 个有效位,但接受 Q0.31 的硬件接口很少使用所有位。
  3. 单精度浮点数具有 23 个显式位以及一个隐藏位和一个符号位,因而一共有 25 个有效位。非规格化数的有效位要少一些。
  4. 单精度浮点数可以表达高达 ±1.7e + 38 的值,这也是余量较大的原因所在。
  5. 所示的动态范围适用于非规格化数一直到最大标称值 ±1.0。请注意,某些针对特定架构的浮点数实现(如 NEON)不支持非规格化数。

转化次数

本部分将讨论各种表示法之间的数据转换

浮点数转换

将值从 Qm.n 格式转换为浮点数:

  1. 将该值转换为浮点数,就像它是一个整数一样(通过忽略该点)。
  2. 乘以 2-n

例如,要将 Q4.27 内部值转换为浮点数,请使用:

float = integer * (2 ^ -27)

从浮点数转换为定点数会遵循以下规则:

  • 单精度浮点数的标称范围为 ±1.0,但中间值的完整范围为 ±1.7e+38。外部表示法中的浮点数和定点数之间的转换(例如输出到音频设备)将仅考虑标称范围,对超过该范围的值会进行限制。尤其是,当 +1.0 被转换为定点数格式时,它将被限制为 +1.0 减去一个 LSB。
  • 非规格化数(次正规数)和 +/- 0.0 在表示法中都允许使用,但在处理过程中可能会静默转换为 0.0。
  • 无穷数可能会通过操作或者静默地硬限制为 +/- 1.0。通常后者用于转换为定点数格式。
  • NaN 行为尚未定义:NaN 可以作为相同的 NaN 传递,也可以转换为默认 NaN;可以静默地硬限制为 +/- 1.0,也可以静默地转换为 0.0,或者导致错误。

定点数转换

不同 Qm.n 格式之间的转换会遵循以下规则:

  • 当 m 增加时,用符号扩展左边的整数部分。
  • 当 m 减小时,限制整数部分。
  • 当 n 增加时,用零扩展右边的小数部分。
  • 当 n 减少时,抖动、舍入或截断右侧的多余小数位。

例如,如需将 Q4.27 值转换为 Q0.15(无抖动或舍入),请将 Q4.27 值右移 12 位,并限制超过 16 位有符号范围的任何结果。这会对齐 Q 表示法的点。

如需将 Q7.24 转换为 Q7.23,可进行带符号除以 2,或者等价地将符号位添加到 Q7.24 整数,然后带符号右移 1。请注意,简单带符号右移不等于带符号除以 2。

有损和无损转换

如果转换可逆,则是无损的:从 A 转换到 B 再到 C,那么可以得出 A = C。否则,转换是有损的

无损转换允许往返格式转换

从具有 25 位或更少有效位的定点数表示法转换到浮点数是无损的。从浮点数转换到任何常见的定点数表示法则是有损的。