7 月 31 日,阿里雲視頻雲受邀參加由開放原子開源基金會、Linux 基金會亞太區、開源中國共同舉辦的全球開源技術峰會 GOTC 2021 ,在大會的音視頻性能優化專場上,分享了開源 FFmpeg 在性能加速方面的實戰經驗以及端雲一體媒體系統建設與優化。
眾所周知,FFmpeg 作為開源音視頻處理的瑞士軍刀,以其開源免費、功能強大、方便易用的特點而十分流行。音視頻處理的高計算復雜度使得性能加速成為 FFmpeg 開發永恆的主題。阿里雲視頻雲媒體處理系統廣泛借鑒了開源 FFmpeg 在性能加速方面的經驗,同時根據自身產品和架構進行了端雲一體媒體系統架構設計與優化,打造出高性能、高畫質、低延時的端雲協同的實時媒體服務。
阿里雲智能視頻雲高級技術專家李忠,目前負責阿里雲視頻雲 RTC 雲端媒體處理服務以及端雲一體的媒體處理性能優化,是 FFmpeg 官方代碼的維護者及技術委員會委員,參與過多個音視頻開源軟件的開發。
本次分享的議題是《從 FFmpeg 性能加速到端雲一體媒體系統優化》,主要介紹三個方面的內容:
一、FFmpeg 中常見的性能加速方法
二、雲端媒體處理系統
三、端 + 雲的協同媒體處理系統
FFmpeg 中常見的性能加速方法
音視頻開發者當前主要面臨的挑戰之一是對計算量的高需求,它不只是單任務算法優化,還涉及到很多硬件、軟件、調度、業務層,以及不同業務場景的挑戰。其次端、雲、不同設備、不同網絡,這些綜合的復雜性現狀,要求開發者要做系統性的架構開發與優化。
FFmpeg 是一個非常強大的軟件,包括音視頻的解碼編碼、各種音視頻的 Filter 、各種協議的支持。作為一個開源軟件 FFmpeg 主要的 License 是 GPL 或者 LGPL,編程語言是 C 和匯編。它還提供了很多打開即用的命令行工具,比如轉碼的 ffmpeg 、音視頻解析的 ffprobe、播放器 ffplayer。其核心的 Library 有負責編解碼的 libavcodec、處理音視頻的 libavfilter 、支持各種協議的 libavformat。
FFmpeg 開發社區中,音視頻性能優化是一個永恆的主題,其開源代碼里也提供了非常多的經典性能優化的實現方法,主要是通用加速、CPU 指令加速、GPU 硬件加速。
通用加速
通用加速主要是算法優化、IO 讀寫優化、多線程優化。算法優化的目標是在不增加 CPU Usage 的前提下提高性能。最典型是編解碼器的各種快速搜索算法,它可以在精度只有少數損失的情況下,大幅優化編碼速度。各種前后處理 Filter 的算法也有類似的方法,也可以通過算法合並來減少冗余的計算,達到性能優化的目的。
下圖是一種典型的降噪與銳化卷積模板,它需要做 3 乘 3 的矩陣卷積。我們可以看到,這里的銳化模板跟平滑模板是類似的,對於同時要做降噪和銳化的操作,只要在平滑的模板的基礎上面做減法可以達到銳化化模板的結果,可以減少冗余的計算,提升性能。當然算法優化也存在局限性,比如編解碼算法有精度上的損失,還可能需要犧牲空間復雜度換取時間復雜度。
第二種性能優化的方法是 IO 讀寫優化,常見方法是利用 CPU 預讀取來改善 Cache Miss 。上圖是通過兩種讀寫的方法達到相同的運算結果,按行讀寫的方法比按列讀寫快,主要原因是 CPU 在按行讀寫時可做預讀取,在處理當前像素的時候,CPU 已經預讀本行的其他像素,可以大大加速 IO 讀寫的速度,提高性能。另外可以盡量減少 Memory Copy,因為視頻處理 YUV 非常大,每讀一幀對性能的損耗比較大。
通用加速的多線程優化主要是利用 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,加速效果非常明顯。
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 。
硬件加速可以顯著提升媒體處理的性能,但是它也會帶來一些問題。
第一,硬件的編碼質量受限於硬件的設計及成本,硬件編碼的質量往往是會比軟件編碼質量差。但硬件編碼有非常明顯的性能優勢,可以用性能去換編碼質量。下圖的例子可看出,硬件編碼器運動搜索的窗口比較小,導致編碼質量的下降。其解決方法是 HME 算法,在搜索窗口比較小的情況下,先把比較大的 Picture 縮放到非常小的 Picture,在這個 Picture 上做運動搜索,再逐級做搜索和放大,這樣可以顯著提高運動搜索的范圍,然后找到最匹配的塊,從而改善編碼質量。
第二,硬件加速的 CPU 和 GPU 的 Memory Copy 性能交互會帶來性能的下降。
CPU 和 GPU 的交互不僅僅是簡單的數據搬移過程,實際上要做對應的像素的格式轉換,比如 CPU 是 I420 linear 格式,GPU 擅長矩陣運算,采用 NV12 Tiled 格式。
這種內存格式的轉化,會帶來明顯的性能損耗。可以通過構建純硬件的 Pipeline ,有效的規避 CPU/GPU Memory 交互的問題。當 CPU 和 GPU 必須交互的情況下,可以采取 Fast Memory Copy 的方式,采用 GPU 去做 Memory Copy ,加速這一過程。
下圖是性能優化的總結大圖。除了前面提到一些優化方法外,客戶端上的媒體處理還有一些特殊性,比如手機 CPU 是大小核架構,線程調度如果調度到小核上,它的性能會明顯比大核要差,導致性能的不穩定。
另外很多的算法不管如何優化,在某些機型上就是無法跑通,這時要在業務策略上面做優化,比如制定黑白名單,不在支持名單的機器就不開啟該算法。
雲端媒體處理系統優化
對於媒體處理來說分為兩大挑戰,一是雲端的成本優化,二是客戶端設備適配及兼容。下圖是雲端媒體處理的典型系統:包括單機層、集群調度層、業務層。
單機層包括 FFmpeg Pipeline 處理框架、編解碼、硬件層。以雲端轉碼系統為例,它的核心技術指標包括畫質、處理速度、延時、成本。畫質方面,阿里雲視頻雲獨創了窄帶高清的技術以及 S265 編碼技術,可以顯著改善編碼畫質。處理速度和延時優化方面,我們廣泛借鑒 FFmpeg 性能加速方法,比如 SIMD 指令、多線程加速以及異構計算的支持。成本是一個比較復雜的系統,它會包括調度層、單機層、業務層,需要進行快速的彈性擴縮容,單機資源精確畫像,減少單任務的計算成本。
雲端成本優化
雲端成本優化的核心是圍繞三條曲線去做優化,針對單任務實際資源消耗、單任務資源預估分配、總資源池這三條曲線分別做對應的優化。在優化過程中需要面對四個現實的問題:
第一,在視頻雲的業務里,業務多樣性的趨勢會越來越明顯,業務包括點播、直播、RTC、 AI 編輯部、雲剪輯。業務多樣性帶來的挑戰是如何將多種業務共用一個資源池做混跑。
第二,大顆粒的任務越來越多,幾年前主流視頻是 480P,而現在的主流是 720P、1080P 的處理任務,未來可以預見 4K、8K、VR 這樣的媒體處理會越來越越多,這帶來挑戰是對單機性能的渴求會越來越大。
第三,調度層需要預估每個任務的資源消耗,但單機任務的實際消耗會受到非常多因素的影響。視頻內容的復雜度,不同算法參數,多進程的切換,都會影響任務資源消耗。
第四,編碼的前處理會越來越多,同時一個轉碼任務需要做多碼率或者多分辨的輸出。各種前處理(畫質增強 / ROI 識別 / 超幀率 / 超分等)都會大幅增加的處理成本。
我們看下從整體思路來看怎么去優化這三條曲線。
實際任務的資源消耗優化,主要方法是每個任務的性能優化、算法的性能優化、Pipeline 架構優化。
資源的分配核心目標就是使上圖的黃色曲線能夠不斷地貼近黑色曲線,減少資源分配的浪費。當資源分配不足的情況下,可以做算法的自動升降級,以免線上任務出現卡頓,比如編碼器的 preset 從 medium 檔降低為 fast 檔。
對於總資源池優化,首先可以看到黃色曲線有波峰波谷,如果當前點播任務處在波谷的狀態,可以把直播的任務調過來,這樣可以在整個池子的峰值沒有變化的情況下跑更多的任務。第二,總資源池怎么樣能夠快速的彈性,在一定時間窗口內能夠快速釋放掉資源,降低資源池消耗,這也是調度需要考慮的成本優化的核心。
下面展開談下一些優化方法。
CPU 指令加速
CPU 機型優化的主要目標是增加 CPU 單機的吞吐量,減少 CPU 碎片。上圖描述了多核 CPU 帶來的優勢。但多核 CPU 也可能會帶來多個 NUMA node 直接的內存訪問,從而導致性能下降。
單機資源精確畫像
單機資源精確畫像主要目標是能夠精確知道每個任務它需要多少資源,它是一個系統性的工具,需要有畫質評估的工具、計算資源統計的工具、需要包括各種多場景復雜的視頻集、以及能夠去做各種計算資源和迭代反饋,修正成本計算的消耗,指導算法的自適應升降級。
1-N 架構優化
一個轉碼任務可能要輸出不同的分辨率和碼率,傳統的方法是起 N 個獨立的一轉一的進程。這樣的架構顯而易見會有一些問題,比如冗余的解碼計算和編碼前處理。一個優化方法是把這些任務做整合,從 N 到 N 的轉碼變成一到 N 的轉碼。這樣視頻解碼和編碼前處理都只需要做一次,從而達到成本優化的目標。
1-N 轉碼也會帶來新的挑戰。FFmpeg 轉碼工具支持 1-N 轉碼,但是各模塊是串行處理的,單個一轉 N 任務的速度會比單個一轉一的任務慢。第二,調度的挑戰,單任務資源顆粒度會更大,所需要資源的分配也更難估計。第三,算法效果的差異,因為有的視頻的前處理可能是在 Scale 之后,對於一到 N 的轉碼架構會把前處理放到 Scale 之前。媒體處理的流程變化會引起算法效果的差別(通常這個問題不是特別大,因為在 Scale 前處理沒有畫質損失,在 Scale 前做處理反而是更好的)。
端 + 雲的協同媒體處理系統
端側媒體處理的優勢是可利用手機端現成的算力來降低成本,所以理想情況是充分利用各種端側的算力,每個算法都做非常好的性能優化、端側的適配,在每個端都能零成本的落地。
但是理想很美滿,現實很骨感。會有四大現實問題:
第一,端側適配的困難。需要大量的 OS 硬件機型適配。
第二,算法接入的困難。現實情況下不可能把所有的算法在所有端上都進行優化,所以端側的性能瓶頸會導致算法落地困難。
第三,體驗優化的困難。客戶會有不同的 SDK ,或者說阿里雲的 SDK 也會有不同的版本,SDK 本身存在碎片化導致一些方案難以落地。比如非標的 H264 編碼,實際上 H265 編解碼算法的落地也遇到挑戰,一些設備並不支持 H265。
第四,用戶接入的困難,客戶升級 SDK 或替換 SDK 的周期比較漫長。
面對這樣的現實,我們提出雲和端協同的媒體處理解決方案。主要思路是通過雲上處理 + 端側渲染的方案,達到比較好的用戶體驗。
雲和端的協同的媒體處理主要類型是轉碼類和預覽類。轉碼類是單向的數據流。預覽類需要把各種流先推到雲端,再加各種特效,然后再拉回來給主播看效果是不是符合他的預期,最后再從 CDN 推到觀眾端。
這樣的方案也會碰到一些挑戰。首先,雲端處理會有計算成本的增加(當然可以有各種方式優化,因為客戶端沒有直接體感)。第二,延時會增加,雲端的處理增加了鏈路的延時。
隨着 RTC 技術越來越成熟,通過 RTC 低延時的傳輸協議,再加雲端的各種成本優化,可以低成本 / 低延時地支持雲上的媒體處理,打造一個雲加端的實時媒體處理服務。阿里雲視頻雲構建的 RTC 實時媒體處理服務 RMS,可以做到高性能、低成本、高畫質、低延時、更智能的雲端協同媒體處理的方案。
上面的左圖是 RMS 整體架構圖,分為 Pipeline 層、模塊層、硬件適配層,硬件層。Pipeline 可以做各種業務場景的組裝模塊層,模塊層是音視頻處理的核心,實現各種 AI 或者是低延時高畫質的效果。
端加雲的協同媒體處理:賦能 RTC+
以剪輯雲渲染為例,傳統的剪輯方案要保證多端體驗一致性及流暢的性能是比較困難的。我們的思路是端上只做指令的下發,視頻的合成、渲染都是在雲上實現,可以支持非常多的特效,也能夠保證多端的效果一致性。
我們看下剪輯雲渲染的 Pipeline。雲渲染的網頁負責信令下發,通過調度層把剪輯指令轉發到 RMS 媒體處理引擎做雲上媒體處理的渲染,合成之后再編碼通過 SFU 推流,最后在剪輯的網頁端看剪輯效果。上圖的 Demo 可以看到,網頁把很多 Track 合成一個 Track ,4 乘 4 的宮格在端上處理的話,在低端機跑起來是比較費力的,但雲能夠輕易跑出這樣的效果。
高碼率低清晰度的視頻流到雲端后,通過阿里雲視頻雲的雲端窄帶高清技術處理,可以達到更高清晰度更低碼率的目標。下圖 Demo 中啟用窄帶高清后,視頻的清晰度有明顯的提升(碼率也有顯著下降)。
同時利用 RTC 低延時,再加 AI 特效的處理,可以產生很多有意思的場景。把真人的流推到雲端,雲端做卡通人像的輸出處理,然后輸出卡通人像做實時的交流,在會場的觀眾相互看到的是各自的卡通人像。
搭配雲端的摳圖技術很容易就能實現虛擬的教育場景和虛擬的會議室場景。比如虛擬課堂,可以把人像摳到 PPT 里增加整個效果演示的沉浸感。虛擬會議室里不同的參會者通過摳圖把他們排列到虛擬的會議室場景里來,達到虛擬會議室的效果。
「視頻雲技術」你最值得關注的音視頻技術公眾號,每周推送來自阿里雲一線的實踐技術文章,在這里與音視頻領域一流工程師交流切磋。公眾號后台回復【技術】可加入阿里雲視頻雲產品技術交流群,和業內大咖一起探討音視頻技術,獲取更多行業最新信息。