基于Android的G.729优化算法的研究与实现

2012-07-18 07:40朱雷坚
关键词:子帧码字矢量

朱雷坚,彭 宏

(浙江省通信网应用技术研究重点实验室,浙江杭州310023)

0 引言

随着多媒体信息技术的发展,人们对信息的要求与日俱增,以往的语音传输模式占用带宽大、延时长,已经无法满足时代发展的要求。如何在有限的带宽上传输尽量多的信息,成为社会关注的焦点[1]。ITU-T于1996年3月发布的G.729语音压缩编解码标准以其8kb/s的传输码率,以及低延时、语音质量高的特点,在IP电话、视频电话、移动通信等领域有广泛应用[2]。而在国内,也有许多关于如何在DSP芯片上实现G.729算法的研究,但是基本都是依赖硬件实现,因为成本过高而未能得到广泛应用[3]。本文研究并实现了一种软件G.729算法,并针对Android平台做了适当的优化,在点对点实时语音通信测试中表现良好。

1 G.729算法基本原理

在编码端,把8kHz/s采样得到的音频数据分为100帧,每帧占据10ms。然后通过对每个语音帧的分析来提取各种参数(包括线性预测滤波器系数、自适应码书延迟、固定码书索引、自适应码书增益和固定码书增益),再把这些参数编码发送。

在解码端,把接收到的比特数据恢复成相应的参数编码,解码后得到各个参数。自适应码矢通过自适应码矢序号从自适应码书中提取,固定码矢通过固定码矢序号从固定码书中提取,两者分别乘以它们的增益后再相加就构成激励序列。计算出合成语音后,用后置滤波器进一步增强音质[4]。

2 G.729算法优化

本文主要对粗化搜索和固定码书搜索的优化算法进行了研究,通过在Android实现相应的优化算法来降低G.729的运算复杂度。

2.1 多级搜索优化

在G.729的算法中,运用了许多多级查询或多级量化的方法。典型的例子是开环基音周期搜索。首先,它利用开环基音搜索得到最佳开环延迟Top;然后,在后续的自适应码书搜索中,将第一子帧的音调延迟T1的搜索范围限定在Top附近的小范围内,而第二子帧的延迟T2的搜索范围又在第一子帧选择的延迟的附近。通过这样的多级运算最终求得两子帧的音调延迟。开环基音搜索(第一级)的方法,是通过加权话音信号sω(n)的相关系数来进行计算的。相关系数的表达式如下:

对该搜索算法进行优化,可以将其中的迭代次数从80次降到40次,而且求解上述相关系数的目的是为了进行比较并得到最大值,最后再将最大值归一化,因此,适当降低迭代次数对最终的结果影响不大,优化后的表达式如下:

2.2 固定码书搜索优化

在G.729的编码中,码书的搜索占据了绝大部分的运算量。对此,本文研究了一种自适应子矢量共扼结构代数码书算法[5]。这种码书的编制方法为:将原G.729固定码书分裂成两个4维的子矢量码书,每个子矢量用40比特表示。第一个子矢量码书结构如表1所示。

表1 第一个子矢量码书结构表

由于语音信号的相关性较强,相邻子帧的激励码字在一定程度上有较短时间的延续。因此,可以考虑用前一子帧的激励码字,对当前子帧激励码字做平滑处理。所以,可以将第二个子矢量码书设计成一个自适应矢量码书,用来存储前一子帧的子矢量码书的激励码字。通过将两个子矢量码书的激励码字组合来构成语音信号子帧的激励码字,省去了G.729固定码书搜索对激励码字的基音预测滤波平滑处理,降低了运算复杂度。激励生成过程如图1所示。

图1 自适应子矢量共轭结构代数码书算法码字生成图

图1中CA为子矢量码书1,Ca(n)为子矢量码书1的当前激励码字,Ca(n-1)为子矢量码书1前一时刻的激励码字,Cb(n)是自适应子矢量码书2的当前激励码字。Cb(n)向右平移1位与Ca(n)组合构成当前子帧的激励码字C(n)。

这种自适应子矢量共扼结构代数码书的激励码字与原G.729固定码书的激励码字具有相同维数和结构,因此完全适用于G.729固定码书增益及符号的计算。从表1可以计算出子矢量1固定码书长度为9,因此只需用9个bit来传输固定码书的索引。因此固定码书索引的计算需做相应的调整,原固定码书的表达式变为:

