obs源码分析【八】:显示器采集 您所在的位置:网站首页 obs显示器采集没有可用属性 obs源码分析【八】:显示器采集

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

2024-04-03 11:31| 来源: 网络整理| 查看: 265

  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以上显示采集 else obs_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_frame if (!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 tex; ComPtr 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 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.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有