编解码器杂谈:浅析 Opus


#1

谈起Opus,对于编解码器有所了解的同学也许会知道,Opus是由两个编解码器-Silk和Celt融合而成。为什么来自两个组织的编解码器会合二为一,Opus的性能又如何,本文将简述一下Opus的前世今生和部分技术分析。

提到Opus,就不得不提到它的主要作者,Jean Marc Valin,他从学生时代就开始致力于高音质编解码算法的实现,著名的编解码器Speex也是他的作品之一。时间回到2007年,Jean Marc Valin在博士后期间,完成了Speex的开发。在当时,业内编解码器主要分为两个流派:高延时的音乐编解码器(如MP3、AAC和Vorbis)和低延时的语音编解码器(AMR、Speex、G.729)。而工业界对低延时音乐编解码器的需求越来越高,于是Celt的开发也被提上了日程。Celt的早期目标是实现4-8ms的编码延时,相比当时MP3和AAC编码的100ms+延时,优势是非常巨大的。

在研发过程中,Jean Marc Valin和其他开发者始终围绕着Vorbis作者Christopher “Monty” Montgomery的意见-“尽量保持信号能量谱的低失真”进行开发,这也是Celt(Constrained Energy Lapped Transform)名字的由来。第一版Celt的研发持续了两年,但因为需要保证低延时的原因,Celt的表现并没有超过MP3和AAC。但在经过了持续六个月的改进后(使用了部分MP3的技术),Celt的表现第一次超过了MP3。也就是在那个时候,Celt逐渐走出实验室,迎来了它在工业界的第一批使用者–部分用户因为低延时的强需求不得不选择了Celt。也就是这一批最早期的用户给了Celt的开发者们宝贵的反馈,使其不断改进Celt。

在Celt开发的同时,另一批来自Skype,以Koen Vos为首的开发者开发了业内领先的语音编解码器Silk,并将其提交至IETF,作为一款免版税的开源编解码器。Celt也紧随Silk的步伐进行了提交。但Silk和Celt都遭遇了很大的阻力,这个阻力的来源更多的不是技术因素,而是政治因素:此前有大量投资者投资了带版税的编解码器,这些投资者在业内的权威也很大。正是这些阻力促使Silk和Celt结合到一起,诞生了Opus。在Opus里,Silk主要负责处理16khz及8khz的信号,而Celt则能处理8khz以上的信号。实际上,关于Opus里Silk和Celt的工作模式并不仅仅这么简单,Opus里共有32种模式用来处理不同种类的信号。Opus编解码器架构如下。
编码器:
image
解码器:
image
为了和Silk结合,Celt做出了一定的改动,之前Celt为了极低延时,把帧长设置的比较短,但Silk需要20ms的帧长,于是Celt牺牲了部分延时和Silk的帧长对齐,但仍能把整体延时控制在10ms。Opus诞生后又经过了很多改进,关键的改进来自于Broadcom提供的一种滤波器,这个滤波器在编码端和解码端各有一个,在编码端,前置滤波器可以保留音乐信号的低频部分,减弱高频部分,这样就可以更高效的去编码;在解码端,后置滤波器可以近乎无损的把被减弱的高频恢复出来。这种前置-后置滤波器结合上述拉长到20ms的帧长,Opus第一次在音乐音质和压缩率上超过了HE-AAC。这对于Opus来说是一个非常重要的节点,因为这代表着Opus在语音、音乐、复杂度和延时上有了全面超越其他编解码器的能力。

而融合进Opus的Silk模块改动则不是很大,主要的改动点都是非常小的细节,我简单整理了一些,如下所示:

一、线性预测部分:二者的计算逻辑是相同的。不同之处有:
1、OPUS的整体计算精度更高一些,由Silk里的Q10转换成了Q14后进行判断,包括短时预测、长时预测和激励部分。
2、在做Delaydecision(一种延时选择算法,可以令标量量化拥有近似矢量量化的效率)的时候,OPUS中对判断算法进行了重写,增加了一个quantoffset参数并重新规划了量化的范围,这里和Silk比较,带来的MOS分增益我自己测的是大约在0.05左右(少量样本测试,不一定准确,仅供参考)。
3、OPUS的Delaydecision模块默认是计算40个采样点的总误差,Silk是32个,选择的采样点越多,误差越小,但延时会越大,这两个我试了一下对MOS分的影响基本没有,。
4、在编码时,OPUS使用SHIFT_ROUND将Q10转化成了Q0传入到编码模块,Silk使用的是SHIFT方法,两者的不同之处在于,SHIFT_ROUND会将[-512,512]的值都转化为0,而SHIFT的置零区间为[0,1024],这里使用不同的SHIFT算法会影响到后续编码激励时分配的码率。
5、OPUS通过调整计算步骤,增加新参数(如delayedgain和diff等)等方法,减少了少量计算量。
二、编码部分:
1、OPUS中的编码模块由依赖Silk中的概率密度函数CDF转成了逆概率密度函数iCDF,尚不清楚做这种改动的原因,从结果上来看,使用CDF和iCDF的编码效率是差不多的。
2、OPUS将编码index和excition的函数区分开了,但函数的实现及各个参数的编码顺序和Silk是相同的,总的来说,这是一个关于模块化的改进。
三、其余部分:
1、增益计算部分,OPUS在较多函数里使用的是Q7,Silk使用的是Q0,因此OPUS对增益的控制能稍微准一些。
2、OPUS对码率控制算法进行了重写,但总体逻辑和Silk是相同的,个人认为OPUS的码率控制更为激进一点,压得狠,放的快。
3、OPUS的抖动算法中Seed的判断方法也改变了,OPUS中通过判断Seed是否小于0进行符号的转换,Silk通过把Seed右移31位后做异或后自减进行判断,其实这两种方法的结果是完全一样的,只是方式一的计算量更小。

Silk和Celt整合到一起后,经过各方努力,Opus在2012年作为免版税的开源编解码器成为了IETF的标准。也就是在差不多那个时候,WebRTC也成为了IETF在Web通信上的标准,而Opus凭借其卓越的性能成为了WebRTC的内置编解码器。一直到今天,Opus仍在不断发布版本,就在前不久,Opus发布了Opus 1.3.1。从发版趋势可以看出,Opus也在拥抱AI化,目前Opus里和AI相关的技术有两个:基于RNN的语音音乐分类器和一个附加的基于RNN的降噪模块(这个降噪模块目前并不在Opus本身的代码里,但不排除以后会和Speex一样,把信号处理模块耦合进编解码器)。

从Opus的诞生和发展历程可以看出,任何产品做到极致都需要付出不懈的努力和漫长的打磨时间,尤其是在创新领域,其路漫漫,道阻且长,各位同学一起加油吧。