日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

obs源码分析【八】:显示器采集

發布時間:2024/3/12 编程问答 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 obs源码分析【八】:显示器采集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??obs的視屏錄制主要分3種:

  • 窗口采集:采集應用程序窗口
  • 顯示器采集:也叫全屏采集,可以采集整個屏幕,當有多個顯示器時,可以設置采集其中一個顯示器
  • 游戲采集:可以采集游戲窗口

??在plugin-main.c可以看到各個采集的定義,代碼如下:

extern struct obs_source_info duplicator_capture_info; extern struct obs_source_info monitor_capture_info; extern struct obs_source_info window_capture_info; extern struct obs_source_info game_capture_info;

??這幾個采集信息的結構體應分別在其它幾個不同的文件定義,所以用extern聲明。
??在第74行,會加載這些采集方式,代碼如下:

if (graphics_uses_d3d11)wgc_supported = win_version_compare(&ver, &win1903) >= 0;if (win8_or_above && graphics_uses_d3d11)obs_register_source(&duplicator_capture_info); //win8以上顯示采集 elseobs_register_source(&monitor_capture_info); //win7及以下顯示器采集//窗口采集 obs_register_source(&window_capture_info);

??由于windows系統的窗口在win8版本換了實現方式,為了采集效率,所以分兩種不同的形式進行采集。窗口采集則是BitBlt或者wcg.
??關于windows的顯示技術,可以去看微軟文檔:【顯示基礎結構的發展】
??從該文檔可知Windows 8 引入了新的 Microsoft DirectX 圖形基礎結構 (基于 DXGI) 的 API,使獨立軟件供應商能夠更輕松地 (isv) 支持桌面協作和遠程桌面訪問方案。
??本篇重點說一下win8以上的系統顯示器采集方式,Windows Desktop duplication
??Windows 8引入了新的基于 Microsoft DirectX 圖形基礎設施 (DXGI) 的 API,使獨立軟件供應商 (ISV) 可以更輕松地支持桌面協作和遠程桌面訪問方案。
??此類應用程序廣泛用于企業和教育方案。 這些應用程序有一個共同的要求:訪問桌面內容,以及將內容傳輸至遠程位置的能力。 桌面Windows 8 API 提供對桌面內容的訪問權限。
??目前,Windows API 都允許應用程序無縫實現此方案。 因此,應用程序使用鏡像驅動程序、屏幕抓取和其他專有方法來訪問桌面的內容。 但是,這些方法具有以下一組限制:
??優化性能可能很有挑戰性。
??這些解決方案可能不支持較新的圖形呈現 API,因為 API 在產品發布后發布。
??Windows并不總是提供豐富的元數據來幫助優化。
??并非所有解決方案都與 Vista 和更高版本的 Windows 中的桌面組合Windows。
??Windows 8引入了一個基于 DXGI 的 API,稱為 桌面復制 API。 此 API 通過使用位圖和關聯的元數據進行優化,提供對桌面內容的訪問。 此 API 適用于啟用的都卡主題,不依賴于應用程序使用的圖形 API。 如果用戶可以在本地控制臺上查看應用程序,則還可以遠程查看內容。 這意味著,即使全屏 DirectX 應用程序也可以復制。 請注意,API 提供保護,防止訪問受保護的視頻內容。
??API 使應用程序能夠請求Windows,以提供對沿監視器邊界的桌面內容的訪問。 應用程序可以復制一個或多個活動顯示。 當應用程序請求重復時,會發生以下情況:
??Windows呈現桌面,并向應用程序提供副本。每個呈現的幀都放置在 GPU 內存中。每個呈現的幀都附帶以下元數據:

  • 臟區域
  • 屏幕到屏幕移動
  • 鼠標光標信息
  • 向應用程序提供對幀和元數據的訪問權限。
  • 應用程序負責處理每個幀:
  • 應用程序可以選擇基于臟區域進行優化。
  • 應用程序可以選擇使用硬件加速處理移動和鼠標數據。
  • 應用程序可以選擇在流式處理之前使用硬件加速進行壓縮。

??obs的桌面復制主要是在duplicator-monitor-capture.c、monitor-capture.c以及core的libobs-d3d11,主要是用DXGI技術獲取屏幕數據,相比于GDI的截圖技術有巨大的效率提升。
??在添加采集源時,可以選擇使用DXGI技術:

??桌面采集,要達到60fps是很有難度的技術,采用DXGI是很好的選擇。
在monitor-capture.c文件中實現了很多于顯示器操作的代碼,如果有需求,可以摘取這部分代碼應用到項目中,例如:

  • 枚舉顯示器
static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,LPARAM param) {struct monitor_info *monitor = (struct monitor_info *)param;if (monitor->cur_id == 0 || monitor->desired_id == monitor->cur_id) {monitor->rect = *rect;monitor->id = monitor->cur_id;}UNUSED_PARAMETER(hdc);UNUSED_PARAMETER(handle);return (monitor->desired_id > monitor->cur_id++); }
  • 獲取顯示器的名字
