5

Android 的 MediaProjection API 有一些问题(实际上更多,但这些是更关键的问题)。阅读图形架构并没有真正的帮助,所以我只是想了解我是否跳过了代码流中的某些内容。

让我们假设:

  1. 我有一个专用的 GL 渲染线程,已初始化,并在其上生成了 GL 纹理。我为纹理设置了 WxH 的默认缓冲区大小。

  2. 我使用 GL 纹理创建了一个 SurfaceTexture,并为此表面纹理创建了一个 Surface。

  3. 通过 MediaProjection 创建一个大小为 WxH 的虚拟显示器,并将其表面设置为上述表面。

问题 1:一切正常(全帧正确输入)或不正常(所有帧都是黑色的;或者例如每帧只有一半可见 - 所有帧的一半相同;或者屏幕的某些部分与其他部分重复部分,有时甚至歪斜)。

问题 2:虽然时间花在一些全屏 GL 游戏中,但经过 FIXED 时间(大约 4 分钟)后,所有传入帧都被冻结(例如,我收到“新”帧,但实际上是一个相同的图像) . 用 glReadPixels 阅读可以确认结果 - 问题是,实际显示超出了该帧。强制它“恢复”的唯一方法是调出状态栏或导航栏,它会立即开始向我发送正确的帧。当然,再过4分钟,它又发生了……

问题 3:在 VirtualDisplay 上调用 resize(),在对 GL 纹理也调用 setDefaultBUfferSize() 之后,最终在 90% 的情况下显示问题 #1(黑色/剪切帧,其他屏幕区域的伪影...... )

我在同一个线程中使用 updateTextureImage -> GL 纹理绘制的调用序列,所以我的正常理解是永远不会发生我以某种方式从半满的 GL 缓冲区或其他东西中读取的情况......对吗?

我还通过将 VirtualDisplay 直接渲染到 MediaCodec 的表面(不涉及自定义 GL)来测试这个问题 - 相同的行为。 更新实际上由于 MediaCodec 具有固定大小的创建表面,因此无法重现该错误,因为我们只能调整虚拟显示器的大小,而不能调整编码器的表面大小,因此这不是真正的错误(但即使这样也可以VirtualDisplay 以某种方式相应地调整表面大小)。

我觉得关闭虚拟显示器时有东西泄漏,或者在创建 VirtualDisplay 之间没有正确初始化,因为它不一致。很可能会发生全新的 MediaProjection 屏幕捕获许可,具有全新的虚拟显示器,具有刚刚创建的表面纹理,最终只会给我半切帧......让我有一张大扑克脸。 ..

PS:所有这一切都发生在装有 Android 6.0.1 的 Nexus 6 上。

4

1 回答 1

1

我放弃了,只是使用新SurfaceTexture 的Surface重新创建了虚拟显示器(但保留了 GL 纹理)。这消除了闪烁和半尺寸的帧。我也有一些 logcat 警告,之前使用的 SurfaceTexture 的 BufferQueue 已被放弃,并且在 VirtualDisplay 上调用 release() 后获得了 1 或 2 个 onFrameAvailable 回调(它可能是异步的,应该等待 stop() 回调,但它得到了那时太复杂了)。

即使在完成所有这些之后,仍然会发生一些非常奇怪的事情:有时捕获只会捕获 MY APPLICATION。如果我向下滑动状态栏或转到主页,一切都会变成黑色(即使我的应用程序位于状态栏窗口后面)。之后唯一的解决方案是关闭/打开屏幕,或将 Camera/Camera2 预览渲染到我的 SurfaceTexture,然后重新创建 VirtualDisplay。关于纹理的幕后肯定有问题。

看起来 VirtualDisplay.resize() 已损坏,同样适用于使用现有 SurfaceTexture 创建新的虚拟显示器。

于 2016-03-30T11:52:20.720 回答