gpt4 book ai didi

android - Android上的零拷贝相机处理和渲染管道

转载 作者:可可西里 更新时间:2023-11-01 16:01:11 24 4
gpt4 key购买 nike

我需要对实时摄像机数据(仅来自Y平面)进行CPU端只读处理,然后在GPU上进行渲染。在处理完成之前,不应该渲染帧(因此,我并不总是希望从摄像机渲染最新的帧,而只是想渲染CPU端已完成处理的最新帧)。渲染与摄影机处理是分离的,即使摄影机帧到达的速率低于该速率,目标还是要达到60 FPS。

Lowest overhead camera to CPU to GPU approach on android上有一个相关但较高级的问题

为了更详细地描述当前设置:我们有一个用于相机数据的应用程序侧缓冲池,其中的缓冲区为“空闲”,“显示中”或“待显示”。当来自摄像机的新帧到达时,我们将获取一个可用缓冲区,将其存储在其中(如果实际数据位于某些系统提供的缓冲池中,则将其存储在其中),进行处理并将结果存储在缓冲区中,然后将缓冲区设置为“待显示”。在渲染器线程中,如果在渲染循环开始时有任何缓冲区“待显示”,我们将其锁存为一个“在显示中”,渲染照相机,并使用从该显示器计算出的已处理信息来渲染其他内容。相机镜框。

感谢@fadden对上面链接的问题的回答,我现在了解了android camera2 API的“并行输出”功能在各种输出队列之间共享缓冲区,因此,至少在现代android上,不应该涉及数据的任何拷贝。

在一条评论中,有人建议我可以同时锁住SurfaceTexture和ImageReader输出,并且只需“坐在缓冲区上”,直到处理完成即可。不幸的是,由于我们仍然希望以60 FPS的速度进行分离的渲染,因此我认为这不适用于我的情况,并且在处理新的帧以确保不会出现问题时,仍然需要访问上一帧不同步。

我想到的一种解决方案是拥有多个SurfaceTexture-在我们的每个应用程序端缓冲区中都有一个(我们目前使用3个)。通过这种方案,当我们获得一个新的相机框架时,我们将从应用程序端池中获得一个空闲缓冲区。然后,我们将在ImageReader上调用acquireLatestImage()以获取要处理的数据,并在可用缓冲区的SurfaceTexture上调用updateTexImage()。在渲染时,我们只需要确保“in display”缓冲区中的SufaceTexture是绑定(bind)到GL的SufaceTexture,并且大多数情况下所有内容都应该同步(因为@fadden评论说,调用updateTexImage()acquireLatestImage()之间存在竞争但是该时间窗口应该足够小,以使其变得很少见,并且无论如何使用缓冲区中的时间戳可能是可分解且可修复的)。

我在文档中注意到,只有将SurfaceTexture绑定(bind)到GL上下文时才能调用updateTexImage(),这表明我也需要在相机处理线程中使用GL上下文,以便相机线程可以在“免费”的SurfaceTexture上执行updateTexImage()。缓冲区,而渲染线程仍能够从“显示中”缓冲区中的SurfaceTexture进行渲染。

