從 FFmpeg 效能加速到端雲一體媒體系統優化

阿里雲視訊雲發表於2021-08-23

7 月 31 日,阿里雲視訊雲受邀參加由開放原子開源基金會、Linux 基金會亞太區、開源中國共同舉辦的全球開源技術峰會 GOTC 2021 ,在大會的音視訊效能優化專場上,分享了開源 FFmpeg 在效能加速方面的實戰經驗以及端雲一體媒體系統建設與優化。

眾所周知,FFmpeg 作為開源音視訊處理的瑞士軍刀,以其開源免費、功能強大、方便易用的特點而十分流行。音視訊處理的高計算複雜度使得效能加速成為 FFmpeg 開發永恆的主題。阿里雲視訊雲媒體處理系統廣泛借鑑了開源 FFmpeg 在效能加速方面的經驗,同時根據自身產品和架構進行了端雲一體媒體系統架構設計與優化,打造出高效能、高畫質、低延時的端雲協同的實時媒體服務。

image.png

阿里雲智慧視訊雲高階技術專家李忠,目前負責阿里雲視訊雲 RTC 雲端媒體處理服務以及端雲一體的媒體處理效能優化,是 FFmpeg 官方程式碼的維護者及技術委員會委員,參與過多個音視訊開源軟體的開發。

本次分享的議題是《從 FFmpeg 效能加速到端雲一體媒體系統優化》,主要介紹三個方面的內容:

一、FFmpeg 中常見的效能加速方法
二、雲端媒體處理系統
三、端 + 雲的協同媒體處理系統

FFmpeg 中常見的效能加速方法

音視訊開發者當前主要面臨的挑戰之一是對計算量的高需求,它不只是單任務演算法優化,還涉及到很多硬體、軟體、排程、業務層,以及不同業務場景的挑戰。其次端、雲、不同裝置、不同網路,這些綜合的複雜性現狀,要求開發者要做系統性的架構開發與優化。

FFmpeg 是一個非常強大的軟體,包括音視訊的解碼編碼、各種音視訊的 Filter 、各種協議的支援。作為一個開源軟體 FFmpeg 主要的 License 是 GPL 或者 LGPL,程式語言是 C 和彙編。它還提供了很多開啟即用的命令列工具,比如轉碼的 ffmpeg 、音視訊解析的 ffprobe、播放器 ffplayer。其核心的 Library 有負責編解碼的 libavcodec、處理音視訊的 libavfilter 、支援各種協議的 libavformat。

image.png

FFmpeg 開發社群中,音視訊效能優化是一個永恆的主題,其開原始碼裡也提供了非常多的經典效能優化的實現方法,主要是通用加速、CPU 指令加速、GPU 硬體加速。

image.png

通用加速

通用加速主要是演算法優化、IO 讀寫優化、多執行緒優化。演算法優化的目標是在不增加 CPU Usage 的前提下提高效能。最典型是編解碼器的各種快速搜尋演算法,它可以在精度只有少數損失的情況下,大幅優化編碼速度。各種前後處理 Filter 的演算法也有類似的方法,也可以通過演算法合併來減少冗餘的計算,達到效能優化的目的。

下圖是一種典型的降噪與銳化卷積模板,它需要做 3 乘 3 的矩陣卷積。我們可以看到,這裡的銳化模板跟平滑模板是類似的,對於同時要做降噪和銳化的操作,只要在平滑的模板的基礎上面做減法可以達到銳化化模板的結果,可以減少冗餘的計算,提升效能。當然演算法優化也存在侷限性,比如編解碼演算法有精度上的損失,還可能需要犧牲空間複雜度換取時間複雜度。

image.png

第二種效能優化的方法是 IO 讀寫優化,常見方法是利用 CPU 預讀取來改善 Cache Miss 。上圖是通過兩種讀寫的方法達到相同的運算結果,按行讀寫的方法比按列讀寫快,主要原因是 CPU 在按行讀寫時可做預讀取,在處理當前畫素的時候,CPU 已經預讀本行的其他畫素,可以大大加速 IO 讀寫的速度,提高效能。另外可以儘量減少 Memory Copy,因為視訊處理 YUV 非常大,每讀一幀對效能的損耗比較大。

