Windows桌面采集技術

在進入具體的方式討論前,我們先看看 Windows 桌面圖形界面的簡化架構,如下圖:

在 Windows Vista 之前,Windows 界面的復合畫面經由 Graphics Device Interface(以下簡稱 GDI)技術直接渲染到桌面上。

在 Windows Vista 以及之后的版本,Desktop Composition 的工作就交由一個新的模塊Desktop Window Manager(以下簡稱 DWM) 來完成了。

如上圖所示,應用程序畫完自己的界面后,提交給 DWM 把它合成到桌面上,而 DWM 經過一系列演進后,為了提效,基于微軟自己的 Direct3D(以下簡稱 D3D) 實現了整套技術,在 D3D 這層的下面是 Windows Display Driver Model(以下簡稱 WDDM,Windows 圖形驅動程序模型)。

? ? ? ? ? ? ? ? ? ? ? ? ? ??

所以在 Windows 下實現錄屏采集,基本上可以從最基本的 GDI 技術和 D3D 技術兩方面考慮。

GDI:第一代桌面采集

Windows 圖形設備接口(GDI)是為與設備無關的圖形設計的。基于 Windows 的應用程序不能直接訪問圖形硬件,應用程序通過 GDI 來與設備驅動程序進行交互。GDI 截圖就是通過屏幕的DC獲取到當前屏幕的位圖數據。

調用過程
GetDC(GetDesktokWindow() )獲取桌面的DC
然后使用CreateDIBSection創建一個設備無關位圖以及內存DC
使用BitBlt把桌面DC的復制到內存DC,這樣通過內存DC就能直接獲取到原始RGB數據。

基本采樣流程

在 Windows 平臺上有過圖形開發經驗的開發者,應該都知道 BitBlt 這個 API, 它為我們實現了 Windows DC 間的內容拷貝,假如將 Source DC 指定為 Window DC 或是 Destop DC,這就實現了對屏幕指定源的畫面截取。下圖說明了基于 GDI 技術錄屏采集的大致調用過程:

? ? ? ? ? ? ? ? ? ? ? ? ? ??

以整個桌面作為采集源舉例,通用做法是調用 GetDC(GetDesktokWindow()) 獲取桌面 DC,通過 CreateDIBSection 創建一個設備無關的位圖對象以及內存 DC,最后調用 BitBlt 把桌面 DC 的原始數據翻轉到內存 DC 上,這樣從內存 DC 上就能直接獲取到桌面的原始 RGB 數據。

需要注意的是,創建一個設備無關的位圖時,CreateDIBSection 的第4個參數 ppvBits 是提前分配好的位圖數據緩沖區。而在以實時視頻流的方式共享屏幕的場景下,需要以每秒十幾次甚至幾十次的頻率進行采樣,從效率的要求考慮,這里自然不可能每次都重新分配緩沖區,所以可以根據源的分辨率,在采集前就分配一個足夠大的空間。

CreateDIBSection的函數原型如下圖所示:

HBITMAP CreateDIBSection(HDC              hdc,const BITMAPINFO *pbmi,UINT             usage,VOID             **ppvBits,HANDLE           hSection,DWORD            offset
);

????????經過以上基本采樣流程,得到的畫面內容是不含鼠標的,如果需要將鼠標還原到畫面中

CURSORINFO ci = { 0 };ci.cbSize = sizeof(ci);ZeroMemory(&ci, sizeof(CURSORINFO));ci.cbSize = sizeof(CURSORINFO);if (::GetCursorInfo(&ci)){POINT ptCursorPos = { 0, 0 };ptCursorPos = ci.ptScreenPos;::DrawIconEx(m_hCompDC,ptCursorPos.x , ptCursorPos.y,ci.hCursor,0, 0, 0, 0,DI_NORMAL | DI_DEFAULTSIZE | DI_COMPAT);}


優缺點


優點:GDI函數實現的通用做法,能在所有windows平臺實現

缺點:通用歸通用,截取的效率則是有點低,尤其是要達到每秒20幀以上的截取,占用CPU有點高,GDI不能獲取鼠標,需要在截取的圖像中把鼠標畫上去。

????????由于整體的運算、拷貝過程都在 CPU 中完成,導致采樣效率偏低,尤其在高頻采樣(> 20fps)時,對 CPU資源的消耗過高,而且后續還要處理為實時視頻流,經過同樣高頻的編碼、網絡包發送,多方面因素疊加,自然對機器性能有更高的要求。 GDI 則可以作為一種保底方案。

