作者:赵晓涵,声网 Agora 音频算法工程师。原文首发于 RTC 开发者社区。
谈起 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编解码器架构如下。
编码器:
解码器:
为了和 Silk 结合,Celt 做出了一定的改动。之前 Celt 为了极低延时,把帧长设置的比较短,但 Silk 需要 20ms 的帧长,于是 Celt 牺牲了部分延时和 Silk 的帧长对齐,但仍能把整体延时控制在 10ms。Opus 诞生后又经过了很多改进,关键的改进来自于 Broadcom 提供的一种滤波器,这个滤波器在编码端和解码端各有一个。在编码端,前置滤波器可以保留音乐信号的低频部分,减弱高频部分,这样就可以更高效的去编码;在解码端,后置滤波器可以近乎无损的把被减弱的高频恢复出来。这种前置-后置滤波器结合上述拉长到 20ms 的帧长,Opus 第一次在音乐音质和压缩率上超过了 HE-AAC。这对于 Opus 来说是一个非常重要的节点,因为这代表着 Opus 在语音、音乐、复杂度和延时上有了全面超越其他编解码器的能力。
而融合进 Opus 的 Silk 模块改动则不是很大,主要的改动点都是非常小的细节,我简单整理了一些,如下所示:
一、线性预测部分:二者的计算逻辑是相同的。不同之处有:
- OPUS 的整体计算精度更高一些,由 Silk 里的 Q10 转换成了 Q14 后进行判断,包括短时预测、长时预测和激励部分。
- 在做 Delaydecision(一种延时选择算法,可以令标量量化拥有近似矢量量化的效率)的时候,OPUS 中对判断算法进行了重写,增加了一个 quantoffset 参数并重新规划了量化的范围,这里和 Silk 比较,带来的 MOS 分增益,我自己测的是大约在 0.05 左右(少量样本测试,不一定准确,仅供参考)。
- OPUS 的 Delaydecision 模块默认是计算 40 个采样点的总误差,Silk 是 32 个,选择的采样点越多,误差越小,但延时会越大,这两个我试了一下对 MOS 分的影响基本没有,。
- 在编码时,OPUS 使用 SHIFT_ROUND 将 Q10 转化成了 Q0 传入到编码模块,Silk 使用的是 SHIFT 方法,两者的不同之处在于,SHIFT_ROUND 会将 [-512,512] 的值都转化为 0,而 SHIFT 的置零区间为 [0,1024],这里使用不同的 SHIFT 算法会影响到后续编码激励时分配的码率。
- OPUS 通过调整计算步骤,增加新参数(如 delayedgain 和 diff 等)等方法,减少了少量计算量。
二、编码部分:
- OPUS 中的编码模块由依赖Silk中的概率密度函数 CDF 转成了逆概率密度函数 iCDF,尚不清楚做这种改动的原因,从结果上来看,使用 CDF 和 iCDF 的编码效率是差不多的。
- OPUS 将编码 index 和 excition 的函数区分开了,但函数的实现及各个参数的编码顺序和 Silk 是相同的,总的来说,这是一个关于模块化的改进。
三、其余部分:
- 增益计算部分,OPUS 在较多函数里使用的是 Q7,Silk 使用的是 Q0,因此 OPUS 对增益的控制能稍微准一些。
- OPUS 对码率控制算法进行了重写,但总体逻辑和 Silk 是相同的,个人认为 OPUS 的码率控制更为激进一点,压得狠,放的快。
- 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 的诞生和发展历程可以看出,任何产品做到极致都需要付出不懈的努力和漫长的打磨时间,尤其是在创新领域,其路漫漫,道阻且长,各位同学一起加油吧。