blob: 574800a25557919c62f799c1ebbe90994723f63b [file] [log] [blame]
<html devsite><head>
<title>数据格式</title>
<meta name="project_path" value="/_project.yaml"/>
<meta name="book_path" value="/_book.yaml"/>
</head>
<body>
<!--
Copyright 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<p>
Android 在内部使用各种音频<a href="http://en.wikipedia.org/wiki/Data_format">数据格式</a>,并在公共 API、<a href="http://en.wikipedia.org/wiki/Audio_file_format">文件格式</a><a href="https://en.wikipedia.org/wiki/Hardware_abstraction">硬件抽象层</a> (HAL) 中公布了其中的一部分。
</p>
<h2 id="properties">属性</h2>
<p>
音频数据格式是按其属性进行分类:
</p>
<dl>
<dt><a href="https://en.wikipedia.org/wiki/Data_compression">压缩</a></dt>
<dd>
<a href="http://en.wikipedia.org/wiki/Raw_data">未压缩</a><a href="http://en.wikipedia.org/wiki/Lossless_compression">无损压缩</a><a href="http://en.wikipedia.org/wiki/Lossy_compression">有损压缩</a>。PCM 是最常见的未压缩音频格式。FLAC 是一种无损压缩格式,而 MP3 和 AAC 是有损压缩格式。
</dd>
<dt><a href="http://en.wikipedia.org/wiki/Audio_bit_depth">位元深度</a></dt>
<dd>
每个音频样本的有效位数量。
</dd>
<dt><a href="https://en.wikipedia.org/wiki/Sizeof">容器大小</a></dt>
<dd>
用于存储或传输样本的位数。通常与位元深度相同,但是有时会为了对齐而分配额外的填充位。例如,一个 24 位样本可以包含在一个 32 位字中。
</dd>
<dt><a href="http://en.wikipedia.org/wiki/Data_structure_alignment">对齐方式</a></dt>
<dd>
如果容器大小与位元深度完全相同,该表示法被称为“打包”。<em></em>否则,表示法为“解包”。<em></em>样本的有效位通常与容器的最左(最高有效)或最右(最低有效)位对齐。<em></em><em></em>通常只有当位元深度不是 <a href="http://en.wikipedia.org/wiki/Power_of_two">2 的幂</a>时,才使用术语“打包”和“解包”。
</dd>
<dt><a href="http://en.wikipedia.org/wiki/Signedness">符号</a></dt>
<dd>
样本是有符号,还是无符号。
</dd>
<dt>表示法</dt>
<dd>
定点数或浮点数(见下文)。
</dd>
</dl>
<h2 id="fixed">定点数表示法</h2>
<p>
<a href="http://en.wikipedia.org/wiki/Fixed-point_arithmetic">定点数</a>是未压缩 PCM 音频数据的最常见表示法,特别是对于硬件接口。
</p>
<p>
定点数在<a href="https://en.wikipedia.org/wiki/Radix_point">小数点</a>前后具有固定(恒定)位数。我们所有的表示法都使用<a href="https://en.wikipedia.org/wiki/Binary_number">基数 2</a>,所以我们用“位”代替“位数”,用“二进制点”或简单的“点”代替“小数点”。<em></em><em><em></em><em></em><em></em></em>点左边的位是整数部分,点右边的位是<a href="https://en.wikipedia.org/wiki/Fractional_part">小数部分</a>
</p>
<p>
我们之所以用“整数 PCM”,是因为定点数值通常作为整数值进行存储和操作。<em></em>作为定点数的解释是隐含的。
</p>
<p>
我们对所有有符号的定点数表示法使用<a href="https://en.wikipedia.org/wiki/Two%27s_complement">二进制补码</a>,因此下列表达式的值可使用一个 <a href="https://en.wikipedia.org/wiki/Least_significant_bit">LSB</a> 来实现:
</p>
<pre class="devsite-click-to-copy">
|largest negative value| = |largest positive value| + 1
</pre>
<h3 id="q">Q 和 U 标记</h3>
<p>
有各种<a href="https://en.wikipedia.org/wiki/Fixed-point_arithmetic#Notation">标记</a>用于整数中的定点数表示法。我们使用 <a href="https://en.wikipedia.org/wiki/Q_(number_format)">Q 标记</a>:Qm.n 表示 m 个整数位,n 个小数位。<em></em><em></em><em></em><em></em>“Q”计为一位,尽管值以二进制补码表示。总位数为 m + n + 1。<em></em><em></em>
</p>
<p>
Um.n 用于无符号数:m 个整数位和 n 个小数位,并且“U”计为零位。<em></em><em></em><em></em><em></em>总位数为 m + n。<em></em><em></em>
</p>
<p>
整数部分可以在最终结果中使用,也可以临时使用。在后一种情况下,构成整数部分的位称为“保护位”。<em></em>保护位允许中间计算溢出,只要最终值在范围内,或者可以限制到范围内。请注意,定点数保护位位于左侧,而用于减少舍入误差的浮点数单元<a href="https://en.wikipedia.org/wiki/Guard_digit">保护位</a>位于右侧。
</p>
<h2 id="floating">浮点数表示法</h2>
<p>
<a href="https://en.wikipedia.org/wiki/Floating_point">浮点数</a>是定点数的替代,其中点的位置可以变化。浮点数的主要优点包括:</p>
<ul>
<li>更大的<a href="https://en.wikipedia.org/wiki/Headroom_(audio_signal_processing)">余量</a><a href="https://en.wikipedia.org/wiki/Dynamic_range">动态范围</a>;在中间计算过程中,浮点数运算能够容许超出标称范围,并且只在最后限制值</li>
<li>支持特殊值,如无穷数和 NaN</li>
<li>在许多情况下,更易于使用</li>
</ul>
<p>
一直以来,浮点数运算比整数或定点数运算慢,但现在只要控制流决策不是基于计算的值,浮点数运算的速度通常会更快。
</p>
<h2 id="androidFormats">Android 音频格式</h2>
<p>
主要的 Android 音频格式如下表所列:
</p>
<table>
<tbody><tr>
<th></th>
<th colspan="6"><center>标记</center></th>
</tr>
<tr>
<th>属性</th>
<th>Q0.15</th>
<th>Q0.7 <sup>1</sup></th>
<th>Q0.23</th>
<th>Q0.31</th>
<th>浮点数</th>
</tr>
<tr>
<td>容器<br /></td>
<td>16</td>
<td>8</td>
<td>24 或 32 <sup>2</sup></td>
<td>32</td>
<td>32</td>
</tr>
<tr>
<td>有效位<br />包括符号</td>
<td>16</td>
<td>8</td>
<td>24</td>
<td>24 或 32 <sup>2</sup></td>
<td>25 <sup>3</sup></td>
</tr>
<tr>
<td>余量<br />(以 dB 为单位)</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>126 <sup>4</sup></td>
</tr>
<tr>
<td>动态范围<br />(以 dB 为单位)</td>
<td>90</td>
<td>42</td>
<td>138</td>
<td>138 到 186</td>
<td>900 <sup>5</sup></td>
</tr>
</tbody></table>
<p>
上述所有定点数格式的标称范围均为 -1.0 至 +1.0 减去一个 LSB。由于采用二进制补码表示法的缘故,负值要比正值多一个。
</p>
<p>
脚注:
</p>
<ol>
<li>
以上所有格式表示的是有符号的样本值。8 位格式通常称为“无符号”,但实际上是偏差为 <code>0.10000000</code> 的有符号值。
</li>
<li>
Q0.23 可以打包成 24 位(三个 8 位字节),或者解包成 32 位。如果解包,则有效位向右对齐到 LSB,以符号扩展填充到 MSB (Q8.23);或向左对齐到 MSB,以零填充到 LSB (Q0.31)。Q0.31 理论上允许多达 32 个有效位,但接受 Q0.31 的硬件接口很少使用所有位。
</li>
<li>
单精度浮点数具有 23 个显式位以及一个隐藏位和符号位,因而一共有 25 个有效位。
<a href="https://en.wikipedia.org/wiki/Denormal_number">非规格化数</a>的有效位要少一些。
</li>
<li>
单精度浮点数可以表达高达 ±1.7e + 38 的值,这也是大余量的原因所在。
</li>
<li>
所示的动态范围适用于非规格化数一直到最大标称值 ±1.0。请注意,某些特定于架构的浮点数实现(如 <a href="https://en.wikipedia.org/wiki/ARM_architecture#NEON">NEON</a>)不支持非规格化数。
</li>
</ol>
<h2 id="conversions">转换</h2>
<p>
本节将讨论各种表示法之间的<a href="https://en.wikipedia.org/wiki/Data_conversion">数据</a>转换。
</p>
<h3 id="floatConversions">浮点数转换</h3>
<p>
将值从 Qm.n 格式转换为浮点数:<em></em><em></em>
</p>
<ol>
<li>将值转换为浮点数,就像它是一个整数(通过忽略该点)。</li>
<li>乘以 2<sup>-n</sup><em></em></li>
</ol>
<p>
例如,要将 Q4.27 内部值转换为浮点数,请使用:
</p>
<pre class="devsite-click-to-copy">
float = integer * (2 ^ -27)
</pre>
<p>
从浮点数转换为定点数会遵循以下规则:
</p>
<ul>
<li>
单精度浮点数的标称范围为 ±1.0,但中间值的完整范围为 ±1.7e+38。外部表示法中的浮点数和定点数之间的转换(例如输出到音频设备)将仅考虑标称范围,对超过该范围的值会进行限制。尤其是,当 +1.0 被转换为定点数格式时,它将被限制为 +1.0 减去一个 LSB。
</li>
<li>
非规格化数(次正规数)和 +/- 0.0 在表示法中都允许使用,但在处理过程中可能会静默转换为 0.0。
</li>
<li>
无穷数可能会通过操作,或者静默硬限制为 +/- 1.0。通常后者用于转换为定点数格式。
</li>
<li>
NaN 行为尚未定义:NaN 可以作为相同的 NaN 传递,也可以转换为默认 NaN;可以静默地硬限制为 +/- 1.0,也可以静默地转换为 0.0,或者导致错误。
</li>
</ul>
<h3 id="fixedConversion">定点数转换</h3>
<p>
不同 Qm.n 格式之间的转换会遵循以下规则:<em></em><em></em>
</p>
<ul>
<li>
当 m 增加时,用符号扩展左边的整数部分。<em></em>
</li>
<li>
当 m 减小时,限制整数部分。<em></em>
</li>
<li>
当 n 增加时,用零扩展右边的小数部分。<em></em>
</li>
<li>
当 n 减少时,抖动、舍入或截断右侧的多余小数位。<em></em>
</li>
</ul>
<p>
例如,要将 Q4.27 值转换为 Q0.15(无抖动或舍入),则将 Q4.27 值右移 12 位,并限制超过 16 位有符号范围的任何结果。这样将对齐 Q 表示法的点。
</p>
<p>要将 Q7.24 转换为 Q7.23,可进行带符号除以 2,或者等价地将符号位添加到 Q7.24 整数,然后带符号右移 1。请注意,简单带符号右移不等于带符号除以 2。<em></em>
</p>
<h3 id="lossyConversion">有损和无损转换</h3>
<p>
如果转换<a href="https://en.wikipedia.org/wiki/Inverse_function">可逆</a>,则是无损的:从 <code>A</code> 转换到 <code>B</code> 再到 <code>C</code>,那么可以得出 <code>A = C</code>。否则,转换是<a href="https://en.wikipedia.org/wiki/Lossy_data_conversion">有损</a>的。<em></em>
</p>
<p>
无损转换允许<a href="https://en.wikipedia.org/wiki/Round-trip_format_conversion">往返格式转换</a>
</p>
<p>
从具有 25 位或更少有效位的定点数表示法转换到浮点数是无损的。从浮点数转换到任何常见的定点数表示法则是有损的。
</p>
</body></html>