Android上最低的摄像头到CPU到GPU的方法

tan*_*avo 7 android opengl-es android-ndk android-camera

我的应用程序需要在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时间帧中实现的,即使是320x240 glTexSubImage2d调用占用了50ms的CPU时间(我猜想,尝试进行纹理调配的不良驱动程序 - 后来在系统更新中显着改善).

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

android.hardware.camera2 API承诺能够将ImageReader和SurfaceTexture连接到捕获会话.不幸的是我无法看到任何方法来确保正确的顺序管道 - 阻止调用updateTexImage()直到CPU处理足够容易,但如果在该处理期间另一帧已到达,则updateTexImage()将直接跳到最新帧.在多个输出中似乎也会有每个队列中帧的独立副本,理想情况下我想避免这些副本.

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

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

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

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

fad*_*den 5

处理视频的最有效方法是完全避免CPU,但听起来这不适合你.公共API通常面向硬件中的所有内容,因为这是框架本身所需要的,尽管RenderScript有一些路径.(我假设您已经看过使用片段着色器的Grafika过滤器演示.)

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

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

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

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

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