Windows桌面共享中一些常見的抓屏技術

本篇博客內容是屬於轉載的,原文地址:

http://www.cppblog.com/weiym/archive/2013/12/01/204536.aspx

 

1. BitBlt

 

我想做Windows開發應該都知道這個API, 它能實現DC間的內容拷貝, 如果我們把源DC指定成Monitor DC或是桌面DC, 它就能實現抓屏功能。

對於通過這種方式的抓屏, 有2點需要特別提醒:

a. 在XP下我們可以通過最後的拷貝標誌來控制是否拷貝layered window, 只有SRCCPY表示拷貝內容不包含layered window, 如果是SRCCPY | CAPTUREBLT表示拷貝包括Layered window在內的所有窗口。 這個標誌在Vista之後的系統(win7/win8),開啓DWM的情況下, 已經失效, 因爲這種情況下所有的窗口都是layered window.
b. 這種方式的抓屏在 Vista之後, 開啓DWM的情況下, 抓屏速度非常慢(30ms +), 具體原因不知道是因爲系統沒有緩存整個屏幕的數據還是GPU向內存拷貝數據太慢了, 有知道的朋友可以提示下。
 

2. Mirror driver

 

這種方法應該是Win8之前最高效的抓屏方法, 也是微軟推薦的遠程桌面共享方案,它通過創建虛擬鏡像驅動, 直接獲取最終屏幕變化數據。

該方法也有一些缺點:

a. 涉及到驅動安裝, 技術難度大, 系統權限要求也高
b. Win8 上該方案已經失效, 但是還是有方法的, 參見 Remote Display Drivers

 

3. GDI hook

 

這種方法應該說是XP時代比較流行的抓屏方法, 因爲所有的繪製都是通過GDI32.dll中的繪圖函數來實現的, 所以我們只要攔截了這些函數, 系統的所有繪製就都讓我們控制了。這種方法應該來說也是一種挺高效的抓屏方法,屏幕的變化也都能讓我們攔截到, 同時因爲好多繪圖函數是以矢量方式實現的,所有抓到的數據包非常小, 即使在低帶寬下也效果挺好。

下面是該方法的一些缺點:

a. Hook技術本身就有其複雜性和不穩定性, 尤其是Hook所有進程
b. Vista只有越來越多程序採用D2D/D3D繪製, GDI Hook對這些繪製無能爲力。
c. Vista之後UAC打開的情況下, 如果我們的程序權限不夠高, Hook不到更高權限的程序。
 

4. Windows Media API

 

Windows Media 9.0 支持用Windows Media Encoder 9 API來抓屏。它有一個編碼器叫Windows Media Video 9 Screen codec,特別爲抓屏優化過。Windows Media Encoder API提供了一個IWMEncoder2接口可以用來高效地捕捉屏幕圖像。

因爲對這組API不熟, 這種抓屏方法我也沒嘗試過, 具體可見Various methods for capturing the screen, 感覺這種方法的最大缺點是用戶機器需要安裝Windows Media Encoder 9。
 

5. DirectX
 

每個DirectX程序都包含一個被我們稱作緩衝的內存區域,其中保存了和該程序有關的顯存內容,這在程序中被稱作後臺緩衝(Back Buffer),有些程序有不止一個的後臺緩衝。還有一個緩衝,在默認情況下每個程序都可以訪問-前臺緩衝。前臺緩衝保存了和桌面相關的顯存內容,實質上就是屏幕圖像。 我們的程序通過訪問前臺緩衝就可以捕捉到當前屏幕的內容。上面的列子中也包含該方法的實現, 是基於DirectX9的,我們可以參考下, 據我測試該方法在DWM打開的情況下抓整屏也要30ms左右。Vista之後的DirectX 10/11相對於DirectX 9 已經發生非常大的變化, 直接用新的接口上面的代碼未必能正常工作。


6. PrintWindow

 

該方法本身不能直接做爲一種抓屏方法, 但是有時候我們要獲取某個窗口的內容, 即使他被其他窗口覆蓋着, 這時候這個函數就很有用。該方該調用法的原理是通過給目標窗口發送WM_PRINT或是WM_PRINTCLIENT消息, 所以如果目標窗口沒有響應, 該調用可能會阻塞抓屏線程, 這種情況下抓屏前最好先用SendMessageTimeout檢測目標窗口是否有響應。另外該方法也抓不到D3D窗口的內容。


7. DWM/Dxgi hook

 

Vista之後微軟放棄了XP時代的XPDM, 採用了全新的WDDM視屏驅動模型, 現在Win8.1上已經是WDDM1.3.

Vista之後底層所有的渲染都是基於D3D技術, 另外我們也知道系統在DWM.exe裏進行窗口邊框的繪畫和合成, 所以理論上我們可以通過HOOK DWM/D3D/DXGI,攔截到整個系統的屏幕內容。當然作爲一種Hook技術, 它也有上面GDI Hook類似的問題。
 

8. Magnification

 

這組API是微軟Vista之後開放給我們開發放大鏡程序的, 它裏面提供了一個API讓我們攔截到顯示的內容, 可惜的是這個關鍵的API  MagSetImageScalingCallback 微軟已經宣佈作廢。另外該方式的抓屏效率也不高, 整屏需要60 ms 左右。
 

9. Desktop Duplication  

 

這是微軟Win8 上宣佈放棄Mirror driver之後推薦採用的抓屏技術, 全部基於D3D/DXGI技術, 效率非常高, 並且包含變化區域和屏幕鼠標光標。它的缺點是沒法抓取某個窗口的內容 。
 

10. GetWindowDC 


該方法和PrintWindow類似,但是它沒有PrintWindow的權限問題, 也沒有超時問題。
這種抓屏方法在Win7/Win8  DWM打開的情況下抓屏,結果會顛覆我們XP時代的知識, 因爲即使窗口被覆蓋, 它也可以正確抓取到被覆蓋窗口下的內容, WebRTC正是用這種方式來Share  Application的。
它的主要問題是有些窗口抓到的內容不包含非客戶區,有些窗口比如任務欄的Thumbnail窗口會抓不到內容。

 

最後簡單總結下 , 我們可以看到Windows系統上基本沒有一種通用的抓屏技術可以高效的抓取所有的系統(XP/Win7/Win8), 很大一部原因是操作系統的顯示驅動模型在從XPDM向WDDM轉變, 應用層的API也在從GDI向D3D轉變 。 相對於Linux的穩定, Window的不斷髮展和進步, 對開發人員究竟是喜是悲?

 

另外還有一篇博文值得參考學習,該博文仔細的介紹了幾種抓屏的方式:

http://blog.csdn.NET/henry19850318/article/details/5732106

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章