如何将Android MediaCodec Surface连接到Vulkan

7

我对使用Android MediaCodec进行解码并将YUV数据通过Surface传输到OpenGL纹理有一定的了解。我希望能够用Vulkan实现类似的功能,但是我没有找到任何相关的文档或样例代码。

我的问题是:我应该如何连接以下的处理流程?

MediaCodec Video Decoder ⇨ Surface ⇨ texture ⇨ Vulkan

详细信息

OpenGL 比较

为了进行比较,在 OpenGL 的情况下,Android Surface 就像这样构建和使用:

 textureId = glGenTextures( &textureId )
 surface = new Surface( new SurfaceTexture( textureId ) )
 mediaCodec.configure( surface )
2个回答

8

目前还无法实现此功能,因为没有办法从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对中。


2

提供信息:我不熟悉Android。

Vulkan中创建“纹理”使用vkCreateImage。与您的OpenGL ES示例不同,这里需要显式管理内存(使用vkAllocateMemoryvkBindImageMemory)。

接下来是更难的一步。目前似乎还没有适用于Vulkan的SurfaceTexture

最近发布了使它从Vulkan方面高效的工作,即Vulkan的VK_KHX_external_memory和相关扩展。因此,希望官方的Android SurfaceTexture也会出现。

话虽如此,您可以自己实现一个新的SurfaceTexture。或者至少将Vulkan图像“导入”到OpenGL ES中。但这样做有以下问题:

  • 这些扩展被认为是实验性的 更新:不再是实验性的
  • 驱动程序可能尚未支持这些扩展
  • 编程可能不是很简单,还可能需要在Android上处理一些低级Linux API。

因此,现在最好的方法是创建一些中间层,以便复制数据。
我会:

  1. 似乎MediaCodec能够使用ByteBuffer而不是Surface。并且ByteBuffer可以包装原始的bytes[]

  2. 创建VkImagesVkBuffer。在设备内存中创建Image(我们想要的结果对象)。在主机上创建Buffer(以便于复制)。

  3. 使用vkMapMemory进行映射,并使用MediaCodec使用的ByteBuffer包装主机端缓冲区。

  4. 每次有新数据时,使用vkCmdCopyBufferToImage提交Vulkan进行复制。

我省略了很多样板文件(特别是同步),但希望您能理解。


谢谢你的回答。你真的期望使用Vulkan比使用GL在处理大型视频时更快吗?在我看来,额外的复制操作会压倒使用Vulkan相对于GL所带来的任何开销减少。 - griffin2000
@griffin2000 如果你所说的“大视频”是指普通视频播放方面的原始性能提升,我不会指望Vulkan可以实现这一点。 - krOoze
但是会慢很多吗?我怀疑这样做会比GL等效方式更慢。因此,在复制所有视频帧的情况下(除非您有非常低分辨率的视频或大量3D绘制调用),在其余应用程序中进行更快的3D调用的开销优势将完全被抵消。这是否正确? - griffin2000
@griffin2000 我不太有信心回答这个问题。可能取决于设备、大小和复制的频率,以及其他应用程序中的“3D调用”。但是,现代RAM可以快速推送大量数据。我提供上述方法只是作为一种绝望或懒惰的解决方法。 - krOoze
我需要以30fps处理4K视频。这个“垫片”解决方案由于复制而太慢了,结果只有不到10fps。 - Peter Tran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接