因此,对于以下问题:

  • 这似乎是明智的做法吗?
  • SurfaceTextures基本上是共享缓冲池周围的轻包装器吗,还是它们消耗了一些有限的硬件资源,应该谨慎使用?
  • SurfaceTexture调用是否都足够便宜,以至于使用多个调用仍然比仅复制数据大有裨益?
  • 是否计划让两个线程具有不同的GL上下文并在每个线程中绑定(bind)不同的SurfaceTexture,这是否可行?或者我是否正在寻求一个痛苦而多虫的驱动程序?

  • 听起来很有前途,我将试一试。但我认为值得在这里询问,以防万一有人(基本上是@fadden!)知道我忽略的任何内部细节,这将使它成为一个坏主意。

    最佳答案

    有趣的问题。

    背景资料

    具有多个具有独立上下文的线程非常常见。每个使用硬件加速的View渲染的应用程序在主线程上都有一个GLES上下文,因此任何使用GLSurfaceView(或使用SurfaceView或TextureView和一个独立的渲染线程滚动自己的EGL)的应用程序都在积极地使用多个上下文。

    每个TextureView内部都有一个SurfaceTexture,因此任何使用多个TextureViews的应用程序都在单个线程上具有多个SurfaceTexture。 (该框架的实现中实际上是had a bug,它导致了多个TextureViews的问题,但这是一个高级问题,而不是驱动程序问题。)

    SurfaceTexture是a/k/a GLConsumer,不会进行大量处理。当帧从源(在您的情况下为摄像机)到达时,它将使用一些EGL函数将缓冲区“包装”为“外部”纹理。您不能在没有EGL上下文的情况下进行这些EGL操作,这就是为什么SurfaceTexture必须附加到其中的原因,并且如果当前的上下文不正确,也无法将新框架放入纹理中。您可以从the implementation of updateTexImage() 中看到,它正在使用缓冲区队列,纹理和围墙来做很多不可思议的事情,但是它们都不要求复制像素数据。您真正占用的唯一系统资源是RAM,如果要捕获高分辨率图像,这并不是很重要的事情。

    连接

    EGL上下文可以在线程之间移动,但一次只能在一个线程上“当前”。来自多个线程的同时访问将需要大量不良同步。给定线程只有一个“当前”上下文。 OpenGL API已从具有全局状态的单线程演变为多线程,并且他们没有重写API,而是将状态推到了线程本地存储中,因此采用了“当前”的概念。

    可以创建在它们之间共享某些东西(包括纹理)的EGL上下文,但是如果这些上下文在不同的线程上,则在更新纹理时必须非常小心。 Grafika提供了getting it wrong的一个很好的例子。

    SurfaceTextures构建在具有生产者-消费者结构的BufferQueue之上。 SurfaceTextures的有趣之处在于它们同时包含了两面,因此您可以在一个过程中将数据提供到另一侧,而另一侧则可以拉出数据(例如,与SurfaceView不同,那里的使用者很远)。像所有Surface东西一样,它们是在Binder IPC之上构建的,因此您可以从一个线程提供Surface,并在另一个线程(或进程)中安全地updateTexImage()。安排API,以便您在用户端(您的过程)创建SurfaceTexture,然后将引用传递给生产者(例如,主要在mediaserver过程中运行的相机)。

    实现

    如果您经常连接和断开BufferQueue,则会导致大量开销。因此,如果要让三个SurfaceTextures接收缓冲区,则需要将所有三个连接到Camera2的输出,并让它们全部接收“广播的缓冲区”。然后,您将以循环方式updateTexImage()。由于SurfaceTexture的BufferQueue在“异步”模式下运行,因此每次调用时都应始终获取最新的帧,而无需“耗尽”队列。

    直到Lollipop时代的BufferQueue多输出更改和引入Camera2之前,这种安排才真正可行,所以我不知道是否有人尝试过这种方法。

    所有SurfaceTextures都将附加到相同的EGL上下文,最好是在View UI线程之外的其他线程中,因此您不必为当前问题而战。如果要从另一个线程中的第二个上下文访问纹理,则需要使用SurfaceTexture attach/detach API调用,该调用明确支持此方法:

    A new OpenGL ES texture object is created and populated with the SurfaceTexture image frame that was current at the time of the last call to detachFromGLContext().



    请记住,切换EGL上下文是用户方的操作,与相机的连接无关,这是生产方的操作。在上下文之间移动SurfaceTexture所涉及的开销应该很小-小于 updateTexImage()-但是您需要采取通常的步骤来确保线程之间进行通信时的同步。

    太糟糕了,ImageReader缺少 getTimestamp()调用,因为这将大大简化从相机匹配缓冲区的过程。

    结论

    使用多个SurfaceTextures缓冲输出是可能的,但很棘手。我可以看到乒乓缓冲区方法的潜在优势,其中一个ST用于在线程/上下文A中接收帧,而另一个ST用于在线程/上下文B中进行渲染,但是由于您是在真实环境中操作时间,除非您试图延长时间,否则我认为额外的缓冲没有任何值(value)。

    与往常一样,建议阅读 Android System-Level Graphics Architecture doc

    关于android - Android上的零拷贝相机处理和渲染管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37592934/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com