由于优化的码书矢量的非零位m比原G.729固定码书矢量减少了一半,因此固定码书搜索的计算量下降了一半左右。此外,每一子帧的固定码书索引从原来的13bit降低到现在的9bit,这样两个子帧又比原来减少8bit的数据量,编码速率从原来的8kbit/s降低到现在的7.2kbit/s。

3 G.729算法移植

G.729算法在Android上的移植通过NDK实现。NDK是一个工具集,它集成了Android的交叉编译环境,并提供了一套比较方便的Makefile。通过NDK,开发者可以快速将C/C++代码编译成能在Android调用的 so动态库文件[6]。

3.1 编写Java接口函数

Java接口函数的主要作用是在Android工程中声明JNI接口,示例代码如下:

其中,Fun1()、Func2()等一系列函数代表G.729库在Android工程中可以调用的接口。

3.2 编写C/C++接口函数

Java中声明过的jni接口函数,由对应的C/C++接口函数实现,示例代码如下:

C/C++接口函数的函数名有固定为“Java+Android工程中包名+Java接口函数所在文件名+Java接口函数名”,参数的前两个也固定为env和thiz。

3.3 编写Android.mk文件

Android.mk是Android交叉编译的Makefile文件,交叉编译器根据该文件指定的规则编译生成so动态库文件。

其中LOCAL_PATH指示c源代码文件的位置;LOCAL_MODULE指示生成的共享库的名称;LOCAL_SRC_FILES指示C/C++代码的文件。

3.4 编译so动态库文件

新建一个名为jni的文件夹,将写好的C/C++接口实现函数、G.729库的源文件和Android.mk都放到jni文件夹下,在jni文件夹这一层目录(不用进入到jni文件夹内)运行ndk-build,如果编译无误的话,就会在libs/armeabi目录下生成所需so动态库文件。

4 结束语

在HTC野火(600M CPU、512M RAM)上对G.729代码进行测试,对比优化前后每一帧的处理时间,以及优化前后音质的MOS得分,具体结果如表2所示:

表2 优化性能总结表

从表2中可以看出,经过对G.729算法的优化,平均一帧处理时间由原来的17.54ms缩短到7.16ms,小于G.729一帧的语音长度10ms。

MOS得分是目前应用最广泛的评价语音质量的方法,MOS得分满分为5分。当MOS大于4.0时,几乎与原音没有区别;当MOS在3.5到4.0之间时,虽然能感觉到失真,但不影响通信;当MOS小于3.0时,难以从噪声中辨别发声者。从表中可知,优化后的G.729语音在MOS得分上仅比优化前降低了0.1分,并且都在3.5到4.0的区间内。因此,无论是在延时方面还是在音质方面,优化后的算法很好的满足了Android平台实时点对点语音传输的需要。

[1] 江波,张江鑫.线性预测编码技术及其在G.729中的应用研究[J].浙江工业大学学报,2009,37(2):46-51.

[2] Regis J,Bates Donald,W Gregory.语音与数据通信第四版[M].北京:人民邮电出版社,2005:236-257.

[3] 胡仕兵,向敬成,翟义然.G.729语音编码器定点DSP的实时实现[J].电子科技大学学报,2003,32(4):12-19.

[4] R Salami,C Laflamme.ITU-T G.729 Annex A:reduced complexity 8 kb/s CS-ACELP codec for digital simultaneous voice and data[J].IEEE Communications Magazine,1997,35(9):56 -63.

[5] 刘晓明,冯荣,田雨.一种改进的G.729标准固定码本快速搜索算法[J].计算机应用研究,2011,28(9):67-73.

[6] 邵长彬,张重阳,郑世宝.基于Android的可视IP电话多媒体终端设计与实现[J].电视技术,2011,35(6):12-19.

猜你喜欢
子帧码字矢量
矢量三角形法的应用
放 下
数据链系统中软扩频码的优选及应用
放下
LAA系统在非授权频段上的动态子帧配置策略
基于矢量最优估计的稳健测向方法
三角形法则在动态平衡问题中的应用
LTE-A异构网中空白子帧的动态配置*
TD—LTE特殊子帧配比的优化设计
长为{4,5,6}的完备删位纠错码的存在性*