如何直接从Android Surface访问EGL图像以用于MediaCodecvideo解码器?

我目前正在编写一个Android应用程序,我需要cachingvideo帧,以便我可以轻松地来回拖动。

现在,我让android通过为MediaCodec对象的Configure调用提供一个Surface并将render标志设置为true来调用releaseOutputBuffer来解码video帧。

我发现访问解码表面数据的唯一方式(除了解码格式似乎依赖于设备的返回的字节缓冲区之外)是调用连接到Surface的SurfaceTexture上的updateTeximage ,将其附加到GL_TEXTURE_EXTERNAL_OES目标并将其渲染为GL_TEXTURE2D目标纹理我创build自己为了caching它。

我想优化这个caching过程,并能够解码不同线程上的帧。 使用我目前的方法,这意味着我将不得不为video解码器创build另一个EGL上下文,共享上下文等…

我的问题是: 是否有可能访问EGL图像或本地缓冲区数据与Surface关联,而无需调用 updateTexImage

这样我可以cachingegl图像(根据EGL_ANDROID_image_native_buffer不需要EGL上下文)。 这也将caching在YUV格式,这将比我现在caching的原始RGB纹理更有效的存储效率。

Solutions Collecting From Web of "如何直接从Android Surface访问EGL图像以用于MediaCodecvideo解码器?"

简短的回答:不。

较长的回答: Surface封装了一个缓冲区队列 。 ( 编辑:系统现在在这里详细解释。)当你调用updateTexImage() ,如果一个新的dataframe可用,头部的缓冲区被删除,队列中的下一个变为当前的。 调用updateTexImage()是必要的,以查看连续的帧; 没有机制检查缓冲区不在头部。

SurfaceTexture包装SurfaceTexture一个实例。 这个消费者需要生产者(video解码器)以可以用作“硬件纹理”的格式生成数据,即设备的GL实现可以理解的东西。 它可能是也可能不是YUV。 更重要的是,消费者不要求缓冲区可用于“软件”,这意味着你不能假定你可以直接访问数据 – 你需要使用GLES。 (请参阅gralloc标题以查看完整的标志列表。)

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

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