【问题标题】:Using DirectX to capture screen on Windows在 Windows 上使用 DirectX 捕获屏幕
【发布时间】:2013-07-23 13:46:45
【问题描述】:

我正在尝试在 Windows 上捕获屏幕的方法,因此决定了最快的方法。最常见的显然是 GDI 方式。而且它的性能也不错。根据系统负载和静态/非静态屏幕内容,屏幕捕获速率范围为 27-47 fps(Windows 7、Intel i5@2.6 GHz、8 GB RAM)。

现在,使用 DirectX 前端缓冲区方法(使用 GetFrontBufferData() API),性能相当,但速度稍慢(我无法达到 48 fps)。

我浏览了这篇文章:Fastest method of screen capturing 并尝试了使用 getRenderTarget() 和 getRenderTargetData() 在接受的答案中建议的方式,但正如 cmets 中所建议的那样,我得到的只是一张黑色图像。这是我的完整代码,包括设备的初始配置:

    IDirect3DSurface9* pRenderTarget=NULL;
    IDirect3DSurface9* pDestTarget=NULL;
    // sanity checks.
    if (g_pd3dDevice == NULL){
      return;
    }
    HRESULT hr;
    // get the render target surface.
    hr = g_pd3dDevice->GetRenderTarget(0, &pRenderTarget);
    // get the current adapter display mode.
    //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

    // create a destination surface.
    hr = g_pd3dDevice->CreateOffscreenPlainSurface(1600, 900, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pDestTarget, NULL);
   //copy the render target to the destination surface.
   hr = g_pd3dDevice->GetRenderTargetData(pRenderTarget, pDestTarget);

   D3DLOCKED_RECT lockedRect;
   hr =pDestTarget->LockRect(&lockedRect,NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);

    for( int i=0 ; i < 900 ; i++)
    {
        for(int j=0; j < 1600; j++){
            memcpy( (BYTE*) data + i * 1600 * 3 + j * 3, (BYTE*) lockedRect.pBits + i* lockedRect.Pitch + j * 4,  3);
        }
    }
    pDestTarget->UnlockRect();
   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();

对于设备初始化部分:

g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); 
D3DPRESENT_PARAMETERS PresentParams; 
memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); 
PresentParams.Windowed = TRUE; 
PresentParams.SwapEffect =D3DSWAPEFFECT_DISCARD;
g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL ,GetDesktopWindow(),D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams,&g_pd3dDevice);

请指出上述代码中的错误。欢迎任何建议。我也尝试了 GetBackBuffer() API,但无法获取图像数据。

编辑:

我的用例是捕获桌面屏幕,这似乎只能通过 DirectX 使用 GetFrontBufferData() 来完成。 GetBackBuffer()/GetRenderTargetData() 不是针对这种情况调用的正确 API。参考:The desktop capture with DirectX does not workHow to get the screenshot of the desktop from back buffer with DirectX

但是,欢迎任何有关捕获桌面屏幕或优化 GDI 方式的更快方法的建议。

【问题讨论】:

  • 我觉得GetRenderTarget 会返回设备的后台缓冲区。您可能想查看GetFrontBufferData 函数。
  • 我已经使用了问题中提到的 GetFrontBufferData(),它工作正常。但是,与 GDI 方式相比,性能没有任何提升。我正在寻找一种更快的方法,如果有的话。
  • 我也在写一个截屏应用。 Here 是我的问题的链接。捕获任何游戏时都会出现黑屏,而对于任何其他应用程序,它会返回正确的捕获屏幕。有什么方法可以让它在全屏游戏中运行?

标签: c++ c windows directx directx-9


【解决方案1】:

你在截屏之前有渲染过什么吗?

  • GetFrontBufferData - 这个函数获取屏幕的数据
  • GetRenderTargetData - 此函数从渲染目标获取数据

所以如果你不渲染任何东西,你肯定会得到一个空白图像。

【讨论】:

  • 我可能在这里断章取义。我的用例是获取桌面屏幕的数据。那么,您是否建议 GetRenderTargetData() 不是要调用的正确 API。能否请您详细说明渲染部分?
  • 在这里检查了你的答案stackoverflow.com/questions/12859894/… .. 所以,GetFrontBufferData() 是唯一用于通过 DirectX 捕获桌面屏幕的 API。
  • 是的,GetRenderTargetData() 用于从应用程序的渲染目标而不是桌面获取数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-17
相关资源
最近更新 更多