Qt 性能优化之二:绘制视频方案选择

一、不太推荐使用 QPainter 绘制视频

在 Qidget 上显示视频,一般是通过 paintEvent,由于 QPainter 不是用来渲染视频的,是用来自绘 GUI 的,用的是 CPU 渲染,而不是 GPU,缺乏显卡加速,性能达不到绘制视频的要求。另外,视频绘制也不应该使用事件驱动,使用事件驱动会让绘制操作运行在主线程里,这有可能阻塞 UI 事件响应,显然是不合理的。另外还有以下缺陷:

  • YUV 转 RGB 转换需要消耗大量 CPU;
  • QPainter 大面积绘制效率不高,测试过,如果只是些小预览窗口绘图还行,如果是大的窗口,越大越消耗 CPU,至于全屏则是会卡到爆。

二、推荐使用 QOpenGLWidget 绘制视频

现在一般性能好点的嵌入式板子都有 GPU,支持 OpenGL的话,最推荐使用 Qt 官方自带的 QOpenGLWidget 来绘图。

具体就是显示视频的那个类, 让它继承 QOpenGLWidget,这样使用的是 GPU 渲染,然后重新使用 paintEvent 函数,就不怎么消耗 CPU 了。

三、CPU 绘图推荐使用 SDL、OpenCV 等第三方库

拿到 widget 的窗口句柄(好像是 winid() 这个函数的返回值)或者窗口位置,配合其他工具(opengl、directx 等,在 linux 中我推荐试试 SDL,接口比较友好)自行绘制。如果是嵌入式板子,需要交叉编译 SDL 等库。

四、如果只能使用 QPainter 下的优化方法

如果嵌入式板子没有 GPU,不支持 OpenGL,只能用 CPU 绘图的话,且由于技术原因或个人喜好等等不想使用第三方库的话,只能使用 QPainter,有下面几种优化方法,尤其是双缓冲机制和多线程渲染。


4.1 利用双缓冲机制绘图

方法是先将要绘制的内容绘制在一个图片中,再将图片一次性地绘制到控件上,而不是在绘图事件中进行渲染处理。这里不再赘述,具体请看我以前写的博客:Qt 绘图进阶之二:双缓冲机制与实例


4.2 多线程渲染后更新绘图

可以采用多线程绘制在图像内存,然后通过信号发送 QPixmap,然后在 UI 主线程绘图。


4.3 拆分绘图数据到哈希表,以空间换时间

这里不再赘述,具体请看博客:QT 2d绘图优化(一)


4.4 使用 QPainterPath 优化

批处理所有相同类型的绘画调用,其中一种类型使用相同的画笔和笔。为此,可以使用类 QPainterPath 并使用 addRect 等函数添加所需的对象。确保在绘画功能之外执行此操作!具体可以参考:c++ - QT 5.0中疯狂的CPU使用率


4.5 定义绘制区域

我们只需要把少部分的区域绘制出来,不用绘制整个图标的数据,所以需要定义一个 viewport。


4.6优化绘图指令

  • 裁剪 :将不需要绘制的数据在渲染前裁剪掉
  • 局部更新:没有变动的地方不渲染
  • 分割缓存:分层或分成多个对象,总之将多变元素和少变元素分开,并缓存少变元素

4.7 其它注意事项

  • 显示视频的那个类,设置父类为 nullptr,这样,CPU 占用率会下降一些;

  • QPainter 要设置为 smooth 模式;

  • 最好选择 QWidget 的绘图事件绘图,而不是使用 QLabel 绘图,QLabel 只适合显示单张图片;

  • 如果绘制多张图片,也最好使用 Qidget 的绘图事件绘图,而不是用 QLabel 的 setPixmap;

  • QImage 到 QPixmap 转换耗费的资源较多。将 QImage 在 QLabel 显示容易卡死;

  • 解码后的数据,如果是通过 memcpy 放到缓存中的话,会比较消耗 CPU。

五、总结

Qt 如果需要高频绘制视频的话,根据嵌入式板子是否有 GPU 来进行方案选择:

  • 如果嵌入式板子有 GPU,则使用 EGLFS 平台插件,最推荐使用 Qt 官方自带的 QOpenGLWidget 来绘图;
  • 如果没有 GPU,一般只能使用 LinuxFB 平台插件,推荐使用 SDL、OpenCV 等第三方库;
  • 如果不想使用第三方库的话,那只能使用 QPainter 实现绘图了,就要注意优化了,否则 CPU 占用率很容易偏高。

参考:

如何提高Qt/MFC控件的绘制效率?

用Qt5的Qpainter画视频解码的图像,发现CPU占用极高(50%),有方法能够降低cpu占用吗?


posted @ 2023-02-22 17:48  fengMisaka  阅读(1545)  评论(0编辑  收藏  举报