音频编解码之G7221编码器

本文对G.722.1的编码器作以介绍,如有表述不当之处欢迎批评指正。欢迎任何形式的转载,但请务必注明出处。

前述

  由于工作需要接触了一段时间的音频编解码算法—G.722.1, 在此作以记录。

简介

  • G.722.1是一种基于变换域编码的算法
  • 采样率: 16000hz
  • 比特率: 24kbit/s 32kbit/s
  • 变换域: MLT(Modulated Lapped Transform)
  • 帧长: 20ms
  • 变换窗长: 40ms
  • 有效编码带宽: 50~7000hz

编码器

图1 G.722.1编码器方框图

1 G.722.1编码器方框图

  上图展示了G.722.1的编码过程, 主要包含三个模块:

  • MLT的幅度包络进行计算、量化和编码
  • 确定编码方法,并对MLT的系数进行归一化、量化和编码

  下面详细分析这几个模块所做的事情。

1. 计算、量化和编码MLT的幅度包络

1-1. MLT重叠调制变换

  MLT是一个严格抽样,完美重建的线形变换过程(引用自G.722.1官方文档中文版)此处不介绍具体公式。前一帧320个采样点与当前帧320个采样点拼接为640个采样点作为MLT变化的输入,MLT变换输出320个系数。
m l t ( m ) , 0 ≤ m < 320 mlt(m), 0\leq{m}<320 mlt(m),0m<320

1-2. 计算、量化MLT的幅度包络

  将MLT输出的320个系数平均分为16 个区域,每个区域包含20个系数,对应500hz带宽,但编码器只对前14个区域也就是0~7000hz进行编码。
  首先根据以下公式计算每个区域的幅度包络:
r m s ( r ) = 1 20 ∑ j = 0 19 m l t ( 20 r + j ) m l t ( 20 r + j ) , 0 ≤ r < 14 rms(r) = \sqrt{\frac{1}{20}\sum_{j=0}^{19}mlt(20r+j)mlt(20r+j)}, 0\leq{r}<14 rms(r)=201j=019mlt(20r+j)mlt(20r+j) ,0r<14
  利用以下量化集合对上述14个区域的幅度包络进行量化,生成量化索引 r m s _ i n d e x ( r ) , 0 ≤ r < 14 rms\_index(r),0\leq{r}<14 rms_index(r)0r<14
2 ( i + 2 2 ) , − 8 ≤ i ≤ 31 , i ∈ Z 2^{(\frac{i+2}{2})}, -8\leq{i}\leq{31}, i\in\mathbb Z 2(2i+2),8i31,iZ
  进一步对第一个区域的量化索引 r m s _ i n d e x ( 0 ) rms\_index(0) rms_index(0)进行限制使得
1 ≤ r m s _ i n d e x ( 0 ) ≤ 31 1\leq{rms\_index(0)}\leq31 1rms_index(0)31
  具体在量化过程中, i i i的取值应该使得幅度包络 r m s ( r ) rms(r) rms(r)处于 2 ( i − 0.5 + 2 2 ) 2^{(\frac{i-0.5+2}{2})} 2(2i0.5+2) 2 ( i + 0.5 + 2 2 ) 2^{(\frac{i+0.5+2}{2})} 2(2i+0.5+2)之间。用下面的例子说明该操作:如果 r m s ( r ) = 310 rms(r)=310 rms(r)=310,则应该将其量化为 2 ( 15 + 2 2 ) 2^{(\frac{15+2}{2})} 2(215+2),也即 r m s _ i n d e x ( r ) = 15 rms\_index(r)=15 rms_index(r)=15,因为 2 ( 15 − 0.5 + 2 2 ) ≤ r m s ( r ) = 310 ≤ 2 ( 15 + 0.5 + 2 2 ) 2^{(\frac{15-0.5+2}{2})}\leq{rms(r)=310}\leq{2^{(\frac{15+0.5+2}{2})}} 2(2150.5+2)rms(r)=3102(215+0.5+2)

1-3. 编码MLT的幅度包络

  使用5bit来编码幅度包络的量化索引 r m s _ i n d e x ( r ) rms\_index(r) rms_index(r)。直接将第零个区域的量化索引 r m s _ i n d e x ( 0 ) rms\_index(0) rms_index(0)进行传输,而其余区域传输的则是与前一个区域量化索引的差值的霍夫曼编码。
d i f f _ r m s _ i n d e x ( r ) = r m s _ i n d e x ( r ) − r m s _ i n d e x ( r − 1 ) , 1 ≤ r < 14 diff\_rms\_index(r)=rms\_index(r)-rms\_index(r-1), 1\leq{r}<{14} diff_rms_index(r)=rms_index(r)rms_index(r1),1r<14
且限定其取值范围
− 12 ≤ d i f f _ r m s _ i n d e x ( r ) ≤ 11 -12\leq{diff\_rms\_index(r)}\leq11 12diff_rms_index(r)11
  也就是说,除了第零个区域外,其余区域传输的都是 d i f f _ r m s _ i n d e x ( r ) diff\_rms\_index(r) diff_rms_index(r)的霍夫曼编码(通过查找两个霍夫曼表实现,一个霍夫曼表表示编码该差值需要多少bit,另一个霍夫曼表表示把该差值具体编码成什么)。

