技術分享 | 趙軍: 騰訊雲+FFmpeg打造一條完備高效的視頻產品鏈

  • 2019 年 10 月 8 日
  • 筆記

伴隨着飛速增長的視頻普及與觀看需求,騰訊雲技術專家、FFmpeg決策委員會委員趙軍認為,視頻行業目前存在一個「技術、需求與現實」的三角博弈,其場景猶如帶着鐐銬的舞蹈,即需要在超高清晰度、計算能力與網絡帶寬約束之下尋求平衡。正是基於這樣一個三角博弈,騰訊雲以「開源、協同」為利器,逐步打磨出一個完備且高效的視頻產品鏈。

文 / 趙軍

大家好,我是騰訊雲的趙軍,同時我也是FFmpeg決策委員會委員、開源愛好者。在2018年成為FFmpeg maintainer,2019年入選 FFmpeg 決策委員會(voting committee),具備豐富的基於Linux 的Router/Gateway 開發經驗,並持續關注Linux 在網絡方面發展。曾開發基於Linux 的高清/ 標清H.264/MPEG2視頻解碼器及圖像處理平台。曾在Intel DCG/NPG 負責基於FFmpeg以及Intel平台上的視頻編碼/解碼/轉碼、視頻後處理、視頻分析的硬件加速的工作。目前在騰訊雲負責視頻雲的系統優化相關工作,除去支持公司內部的項目開發以外,也在持續向FFmpeg社區提交patch,同時也倡導引領同事以開放的心態擁抱開源。

今天的演講將分為明眸、智眸、雲剪和開源四個部分來講解,其中明眸主要針對音視頻編解碼與畫質增強方案,智眸主要涉及智能媒體檢索、分析和審核方案,雲剪主要提供在線媒體內容生產方案,而開源則是本次演講中將重點介紹的內容。

音視頻發展現狀

在騰訊雲團隊看來,目前音視頻技術的發展現狀更偏向於清晰、流暢和品質這三者的博弈,對於視頻來說,體育賽事、遊戲等領域對直播清晰度要求不斷提升,國家政策也在鼓勵4K和8K的增長,這些因素使得超高清晰度視頻內容成為音視頻技術發展的重要方向,與此同時,人們開始追求更多的趣味性和附加能力,但硬件計算能力或者軟件性能並沒完全跟上,這使得成像品質以及其他附屬能力所需要的計算能力也位於了問題之列;一如既往的,無論是4G還是即將到來的5G時代,網絡的制約在能預計的時間內,依然也還是一個不可忽視的影響因素之一。

1. 音視頻技術+AI,打造從內容生產、極速高清到視頻識別分析全鏈路產品

1.1 明眸:極速高清-智能動態編碼

提到極速高清就不得不聊聊視頻編碼,上圖從Codec和系統工具的角度,以MPEG組織為基準描述了發展歷史,圖片下方是容器格式,做過工程的人都了解,很多時候相比Codec,容器格式有時會暴露很多的工程問題。圖中色塊分別代表不同階段的技術發展,紅色部分已經是歷史,橙色部分表示過渡,藍色部分更像是現在和不遠的將來的交界。

明眸主體由場景識別、前置處理和編碼算法動態優化三部分組成,場景識別主要是對場景進行切分,根據場景預設編碼模板。其次前置處理主要解決的問題是多次轉碼帶來的副作用,最後在基於以上兩部分的前提下做編碼算法的動態優化。

當場景識別、前置處理和編碼算法動態優化三部分做完之後,我們可以得到一些基本的結論,由於直播客戶更在意主觀質量,明眸以VMAF為目標做開發。簡單提及一下,騰訊雲在對VMAF和PSNR做比較時發現,如果VMAF的分數在70分左右甚至更高,VMAF的分數會與PSNR正相關,倍數關係大概在2.5-3倍之間,反之,我們也發現,PSNR分數比較高時,VMAF的分數不一定高,所以我們認為,以VMAF為目標的優化也大概率的涵蓋了PSNR的目標值。明眸可以在相同碼率下將VMAF評分提升10+,同VMAF分下碼率節省可以達到30%左右。當然VMAF也存在一些問題,比如對小分辨率的適配並不是很好,這可能與Netflix自身由點播內容居多,並且片源的質量都非常高有關。

1.2 智眸:智能媒體生產平台

