[英]How to access EGL Image directly from Android Surface for use in MediaCodec video decoder?
我正在编写一个Android应用程序,我需要缓存视频帧,以便我可以轻松地来回转移,几乎没有延迟。
现在我通过向MediaCodec
对象的Configure调用提供Surface并调用releaseOutputBuffer
并将render标志设置为true
来让android解码视频帧。
我发现访问解码表面数据的唯一方法(除了解码返回的bytebuffer,其格式似乎与设备有关)是调用链接到Surface的SurfaceTexture
上的updateTeximage
,将其附加到GL_TEXTURE_EXTERNAL_OES
目标并将其渲染到GL_TEXTURE2D
我自己创建的目标纹理是为了缓存它。
我想优化这个缓存过程,并能够解码不同线程上的帧。 使用我当前的方法,这意味着我将不得不为视频解码器创建另一个EGL上下文,共享上下文等...
我的问题是: 是否可以在不调用 updateTexImage
情况下访问与Surface关联的EGL图像或本机缓冲区数据 ?
这样我就可以缓存egl图像(根据EGL_ANDROID_image_native_buffer
不需要EGL上下文)。 这也将以YUV格式缓存,这比我现在缓存的原始RGB纹理更具存储效率。
简答:不。
更长的答案: Surface
封装了一个缓冲区队列 。 ( 编辑: 此处详细解释了系统。)当您调用updateTexImage()
,如果有新的数据帧可用,则会丢弃头部的缓冲区,队列中的下一个缓冲区将变为当前状态。 调用updateTexImage()
是查看连续帧所必需的; 没有机制可以检查不在头部的缓冲区。
一个SurfaceTexture
包装的实例GLConsumer 。 该消费者要求制作者(视频解码器)以可以用作“硬件纹理”的格式生成数据,即设备的GL实现可以理解的东西。 它可能是也可能不是YUV。 更重要的是,消费者不要求缓冲区可用于“软件”,这意味着您不能假设您可以直接访问数据 - 您需要使用GLES。 (有关标志的完整列表,请参阅gralloc标头 。)
这里最好的是能够将缓冲区从BufferQueue
的头部BufferQueue
到单独的数据结构( BufferArrayList
?)而无需进行格式转换,但目前还没有类似的机制(Android 4.3)。 我不知道比你描述的更好的方式(共享EGL上下文等)。
更新:我的办公室伙伴提出了一个建议:使用着色器将缓冲区渲染为两个纹理,一个用于Y和用于CbCr(在GLES 3中,您可以使用RG纹理)。 这保留了GLES中的所有操作,而不会扩展为完整的RGB。 在内部,它会将MediaCodec
输出转换为RGB并通过它进行两次研磨,但这可能比将其复制到用户空间并在CPU上自行完成更便宜。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.