如何将 Android MediaCodec Surface 连接到 Vulkan

How to connect Android MediaCodec Surface to Vulkan

我对使用 Android MediaCodec 解码以及通过 Surface 将 YUV 馈送到 OpenGL 纹理有很好的理解。我想用 Vulkan 做一些类似的事情。但是我没有成功找到任何文档或示例代码。

我的问题是:如何连接以下管道?

MediaCodec Video Decoder ⇨ Surface ⇨ texture ⇨ Vulkan

详情

OpenGL 比较

为了比较,在 OpenGL 的情况下,Android 表面的构造和使用方式如下

 textureId = glGenTextures( &textureId )
 surface = new Surface( new SurfaceTexture( textureId ) )
 mediaCodec.configure( surface )

仅供参考:我不太了解 Android。

使用 vkCreateImage 创建 Vulkan“纹理”。与您的 OpenGL ES 示例不同,有一些额外的工作明确地管理内存(使用 vkAllocateMemoryvkBindImageMemory)。

下一步将是艰难的一步。 Vulkan 显然还没有 SurfaceTexture

最近发布了从 Vulkan 方面提高效率的工作。 IE。 VK_KHX_external_memory 和 Vulkan 的相关扩展。所以希望 Vulkan 的官方 Android SurfaceTexture 也能来。

也就是说,您可以自己实现一个新的 SurfaceTexture。或者至少将 Vulkan 图像“导入”到 OpenGL ES 中。问题是:

  • 扩展被认为是实验性的更新:不再是
  • 驱动程序可能无论如何都不支持扩展
  • 编程可能并不简单,而且可能需要在 Android.
  • 上处理一些低级 linux API

因此,目前最好的方法是创建一些 shim,它会复制数据。
我会:

  1. 似乎 MediaCodec 可以使用 ByteBuffer 而不是 SurfaceByteBuffer 可以包装原始 bytes[].

  2. 创建 VkImagesVkBuffer。设备内存中的图像(我们想要的结果对象)。以及Host端的Buffer(方便复制)

  3. Map (vkMapMemory),并用 MediaCodec.

    使用的 ByteBuffer 包装主机端缓冲区
  4. 每次有新的数据通过在 Vulkan 中提交 vkCmdCopyBufferToImage 复制它。

我省略了很多样板文件(尤其是同步),但希望你明白了。

这目前是不可能的,因为无法从 Vulkan 外部或任何可以导出 Surface 的 SDK Vulkan 对象导入内存对象。查看 VK_KHX_external_memory 和相关扩展,了解其中的某些部分在未来可能如何工作。

编辑 2018-05-23:现在可以使用 VK_ANDROID_external_memory_android_hardware_buffer 扩展及其依赖的扩展。您可以使用 AImageReader_newWithUsage() 创建与 GPU 采样兼容的 AImageReader。从 AImageReader 获取 ANativeWindow 并将其用作 AMediaCodec 的输出表面。然后,对于您收到的每张图片,获取 AHardwareBuffer 并使用扩展名将其导入 VkDeviceMemory/VkImage 对。