Android调整VirtualDisplay的大小

Adr*_*ețu 5 android mediacodec android-mediaprojection

使用Android的MediaProjection API,我遇到了一些问题(实际上更多,但这些问题更为重要).阅读图形架构并不会有所帮助,所以我只想了解我是否在代码流中跳过了某些内容.

我们假设:

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

  2. 我使用GL纹理创建SurfaceTexture,为此表面纹理创建Surface.

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

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

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

问题3:调用VirtualDisplay上的resize(),同时调用setDefaultBUfferSize()到GL纹理后,最终在90%的情况下展示问题#1(黑色/切割帧,其他屏幕区域的工件...... )

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

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

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

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

Adr*_*ețu 1

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

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

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