英特爾提供了一套基于VA-API/Media SDK的硬件加速方案,通過在FFmpeg中集成Intel GPU的媒體硬件加速能力,為用戶提供更多的收益。本文來自英特爾資深軟件開發工程師趙軍在LiveVideoStackCon 2017大會上的分享,并由LiveVideoStack整理而成。
大家好,今天與大家分享的主題是FFmpeg在 Intel GPU上的硬件加速與優化。
1、Media pipeline review
上圖展示的是典型的Media Pipeline。我們知道,FFmpeg對輸入格式支持非常的全面,可以是文件、網絡流等,也可以使用Device的Caputer作為輸入;輸入的音視頻經過Splitter后一般會分為兩種常見場景:Play Back與Transcoder。上圖的右上半部分實際是一個Transcoder的基本流程,解復用之后的Video、Audio的ES流,再經過Video、Audio的Filter,大部分情況下,Video有可能在AVFilter執行一些Scale、Frc、Crop操作(也可以在AVFiter中抓取有價值的信息);隨后音視頻數據會被轉碼成為用戶指定的格式,轉碼時候多伴隨著碼率轉換、指定IPB幀類型等;Audio也會經過類似的處理流程。上圖的右下半部可以視為播放器處理流程也就是Playback,Playback流程與Transcoder處理流程的主要差異在于對解碼的數據是否進行再次編碼或者直接顯示。另外,眾所周知,Encoder與Decoder的復雜程度存在一個數量級的差異,計算復雜度大概為10:1,且一般情況下Encoder每十年進化為一代,從MPEG2發展到H264大概用了十年時間,而從H264發展到HEVC將近十年時間(實際不到十年),其計算復雜度提升均為上一代的十倍左右,但壓縮率提升大概只有40%到50%,其背后是對計算量的大幅渴求,CPU的計算能力有時不能實時跟上計算量的需求或在高轉碼密度條件下不能提供較好的性價比,在此背景下,Intel提出了基于Intel GPU的媒體硬件加速解決方案。
2、何謂FFmpeg/VA-API?
作為最為流行的開源媒體解決方案,FFmpeg有兩種使用方式:直接使用它自帶Tools,或者把FFmpeg作為Library調用它的API而實現自己的邏輯。其中的Tools包含我們經常看到的轉碼工具FFmpeg;輕量媒體播放器FFPlayer;進行格式的探測分析的FFProbe ;輕量級流媒體測試的服務器FFServer等。另外,FFmpeg的內部實現基本以C語言為主,輔助以部分匯編優化;同時它支持Linux、MacOSX、Android、Windows等不同OS,有著良好的跨平臺兼容性。這里另外強調一點的是FFmpeg自身的License問題,也許國內的廠商不會特別在意License,但在實際使用場景中,所使用軟件或者庫的License即版權是不能不考慮的問題。最近幾年FFmpeg已經將License的問題澄清得比較清楚,目前它的大多數內部實現代碼使用GPL2.1版本的License。
3、Linux Video API
接下來我將介紹Linux平臺上Video加速API的進化歷史。我們知道,每一個突破性創新都是從細微之處開始慢慢演化,最后才可能成為舉世矚目的創造;另外很多技術的進化過程中,都是工程與算法科學相互交織,Linux上的硬件加速API的進化流程也遵循了這一點。最初的Linux Video API被稱為Xv,基本只能借助硬件加速實現Scaling與Color Space Conversion兩個功能,明顯無法滿足行業需求;隨后經過擴展,使得在那個MPEG-2稱霸的時代實現了對MPEG-2 Decoding硬件加速API的支持, 也就是Xv/XvMC,不過這一部分在當時還停留在比較初級的階段,iDCT、XvMC-VLD等還未實現被API所標準化;隨后社區便開始嘗試實現Slice層加速API標準化,以避免之前包括不支持解碼所有階段硬件加速且依賴于X-Protocol協議等在內的諸多問題,演化到現在,最終的結果就是VA-API。
4、VA-API
當時的英特爾開始涉足硬件加速領域,于是在1999年左右英特爾提出VA-API接口。這是一套在Linux上的標準接口,從上層來看大家可以將其理解為一個OS層面的Video加速Spec,且與硬件無直接關聯。這套通用接口,同時需要特定的后端實現支持。與大多數開源項目相似,VA-API并沒有一個特別好的Document進行說明,需要自己仔細的去讀它的頭文件以了解其設計思想和細節。另外,既然這是一個Spec,其設計上自然想剝離與特定硬件的強關聯,所以雖然今天我的分享主要圍繞Intel GPU實踐進行,但實際上VA-API這套Spec并不只限于英特爾的GPU。
5、VA-API可用的后端驅動
VA-API可用的后端驅動非常多:Intel VA(i965)Driver是Intel OTC Team開發的一套全開源驅動,隨后也出現了Intel Hybird Driver、Intel iHD Driver等;在后端實現中還有Mesa‘S state-trackers包括Radeon、Nouveau、Freedreno等的支持,另外,還有些公司開發了一些API Bridge,包括Vdpau-va Bridge、Powervr-va的bridge以提供VA-API的支持,但這些bridge大部分由于種種原因慢慢轉為封閉而逐漸被廢棄;與此同時,英特爾的態度則更為開放,它希望大部分的開發者有能力在現有成熟平臺上進行更深層次的定制與探索,開放出更多的硬件能力以及驅動代碼,這也是英特爾作為一個開源大廠的風范吧。
6、Intel GPU
Intel GPU從Gen 3的Pinetrail發展到Gen 9.5的Kabylake,每一代GPU的功能都在增強,在Media上的能力也在增強。關于GPU性能我們比較關注以下三部分指標:第一部分是3D渲染能力,這一部分的標準化程度較好,可以使用標準接口包括OpenGL或Vulkan,當然也有Windows上可與OpenGL與Vulkan適配的DirectX等;第二部分是Media;第三部分則為通用計算,其中包括NVIDIA的CUDA與AMD、ARM等公司采用的OpenLL。附帶說一句,有人會混淆GPU的通用計算能力與Media處理能力,以為通用計算能力很強,則Media能力就很強,這并不正確,實際使用中,需要把這三個指標分開來根據具體的使用場景來分析與比較,以挑選最合適的硬件方案。
6.1 Intel GPU Media 硬件編程模型
從FFmpeg到具體的GPU,是如何進行一些Media處理的?首先FFmpeg會通過VA-API接口,調到對應的Driver例如i965或iHD,之后數據經過OS Scheduler進入OS KMD,接下來經過一系列硬件編程抽象和GPU&CPU數據交換,生成Command streamer并傳輸給EU(也就是Intel GPU中的一個計算執行單元)或者特定的IP以執行相關的Media任務。注意,GPU的Media部分有時也會使用EU這些通用計算資源,而像Sampler、VDBOX、VEBOX、SFC等都是基于一些特定的Fix Function硬件實現相應功能。所以,可以這樣理解,英特爾的GPU實際上是將媒體的大部分功能通過Fix Function方式實現,同時必要時候使用EU作為一個通用的計算資源這樣協同工作的。
6.2 FFmpeg & Intel GPU加速方案
大部分客戶偏向于使用FFmpeg的同時,也希望其具備出色的硬件加速能力,我們現在致力于在FFmpeg中集成Intel GPU諸多的媒體硬件加速能力,使用戶可通過FFmpeg的接口使能調用英特爾的GPU的各種能力從而帶來更多收益。這里的集成方式主要有兩種:1)直接實現為與FFmpeg融為一體的Native Decode/Encode。FFmpeg的大部分Decode如H.264、H.265、VP8、VP9等都使用Native Decoder的方式,2)Warpper第三方庫的,如在FFmpeg中集成Libx264的方式;現在部分Encode都以第三方庫的形式集成進FFmpeg的。根據上圖我們可以看到在Intel GPU中集成了兩個Plugin到FFmpeg中:第一個是QSV Plugin,其類似于libx265的做法,其Codec實現的底層與MediaSDK相關;但FFmpeg社區更傾向于基于libva/vaapi的方式,即直接在FFmpeg中進行集成,不warpper第三方的庫,一是因為此方案相對而言更加輕量,二是因為此方案更加開放;這樣做意味著將全部的硬件Codec部分的代碼都集成在FFmpeg中,與FFmpeg融為一體,如果客戶希望進行定制或改變,那么直接在FFmpeg內部代碼中修改即可實現。除了解決基本的解碼/編碼硬件加速問題,我們也在考慮集成OpenCL、OpenCV等以適應客戶的一些其他需求。
6.3 Intel GPU 支持
1)解碼支持
上圖展示的是Intel GPU Decode部分的的支持狀況。一般情況下我們可以將Decode分為8Bit與10Bit,以HEVC為例,有一些數據顯示10bit的壓縮率要高于8bit,感興趣的同學可以思考一下其原因。從表也可以看到,英特爾的各代GPU逐漸進化,從開始只支持MPEG-2、H.264、VC-1解碼的Sandy Bridge到增加了MJPEG解碼支持的Ivy Bridge再到多用于嵌入式平臺的Bay Trail乃至之后的Haswell,從Broadwell開始對VP8的支持與Cherry Trail/ Braswell對HEVC的支持再到Skylake之后的Apollo lake與 Kaby lake對VP9解碼與10bit HEVC&VP9的解碼支持,其解碼能力穩步增加。
2)編碼支持
編碼方面,Intel GPU很早開始就支持了H.264編碼,到了Broadwell增加了對VP8的支持;而Skylake則增加HEVC和MJPEG,到了Kaby Lake時我們增加了對VP9和10Bit HEVC的編碼支持。關于VP9我想強調一點,據我所知,現在量產的SoC/GPU/CPU中可能只有英特爾的Kaby Lake及其后續的產品與三星的SoC支持VP9的編碼硬件加速。
6.4 使用案例
上圖展示的這些Use Cases可基本涵蓋大部分用戶的使用場景。解碼部分主要是使用hwaccel vaapi進行硬件解碼,由于一款設備上可能存在多款GPU,因此我們需要是hwaccel_device選擇不同的硬件設備。對比硬件編碼與硬件解碼我們不難發現,在解碼部分我們使用hwaccel_device而編碼部分則使用vaapi_device。這里的vaapi_device是一個Group Option,因為FFmpeg中存在Group Option與Per-Stream Option,解碼部分的hwaccel_device是Per-Stream Option,而編碼部分的vaapi_device是全局的并且Decoder和Encoder只需指定一次。從上面看來,轉碼的例子更為復雜,首先進行硬件解碼,而后在GPU中進行de-interlace與Scall和HEVC編碼,實際上整個過程是一個硬件解碼結合GPU中的Deinterlace/Scale和隨后的HEVC硬編的過程,這里需要注意一些關于碼控設定的問題,對此問題有興趣的同學可以直接閱讀FFmpeg的文檔或者代碼。
7、FFmpeg硬件加速全覽
上圖展示的是FFmpeg硬件加速全覽,我想這一部分對探索基于FFmpeg實現跨平臺的開發者來說非常有幫助。開發者經常需要面對不同的硬件廠商:Intel、NVIDIA、AMD等等,他們希望僅僅與FFmpeg經過一次集成,就可在不同硬件上實現同樣的功能。而現實情況,即是存在OS層面可以進行硬件優化的API諸如Windows上的Dxva或MacOS上的VideotoolBox、Linux的Vaapi等,其實現可能還是非常分散,而FFmpeg在支持各種硬件加速接口之后,則幫助解決了上面的這個問題。另外,對于上表,Decoder部分只列舉了是否支持硬件surface的輸出。除此之外還有一些附加功能例如Filter,作為FFmpeg中非常重要的一部分,它主要是為了進行Video 后處理等;上表中的Hardware Context是指基于FFmpeg內部的硬件加速接口的實現,Useable from FFmpeg CLI是指FFmpeg的命令行是否直接可用硬件加速(它的典型使用場景是,在Server端將FFmpeg直接作為工具使用,通過PHP在后端直接調用FFmpeg的Tools)。另外,如果開發者需要調用FFmpeg API進行解碼,此時需要關注Hwaccel的支持情況。最后我想強調一下圖中Decoder部分里的Internal和Standalone。它實際上是一個歷史遺產,在FFmpeg中,很早便實現了H.264的軟解碼,在此基礎上,如果想使能GPU的解碼能力則需要面臨以下兩個選擇:可以選擇重新實現有別于軟解碼的另一套基于GPU解碼實現,可以考慮為需要完整實現一個類似h264_vaapi的解碼其;也可將解碼相關的一些硬件加速工作直接Hook在已有的軟解碼Codec中,當時的開發者選擇了后者,所以大部分基于OS的硬件加速解碼方案都基于后者的方案也就是Internal AVHWaccel;但諸如NVIDIA等提供NVDEC,NVENC的方案,因為自身已經是一個完整的硬件解碼器,所以在FFmpeg內只需實現成一個簡單的wrappe人即可,不需要借助FFmpe已有的軟解碼Codec的任何功能。
8、FFmpeg VA-API的細節信息
上圖展示的是FFmpeg VAAPI的一些細節信息,之前我已經對HWAcceled的解碼與Native的解碼進行了說明。提及編碼,硬件加速的編碼帶來的最大好處是速度優勢:我曾經基于Skylake-U這樣雙核四線程的低電壓CPU上測試1080P的轉碼,基本可實現240FPS的實時轉碼;同時,在大規模部署時不能不考慮功耗比與性價比,也就是單路的編碼或轉碼需要消耗多少電能以及單路轉碼的成本。現在集成了GPU的英特爾PC處理器,其功耗在40~65w,如果是面向服務器工作站的Xeon E3系列,可在一個65w的處理器上實現14到18路的1080P轉碼,而能達到相同性能的NVIDIA GPU所需的能耗大約在300w左右。另外,對于硬件編碼,有一些客戶可能在圖像質量上有更高的需求,現在英特爾的GPU在低碼率上處理效果還有提升空間,但在處理中高碼率文件時,其評測結果與X264相比并無明顯的差距。如果客戶期望借助自己的一些高階算法通過更深度的定制實現更強大的功能,Intel也開放了被稱為Flexible Encoder Interface (FEI)的底層接口。此接口可詳細全面展示Intel GPU的全部硬件編碼能力,并讓用戶擁有足夠的靈活度去Tunning各種算法;如果說FFmpeg代表的是一個可以直接調用的成熟平臺,那么FEI則是可定制Codec算法的通用接口。與此同時,FEI對客戶的能力要求也更高,如果有高階深層次定制化的編碼需求,可以考慮FEI。最后,附帶一句,我們同樣在AVFilter中集成了GPU的VPP以實現硬件加速的Scaling與Deinterlace等操作,后續也會支持Overlay、CSC等。
9、其他問題
9.1 CPU與GPU的數據交換
當我們在處理一些異構計算時,始終需要面對此問題:CPU與GPU、DSP之間的數據交換。數據從CPU拷貝到GPU與從GPU拷貝到CPU并不是一個對等關系,一般而言,數據從CPU到GPU進行拷貝的速度很快且不存在性能瓶頸;而如果是GPU到CPU的拷貝交換有可能面臨性能瓶頸,其原因是兩者使用了不同的緩存策略。如果我們通過mmap GPU的memory到CPU側,之后不進行任何優化而是直接使用諸如memcpy函數將數據拷貝到CPU側,會發現性能可能不如預期。關于這個問題,英特爾也提供了一些優化辦法,例如使用SSE4/AVX等指令集中提供的bypass Cache的特定指令,也就是所謂的Faster Copy背后的特定指令;另外,也可考慮直接用GPU進行拷貝而非使用CPU,或者考慮從OpenCL層面進行優化。
9.2 FFmpeg中的硬件加速
FFmpeg提供了一些Filter用于實現硬件加速pipeline的建立,分別為Hwupload、Hwdownload、Hwmap、Hwunmap,使得在組成硬件的Pipeline時盡量避免大量的數據交換,所有操作盡量在GPU內部直接完成以提升性能。
9.3 硬件或驅動不支持
如果完成了編解碼的部署,需要AVFilter相關的優化但硬件或者驅動層面卻不支持,面對這種情況,我們可考慮OpenCL。因為OpenCL現在可與FFmpeg Video的編解碼進行Buffer Sharing,這相當于是一個GPU內部零拷貝的過程;只需要依靠Hwmap和Hwunmap實現的map就能直接用OpenCL對現有的AVFilter進行優化,從而幫助開發者解決此類由于CPU/GPU的數據交換導致的性能問題,與此同時,把OpenCL作為對GPU通用計算的標準接口,來優化我們的各種視頻或圖像的處理;另外,我們可以將此思路放得更寬一點,如果客戶不希望直接使用來OpenCL來手動優化AVFilter,也可考慮把OpenCV作為一個已經被OpenCL優化好的算法集合再集成進FFmpeg中。我們現在也在考慮此類方式并在其上進行嘗試。
10、To Do List
上圖展示的是我們正在實踐與探索的技術點,期待通過以上優化為音視頻行業帶來技術進步與行業發展。
-
gpu
+關注
關注
28文章
4777瀏覽量
129362 -
intel
+關注
關注
19文章
3483瀏覽量
186446 -
ffmpeg
+關注
關注
0文章
46瀏覽量
7429
原文標題:FFmpeg在Intel GPU上的硬件加速與優化
文章出處:【微信號:livevideostack,微信公眾號:LiveVideoStack】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論