在具體實現中,還有兩點需要特別提醒:

1)在 Windows XP 下,可以通過 BitBlt 函數最后的參數,來控制是否拷貝 Layered Window。只有 SRCCPY 標識,表示拷貝內容不包含 Layered Window;如果是SRCCPY | CAPTUREBLT,則表示拷貝包括 Layered Window 在內的所有窗口。而這個標識,在 Windows Vista 之后的系統版本開啟 DWM 的情況下,已經無效,因為這種情況下所有的窗口都是 Layered Window;

2)在 Windows Vista 之后的系統版本開啟 DWM 的情況下,單次抓取速度變得非常慢(作者機器實測 30ms +)

且無法采集到使用gpu渲染的窗口,顯示黑屏:

DXGI:高性能桌面采集技術

DXGI(Microsoft DirectX Graphics Infrastructure)是微軟提供的一種可以在win8及以上系統使用的圖形設備接口。它負責枚舉圖形適配器、枚舉顯示模式、選擇緩沖區格式、在進程之間(例如,在應用程序和桌面窗口管理器(DWM)之間)共享資源,以及將呈現的幀傳給窗口或監視器以供顯示。其直接和硬件設備進行交互,具有很高的效率和性能。

基本采樣流程

除了用 GDI 技術實現錄屏,實際上在 Windows 平臺上,微軟提供了多種錄屏方案,相對 GDI 技術來說,其大多數接口的處理性能并不理想,或存在諸多限制,通用性不足。

從 Windows 8 開始,微軟引入了一套新技術叫 Desktop Duplication API,應用程序可以通過這套 API 請求桌面的圖形數據。由于 Desktop Duplication API 是通過 DirectX Graphics Infrastructure(以下簡稱 DXGI)來提供桌面圖像的,競爭的是 GPU 流水線資源,所以 CPU 占用率很低,采集性能非常高。

由于這套能力整合在 DirextX 中提供,所以與大部分 DirectX 接口的使用方式基本一致,其流程概括如下圖。

如圖所示,使用 DXGI 需要一些簡單的 DirectX 基礎知識,通過各種 DirectX COM 接口的查詢,最終獲取 IDXGIOutputDuplication 接口指針,截屏時使用其中核心的AcquireNextFrame API 獲取當前桌面圖像,此外,它還提供 GetFrameDirtyRects 等 API,可以獲取經過 GPU 計算后發生了變化的臟矩形區域。

繪制鼠標

和 GDI 面臨相同的問題,直接通過 AcquireNextFrame API 獲取到的畫面中,也是不含鼠標圖像的。想要將鼠標繪制到畫面中,我們需要和GDI相關的API配合使用。

在采集之前創建數據緩沖區時,將緩沖區關聯到設備無關的位圖上,并將位圖選入臨時的內存DC(一般由桌面DC生成的臨時內存DC),再將通過 AcquireNextFrame獲取的畫面拷貝到緩沖區后,這時可以使用GDI繪制鼠標的方法,將鼠標繪制到位圖上,這樣數據緩沖區中的圖像數據就包含了鼠標了。

優劣勢分析

在 Windows 平臺上,從現有的錄屏采集方式(包括GDI采集和放大鏡采集)來看,DXGI 是性能最好的。

其劣勢是只在 Windows 8 系統版本及以上才支持,所以在整體方案中,一般要與 GDI 共同組合提供。此外,它無法指定某個程序窗口進行采集

? 特點:Win Vista 以后支持,使用GPU直接處理紋理,效率最高;

? 缺點:根據Direct3D?版本不同,存在硬件的支持以及調用特性 的區別,且因為采集需要獲取設備的adapter,所以無法采集桌面窗口。、???????

? ? ? ? 如果用戶機器有A卡和N卡,出現了跨卡問題導致采集失效,禁用AMD顯卡后問題解決

Magnification:彎道超車的采集技術

Magnification API 使用于放大屏幕某個區域的 輔助應用技術,初衷是用于協助視力存在問題或者色弱的用戶能跟方便的看到桌面內容的api

? 特點:能實現放大縮小顏色轉換等操作,能過濾窗口

基本采樣流程

前面所述的兩種方式都可以實現錄屏采集,也是最常用的兩種方式。

