公共虚拟显示器通过scrcpy访问显示黑屏问题求助
问题场景
基于官方ScreenCapture示例修改代码,给虚拟显示器加上DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC以便scrcpy访问,代码如下:
mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture", mSurfaceView.getWidth(), mSurfaceView.getHeight(), mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, null);
本地SurfaceView预览正常,但scrcpy连接该显示器时完全黑屏,同时scrcpy输出警告:
WARN: Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted
已知普通应用无法创建带FLAG_SUPPORTS_PROTECTED_BUFFERS的安全虚拟显示器,该权限仅系统应用持有。
可行解决方案
方案1:用MediaCodec中转帧数据
不要直接把同一个Surface同时给本地预览和虚拟显示器,而是通过MediaCodec做帧转发,同时支持本地预览和scrcpy的网络传输:
- 初始化H.264编码的MediaCodec,配置对应分辨率和帧率参数。
- 将MediaCodec生成的
InputSurface作为虚拟显示器的输出Surface。 - 启动MediaCodec的异步处理流程,从输出缓冲区中取出编码后的H.264帧。
- 一方面把解码后的帧渲染到本地SurfaceView做预览,另一方面把编码帧通过Socket发送到电脑端,用scrcpy或自定义工具接收播放。
这种方式绕开了虚拟显示器的安全权限限制,不需要依赖Public虚拟显示器的系统捕获能力。
方案2:直接让scrcpy捕获主屏幕(放弃本地预览)
如果不需要本地预览功能,直接使用scrcpy默认的屏幕捕获方式即可,无需自己创建虚拟显示器。如果必须通过应用触发捕获,可以在应用申请到MediaProjection权限后,通过ADB命令将权限传递给scrcpy(需要修改scrcpy源码或使用自定义启动脚本)。
问题根源
普通应用创建的虚拟显示器缺少FLAG_SUPPORTS_PROTECTED_BUFFERS标志,系统会限制敏感内容输出;同时scrcpy作为外部工具,无法正确读取非安全虚拟显示器的帧缓冲区数据,即使加上VIRTUAL_DISPLAY_FLAG_PUBLIC也只能让系统识别该显示器,无法突破权限限制。
内容的提问来源于stack exchange,提问作者Kidades

