[英]Get screenshot of EGL DRM/KMS application
如何以編程方式獲取圖形應用程序的屏幕截圖? 應用程序通過 DRM/KMS 使用 EGL API 繪制其窗口。
我使用 Ubuntu Server 16.04.3 和使用 Qt 5.9.2 編寫的圖形應用程序和 EGLFS QPA 后端。 它從第一個虛擬終端(如果重要)開始,然后以全高清圖形模式將顯示切換到輸出。
當我使用在/dev/fb?
上運行的實用程序(例如fb2png
)時/dev/fb?
,然后只有第一個虛擬終端( Ctrl+Alt+F1 )的文本模式內容被保存為屏幕截圖。
幾乎沒有 EGL API 可以從另一個進程的上下文中獲取任何緩沖區的內容(這將是不安全的),但是也許有某種機制(和庫)可以訪問 GPU 的最終輸出?
一種方法是從應用程序中獲取屏幕截圖,使用glReadPixels()
讀取后台緩沖區的內容。 或者使用QQuickWindow::grabWindow() ,它在內部以正確的方式使用glReadPixels()
。 這似乎不是您的選擇,因為您需要在 Qt 應用程序凍結時截取屏幕截圖。
另一種方法是使用 DRM API 來映射幀緩沖區,然后memcpy
映射的像素。 這是在 Chromium OS 中使用 Python 實現的,可以輕松轉換為 C,請參閱https://chromium-review.googlesource.com/c/chromiumos/platform/factory/+/367611 。 除了進行渲染的 Qt UI 進程之外,其他進程也可以使用 DRM API。
這是一個非常有趣的問題,我從多個角度解決了這個問題。
問題非常復雜並且取決於平台,您似乎在 EGL 上運行,這意味着嵌入式,除非您的平台提供,否則您幾乎沒有選擇。
您擁有的選項是:
glTexSubImage2D可以將多種緩沖區從 OpenGL 紋理復制到 CPU 內存。 不幸的是,GLES 2/3 不支持它,但您的嵌入式提供商可能通過擴展支持它。 這很好,因為您可以渲染到 FBO 或從您需要的特定紋理中獲取像素。 它還需要最少的代碼交互。
glReadPixels是下載已渲染的全部或部分 GPU 像素的最常用方法。 盡管速度很慢,但它適用於 GLES 和桌面。 在具有不錯 GPU 的台式機上可以承受交互式幀速率,但要注意嵌入式它可能會很慢,因為它會停止渲染線程以獲取數據(確保可怕的掉幀)。 您可以保存代碼,因為只需修改最少的代碼即可使其工作。
一旦您開始進行真正的研究, PBO就會到處出現,因為它們可以異步工作。 它們通常也不受嵌入式支持,但即使在平庸的 GPU 上也可以在桌面上很好地工作。 設置也有點棘手,需要特定的渲染修改。
在嵌入時,有時你已經渲染到幀緩沖區,所以去那里獲取像素。 也適用於桌面。 您可以將mmap()
緩沖區封裝到文件中並輕松獲取部分內容。 但要注意,在許多嵌入式系統中,EGL 不適用於幀緩沖區,而是在不同的“覆蓋”上工作,因此您可能會對其背景進行快照。 還要注意一些多媒體應用程序在 EGL 上運行 UI,在幀緩沖區上運行媒體播放器。 因此,如果您只需要捕獲視頻播放器,這可能適合您。 在其他情況下,有 EGL 目標是復制到幀緩沖區的紋理,它也可以正常工作。
據我所知渲染到紋理和流到幀緩沖區是他們制作你在Ableton Push 2上看到的甜美 Qt UI 的方式
在某些嵌入式系統(特別是 Raspberry Pi 和大多數 Broadcom Videocore 的)上,您有 DispmanX。 這真的很有趣:
這很有趣:
訪問 GPU 的最低級別似乎是通過名為 Dispmanx[...] 的 API
它繼續...
只是為了讓您完全缺乏使用 Dispmanx 的鼓勵,幾乎沒有任何示例,也沒有嚴肅的文檔。
基本上 DispmanX 非常接近裸機。 所以它比幀緩沖區或 EGL 更深。 非常有趣的東西,因為您可以使用vc_dispmanx_snapshot()
並真正快速地獲得所有內容的快照。 快速我的意思是我獲得了 30FPS RGBA32 屏幕捕獲,屏幕上沒有明顯的卡頓,並且在 Rasberry Pi 上有大約 4% 到 6% 的額外 CPU 開銷。 即使是 1x1 像素捕獲,由於 glReadPixels 得到的日夜都會產生非常明顯的掉幀。
這幾乎就是我發現的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.