但有時,我們要指定源來采集,并且希望采集到的畫面不被其他內容干擾。

在 Windows XP 時代,用 GDI 的 BitBlt API 進行采集時,指定一個 Window DC,并且對最后一個參數去掉 CAPTUREBLT 標識,即可排除掉其他 Layered Window 的干擾。但如今 Windows XP 已成過去式,這項措施無法解決現有系統的過濾問題,必須找到另一替代方案。

從 Windows Vista 開始,微軟新引入了一個新的 Magnification API(放大鏡效果),當我們將放大倍率設置成1(默認倍率就是1)亦可以用它來截取屏幕圖像。MSDN上提供了該庫的完整文檔。根據文檔,可以通過以下步驟簡單地完成錄屏采集過程:

在初始化相關模塊后,首先創建放大鏡控件的主窗口,并且將其設置為全屏不可見,因為我們要使用它來捕獲圖像,它只是一個工具,所以不能也不需要在用戶側顯示它。因此,設置窗口擴展屬性 WS_EX_LAYERED,調用 SetLayeredWindowAttributes 設置全透明。

::SetLayeredWindowAttributes(hwnd, 0 ,255, LWA_ALPHA);

接著創建放大鏡窗口作為主窗口的子窗口,窗口類名必須為“Magnifier”。如果要捕獲鼠標光標,還要設置窗口屬性為 MS_SHOWMAGNIFIEDCURSOR。

hwndMag = ::CreateWindow(WC_MAGNIFIER, TEXT("Magnifier"), WS_CHILD /*| MS_SHOWMAGNIFIEDCURSOR */| WS_VISIBLE,0, 0, m_ScreenX, m_ScreenY, hostDlg->GetSafeHwnd(), NULL, hInstance, NULL );

最關鍵的部分,利用 MagSetWindowFilterList 這個神奇的 API,它能夠指定一些窗口,在我們截取指定源目標時,從采集到的圖像中將 FilterList 中的窗口過濾掉,好像這些窗口根本沒有顯示一樣。這就是我們使用這放大鏡方案的主要原因。

那么如何獲得錄屏圖像呢?每當我們調用 MagSetWindowSource 時,都會觸發回調MagSetImageScalingCallback數據回調。原型如下:

BOOL MagImageScaling(HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty)

其中第二個參數 srcdata 就是指向錄屏結果圖像的原始數據,srcheader 則包含數據的長度,以及圖像長寬等元信息,至此,我們可以使用這兩個參數來構建位圖了。

Magnification

Window Graphics Capturer:新世代采集技術

WGC 全稱為 Windows Graphics Capture 是微軟目前主推的一個桌面/窗口采集技術,使用 D3D11 庫實現。該采集技術最早在Windows 10 18年3月份的更新中提供。WGC 對比放大鏡采集(Magnification Capture) 具有更高的性能、更低CPU及GPU消耗。但是在 使用方面比起其他采集方式會更復雜。

  • 系統版本不低于10.0.17134.0 (Windows 10, version 1803)
  • 相關接口均基于微軟的新一代運行時庫接口C++/WinRT,而且是最低要求 C++17

????????鼠標支持,自Windows 10, version 2004 (introduced in 10.0.19041.0)才開始支持捕獲鼠標。
GraphicsCaptureSession.IsCursorCaptureEnabled Property
????????黃色邊框去除,自Windows 10, version 2104 (introduced in 10.0.20348.0)才開始去除采集目標的黃色邊框。
GraphicsCaptureSession.IsBorderRequired

FFMPEG錄屏(15)---- WGC 捕獲桌面(三) WGC(Windows Graphics Capture)采集_ffmpeg采集桌面-CSDN博客

? 特點:效率高,拓展屏采集支持高,1080p采集消耗gpu達到個位數;

? 缺點:

1. 當Capture Session開始采集后,在剛開始采集的時候可能存在 HRESULT 為S_OK ,但是畫面數據為空,因為這個時候采集Engine可能處于啟動中狀態;

2. 當開始采集是,Windows會在采集源(窗口或桌面)區域增加一個黃色邊框去標識正在采集的區域,目前無法設置該邊框的樣式或者去除該邊框;

3. WGC 使用SetWindowDisplayAffinity 實現窗口過濾,但是設置的窗口必須為當前進程創建的子窗口才能設置成功,否則無法實現過濾。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898956.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898956.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898956.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ElementPlus 快速入門