2. 确定编码方法、量化和编码MLT的系数

  第一部分主要是量化和编码每个区域的幅度包络,该部分主要用于确定一些量化和编码MLT系数相关的参数,并用这些参数对MLT系数进行量化。这部分相比第一部分增加了难度,笔者刚开始接触的时候看了好几遍才算看懂。笔者在这尽量用简洁的语言描述清楚该部分所做的事情。

2-1. 产生16组不同的编码(分类)方法

  该部分根据编码完MLT的幅度包络所剩下的比特数以及 r m s _ i n d e x ( r ) rms\_index(r) rms_index(r)产生16种不同的编码方法(或者说产生16种不同的参数,这些参数用于对MLT系数进行量化和编码)并从中选取最合适的一种编码方法(或者说选取最合适的一种参数)。下面简单介绍一下这16种不同的编码方法。
  编码器会给14个区域中的每个区域都分配一个类别,共有0~78种可选类别。每种类别决定了该区域的量化和编码参数,并决定了量化该区域的MLT系数预计所需的比特数,如图2所示。

1 G.722.1每一类别预计所需的比特数

表1 G.722.1 每一类别预计所需的比特数
  由于每个区域有8种类别可选,因此从算术上来说应该有 8 14 8^{14} 814 种不同的编码方法,但这其中有许多编码方法是不合理的,G.722.1编码器最终只生成16种不同的编码方法,并且这16种编码方法之间是有联系的,那就是每种编码方法和与其相邻的编码方法之间只有一个区域分配的类别不同,并且该区域的类别值只相差1。这块可能有点绕,既有16种编码方法,又有14个区域,还有8种区域类别,这几个数字之间到底是什么关系哪,下面举个例子来说明一下,见表1

2 G.722.1编码方法示例
编码方法1 编码方法2 编码方法3 *** 编码方法16
区域0 2 2 2 * *
区域1 1 1 1 * *
区域2 2 2 2 * *
区域3 1 0 0 * *
区域4 2 2 2 * *
区域5 4 4 4 * *
区域6 3 3 2 * *
区域7 4 4 4 * *
区域8 3 3 3 * *
区域9 6 6 6 * *
区域10 5 5 5 * *
区域11 7 7 7 * *
区域12 6 6 6 * *
区域13 7 7 7 * *
  表中展示了编码器产生的16种编码方法之间的关系,可以看到第2种编码方法与第1种编码方法只在区域3的类别分配上不同,第1种编码方法给区域3分配的是类别1,第2种编码方法给区域3分配的是类别0,两者区域3的类别值只差1。第3种编码方法与第2种编码方法也是类似的关系, 依次类推,其余第n种编码方法与第n-1种编码方法也是类似的关系。通过表1,相信读者现在已经能捋清楚16种编码方法、14个区域和8种区域类别之间的关系了。还有需要注意的一点是,最终产生的16种编码方法是按照所用比特数从大到小依次排列的,也就是第0种编码方法所用比特数最多,第15种编码方法所用比特数最少。
  写到这,其实并没有具体提到这16种编码方法到底是如何根据前面所说的剩余比特数和 r m s _ i n d e x ( r ) rms\_index(r) rms_index(r)产生的。笔者也不打算在这详说,因为这部分比较繁琐,笔者不一定能说清楚,最重要的是笔者也没太理解其中公式的具体含义。。。。。。感兴趣的可以根据G.722.1官方文档以及源码作进一步了解。

2-2. 归一化、量化和编码MLT系数

  该部分对类别分配为0~6的区域的MLT系数进行所谓的标量量化矢量霍夫曼编码(SQVH),而对类别分配为7的区域的MLT系数不进行编码,认为该区域没有有效的音频信息
  首先,编码器对每个区域的MLT系数的绝对值进行归一化和量化,产生量化索引 k ( j ) k(j) k(j):
k ( j ) = m i n { ⌊ ∣ x ∗ m l t ( 20 r + j ) ∣ + d e a d z o n e _ r o u n d i n g ⌋ , k m a x } k(j)=min\{\lfloor|x*mlt(20r+j)|+deadzone\_rounding\rfloor,kmax\} k(j)=min{ xmlt(20r+j)+deadzone_roundingkmax}
  其中
0 ≤ j < 20 0\leq{j}<20 0j<20 x = 1 / ( s t e p s i z e ∗ ( r m s ( r ) 的 量 化 值 ) ) x=1/(stepsize*(rms(r)的量化值)) x=1/(stepsize(rms(r)))
  上式中所用的参数见表3

3 G.722.1 SQVH程序所用参数表 1

