使用Android的MediaProjection API,我遇到了一些问题(实际上更多,但这些问题更为重要)。阅读graphics architecture并没有什么帮助,所以我只想了解我是否在代码流程中跳过了某些内容。
我们假设:
我有一个专门的GL渲染线程,已初始化,并在其上生成GL纹理。我为纹理设置了默认缓冲区大小WxH。
我使用GL纹理创建SurfaceTexture,为此表面纹理创建Surface。
通过MediaProjection创建一个大小为WxH的虚拟显示器,并将其表面设置为上面的表面。
问题1:一切正常(全帧正确进入)或不是(所有帧都是黑色;或者每帧只有一半是可见的 - 所有帧的相同一半;或者屏幕的某些部分是重复到其他部分,有时甚至是倾斜的。)
问题2:在一些全屏幕GL游戏中花费时间,在一段固定的时间(大约4分钟)之后,所有传入的帧都被冻结(例如,我收到“新”帧,但实际上是一帧和相同的图像)。用glReadPixels读取确认结果 - 问题是,实际显示是超过该帧。强制它“恢复”的唯一方法是调出状态栏或导航栏,立即开始向我发送正确的帧。当然,又过了4分钟,又发生了......
问题3:在将调用setDefaultBUfferSize()调用到GL纹理之后调用VirtualDisplay上的resize(),最终会在90%的情况下显示问题#1(黑色/剪切帧,其他屏幕区域的伪像) ...)
我正在使用updateTextureImage的调用序列 - > GL纹理在相同的线程中绘制,所以我的正常理解是它永远不会发生我从某个半满的GL缓冲区读取,或者某种东西......对吗?
我也通过将VirtualDisplay直接渲染到MediaCodec的表面(没有涉及自定义GL)来测试这个问题 - 相同的行为。 更新实际上,由于MediaCodec具有固定大小的创建表面,因此我们只能调整虚拟显示器的大小,而不能调整编码器的表面大小,因此无法重现该错误,因此这不是一个真正的错误(甚至是像这样,VirtualDisplay会以某种方式相应地调整表面大小。)
我觉得在关闭虚拟显示器时有些东西在泄漏,或者在VirtualDisplay的创建之间没有正确初始化,因为它不一致。很有可能一个全新的MediaProjection屏幕捕获权限,全新的虚拟显示器,刚刚创建的表面纹理,最终只会给我一半的框架......让我有一个大的扑克脸。 ..
PS:所有这一切都发生在带有Android 6.0.1的Nexus 6上。
答案 0 :(得分:1)
我放弃了,只是使用新 SurfaceTexture的新曲面(但保留了GL纹理)一起重新创建虚拟显示。这摆脱了闪烁和半尺寸的帧。我还有一些logcat警告说,以前使用的SurfaceTexture的BufferQueue被放弃了,并且在VirtualDisplay上调用release()之后得到了1或2个onFrameAvailable回调(它可能是异步的并且应该等待stop()回调,但在那一点上变得太复杂了。)
即使在完成所有这些之后,仍会发生一些非常奇怪的事情:有时捕获只会捕获我的应用程序。如果我向下滑动状态栏或转到主页,一切都会变为黑色(即使我的应用程序位于状态栏窗口后面)。此后唯一的解决方案是关闭/打开屏幕,或者将Camera / Camera2预览渲染到SurfaceTexture,然后重新创建VirtualDisplay。关于纹理的幕后事情肯定是错误的。
看起来VirtualDisplay.resize()已被破坏,同样适用于使用现有SurfaceTexture创建新的虚拟显示器。