用Elevator優化AV1影片播放
- 2019 年 12 月 31 日
- 筆記
AOM會員Vimeo通過Elevator改善AV1解碼過程中的丟幀和品質下降問題。感謝Google軟體工程師姜健對本文做的技術審校。
文 / Raphaël Zumer
譯 / 劉俊
技術審校 / 姜健
原文
https://medium.com/vimeo-engineering-blog/enhancing-av1-playback-with-elevator-6a2991c1aac0
作為AV1編碼標準的早期使用者,為了給Vimeo網站的用戶帶來更好的影片觀看體驗,我們需要開發諸多處理方案。其中有一種方案,取名為Elevator,是一個能在AV1格式影片碼流中設置儘可能最低的編碼等級的工具。在解碼器端無法判斷影片編碼等級的時候,這種處理能優化播放過程中丟幀和影片品質下降的問題,在當前以及將來保證儘可能多的設備能夠解碼播放我們的影片內容。
Elevator工具在2019年9月公開發布,並且於當月在日本東京舉辦的影片技術開發日大會上首次展示。在這篇文章中,我們將介紹一些AV1格式的背景知識;結合一些例子來介紹Elevator是如何工作的;並分享我們在開發過程中的所思所得。
理解AV1格式的編碼等級
AV1格式的編碼等級是一組影片碼流參數約束,一般每幀或每秒計算所得,包括碼率、幀率等。從MPEG-2發布以來,編碼等級的概念就存在於每一個當今常用的影片編解碼器中。據編碼等級規範約定,給定等級的解碼器必須能夠解碼符合該編碼等級的碼流。影片編碼等級使那些低功耗、解碼能力有限的設備能夠能夠提供性能保證,在不犧牲用戶體驗的前提下,提前確定是否能正常播放給定碼流。
在AV1和其他編碼標準中,影片的編碼等級參數在編碼的早期階段就已經確定了。對編碼器而言,為準確設定等級有如下三種方式可用:
- 將等級參數設置為可能的最大值(對碼流參數無約束)
- 在編碼時收集數據,將數據返回到包頭,最終獲知準確的編碼等級(這種方式不適用於某些部分編碼過程,比如直播)
- 編碼之前設定編碼等級,在整個編碼過程中嚴格執行該等級約束。
編碼器也可以嘗試預估得到準確的編碼等級並且有一定的成功率。但由於不可預測的碼率突增,這種方法不可能每次都輸出有效碼流。如下圖中示例,Elevator工具為Chimera AV1格式的示例影片計算得到的編碼等級就比由libaom參考編碼器在編碼時設置的可能的等級要高。

我們在Vimeo網站上編碼AV1影片使用的編碼器,rav1e,採用上述方法中的第一種。雖然這是最簡單的,但是其前向兼容性並不夠理想。我們希望高編碼級別的碼流不會被錯誤地送到只能解碼低編碼等級的低功耗設備上,於是我們開發了與rav1e不一樣的Elevator,用於分析已編碼的影片,設置準確的編碼等級。
Elevator能做什麼?
Elevator是一個用於計算AV1格式影片編碼等級相關參數的開源命令行工具。這個工具計算碼流所符合的最低編碼等級,將該值輸出在命令行窗口,也可以直接將其設置到影片流或新文件中。
儘管我們使用Elevator去降低Vimeo網站上被高估的編碼等級,在編碼器無法有效地約束影片的編碼等級的時候,Elevator的表現也很出色。比如,我們根據Elevator計算結果回饋,逐步調整參數去重新編碼影片內容,最終可得到足夠低的編碼級別。
為了充分利用Av1parser(開放多媒體聯盟的AV1影片解析器),Elevator採用Rust語言編寫。據我們所知,Av1parser在開發的時候是唯一獨立的AV1碼流解析器。由於計算編碼等級參數所需資訊的有些內容被封裝在碼流中間的包頭中,編寫我們自己的解析邏輯困難又耗時。我們對Av1parser做了很少一些改造,將這些問題的處理交給Av1parser,這樣我們就少編寫了很多用於分析複雜的AV1碼流的程式碼。Elevator中唯一需要的位計數和位操作是在處理結束時將影片的編碼等級設置為正確值。
由於某些碼流特性以我們尚未支援的方式影響著參數的計算,Elevator尚不支援所有的AV1格式影片。到目前為止,Elevator只支援處理IVF容器封裝的影片。在此,我們特別歡迎任何對該項目感興趣的人在本項目GitHub上貢獻缺陷報告、功能建議,或者上傳修補程式。
Elevator做了什麼
Elevator的使用可以高度概括為兩個步驟:分析和修補(後者是可選的)。修補步驟相對簡單,因為編碼等級參數被設定在AV1碼流序列頭的開始部分。在分析過程中,我們把序列頭的位置記錄下,以方便後續再次查找;然後,統計等級資訊在碼流序列頭部中的偏移位元組數,確保在準確的位置對編碼等級進行編輯。
下圖為分析的處理流程圖:

圖 1 分析步驟流程圖
在處理完容器的數據後,Elevator進入分析的主循環:對影片中的每個OBU進行解析,每當遇到時間分隔符則保存下每幀內容的幀大小、頭部數目等相關資訊(OBU,即Open Bitstream Unit,開放比特單元,是AV1格式數據的最小劃分單元)。
在分析階段的最後,根據主循環更新迭代每幀內容得到的參數最大值,計算編碼等級。然而,等級參數的定義並未統一,或是以每幀,或是以每秒計算。正因為如此,在AV1規範中沒有明確定義該如何計算等級參數。在開發過程中我們得到的一些或許可行的計算方法如下:
- 統計每幀的指標,將結果縮放至以秒為度量;
- 統計每秒的指標,向下取整到最接近的幀數;
- 統計每秒的指標,向上取整到最接近的幀數;
我們發現,計算每幀的參數再將結果進行縮放處理會由於參數的尖峰異常值而得到與實際不符的編碼等級。因此我們換了個方法,同樣使用每幀的數據來更新參數,但使用每秒影片的多幀數據為組進行計算。如果幀率非整值,則對數據作向上取整處理,例如,對於幀率為23.976fps的影片,取24幀為一組。為抵消由於向上取整導致的計算偏差,我們會將結果適度縮小,比如,在23.976fps的情況下,將結果乘以23.976/24。
在實驗過程中,我們發現相當多不太規範的AV1格式影片(如上面提到的Chimera的示例影片),其編碼等級低於Elevator的計算值。如果Elevator計算的結果是正確的,這意味著在其他平台可能發布了大量不符合AV1編碼規範的影片。不幸的是,目前並沒有驗證AV1編碼等級正確性的公共測試序列。我們希望隨著越來越多的硬體解碼器在市場上發布,人們會更加關注正確標註影片編碼等級的問題,產生更多能相互驗證的解決方案或工具。
參考鏈接
- Chimera的示例影片 http://download.opencontent.netflix.com.s3.amazonaws.com/Chimera/Chimera_DCI4k2398p_HDR_P3PQ.mp4
- libaom參考編碼器 https://github.vimeows.com/gist/raphael-zumer/d9fd0419827b64da1554e70b93de46f5
- rav1e項目 https://github.com/xiph/rav1e
- av1parser項目 https://github.com/yohhoy/av1parser