6

客户端视频渲染目前最理想的解决方案 - 启程软件

 1 year ago
source link: https://www.cnblogs.com/setoutsoft/p/16994865.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

客户端视频渲染目前最理想的解决方案

很多客户端产品有视频渲染需求。视频渲染有软件渲染和硬件渲染两种方案。

软件渲染一般来说需要将常见的yuv视频流转换成rgb/rgba视频流,再通过GDI绘制到窗口上。软件渲染的优势在于可以方便的和客户端界面做融合,达到更好的界面效果,比如通过alphablend等API实现前景,背景的混合。

然后软件渲染性能存在比较大的瓶颈,现阶段最好的电脑可能也带不动1080P, 30帧的视频。只适合小视频窗口的渲染。

硬件渲染则是使用硬件加速接口,直接将视频渲染到显示器,通常对yuv流的支持都很友好,不需要做格式转换,同时性能会高很多,轻松视频4K视频的高帧率渲染。然而硬件渲染需要将视频流转换成硬件支持的Texture, 并占满整个HWND窗口空间,导致很难和GDI绘制的界面元素融合。

有没有再使其美的办法呢?

659063-20221220182257052-12055553.png

我一直在问为什么手机上做视频渲染这么简单,视频和其它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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK