如何将 Android MediaCodec Surface 连接到 Vulkan
How to connect Android MediaCodec Surface to Vulkan
我对使用 Android MediaCodec 解码以及通过 Surface 将 YUV 馈送到 OpenGL 纹理有很好的理解。我想用 Vulkan 做一些类似的事情。但是我没有成功找到任何文档或示例代码。
我的问题是:如何连接以下管道?
MediaCodec Video Decoder ⇨ Surface ⇨ texture ⇨ Vulkan
详情
- 视频解码器配置使用 MediaCodec#configure
- 曲面是一个 Android 曲面 (link to API, link to arch.)
OpenGL 比较
为了比较,在 OpenGL 的情况下,Android 表面的构造和使用方式如下
textureId = glGenTextures( &textureId )
surface = new Surface( new SurfaceTexture( textureId ) )
mediaCodec.configure( surface )
仅供参考:我不太了解 Android。
使用 vkCreateImage
创建 Vulkan“纹理”。与您的 OpenGL ES 示例不同,有一些额外的工作明确地管理内存(使用 vkAllocateMemory
和 vkBindImageMemory
)。
下一步将是艰难的一步。 Vulkan 显然还没有 SurfaceTexture
。
最近发布了从 Vulkan 方面提高效率的工作。
IE。 VK_KHX_external_memory
和 Vulkan 的相关扩展。所以希望 Vulkan 的官方 Android SurfaceTexture
也能来。
也就是说,您可以自己实现一个新的 SurfaceTexture
。或者至少将 Vulkan 图像“导入”到 OpenGL ES 中。问题是:
扩展被认为是实验性的更新:不再是
- 驱动程序可能无论如何都不支持扩展
- 编程可能并不简单,而且可能需要在 Android.
上处理一些低级 linux API
因此,目前最好的方法是创建一些 shim,它会复制数据。
我会:
似乎 MediaCodec
可以使用 ByteBuffer
而不是 Surface
。 ByteBuffer
可以包装原始 bytes[]
.
创建 VkImages
和 VkBuffer
。设备内存中的图像(我们想要的结果对象)。以及Host端的Buffer(方便复制)
Map (vkMapMemory
),并用 MediaCodec
.
使用的 ByteBuffer
包装主机端缓冲区
每次有新的数据通过在 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
对。
我对使用 Android MediaCodec 解码以及通过 Surface 将 YUV 馈送到 OpenGL 纹理有很好的理解。我想用 Vulkan 做一些类似的事情。但是我没有成功找到任何文档或示例代码。
我的问题是:如何连接以下管道?
MediaCodec Video Decoder ⇨ Surface ⇨ texture ⇨ Vulkan
详情
- 视频解码器配置使用 MediaCodec#configure
- 曲面是一个 Android 曲面 (link to API, link to arch.)
OpenGL 比较
为了比较,在 OpenGL 的情况下,Android 表面的构造和使用方式如下
textureId = glGenTextures( &textureId )
surface = new Surface( new SurfaceTexture( textureId ) )
mediaCodec.configure( surface )
仅供参考:我不太了解 Android。
使用 vkCreateImage
创建 Vulkan“纹理”。与您的 OpenGL ES 示例不同,有一些额外的工作明确地管理内存(使用 vkAllocateMemory
和 vkBindImageMemory
)。
下一步将是艰难的一步。 Vulkan 显然还没有 SurfaceTexture
。
最近发布了从 Vulkan 方面提高效率的工作。
IE。 VK_KHX_external_memory
和 Vulkan 的相关扩展。所以希望 Vulkan 的官方 Android SurfaceTexture
也能来。
也就是说,您可以自己实现一个新的 SurfaceTexture
。或者至少将 Vulkan 图像“导入”到 OpenGL ES 中。问题是:
扩展被认为是实验性的更新:不再是- 驱动程序可能无论如何都不支持扩展
- 编程可能并不简单,而且可能需要在 Android. 上处理一些低级 linux API
因此,目前最好的方法是创建一些 shim,它会复制数据。
我会:
似乎
MediaCodec
可以使用ByteBuffer
而不是Surface
。ByteBuffer
可以包装原始bytes[]
.创建
VkImages
和VkBuffer
。设备内存中的图像(我们想要的结果对象)。以及Host端的Buffer(方便复制)Map (
使用的vkMapMemory
),并用MediaCodec
.ByteBuffer
包装主机端缓冲区每次有新的数据通过在 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
对。