作者:趙曉涵,聲網 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 的誕生和發展歷程可以看出,任何產品做到極致都需要付出不懈的努力和漫長的打磨時間,尤其是在創新領域,其路漫漫,道阻且長,各位同學一起加油吧。