image.png

通用加速的多執行緒優化主要是利用 CPU 多核做多執行緒的並行加速來大幅提升效能。上圖中左下角的圖表表明隨著執行緒數的增加,效能提升了 8 倍。隨之也會產生一個問題,普遍被使用的多執行緒加速,執行緒數是不是越多越好呢?

答案是 No 。

首先,因為 CPU 核數限制,多執行緒等待和排程,多執行緒優化會碰到效能瓶頸。以左下角的圖表為例,執行緒數等於 10 的加速比跟執行緒數等於 11 時非常接近,可以看出多執行緒優化存在邊際效應的遞減,同時也會帶來延時和記憶體消耗的增加(尤其是普遍使用的幀間多執行緒)。

第二,幀間(Frame level)多執行緒需要建立 Frame Buffer Pool 進行多執行緒並行,這需要緩衝很多幀,對於延遲非常敏感的媒體處理,比如低延時直播、RTC ,會帶來比較大的負面效應。與之對應的是,FFmpeg 支援幀內(Slice level)的多執行緒,可以把一幀劃分成多個 Slice,然後做並行處理,這樣能夠有效避免幀間的 Buffer 延遲。

第三,當執行緒數增多,執行緒同步和排程的成本也會增加。以右下圖的一個 FFmpeg Filter 加速為例,隨著執行緒數的增加,CPU Cost 也在明顯增加, 且圖表曲線末端開始往上傾斜,這表明其成本的增加變得更明顯。

CPU 指令加速

CPU 指令加速即 SIMD(單指令多資料流)指令加速。傳統通用的暫存器和指令,一條指令處理一個元素。但一條 SIMD 指令可以處理一個陣列中的多個元素,從而達到非常顯著的加速效果。

現在主流的 CPU 架構都有對應的 SIMD 指令集。X86 架構 SIMD 指令包括 MMX 指令、SSE 指令、AVX2、AVX-512 指令。其中 AVX-512 的一條指令可處理 512 個 bits,加速效果非常明顯。

image.png

FFmpeg 社群的 SIMD 指令寫法包括內聯彙編、手寫彙編。FFmpeg 社群不允許使用 intrinsic 程式設計,原因是它對編譯器的版本存在依賴,不同編譯器編譯出的程式碼及其加速效果也是不一致的。

雖然 SIMD 指令有好的加速效果,但它也存在一定的侷限性。

首先,很多的演算法不是並行處理的,不能進行 SIMD 指令優化。

其次,程式設計難度比較大。彙編程式設計的難度就要大些,另外 SIMD 指令對程式設計有一些特殊的要求,比如 Memory 對齊。AVX-512 要求 Memory 最好能夠做到 64 位元組對齊,如果沒有對齊的話,可能會有效能上的損耗,甚至會引起程式的 Crash。

我們看到不同的 CPU 廠商都在做指令集競賽,支援的位寬越來越多,從 SSE 到 AVX2 再到 AVX-512 ,位寬顯著增加。那位寬是不是越寬越好?上圖可以看到 X265 編碼 AVX 512 相對 AVX 2 的提速情況,AVX 512 的位寬是 AVX 2 位寬的兩倍,但效能提升實際上往往遠達不到一倍,甚至達不到 10%。在某些情況下,AVX 512 的效能會比 AVX 2 還要低。

原因是什麼呢?

首先,一次性的資料輸入可能並沒有 512 bits 這麼多,可能只有 128 bits 或者是 256 bits。

第二,有很多的複雜運算步驟(如編碼器)不能做指令集的並行。