表3 G.722.1 SQVH程序所用参数表1
  上面展示了如何对MLT系数的绝对值进行归一化和量化,但为何通过这种方式来做、表3中参数的具体值是如何得到的以及deadzone_round的作用是什么,笔者现在还没搞太懂。介绍完MLT系数的归一化,下面就介绍如何对这些归一化之后的系数进行量化和编码。
  先看表4,定义了几个参数 vdvpru

4 G.722.1 SQVH程序所用参数表 2

表4 G.722.1 SQVH程序所用参数表2
  要理解表4中的几个参数的具体含义就要和表3一起对照着看。可以观察到表4中每一行均满足以下关系:
v d ∗ v p r = 20 \bm{vd}*\bm{vpr}=20 vdvpr=20 u = ( k m a x + 1 ) v d \bm{u}=(kmax+1)^{\bm{vd}} u=(kmax+1)vd
  先看第一个公式中的20是什么意思哪,回想一下,这个20正是每个区域中所包含的MLT系数的个数。因此, v d \bm{vd} vd v p r \bm{vpr} vpr所代表的含义也就比较明显了:将每个区域的20MLT系数,每 v d \bm{vd} vd个组成一个矢量,总共有 v p r \bm{vpr} vpr个矢量。类别为0的区域矢量数最多,总共有10个矢量。类别为5、6的区域矢量数最少,总共有4个矢量。
  再看第二个公式, k m a x kmax kmax是在表3中定义的,是指不同类别的区域的MLT系数归一化之后能取到的最大值。比如,类别为0的区域,其MLT系数归一化之后能取到的最大值是13,最小值是0,总共有14种可能的取值;类别为6的区域,其MLT系数归一化之后能取到的最大值是1,最小值是0,总共有2种可能的取值; k m a x + 1 kmax+1 kmax+1就是指该类别的区域的MLT系数归一化之后所有可能的取值数目。因此第二个公式代表的意思就是该类别的区域的每个矢量(每个矢量共包含 v d \bm{vd} vd个标量)所有可能取值数目。
  上面讲了如何对不同类别的区域的MLT系数的绝对值进行归一化,并如何组合成矢量,下面就开始介绍如何对这些组合成的矢量进行编码。
  将每个区域的各个矢量按照下面的公式量化为标量:
v e c t o r _ i n d e x ( v ) = ∑ l = 0 v d − 1 k ( v ∗ v d + l ) ( k m a x + 1 ) v d − ( l + 1 ) vector\_index(v)=\sum_{l=0}^{\bm{vd}-1}{k(v*\bm{vd}+l)(kmax+1)^{\bm{vd}-(l+1)}} vector_index(v)=l=0vd1k(vvd+l)(kmax+1)vd(l+1)
  其中
   0 ≤ v ≤ v p r − 1 0\leq{v}\leq{\bm{vpr}-1} 0vvpr1表示区域 r r r中的第 v v v个矢量
  再将 v e c t o r _ i n d e x ( v ) vector\_index(v) vector_index(v)通过查表的方式进行霍夫曼编码(此处同样有两张表,一张表表示编码该值需要多少比特,另一张表表示将该值具体编码成什么)。上述所描述的从MLT系数的归一化到最终的霍夫曼编码的整个过程称为标量量化矢量霍夫曼编码(SQVH) 。
  至此,G.722.1编码器的主要部分已讲的差不多了。还有一些细节需要了解。

3. 细节

3-1. 符号比特

  刚才讲的是对MLT系数的绝对值进行归一化、量化和编码,并没提到符号位,实际上在具体传输比特的过程中,符号比特直接位于表示 v e c t o r _ i n d e x ( v ) vector\_index(v) vector_index(v)的比特的后面。 v e c t o r _ i n d e x ( v ) vector\_index(v) vector_index(v)里面对应包含了多少非零值。后面就有多少个符号比特,其中正数的符号比特为1

3-2. 确定最终编码方法

  之前提到总共有16种编码方法,且第0种编码方法使用的比特数最多,第15种编码方法使用的比特数最少,最终传输的过程中只选用其中最合适的一种。比如第0种编码方法使用了500个比特,1种编码方法使用了470个比特,但每一帧最多只能用480个比特,所以最终选择第1种编码方法,多出来的10个比特全部置为1;还有比如第0~15种编码方法所用比特数都大于480,那么最终选取第15种编码方法,传输过程中只传输前480个比特,剩余的比特不传输

3-3. 比特流模块

  最终编码后的比特流包含三个部分:
图2 G.722.1 编码器主要比特流字段及其传输顺序

2 G.722.1 编码器主要比特流字段及其传输顺序

  第一部分和第三部分比较清楚,第二部分就是指具体使用的哪种编码方法,因为总共有 16种编码方法,所以用 4个比特表示。

4. 总结

  G.722.1的编码器部分终于讲的差不多了,其中有很多细节笔者也没太搞懂,若是读者了解其中缘由,希望能指教一二。还有就是G.722.1在实际代码实现过程中可能不完全和文档中的一样,感兴趣的可以阅读源码了解细节。

猜你喜欢

转载自blog.csdn.net/wjrenxinlei/article/details/105140070