目錄 前言 為什么要學習 ElementPlus? 正文 步驟 1 創建 一個工程化的vue 項目 ?2 安裝 element-Plus :Form 表單 | Element Plus 1 點擊 當前界面的指南 2 點擊左邊菜單欄上的安裝,選擇包管理器 3 運行該命令 demo(案例1 ) 步驟 …

TypeScript語言的設備管理

TypeScript 設備管理系統的設計與實現 引言 在現代社會,設備管理已成為企業和組織運營中不可或缺的一部分。無論是IT設備、辦公家具還是生產機器,企業都需要一種有效的方式來管理、追蹤和維護這些資產。隨著前端技術的不斷發展,TypeScript作…

Ubuntu20.04.6系統根目錄擴容

文章目錄 方法一:**1. 檢查磁盤和分區情況****2. 擴展 vda3 分區****3. 擴展 LVM 物理卷****4. 擴展 LVM 邏輯卷****5. 擴展文件系統** 方法二:1. 查看當前磁盤分區情況2. 創建新分區3. 重新加載分區表4. 擴展物理卷(PV)5. 擴展邏輯卷&#x…

[藍橋杯 2023 省 A] 異或和之和

題目來自洛谷網站&#xff1a; 暴力思路&#xff1a; 先進性預處理&#xff0c;找到每個點位置的前綴異或和&#xff0c;在枚舉區間。 暴力代碼&#xff1a; #include<bits/stdc.h> #define int long long using namespace std; const int N 1e520;int n; int arr[N…

python學習筆記--實現簡單的爬蟲(二)

任務&#xff1a;爬取B站上最愛歡迎的編程課程 網址&#xff1a;編程-嗶哩嗶哩_bilibili 打開網頁的代碼模塊&#xff0c;如下圖&#xff1a; 標題均位于class_"bili-video-card__info--tit"的h3標簽中&#xff0c;下面通過代碼來實現&#xff0c;需要說明的是URL中…

微服務分層架構詳解:表示層、應用層與基礎設施層的協同工作

微服務分層架構詳解&#xff1a;表示層、應用層與基礎設施層的協同工作 文章目錄 微服務分層架構詳解&#xff1a;表示層、應用層與基礎設施層的協同工作1. 表示層&#xff08;Presentation Layer&#xff09;1.1 表示層的作用1.2 技術選型1.3 表示層的挑戰 2. 應用層&#xff…

[C++面試] 你了解transform嗎?

層級核心知識點入門基本語法、與for_each對比、單/雙范圍操作進階動態擴展、原地轉換、類型兼容性、異常安全高階性能優化、C20 Ranges、transform_if模擬 一、入門 1、描述std::transform的基本功能&#xff0c;并寫出兩種版本的函數原型 std::transform函數是 C 標準庫<…

windows清除電腦開機密碼,可保留原本的系統和資料,不重裝系統

前言 很久的一臺電腦沒有使用了&#xff0c;開機密碼忘了&#xff0c;進不去系統 方法 1.將一個閑置u盤設置成pe盤&#xff08;注意&#xff0c;這個操作會清空原來u盤的數據&#xff0c;需要在配置前將重要數據轉移走&#xff0c;數據無價&#xff0c;別因為配置這個丟了重…

5.4 位運算專題:LeetCode 137. 只出現一次的數字 II

1. 題目鏈接 LeetCode 137. 只出現一次的數字 II 2. 題目描述 給定一個整數數組 nums&#xff0c;其中每個元素均出現 三次&#xff0c;除了一個元素只出現 一次。請找出這個只出現一次的元素。 要求&#xff1a; 時間復雜度為 O(n)&#xff0c;空間復雜度為 O(1)。 示例&a…

C語言:掃雷

在編程的世界里&#xff0c;掃雷游戲是一個經典的實踐項目。它不僅能幫助我們鞏固編程知識&#xff0c;還能鍛煉邏輯思維和解決問題的能力。今天&#xff0c;就讓我們一起用 C 語言來實現這個有趣的游戲&#xff0c;并且通過圖文并茂的方式&#xff0c;讓每一步都清晰易懂 1. 游…

【論文#目標檢測】YOLO9000: Better, Faster, Stronger