從上圖可以看到目前視頻AI比較通用的流程,視頻源從左向右邊,解碼之後如果要做對象探測會有一個Scale和CSC,如果做Tracking會向下走,如果做ROI coordinates會向上進行正常的解碼。這個流程圖看似簡單,但在工程中需要各種各樣的考量,其中的每一個點都可能會成為潛在的性能瓶頸。

以上是智眸的一些基本能力,包括人像、聲音/文字、圖像以及基本物體的識別、智能分析和審核,它可以根據需求靈活組合,圖中也列出了很多的應用場景。

在客戶使用和對接時,基本上是以Rest API做對接,圖中清晰展示了整個流程運行起來的全貌。

以上是騰訊雲在視頻識別和視頻分析中要解決的問題,其中智能拆條需要根據內容或關鍵人物出現進行拆分,智能集錦應用在體育場景中較多,比如製作進球或得分集錦。

1.3 雲剪:助力提升視頻生產效能

如果將視頻當作一條鏈路來考慮,可以看到視頻從最初上傳到製作處理,再到內容管理、傳輸分發,最後在終端播放,其中製作與處理部分騰訊雲存在一些技術缺失,因此騰訊雲做了雲剪來彌補這部分的功能,主要目的是讓用戶實現在雲端不需要SDK就可以對視頻數據做處理,這種場景中比較具有代表性的是電競行業,它的素材可能在PC端已經做好,不用在移動端進行處理。

雲剪目前也是一個把騰訊雲已有的能力打包,用以解決行業痛點的一個綜合性質的產品。

2. 擁抱開源,以開放的心態加速技術升級

2.1 FFmpeg簡介

從事多媒體行業,基本沒有人可以完全忽視 FFmpeg這個開源界中最流行的多媒體庫,FFmpeg庫有着多平台的支持,無論是服務器Linux、移動端Android、PC 端的MAC以及Windows都可以使用,使用方式分為tools和C libraries兩種,tools包括ffmpeg、ffplay、ffprobe等,另一種方式則是C libraries,但C libraries場景時候,我們也發現它在某些場景下缺乏一定的靈活性。

2.2 開源與協同

在剛進騰訊雲時,大的部門中有38個repo都叫FFmpeg,這可能也是業務快速發展過程中所經歷的一些痛處。我們開始嘗試做一個統一版本,嘗試將部門將不同repo中,比較有價值的部分提煉出來,構造一個內部完整而統一的Repo;另一方面,我們認為,既然使用的FFmpeg來自開源,我們在它上面的工作成果,也應該讓它最終返回到開源社區去。這樣,一方面可以使得原來內部的FFmpeg庫統一,減少內部的重複性工作,另一方面對於社區來說騰訊雲及時將Feature、Bug Fix、性能優化、文檔更新和samples反饋給它,在這個過程中,也順勢打造了一個非常完整流暢的工作流程,用於支持內部的開發,也用於反饋給開源社區。

2.3 接口與框架

提及接口和框架的問題,首先想到的是上面這段話,簡單說來,猶如為院子造牆,什麼放在牆外,什麼放在牆內,門開在什麼地方,還要提防想着把牆推倒的人;在實際的項目中,也有類似的問題,如果項目要和別人合作,首先需要明確兩人的職責,這是最容易出問題的部分;具體到FFmpeg,一方面,它需要解決怎麼屏蔽不同的Os、硬件平台和Codec細節,並保持使用過程中能靈活構建media pipeline的能力,與此同時,在AI大潮中,它也面臨著是否需要集成Deep Learning框架到AVFilter模塊的這種現實問題。

2.4 性能之痛

性能在多媒體技術中一直是一個永恆的話題,例如壓縮技術在十年間可以提升50%的壓縮率,但複雜度卻會提升10倍以上,這對計算能力提出了一個非常大的挑戰。我們知道,所有優化的前提是理解算法與數據流向,並且有Profiling的數據作為支撐,除了算法上面的提升以外,也需要更好更充分的利用已有的硬件資源。大部分情況下,硬件性能優化是在CPU和GPU上完成。以FFmpeg為例,它的CPU優化在上體現在多線程和SIMD優化兩個方面,在解碼過程中使用了基於Frame和Slice的線程以及更為底層的SIMD優化,在Filter中只用了基於Slice的線程與SIMD。GPU一般來說有二個優化方向,一個是專有硬件,比如Intel GPU中的QSV部分,一塊是通用計算加速和3D渲染,分別是CUDA,以及嘗試和CUDA對抗的OpenCL,還有歷史悠久的OpenGL以及它的繼任者Vulkan。

