伴隨着飛速增加的視頻普及與觀看需求,騰訊雲技術專家、FFmpeg決策委員會委員趙軍認爲,視頻行業目前存在一個「技術、需求與現實」的三角博弈,其場景猶如帶着鐐銬的舞蹈,即須要在超高清晰度、計算能力與網絡帶寬約束之下尋求平衡。正是基於這樣一個三角博弈,騰訊雲以「開源、協同」爲利器,逐步打磨出一個完備且高效的視頻產品鏈。本文來自於趙軍在LiveVideoStackCon2019北京站上的精彩分享。算法
文 / 趙軍
整理 / LiveVideoStack性能優化
你們好,我是騰訊雲的趙軍,同時我也是FFmpeg決策委員會委員、開源愛好者。在2018年成爲FFmpeg maintainer,2019年入選 FFmpeg 決策委員會(voting committee),具有豐富的基於Linux 的Router/Gateway 開發經驗,並持續關注Linux 在網絡方面發展。曾開發基於Linux 的高清/ 標清H.264/MPEG2視頻解碼器及圖像處理平臺。曾在Intel DCG/NPG 負責基於FFmpeg以及Intel平臺上的視頻編碼/解碼/轉碼、視頻後處理、視頻分析的硬件加速的工做。目前在騰訊雲負責視頻雲的系統優化相關工做,除去支持公司內部的項目開發之外,也在持續向FFmpeg社區提交patch,同時也倡導引領同事以開放的心態擁抱開源。服務器
今天的演講將分爲明眸、智眸、雲剪和開源四個部分來說解,其中明眸主要針對音視頻編解碼與畫質加強方案,智眸主要涉及智能媒體檢索、分析和審覈方案,雲剪主要提供在線媒體內容生產方案,而開源則是本次演講中將重點介紹的內容。網絡
音視頻發展示狀多線程
.png](/img/bVbx2iS)
晰、流暢和品質這三者的博弈,對於視頻來講,體育賽事、遊戲等領域對直播清晰度要求不斷提高,國家政策也在鼓勵4K和8K的增加,這些因素使得超高清晰度視頻內容成爲音視頻技術發展的重要方向,與此同時,人們開始追求更多的趣味性和附加能力,但硬件計算能力或者軟件性能並沒徹底跟上,這使得成像品質以及其餘附屬能力所須要的計算能力也位於了問題之列;一如既往的,不管是4G仍是即將到來的5G時代,網絡的制約在能預計的時間內,依然也仍是一個不可忽視的影響因素之一。框架
1.1 明眸:極速高
提到極速高清就不得不聊聊視頻編碼,上圖從Codec和系統工具的角度,以MPEG組織爲基準描述了發展歷史,圖片下方是容器格式,作過工程的人都瞭解,不少時候相比Codec,容器格式有時會暴露不少的工程問題。圖中色塊分別表明不一樣階段的技術發展,紅色部分已是歷史,橙色部分表示過渡,藍色部分更像是如今和不遠的未來的交界。ide
處理和編碼算法動態優化三部分組成,場景識別主要是對場景進行切分,根據場景預設編碼模板。其次前置處理主要解決的問題是屢次轉碼帶來的反作用,最後在基於以上兩部分的前提下作編碼算法的動態優化。工具
當場景識別、前置處理和編碼算法動態優化三部分作完以後,咱們能夠獲得一些基本的結論,因爲直播客戶更在乎主觀質量,明眸以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.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上的硬件加速與優化)。