客戶端影片渲染目前最理想的解決方案

啟程軟體發表於2022-12-20

很多客戶端產品有影片渲染需求。影片渲染有軟體渲染和硬體渲染兩種方案。

軟體渲染一般來說需要將常見的yuv影片流轉換成rgb/rgba影片流,再透過GDI繪製到視窗上。軟體渲染的優勢在於可以方便的和客戶端介面做融合,達到更好的介面效果,比如透過alphablend等API實現前景,背景的混合。

然後軟體渲染效能存在比較大的瓶頸,現階段最好的電腦可能也帶不動1080P, 30幀的影片。只適合小影片視窗的渲染。

硬體渲染則是使用硬體加速介面,直接將影片渲染到顯示器,通常對yuv流的支援都很友好,不需要做格式轉換,同時效能會高很多,輕鬆影片4K影片的高幀率渲染。然而硬體渲染需要將影片流轉換成硬體支援的Texture, 並佔滿整個HWND視窗空間,導致很難和GDI繪製的介面元素融合。

有沒有再使其美的辦法呢?

先看圖:

 

我一直在問為什麼手機上做影片渲染這麼簡單,影片和其它UI元素可以完美的組合?瀏覽器好像也可以達到類似的效果。

前段時間我也有嘗試使用sdl來實現影片和soui繪製的視窗進行融合渲染(sdlplayer),效果還比較理想。當時的實現還限於當時對影片渲染的認知不夠,還是需要為影片建立一個獨立的HWND,只是在將影片流繪製到這個HWND之後,再將影片上的UI前景再疊加到影片流上。

這樣做基本達到了將影片使用硬體渲染,同時又能和UI前景融合的問題。不夠理想在於,它還是需要多一個HWND,而且操作這些前景需要多做一次中轉。

事件的轉機在一個朋友提的一個問題:SOUI可不可以使用opengl來渲染介面,而繪製流程保持不變?

既然SOUI內部已經將介面效果渲染到了記憶體點陣圖上了,上顯示器為什麼一定要用GDI呢?

結合前段時間做sdlplayer的經驗,透過簡單的將上屏流程抽象出一個IPresenter介面,再使用sdl來實現這個介面,即可以方便的切換到使用sdl來上屏,從而實現上屏過程的硬體加速。

當然,只是抽象出IPresenter還不夠。如果一個影片佔滿整個視窗空間,當然沒有問題,介面上的前景繪製好後直接生成一個rgba的sdl_texture,再帖到影片的yuv_texture上面即可。但是如果要達到使用單一的HWND實現影片和UI的融合,則需要支援影片顯示在視窗的任意位置。

要解決這個問題,首先需要在Presenter中影片到達的時候,知道這一幀影片需要渲染到什麼地方。

這個問題好辦,在影片到達的時候,問一下SOUI,哪個控制元件佔的位置是留給影片的即可。

然後,SOUI需要保證這個位置上在繪製影片前不能繪製背景。常規流程下,SOUI在渲染UI元素時是自動將整個視窗的空間重新整理的,不區分哪一塊是留給影片渲染的。假定視窗有一個白色的背景,那麼整個視窗的記憶體點陣圖就會被白色填充。在將這個記憶體點陣圖疊加到影片上以後,影片就看不到了。

要解決這個問題,SOUI的方法是:視窗重新整理的時候,先將整個畫布清空(alpha=0,視窗全透明),再使用clip剪下掉影片佔用的位置,保證後面的繪製流程不繪製影片位置。經過這樣處理,影片在SOUI給定的位置渲染後,再疊加SOUI的渲染結果,就會出現影片和SOUI融合的情況。

然而這隻解決了一個問題,讓SOUI繪製不遮擋影片。由於前面將影片渲染位置使用clip來保證不做渲染,影片的前景也同樣沒有渲染。

為解決這個問題,只需要在做完前面的繪製流程後,再做一次只繪製影片前景的流程即可:清除前面的clip,從影片視窗的dui元素層開始繪製前景(如果有的話)。這樣處理後就可以實現影片和UI元素的完美融合。

最後給出原始碼:

https://github.com/setoutsoft/soui4js

 

相關文章