10

我目前正在编写一个 android 应用程序,我需要在其中缓存视频帧,以便我可以轻松地来回切换,几乎没有延迟。

MediaCodec现在,我通过向对象的 Configure 调用提供 SurfacereleaseOutputBuffer并将渲染标志设置为true.

我发现访问解码的表面数据的唯一方法(除了解码返回的字节缓冲区,其格式似乎与设备相关)是调用链接到表面updateTeximage的链接,将其附加到目标并将其渲染到我创建的目标纹理我自己为了缓存它。SurfaceTextureGL_TEXTURE_EXTERNAL_OESGL_TEXTURE2D

我想优化这个缓存过程并能够在不同的线程上解码帧。使用我当前的方法,这意味着我必须为视频解码器创建另一个 EGL 上下文,共享上下文等...

我的问题是:是否可以在不调用的情况下访问与 Surface 关联的 EGL 图像或本机缓冲区数据 updateTexImage

这样我就可以缓存 egl 图像(根据 ,它不需要 EGL 上下文EGL_ANDROID_image_native_buffer)。这也将以 YUV 格式缓存,这将比我现在缓存的原始 RGB 纹理更节省存储。

4

1 回答 1

6

简短的回答:没有。

更长的答案:Surface封装了一个缓冲区队列。(编辑:系统现在在这里详细解释。)当你调用时updateTexImage(),如果有新的数据帧可用,则头部的缓冲区被丢弃,队列中的下一个缓冲区变为当前的。调用updateTexImage()是查看连续帧所必需的;没有检查不在头部的缓冲区的机制。

ASurfaceTexture包装了一个GLConsumer的实例。该消费者要求生产者(视频解码器)以可用作“硬件纹理”的格式生成数据,即设备的 GL 实现可以理解的格式。它可能是也可能不是 YUV。更重要的是,消费者不需要“软件”可以使用缓冲区,这意味着您不能假设您可以直接访问数据——您需要使用 GLES。(有关标志的完整列表,请参阅gralloc 标头。)

这里有什么好处是能够将缓冲区从头部复制BufferQueue到单独的数据结构(BufferArrayList?)而不进行格式转换,但目前没有这样的机制(Android 4.3)。我不知道比您描述的更好的方法(共享 EGL 上下文等)。

更新:我的办公室伙伴有一个建议:使用着色器将缓冲区渲染为两个纹理,一个用于 Y 和 CbCr(在 GLES 3 中,您可以使用 RG 纹理)。这样可以保留 GLES 中的所有操作,而无需扩展到完整的 RGB。在内部,它将MediaCodec输出转换为 RGB 并研磨两次,但这可能比将其复制到用户空间并在 CPU 上自己完成要便宜。

于 2013-09-12T20:10:52.497 回答