2.4.1 CPU加速

CPU的加速中,首先想到的是線程,本質上說,使用線程能力優化是想充分釋放多核的能力,目前對於大部分的PC來說以4線程或8線程居多,但對於Sever來說核數可能會更多,目前的環境多以48或96線程為主,因此在不互相影響的前提下調動多核的積極性是CPU加速所要解決的首要問題。在FFmpeg中,以AVFilter為例,他有一個AVFILTER_FLAG_SLICE_THREADS的標識,很多實現上,是把一個Frame中不相關的數據以行或者列的方式做加速,以我的經驗來看,如果程序出現性能問題,首先應該考慮的問題是是否使用了CPU的多線程能力。第二種CPU加速方式是SIMD加速,SIMD彙編優化形式一般有intrinsics、inline assembly、hand-written assembly三種,FFmpeg彙編優化以第三種為主,這是由於intrinsics在封裝是有些潛在的性能損失,相同的功能用intrinsics和hand-written assembly去解決,前者可能會引入一些性能損失;而inline assembly的問題在於比較難以跨平台,比如Linux和Windows,而FFmpeg的跨平台是它的目標之一。所以,現在FFmpeg社區更偏向於hand-written assembly方式,另外,大部分的hand-written assembly彙編優化其實是以x264的彙編優化庫為基礎做的,並且選擇nasm為彙編器(不選擇yasm是由於它沒有支持最新的一些CPU指令)。

提及了多線程優化,我們也以使用者的角度看着,使用FFmpeg API的時候,如何設置線程。對於FFmpeg來說,大部分的情況下可能並未考慮在高負載/重耦合場景下運行的情況,FFmpeg在解碼時的默認策略是根據CPU的核數創建線程,目前大部分的PC設備都是四核八線程的配置,但一個典型的數據中心的Server有48核96線程,但解碼器實際上並沒法同時使用這麼多的核,這種情況下,需要自己控制解碼線程,而非使用FFmpeg的默認策略,我們也遇到過使用FFmpeg API時候,默認創建超過1200個線程的問題。第三個是BUG的問題,FFmpeg集成時很多時候只在PC端測試過,並未在擁有這麼多核的服務器上測試,使得FFmpeg的VP9encoder當時甚至會在多核服器上crash,種種事情表明,在多核服務器下使用FFmpeg,需要在多線程上做更細緻的控制,而僅僅只使用其默認線程策略。另外,還有一點要提及,線程並不只是影響性能,它也會影響圖像質量,我們也發現,在編碼時候,隨着編碼器使用的線程數目的增加,其VMAF分數可能會降低。在服務器端,使用FFmpeg這類框架時候,如何在保證性能以及圖像質量的前提下,怎麼更好的控制線程(使用CPU的計算能力),是個非常有趣的問題。

在性能優化過程中,SIMD優化也面臨著一些挑戰,一是在使用SIMD優化時需要將算法改造成適合SIMD的算法,這並不總是一件容易的事情,其次需要考慮不同硬件之間的移植性。另外,對於SIMD一般都有內容對齊的需求,且算法上要盡量避免分支使得數據可以流化,同時,算法上的一些操作並不都被SIMD指令支持(相較而言x86的SIMD指令要比arm更為豐富一些);另外,還有考慮不同硬件之間浮點算法的精確性,種種挑戰,使得SIMD的優化的使用上並不特別的便利。

2.4.2 GPU優化

當時我基於英特爾的GPU做整個轉碼鏈路的優化,Codec解碼主要有兩套plugins,一套是基於MSDK,類似FFmpeg集成x264後依賴第三方去做解碼。第二套思路是基於VAAPI的interface去做,使得整個硬件加速Codec是FFmpeg自身的一部分。除了做Codec的加速以外,團隊同時還用OpenCL做了一些AVFiltrer的優化,這兩種優化之間各有優勢。順帶提及一句,即使GPU已經加速,在API的角度依然無法判斷是否使用了GPU資源,這個問題目前只能歸結到FFmpeg API的設計缺陷。另外,關於更多GPU的優化問題,可以參考我之前的一些文章(FFmpeg在Intel GPU上的硬件加速與優化)。

長按識別二維碼,關注騰訊雲視頻

點「在看」給我一朵小黃花