在Android上使用CPU到GPU的最低开销相机

我的应用程序需要在cpu上对实时相机帧进行一些处理,然后再在GPU上进行渲染.还有一些其他的东西在GPU上呈现,这取决于cpu处理的结果;因此,保持所有内容同步非常重要,这样我们就不会在GPU上渲染帧本身,直到该帧的cpu处理结果也可用.

问题是在Android上这个最低的开销方法是什么?

在我的情况下cpu处理只需要一个灰度图像,因此Y平面打包的YUV格式是理想的(并且往往与相机设备的原生格式很好地匹配). NV12,NV21或全平面YUV都可以提供理想的低开销灰度访问,因此在cpu方面是首选.

在原始相机API中,setPreviewCallbackWithBuffer()是将数据输入cpu进行处理的唯一合理方法.这使得Y平面分离,因此非常适合cpu处理.将此框架提供给OpenGL以便以低开销方式呈现是更具挑战性的方面.最后,我编写了一个NEON颜色转换例程来输出RGB565,并且只需使用glTexSubImage2d就可以在GPU上使用它.这是在Nexus 1时间帧中首次实现的,即使是320×240 glTexSubImage2d调用也需要50ms的cpu时间(我猜想,尝试进行纹理调配的不良驱动程序 – 后来在系统更新中显着改善).

回到那一天,我研究了像eglImage扩展这样的东西,但它们似乎不适用于用户应用程序,也没有足够的文档记录.我对内部android GraphicsBuffer类进行了一些研究,但理想情况下希望保留在受支持的公共API的世界中.

android.hardware.camera2 API承诺能够将ImageReader和SurfaceTexture连接到捕获会话.不幸的是我无法看到任何确保正确的顺序管道的方法 – 在cpu处理完毕之前暂停调用updateTexImage()很容易,但如果在处理过程中另一帧已经到达,那么updateTexImage()将直接跳到最新帧.在多个输出中似乎也会有每个队列中帧的独立副本,理想情况下我想避免这些副本.

理想情况下,这就是我想要的:

>相机驱动程序使用最新帧填充一些内存
> cpu获取指向内存中数据的指针,可以读取Y数据而无需复制
>当帧准备就绪时,cpu处理数据并在我的代码中设置一个标志
>开始渲染帧时,检查新帧是否准备就绪
>调用一些API来绑定与GL纹理相同的内存
>准备好较新的帧时,将保留前一帧的缓冲区释放回池中

我无法看到在Android上使用公共API完全实现零拷贝样式的方法,但是最接近它的是什么?

我试过的一个疯狂的事情似乎有用,但没有记录:ANativeWindow NDK API可以接受数据NV12格式,即使适当的格式常量不是公共标题中的那个.这允许通过memcpy()填充SurfaceTxture的NV12数据,以避免cpu端颜色转换以及glTexImage2d中驱动程序端发生的任何混乱.这仍然是数据的额外副本,虽然感觉它应该是不必要的,并且再次因为它没有文档可能不适用于所有设备.支持的顺序零拷贝相机 – > ImageReader – > SurfaceTexture或同等产品将是完美的.

解决方法

处理视频的最有效方法是完全避免cpu,但听起来这不是你的选择.公共API通常适用于在硬件中执行所有操作,因为这是框架本身需要的内容,尽管RenderScript有一些路径. (我假设您已经看过使用片段着色器的 Grafika filter demo.)

访问cpu上的数据用于表示慢速Camera API或使用GraphicBuffer和相对模糊的EGL功能(例如this question). ImageReader的目的是提供对来自相机的YUV数据的零拷贝访问.

你无法真正序列化相机 – > ImageReader – > SurfaceTexture作为ImageReader没有“转发缓冲区”API.这是不幸的,因为这将使这个微不足道.您可以尝试复制SurfaceTexture所做的事情,使用EGL函数将缓冲区打包为外部纹理,但是再次进入非公共GraphicBuffer-land,我担心缓冲区的所有权/生命周期问题.

我不确定并行路径如何帮助你(Camera2 – > ImageReader,Camera2 – > SurfaceTexture),因为发送到SurfaceTexture的内容不会有你的修改. FWIW,它不涉及额外的副本 – 在Lollipop或其周围,BufferQueue已更新,允许单个缓冲区通过多个队列.

完全有可能有一些我尚未见过的新奇特API,但据我所知,你的ANativeWindow方法可能就是胜利者.我怀疑使用其中一种相机格式(YV12或NV21)比NV12更好,但我不确定.

如果您的处理时间过长,您将丢帧,但除非您的处理不均匀(某些帧比其他帧花费的时间长),否则无论如何都要丢帧.再次进入非公共API的领域,您可以将SurfaceTexture切换到“同步”模式,但如果缓冲区填满,您仍然会丢帧.

相关文章

这篇“android轻量级无侵入式管理数据库自动升级组件怎么实现...
今天小编给大家分享一下Android实现自定义圆形进度条的常用方...
这篇文章主要讲解了“Android如何解决字符对齐问题”,文中的...
这篇文章主要介绍“Android岛屿数量算法怎么使用”的相关知识...
本篇内容主要讲解“Android如何开发MQTT协议的模型及通信”,...
本文小编为大家详细介绍“Android数据压缩的方法是什么”,内...