第三,AVX 512 功耗較高,會引起 CPU 的降頻,導致 CPU 整體處理的速度會有所下降。我們看上圖的 X265 ultrafast 檔次編碼,AVX 512 的編碼比 AVX 2 還要慢。(詳見:https://networkbuilders.intel.com/docs/accelerating-x265-the-hevc-encoder-with-intel-advanced-vector-extensions-512.pdf)

硬體加速

FFmpeg 比較主流的硬體加速是 GPU 加速。硬體加速介面分為兩大塊,一是硬體廠商提供不同的加速介面。英特爾主要提供 QSV 和 VAAPI 的介面,英偉達提供 NVENC、CUVID、NVDEC 、VDPAU,AMD 提供 AMF 和 VAAPI 的介面。二是不同的 OS 廠商提供不同的加速介面和方案,比如 Windows 的 DXVA2,安卓的 MediaCodec ,蘋果的 VideoToolbox 。

image.png

硬體加速可以顯著提升媒體處理的效能,但是它也會帶來一些問題。

第一,硬體的編碼質量受限於硬體的設計及成本,硬體編碼的質量往往是會比軟體編碼質量差。但硬體編碼有非常明顯的效能優勢,可以用效能去換編碼質量。下圖的例子可看出,硬體編碼器運動搜尋的視窗比較小,導致編碼質量的下降。其解決方法是 HME 演算法,在搜尋視窗比較小的情況下,先把比較大的 Picture 縮放到非常小的 Picture,在這個 Picture 上做運動搜尋,再逐級做搜尋和放大,這樣可以顯著提高運動搜尋的範圍,然後找到最匹配的塊,從而改善編碼質量。

image.png

第二,硬體加速的 CPU 和 GPU 的 Memory Copy 效能互動會帶來效能的下降。

image.png

CPU 和 GPU 的互動不僅僅是簡單的資料搬移過程,實際上要做對應的畫素的格式轉換,比如 CPU 是 I420 linear 格式,GPU 擅長矩陣運算,採用 NV12 Tiled 格式。

這種記憶體格式的轉化,會帶來明顯的效能損耗。可以通過構建純硬體的 Pipeline ,有效的規避 CPU/GPU Memory 互動的問題。當 CPU 和 GPU 必須互動的情況下,可以採取 Fast Memory Copy 的方式,採用 GPU 去做 Memory Copy ,加速這一過程。

下圖是效能優化的總結大圖。除了前面提到一些優化方法外,客戶端上的媒體處理還有一些特殊性,比如手機 CPU 是大小核架構,執行緒排程如果排程到小核上,它的效能會明顯比大核要差,導致效能的不穩定。

image.png

另外很多的演算法不管如何優化,在某些機型上就是無法跑通,這時要在業務策略上面做優化,比如制定黑白名單,不在支援名單的機器就不開啟該演算法。

雲端媒體處理系統優化

對於媒體處理來說分為兩大挑戰,一是雲端的成本優化,二是客戶端裝置適配及相容。下圖是雲端媒體處理的典型系統:包括單機層、叢集排程層、業務層。

image.png

單機層包括 FFmpeg Pipeline 處理框架、編解碼、硬體層。以雲端轉碼系統為例,它的核心技術指標包括畫質、處理速度、延時、成本。畫質方面,阿里雲視訊雲獨創了窄帶高清的技術以及 S265 編碼技術,可以顯著改善編碼畫質。處理速度和延時優化方面,我們廣泛借鑑 FFmpeg 效能加速方法,比如 SIMD 指令、多執行緒加速以及異構計算的支援。成本是一個比較複雜的系統,它會包括排程層、單機層、業務層,需要進行快速的彈性擴縮容,單機資源精確畫像,減少單任務的計算成本。

雲端成本優化

雲端成本優化的核心是圍繞三條曲線去做優化,針對單任務實際資源消耗、單任務資源預估分配、總資源池這三條曲線分別做對應的優化。在優化過程中需要面對四個現實的問題:

第一,在視訊雲的業務裡,業務多樣性的趨勢會越來越明顯,業務包括點播、直播、RTC、 AI 編輯部、雲剪輯。業務多樣性帶來的挑戰是如何將多種業務共用一個資源池做混跑。

第二,大顆粒的任務越來越多,幾年前主流視訊是 480P,而現在的主流是 720P、1080P 的處理任務,未來可以預見 4K、8K、VR 這樣的媒體處理會越來越越多,這帶來挑戰是對單機效能的渴求會越來越大。

第三,排程層需要預估每個任務的資源消耗,但單機任務的實際消耗會受到非常多因素的影響。視訊內容的複雜度,不同演算法引數,多程式的切換,都會影響任務資源消耗。

第四,編碼的前處理會越來越多,同時一個轉碼任務需要做多位元速率或者多分辨的輸出。各種前處理(畫質增強 / ROI 識別 / 超幀率 / 超分等)都會大幅增加的處理成本。

我們看下從整體思路來看怎麼去優化這三條曲線。

image.png

實際任務的資源消耗優化,主要方法是每個任務的效能優化、演算法的效能優化、Pipeline 架構優化。

資源的分配核心目標就是使上圖的黃色曲線能夠不斷地貼近黑色曲線,減少資源分配的浪費。當資源分配不足的情況下,可以做演算法的自動升降級,以免線上任務出現卡頓,比如編碼器的 preset 從 medium 檔降低為 fast 檔。

對於總資源池優化,首先可以看到黃色曲線有波峰波谷,如果當前點播任務處在波谷的狀態,可以把直播的任務調過來,這樣可以在整個池子的峰值沒有變化的情況下跑更多的任務。第二,總資源池怎麼樣能夠快速的彈性,在一定時間視窗內能夠快速釋放掉資源,降低資源池消耗,這也是排程需要考慮的成本優化的核心。

下面展開談下一些優化方法。

CPU 指令加速

image.png

CPU 機型優化的主要目標是增加 CPU 單機的吞吐量,減少 CPU 碎片。上圖描述了多核 CPU 帶來的優勢。但多核 CPU 也可能會帶來多個 NUMA node 直接的記憶體訪問,從而導致效能下降。

單機資源精確畫像

單機資源精確畫像主要目標是能夠精確知道每個任務它需要多少資源,它是一個系統性的工具,需要有畫質評估的工具、計算資源統計的工具、需要包括各種多場景複雜的視訊集、以及能夠去做各種計算資源和迭代反饋,修正成本計算的消耗,指導演算法的自適應升降級。

image.png

1-N 架構優化

一個轉碼任務可能要輸出不同的解析度和位元速率,傳統的方法是起 N 個獨立的一轉一的程式。這樣的架構顯而易見會有一些問題,比如冗餘的解碼計算和編碼前處理。一個優化方法是把這些任務做整合,從 N 到 N 的轉碼變成一到 N 的轉碼。這樣視訊解碼和編碼前處理都只需要做一次,從而達到成本優化的目標。

image.png

1-N 轉碼也會帶來新的挑戰。FFmpeg 轉碼工具支援 1-N 轉碼,但是各模組是序列處理的,單個一轉 N 任務的速度會比單個一轉一的任務慢。第二,排程的挑戰,單任務資源顆粒度會更大,所需要資源的分配也更難估計。第三,演算法效果的差異,因為有的視訊的前處理可能是在 Scale 之後,對於一到 N 的轉碼架構會把前處理放到 Scale 之前。媒體處理的流程變化會引起演算法效果的差別(通常這個問題不是特別大,因為在 Scale 前處理沒有畫質損失,在 Scale 前做處理反而是更好的)。

端 + 雲的協同媒體處理系統

端側媒體處理的優勢是可利用手機端現成的算力來降低成本,所以理想情況是充分利用各種端側的算力,每個演算法都做非常好的效能優化、端側的適配,在每個端都能零成本的落地。

但是理想很美滿,現實很骨感。會有四大現實問題:

第一,端側適配的困難。需要大量的 OS 硬體機型適配。

第二,演算法接入的困難。現實情況下不可能把所有的演算法在所有端上都進行優化,所以端側的效能瓶頸會導致演算法落地困難。

第三,體驗優化的困難。客戶會有不同的 SDK ,或者說阿里雲的 SDK 也會有不同的版本,SDK 本身存在碎片化導致一些方案難以落地。比如非標的 H264 編碼,實際上 H265 編解碼演算法的落地也遇到挑戰,一些裝置並不支援 H265。

第四,使用者接入的困難,客戶升級 SDK 或替換 SDK 的週期比較漫長。

面對這樣的現實,我們提出雲和端協同的媒體處理解決方案。主要思路是通過雲上處理 + 端側渲染的方案,達到比較好的使用者體驗。

image.png

雲和端的協同的媒體處理主要型別是轉碼類和預覽類。轉碼類是單向的資料流。預覽類需要把各種流先推到雲端,再加各種特效,然後再拉回來給主播看效果是不是符合他的預期,最後再從 CDN 推到觀眾端。

這樣的方案也會碰到一些挑戰。首先,雲端處理會有計算成本的增加(當然可以有各種方式優化,因為客戶端沒有直接體感)。第二,延時會增加,雲端的處理增加了鏈路的延時。

隨著 RTC 技術越來越成熟,通過 RTC 低延時的傳輸協議,再加雲端的各種成本優化,可以低成本 / 低延時地支援雲上的媒體處理,打造一個雲加端的實時媒體處理服務。阿里雲視訊雲構建的 RTC 實時媒體處理服務 RMS,可以做到高效能、低成本、高畫質、低延時、更智慧的雲端協同媒體處理的方案。

image.png

上面的左圖是 RMS 整體架構圖,分為 Pipeline 層、模組層、硬體適配層,硬體層。Pipeline 可以做各種業務場景的組裝模組層,模組層是音視訊處理的核心,實現各種 AI 或者是低延時高畫質的效果。

端加雲的協同媒體處理:賦能 RTC+

以剪輯雲渲染為例,傳統的剪輯方案要保證多端體驗一致性及流暢的效能是比較困難的。我們的思路是端上只做指令的下發,視訊的合成、渲染都是在雲上實現,可以支援非常多的特效,也能夠保證多端的效果一致性。

image.png

我們看下剪輯雲渲染的 Pipeline。雲渲染的網頁負責信令下發,通過排程層把剪輯指令轉發到 RMS 媒體處理引擎做雲上媒體處理的渲染,合成之後再編碼通過 SFU 推流,最後在剪輯的網頁端看剪輯效果。上圖的 Demo 可以看到,網頁把很多 Track 合成一個 Track ,4 乘 4 的宮格在端上處理的話,在低端機跑起來是比較費力的,但云能夠輕易跑出這樣的效果。

高位元速率低清晰度的視訊流到雲端後,通過阿里雲視訊雲的雲端窄帶高清技術處理,可以達到更高清晰度更低位元速率的目標。下圖 Demo 中啟用窄帶高清後,視訊的清晰度有明顯的提升(位元速率也有顯著下降)。

image.png

同時利用 RTC 低延時,再加 AI 特效的處理,可以產生很多有意思的場景。把真人的流推到雲端,雲端做卡通人像的輸出處理,然後輸出卡通人像做實時的交流,在會場的觀眾相互看到的是各自的卡通人像。

搭配雲端的摳圖技術很容易就能實現虛擬的教育場景和虛擬的會議室場景。比如虛擬課堂,可以把人像摳到 PPT 裡增加整個效果演示的沉浸感。虛擬會議室裡不同的參會者通過摳圖把他們排列到虛擬的會議室場景裡來,達到虛擬會議室的效果。

「視訊雲技術」你最值得關注的音視訊技術公眾號,每週推送來自阿里雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。公眾號後臺回覆【技術】可加入阿里雲視訊雲產品技術交流群,和業內大咖一起探討音視訊技術,獲取更多行業最新資訊。

相關文章