获取EGL DRM/KMS应用程序的屏幕截图

7
如何以编程方式获取图形应用程序的屏幕截图?应用程序使用EGL API通过DRM / KMS绘制其窗口。
我使用Ubuntu Server 16.04.3和使用EGLFS QPA后端编写的Qt 5.9.2图形应用程序。它从第一个虚拟终端开始(如果有影响),然后将显示切换到完整高清图形模式输出。
当我使用实用程序(例如fb2png)对/dev/fb?进行操作时,只保存第一个虚拟终端(Ctrl + Alt + F1)的文本模式内容作为屏幕截图。
很难想象,有EGL API可以从另一个进程的上下文中获取任何缓冲区的内容(这将是不安全的),但也许有一些机制(和库)可以访问GPU的最终输出?

也许可以制作一个 shim 库,用于转发 EGL 调用,并在启动应用程序时使用 LD_PRELOAD 加载它。 - Velkan
@Velkan 有趣的想法,谢谢。 即使图形应用程序的进程没有响应,我仍然需要看到屏幕。 - Tomilov Anatoliy
2个回答

4
  1. 一种方法是从应用程序内部获取屏幕截图,使用glReadPixels()读取后缓冲区的内容。或者使用QQuickWindow::grabWindow(),它在正确的方式下内部使用glReadPixels()。但这似乎不适用于你,因为你需要在Qt应用程序冻结时进行截图。

  2. 另一种方法是使用DRM API映射帧缓冲区,然后memcpy映射像素。在Chromium OS中使用Python实现,并且可以轻松转换成C语言,详情请参见https://chromium-review.googlesource.com/c/chromiumos/platform/factory/+/367611。DRM API也可以被用于渲染的Qt UI进程之外的其他进程。


1

这是一个非常有趣的问题,我从多个角度解决了这个问题。

这个问题相当复杂,取决于平台,你似乎在运行EGL,这意味着嵌入式系统,除非你的平台提供其他选项,否则你的选择很少。

你可以选择以下选项:

glTexSubImage2D

glTexSubImage2D 可以将OpenGL纹理中的多种缓冲区复制到CPU内存。不幸的是,在GLES 2/3中不支持它,但是你的嵌入式提供商可能通过扩展支持它。这很好,因为你可以渲染到FBO或者从特定的纹理中获取像素。它还需要最少的代码修改。

glReadPixels

glReadPixels 是下载已经渲染的GPU像素的最常见方式,虽然速度较慢,但适用于GLES和桌面。在带有良好GPU的桌面上,可承受交互式帧速率,但请注意,在嵌入式设备上可能非常缓慢,因为它会停止您的渲染线程以获取数据(保证了可怕的帧率下降)。您可以节省代码,因为它可以通过最小的代码修改来实现。

像素缓冲对象(PBO)

一旦您开始进行真正的研究,PBO 就会出现在这里和那里,因为它们可以异步地工作。它们通常不支持嵌入式设备,但即使在普通GPU上也可以很好地工作。设置起来有点棘手,需要特定的渲染修改。

帧缓冲

在嵌入式系统中,有时您已经渲染到了帧缓冲区,因此可以直接获取像素。这在桌面上也适用。您甚至可以使用mmap()将缓冲区映射到文件并轻松获取部分内容。但请注意,在许多嵌入式系统中,EGL不在帧缓冲区上工作,而是在另一个“叠加层”上工作,因此您可能会捕获其背景。还要注意的是,一些多媒体应用程序在EGL上运行UI,并在帧缓冲区上运行媒体播放器。因此,如果您只需要捕获视频播放器,则可能适用于您。在其他情况下,EGL会针对纹理进行定位,然后将其复制到帧缓冲区,这也可以正常工作。
据我所知,将渲染到纹理并流式传输到帧缓冲区是制作Ableton Push 2上看到的漂亮Qt UI的方法。enter image description here 更多异国情调的Dispmanx/OpenWF。
在一些嵌入式系统中(特别是树莓派和大多数Broadcom Videocore),您有DispmanX。这真的很有趣: Whichs is really interesting
这很有趣:
最低级别访问GPU的API似乎是称为Dispmanx的API[...]。
它继续说...
只是为了让你对使用Dispmanx感到完全不鼓舞,几乎没有任何示例和严肃的文档。
基本上,DispmanX非常接近裸机。因此,它甚至比framebuffer或EGL更深入。这真的很有趣,因为您可以使用vc_dispmanx_snapshot()并快速获取所有内容的快照。快速的意思是我在Raspberry Pi上捕获30FPS RGBA32屏幕截图,屏幕上没有明显的卡顿,额外的CPU开销约为4〜6%。晚上和白天,因为即使对于1x1像素捕获,glReadPixels也会产生非常明显的帧掉落。
那就是我找到的。

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