OBS的插件-画板实现(基于Qt)
简介
OBS基于OpenGL和D3D11实现了一个通用的图形库,可以利用这个图形库来实现简单的画板,至于更复杂的画板实现的原理也是一样的。实现图如下。

原理
说明一下,因为OBS自带的做图非常麻烦且无法满足要求,这里使用Qt自带的QPainter进行内存做画,然后输出RGBA像素数据。
在使用插件之前我们要对插件进行注册
实现方式一:obs_source_output_video
obs_source_output_video使用异步视频源,注意插件的output_flags使用OBS_SOURCE_ASYNC_VIDEO这个标志,当画面需要更新时,使用obs_source_output_video将帧输出源中。
大致代码如下:
上述代码很好地展示了绘制后立即输出到源上,但上面的代码有一定的性能问题。
问题:当鼠标事件瞬时非常多时,会出现fps过高导致CPU和内存暴涨,那么这时候,我们可以加一个定时器解决,比如我们限定最多30fps。
我们修改了updateRect代码,使得将更新的频率固定住,这样不管鼠标事件多么的多,我们最多只会33ms更新一次(fps=30)。
上面的代码看上去比之前还要好了,但还是有优化的空间,因为每一次更新的是局部图片,但是输出却是完整的像素,会重复拷贝内存像素数据到显存,分辨率较小时体现不出来,一是分辨率稍微大一点也会有严重的内存和CPU性能问题,此时这种方法已经无法满足要求了。
实现方式二:使用纹理
第一种方式使用了异步视频源,这种方式在需要的时候输出帧就可以了,但是有一定的性能问题,那么可以可以使用纹理贴图的方法。如果要使用纹理贴图我们首先要指定插件的渲染回调函数。
接下来,我们将将内存数据贴到纹理上。
这样就实现了对纹理的贴图,但是上面的方法还有一个性能问题。问题在于,只要渲染就将所有像素数据拷贝到显存,显然是没有必要的。我们应该使用局部更新,在需要更新的时候将那些需要更新的像素拷贝到显卡。也就是dirtyRect那个部分。很遗憾的事OBS没有这个接口,所以我们自己实现一个。
在实现之前我们看一下全局更新的代码,gs_texture_set_image如下。
然后在调用的时间传入dirtyRect就可以了。
到此,所以优化就结束啦。
实现
代码整理中,即将扩充各种图形,联系[email protected]
Last updated