目錄 摘要1.引言2.更好&#xff08;Better&#xff09;3.更快&#xff08;Faster&#xff09;4.更健壯&#xff08;Stronger&#xff09;使用 WordTree 組合數據集聯合分類和檢測評估 YOLO9000 5.結論 Author: Joseph Redmon; Ali Farhadi Published in: 2017 IEEE Conference …

數據庫誤更新操作 如何回滾

1.未提交 直接 rollback 2.已提交 步驟 查詢指定時間內修改前數據庫數據&#xff1a; -- 查詢誤操作前的數據&#xff08;例如 10 分鐘前&#xff09; SELECT * FROM 表名 AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL 10 MINUTE) WHERE 條件;-- 將數據恢復&#xff08;需確保有…

大數據運維實戰之YARN任務內存泄露排查實戰:從節點掉線到精準定位的完整指南

1.問題背景&#xff1a;集群內存風暴引發的危機 最近某大數據集群頻繁出現節點掉線事故&#xff0c;物理內存監控持續爆紅。運維人員發現當節點內存使用率達到95%以上時&#xff0c;機器會進入不可響應狀態&#xff0c;最終導致服務中斷。這種"內存雪崩"現象往往由單…

AI+金融 應用 使用DeepSeek、Qwen等大模型輸入自然語言,得到通達信等行情軟件公式代碼,導入后使用

AI金融 應用 使用DeepSeek、Qwen等大模型輸入自然語言&#xff0c;得到通達信等行情軟件公式代碼&#xff0c;導入后使用。不會編程&#xff0c;也能行情軟件中實現個性化條件選股&#xff0c;個性化技術指標。 AIbxm低估值趨勢選股策略&#xff0c;參考提示詞&#xff1a; 編…

[Xilinx]工具篇_PetaLinux自動編譯

[Xilinx]工具篇_PetaLinux自動編譯 若該文為原創文章&#xff0c;未經允許不得轉載風釋雪QQ:627833006E-mail:hn.cyfoxmail.comCSDN博客: https://blog.csdn.net/weixin_46718879知乎&#xff1a;https://www.zhihu.com/people/abner-80-4 1.版本 日期作者版本說明2025XXXX風釋…

多語言語料庫萬卷·絲路2.0開源,數據模態全面升級,搭建文化交流互鑒AI橋梁

3月22日&#xff0c;上海人工智能實驗室&#xff08;上海AI實驗室&#xff09;聯合新華社新聞信息中心、上海外國語大學、外研在線等&#xff0c;發布全新升級的“萬卷絲路2.0”多語言語料庫&#xff0c;通過構建多語言開源數據底座&#xff0c;以人工智能賦能“一帶一路”高質…

多語言生成語言模型的少樣本學習

摘要 大規模生成語言模型&#xff0c;如GPT-3&#xff0c;是極具競爭力的少樣本學習模型。盡管這些模型能夠共同表示多種語言&#xff0c;但其訓練數據以英語為主&#xff0c;這可能限制了它們的跨語言泛化能力。在本研究中&#xff0c;我們在一個涵蓋多種語言的語料庫上訓練了…

Linux運維篇-系統io調優

目錄 磁盤文件系統虛擬文件系統 文件系統的工作原理文件系統 I/OI/O 的分類緩沖與非緩沖 I/O直接與非直接 I/O阻塞與非阻塞 I/O同步與異步 I/O 查看文件系統容量目錄項和索引節點緩存 通用塊層I/O 棧磁盤性能指標磁盤 I/O 觀測進程 I/O 觀測I/O瓶頸的排查思路思路一思路二 I/O優…

C語言筆記(鵬哥)上課板書+課件匯總(動態內存管理)--數據結構常用

動態內存管理 引言&#xff1a;將內存升起一段空間存放數據有幾種手段 創建變量&#xff1a;存放一個值創建數組&#xff1a;存放多個連續的一組值 以上開辟的內存空間是固定的&#xff0c;創建大了&#xff0c;空間浪費&#xff0c;創建小了&#xff0c;空間不夠。并且一旦…

uv - Getting Started 開始使用 [官方文檔翻譯]

文章目錄 uv亮點安裝項目腳本工具Python 版本pip 接口了解更多 入門安裝 uv安裝方法獨立安裝程序PyPICargoHomebrewWinGetScoopDockerGitHub 發布 升級 uvShell 自動補全卸載 第一次使用 uv特性Python 版本腳本項目工具pip 接口實用工具 獲取幫助幫助菜單查看版本故障排除問題在…