代码之家  ›  专栏  ›  技术社区  ›  Tomilov Anatoliy

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

  •  7
  • Tomilov Anatoliy  · 技术社区  · 8 年前

    如何以编程方式获取图形应用程序的屏幕截图?应用程序通过DRM/KMS使用EGL API绘制其窗口。

    我使用Ubuntu Server 16.04.3和使用Qt5.9.2编写的图形应用程序,带有EGLFS QPA后端。它从第一个虚拟终端开始(如果需要的话),然后将显示切换到全高清图形模式的输出。

    当我使用实用程序时(例如。 fb2png )在上运行 /dev/fb? ,则只显示第一个虚拟终端的textmode内容( Ctrl+Alt+F1 )保存为屏幕截图。

    很难有EGL API从另一个进程的上下文中获取任何缓冲区的内容(这是不安全的),但可能有某种机制(和库)来访问GPU的最终输出?

    2 回复  |  直到 8 年前
        1
  •  4
  •   Thomas McGuire    8 年前
    1. 一种方法是从应用程序中获取屏幕截图,使用 glReadPixels() . 或使用 QQuickWindow::grabWindow() ,内部使用 glReadPixels() 以正确的方式。这似乎不是你的选择,因为当Qt应用程序冻结时,你需要截屏。

    2. 另一种方法是使用DRM API映射帧缓冲区,然后 memcpy 映射的像素。这是用Python在Chromium操作系统中实现的,可以轻松地转换为C语言,请参阅 https://chromium-review.googlesource.com/c/chromiumos/platform/factory/+/367611 . DRM API还可以由另一个进程使用,而不是执行渲染的Qt UI进程。

        2
  •  1
  •   Community Mohan Dere    6 年前

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

    这个问题相当复杂,并且取决于平台,您似乎在EGL上运行,这意味着嵌入式,在那里,除非您的平台提供,否则您几乎没有选择。

    您可以选择:

    glTexSubImage2D

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

    GLREAD像素

    glReadPixels 是下载已渲染的全部或部分GPU像素的最常见方式。虽然速度很慢,但它可以在GLE和桌面上运行。在桌面上,有一个像样的GPU可以承受高达交互式帧速率,但在嵌入式上要小心 真正地 速度较慢,因为它会停止渲染线程以获取数据(确保了可怕的帧丢失)。您可以保存代码,因为它可以在最小的代码修改下工作。

    像素缓冲区对象(PBO)

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

    帧缓冲区

    mmap() 缓存到文件中,可以轻松获取部分内容。但是要注意,在许多嵌入式系统中,EGL不能在帧缓冲区上工作,而是在不同的“覆盖”上工作,因此您可能正在拍摄它的背景。还需要注意的是,一些多媒体应用程序在EGL上运行UI,在帧缓冲区上运行媒体播放器。因此,如果你只需要捕获视频播放器,这可能适合你。在其他情况下,EGL以复制到帧缓冲区的纹理为目标,它也可以正常工作。

    据我所知,渲染到纹理和流到帧缓冲区是他们制作您在 Ableton Push 2 enter image description here

    更奇特的Dispmanx/OpenWF

    在一些嵌入式系统(尤其是Raspberry Pi和大多数Broadcom Videocore)上,您可以使用DispmanX。 Whichs is really interesting :

    这很有趣:

    访问GPU的最低级别似乎是通过名为Dispmanx的API[…]

    只是想让您完全缺乏使用Dispmanx的鼓励,几乎没有任何示例和认真的文档。

    基本上,DispmanX非常接近纯金属。因此,它甚至比帧缓冲区或EGL更深。非常有趣的东西,因为你可以使用 vc_dispmanx_snapshot() 然后很快地拍到所有东西的快照。说到快速,我的意思是我得到了30FPS的RGBA32屏幕截图,屏幕上没有明显的口吃,在Rasberry Pi上大约有4-6%的额外CPU开销。因为glReadPixels得到了日以继夜的效果,即使对于1x1像素的捕获,也会产生非常明显的掉帧。

    这几乎就是我发现的。

    推荐文章