虚拟摄像头搭配高德AR导航出现的内存和cpu问题
最近在处理虚拟摄像头搭配高德AR导航时,出现了一些内存和cpu问题,这里做个初步记录,后面再完善
1.)开一个hal3的后台录相、预览app,再开一个高德AR导航虚拟摄像头。这时cpu消耗最高达到了600%以上, AR导航界面卡顿严重,录相APP录下来的帧丢帧严重。
刚开始是从降cpu着手的,因为AR导航占用的cpu达到了300以上,加上地图的其他进程消耗,高德一个APP就达到了400%以上。
刚开始降cpu手段:
1.在虚拟摄像头hal3的proce*tureRequest函数里,将收到的数据,从yv12转i420,再转rgba的这个过程,合并一个过程。因为yv12和i420的y都是相同的,只是u和发刚好相反,所以直接从yv12指定的位置传给libyuv:i420toRGBA,这样就省去了从yv12拷到i420的这个memcpy过程。因为一张1920*1080的yv12大概有w*h*1.5,有3M左右大小,这个拷贝是非常费时的,所以可以省去8%左右的cpu.
2.)将我们的录相app从api2改为api1。因为api2里面,每一个流都是一个surface,而每一个surface,无论你显示还是不显示,都会在SurfaceTextureRenderer.java里的drawIntoSurfaces函数里去渲染。在只有一个surface时这个渲染过程以及api2的requestThreader线程,app的占用的cpu在60%以上。如果有两个surface,大概还要增加20%左右。我们api2录相时,会有一个preview的suface,一个recorder的surface。如果改用api1的话,这两个渲染过程,就可以省掉,也就是可以省50%以上的cpu.
3.)在mtk的displayClient.out.cpp文件里的handlebuffer函数中,将预览的数据送显代码给动态关闭。让录相app在后台时,就关闭预览,在前台时,就打开预览。少了这个送显的过程,还可以降10%左右的cpu。
4.)因为高德的AR导航用到了ImageReader,而它们将这个ImageReader的获取格式,设置的是YUV_420_888。但是ImageReader里的surface的grallocbuffer的格式,android结构上,都统一默认用的是rgb的。所以在SurfaceTextureRenderer.java的drawIntoSurfaces函数中渲染时,会先通过GLES20.glReadPixels,将当前这一帧的数据,从gpu里拷出来,然后再在外面转成了yuv的,这样才能返回给app正确的格式。但是GLES20.glReadPixels是一个非常耗时耗cpu的操作。而如果app上将imagereader的格式,设为rgba,也就是和surface里的格式保持一致的话,surface渲染时,可以直接使用这数据,而不用去转换。这里可以省掉10%左右的cpu.
通过上面的这些优化,一共省掉了80%以上的cpu。但是这个时候,预览还是非常的卡顿。而我们是8核的cpu,卡顿时最高的cpu才60%多,并没有到极限,且我们已经将cpu的工作频率设为了最大,模式也是全功率工作模式,但是仍然会卡。这时我们怀疑,应该不是cpu的问题了。于是我们开始了内存的优化。
内存:
1.)通过procrank发现在android.hardware.camera.provider@2.4-service进程,占用了60m左右的空间。这个空间有点偏高。于是用dumpsys media.camera查看相关的信息,发现hal3的max HAL buffers为8. 当我们的分辨率为1920*1080时,一张图片大概要3m左右的内存。这里用8个buff的话,就是24m左右。因为我们的cpu是8核,还没有达到使用的极限,显然这个buff个数不需要这么多,减掉一半,用4个,cpu处理速度了来得及。于是将这里改成了4. 省下了12m左右的空间。 但是这个内存,仍然有些不正常,不应该有这么高。但是暂时没有什么头绪,就先去看下高德的app
再 adb shell showmap 268查看268进程的各个.so以及 heap,stack的使用情况,做初步的判断
2.)我们在AR卡的时候,通过free将剩余的空间打了出来,发现只剩几m的空间了。且swap空间里用了几百m。再通过procrank查看AR导航的内存使用情况,从VSS(虚拟耗用内存,包括共享库占用的内存)和uss(进程独自占用的物理内存)发现AR导航一个应用就占了近200m的空间。高德是个大头,但是他们不改,没办法,只能我们去改。
3.)我们经过反复测试,发现AR卡的时候,是车机进入待机后恢复后,变卡的。于是我将待机前的top AR导航和hal3的cpu占用率,以及procrank的uss保存起来,和从待机到唤醒后的cpu、内存对比。发现待机后,hal3的占用率和内存比之前的高了一倍。这时再查看刚刚用adb logcat 抓的log,发现唤醒后,高德又调用了一次cameraService里的connect。也就是说,每次唤醒,他们都重新open了一次camera,但是待机时,他们显然忘记释放camera了。
而hal3的android.hardware.camera.provider@2.4-service进程,正常是在70%左右。如果没有释放的话,会多出70%。内存正常是30m左右,没有释放的话,也多出了30m。
后来通知高德修改后,cpu一共省了这里的70%和前面的几种优化80%,一共省了150%以上。内存40m以上。然后再将fstab.swap里的swapsize大小从1g调到500m。可用空间多了500m。速度一下就上来了,不再卡顿了
本文地址:https://blog.csdn.net/xuhui_7810/article/details/107393920
上一篇: Java 实现常见的非对称加密算法