You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中使用OBS graphics-hook捕获游戏画面?

游戏画面捕获实现方案(针对硬件加速游戏)

核心原理

这类导致黑屏的游戏通常采用DirectX 11/12或OpenGL进行硬件加速渲染,画面直接输出到GPU纹理,而非GDI设备上下文(DC),普通的BitBlt、PrintWindow等GDI捕获方法无法读取GPU中的渲染数据。OBS游戏捕获的核心是通过Hook渲染API或共享GPU纹理的方式,直接从GPU获取帧数据。

实现步骤(以DirectX 11为例)

1. 注入目标游戏进程

要捕获游戏的渲染数据,需要将捕获代码注入到游戏进程中(DirectX资源存在进程隔离)。可通过CreateRemoteThread+LoadLibrary实现注入:

// 简化注入代码
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
LPVOID pRemoteBuf = VirtualAllocEx(hProcess, NULL, strlen(dllPath)+1, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRemoteBuf, dllPath, strlen(dllPath)+1, NULL);
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);

2. Hook DirectX 11的SwapChain::Present方法

游戏帧渲染完成后会调用Present提交到屏幕,Hook该方法即可获取当前帧纹理:

  • 先通过游戏窗口HWND枚举系统中的IDXGISwapChain,找到对应窗口的实例;
  • 用Detours库(或手动Hook)替换Present函数:
// 原始Present函数指针
typedef HRESULT(WINAPI* PFN_PRESENT)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
PFN_PRESENT g_pOriginalPresent = nullptr;

// 自定义Hook后的Present函数
HRESULT WINAPI HookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
    // 获取后台缓冲区纹理
    ID3D11Texture2D* pBackBuffer = nullptr;
    pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    
    // 此处可对pBackBuffer进行数据处理(如复制、保存)
    // 优先用GPU纹理操作,避免CPU-GPU拷贝损耗
    
    pBackBuffer->Release();
    // 调用原始Present方法
    return g_pOriginalPresent(pSwapChain, SyncInterval, Flags);
}

// 初始化Hook
void InitHook(IDXGISwapChain* pSwapChain)
{
    g_pOriginalPresent = (PFN_PRESENT)GetProcAddress(GetModuleHandleA("dxgi.dll"), "Present");
    // 用Detours安装Hook
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)g_pOriginalPresent, HookedPresent);
    DetourTransactionCommit();
}

3. 纹理数据读取与导出

若需将GPU纹理读到CPU内存,可创建CPU可访问的staging纹理,复制后读取:

// 创建CPU可读纹理
D3D11_TEXTURE2D_DESC desc;
pBackBuffer->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;

ID3D11Texture2D* pStagingTexture = nullptr;
pDevice->CreateTexture2D(&desc, nullptr, &pStagingTexture);

// 复制后台缓冲区到staging纹理
pContext->CopyResource(pStagingTexture, pBackBuffer);

// 映射纹理到CPU内存
D3D11_MAPPED_SUBRESOURCE mappedResource;
pContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource);

// 读取mappedResource.pData中的RGBA像素数据,可保存为图片或传输
pContext->Unmap(pStagingTexture, 0);
pStagingTexture->Release();

4. 跨进程传输帧数据(可选)

若不想在游戏进程内处理数据,可创建共享GPU纹理,将后台缓冲区复制到共享纹理后,在捕获进程中打开该纹理直接读取GPU数据,大幅降低性能损耗。

关键注意事项

  • 需针对游戏使用的渲染API(DX9/11/12、OpenGL)适配不同的Hook方案;
  • 注入和Hook可能触发游戏反作弊系统,需做兼容性适配;
  • 优先使用成熟Hook库(如Detours)简化实现,避免手动编写汇编;
  • 性能优化:尽量用GPU内纹理操作,减少CPU-GPU数据拷贝,尤其是高分辨率场景。

内容的提问来源于stack exchange,提问作者Gürkan KARADAĞ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 18:06:32