static const char *monitor_capture_getname(void *unused) {UNUSED_PARAMETER(unused);return TEXT_MONITOR_CAPTURE; }

??該文件主要是對應win7以下的顯示器桌面,采集方法用的是BitBlt, 對于win8以上的桌面OBS主要提供WCG和DXGI這兩種方式進行采集,則在duplicator-monitor-capture.c中實現,duplicator_capture_tick方法決定是采用WCG還是DXGI, 主要代碼如下:

if (capture->capture_winrt) {capture->exports.winrt_capture_free(capture->capture_winrt);capture->capture_winrt = NULL; }if (!capture->duplicator) {capture->reset_timeout += seconds;if (capture->reset_timeout >= RESET_INTERVAL_SEC) {capture->duplicator = gs_duplicator_create(capture->dxgi_index);capture->reset_timeout = 0.0f;} }if (capture->duplicator) {if (capture->capture_cursor)cursor_capture(&capture->cursor_data);//調用libobs-d3d11的導出函數gs_duplicator_update_frameif (!gs_duplicator_update_frame(capture->duplicator)) {free_capture_data(capture);} else if (capture->width == 0) {reset_capture_data(capture);} }

??如果是使用DXGI, 在采集時gs_duplicator_update_frame一直會被調用,獲取桌面資源,該函數封裝在libobs-d3d11這個dll中:

EXPORT bool gs_duplicator_update_frame(gs_duplicator_t *d) {DXGI_OUTDUPL_FRAME_INFO info;ComPtr<ID3D11Texture2D> tex;ComPtr<IDXGIResource> res;HRESULT hr;if (!d->duplicator) {return false;}if (d->updated) {return true;}hr = d->duplicator->AcquireNextFrame(0, &info, res.Assign());if (hr == DXGI_ERROR_ACCESS_LOST) {return false;} else if (hr == DXGI_ERROR_WAIT_TIMEOUT) {return true;} else if (FAILED(hr)) {blog(LOG_ERROR,"gs_duplicator_update_frame: Failed to update ""frame (%08lX)",hr);return true;}hr = res->QueryInterface(__uuidof(ID3D11Texture2D),(void **)tex.Assign());if (FAILED(hr)) {blog(LOG_ERROR,"gs_duplicator_update_frame: Failed to query ""ID3D11Texture2D (%08lX)",hr);d->duplicator->ReleaseFrame();return true;}copy_texture(d, tex);d->duplicator->ReleaseFrame();d->updated = true;return true; }

??這里要注意的是AcquireNextFrame的返回值,當桌面畫面沒有變化或沒有新圖像到來時會返回DXGI_ERROR_WAIT_TIMEOUT,此時無需做圖像更新操作,直接返回循環等待下一幀圖像。下面是微軟的官方說明:

AcquireNextFrame returns:S_OK if it successfully received the next desktop image. DXGI_ERROR_ACCESS_LOST if the desktop duplication interface is invalid. The desktop duplication interface typically becomes invalid when a different type of image is displayed on the desktop. Examples of this situation are: Desktop switch Mode change Switch from DWM on, DWM off, or other full-screen application In this situation, the application must release the IDXGIOutputDuplication interface and create a new IDXGIOutputDuplication for the new content. DXGI_ERROR_WAIT_TIMEOUT if the time-out interval elapsed before the next desktop frame was available. DXGI_ERROR_INVALID_CALL if the application called AcquireNextFrame without releasing the previous frame. E_INVALIDARG if one of the parameters to AcquireNextFrame is incorrect; for example, if pFrameInfo is NULL. Possibly other error codes that are described in the DXGI_ERROR topic.

??獲取到紋理數據后,需要做拷貝,調用copy_texture。
??dx的接口是基于com開發的,如果不熟悉com技術,這些代碼看起來很吃力,畢竟dx是微軟最難的sdk。
??了解com技術的會,應該知道,任何基于com的對象,都得派生于IUnknown,例如DXGIObject

MIDL_INTERFACE("aec22fb8-76f3-4639-9be0-28eb43a67a2e")IDXGIObject : public IUnknown

??IDXGIOutputDuplication派生于DXGIObject,作為結構體gs_duplicator的成員

struct gs_duplicator : gs_obj {ComPtr<IDXGIOutputDuplication> duplicator;gs_texture_2d *texture;int idx;long refs;bool updated;void Start();inline void Release() { duplicator.Release(); }gs_duplicator(gs_device_t *device, int monitor_idx);~gs_duplicator(); };

??在構造時,調用Start().
??另外說明一點,采用DXGI時,obs依賴于libobs-winrt項目. 在使用obs sdk二次開發時,要注意帶上libobs-winrt生成的dll.

總結

以上是生活随笔為你收集整理的obs源码分析【八】:显示器采集的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。