很多年没有写过东西了,换工作后使用Qt,很多东西都是在CSDN上找,这里也记录一些碰到的问题和解决方法。
目前做的产品需要有一个倒车影像(根据功能不同,可能还需要更多的摄像头显示)。之前的项目已经有了一个摄像头显示的实现,是基于 Qt Widget的方式,目前项目是使用QML做界面,如何实现摄像头功能就成了一个问题。
1. QML有一个MultiMedia的model, 但是这个在我们的系统还没有包含,所以用不了。
2. 在QML中嵌入Widget来显示。
3. 实现一个QML的model,直接在QML中调用这个model就可以。
目前后面两种方法都实现了,但是QML的方式有点问题。所以暂时使用第二种方式来做。
如何在QML中使用Widget,网上查了资料,好多都是在Widget中使用QML的,但是如何在QML中使用Widget的很少,还有提到说无法再QML中使用Widget的。 后来找到这个帖子的内容,在Main函数调用Widget,就可以把这个Widget显示在QML的界面中。
https://blog.csdn.net/r5014/article/details/72528418
要在QML中使用Widget,在Main函数中,要使用QApplication app(argc,argv)。而不能用QGuiApplication app(argc,argv)。之后可以通过调用setVisible来控制该Widget是否显示。
在解决了上述问题之后, 同事在测试时发现,在切入到倒车影像界面后, CPU使用率达到了40%多。如果有2个Camera界面,CPU使用可以达到将近90%。 同事比较疑惑, 我们的设备上是有GPU的,为什么CPU占用会这么高。
这个问题很难搞啊,Qt是换工作刚学,底层驱动也看不到。Camera的实现是使用GStreamer的结构,OpenGL也完全不懂。每一部分都有的好研究一番,感觉真的是无从下手。 但是工作还是要做的,Camera的实现是使用GStreamer. 使用了imxv4l2src, videoscale和qt5videosink这三个element。qt5videosink直接包办了图像的显示, 这个element有个函数“paint”,我们只需要把Qt Painter指针和需要显示的尺寸位置作为参数发给它就可以,剩下的工作就不用管了。 但是现在要看为什么CPU占用高,图像数据都拿不到,怎么进行下一步研究? 好在GStreamer有提供一个sink element, appsink。这个element可以暴露出最后的数据供应用程序使用。那么就把原来的pipeline改了,最后的sink element把qt5videosink换成appsink。 我们这里没有直接使用appsink,因为我们使用的QtGStreamer,是把GStreamer弄到Qt环境下的,简单说是把很多GStreamer的函数重新封装了一下,方便在Qt下使用。 通过appsink,拿到每一帧的图像数据,这个数据是I420的,而最后的显示是需要RGB格式,这里就需要把I420转成RGB,利用OpenGL的Shader,可以把这部分装换的工作交给GPU去做。 我们只需要创建Texture,并把appsink这里拿到的数据贴到Texture上,后续就由GPU自己去完成了。 按照这个做出来,最后的CPU使用还是在40%。 后续又查了一些资料,因为在贴图到Texture上时调用glTexImage2D,执行这个函数等于做了内存拷贝, 把应用程序(Client)的图像传到OpenGL(Server) 的Buffer。这个操作是CPU介入的,CPU的消耗应该是花在内存拷贝上了。 后续把摄像头的刷新显示的频率改低了一些,100ms一次的话,CPU的使用率就下降到20%了。
那么有没有办法再对这个内存拷贝进行优化呢? 应该是可以的,搜到这个文章,
https://blog.csdn.net/panda1234lee/article/details/51546502
使用PBO可以将glTexImage2D的内存拷贝由DMA来完成。 不过这里涉及到对应PBO属性的支持,目前OpenGL/ES2.0 并不支持PBO的PACK和UNPACK属性,所以这个是没法使用的。 据说是OpenGL/ES3.0 才支持这个属性。 所以目前就只能先这样了。