使用DirectX进行桌面捕获不起作用

时间:2012-10-12 13:15:13

标签: directx screenshot desktop capture

由于D3DPOOL_SCRATCH的处理速度很慢,我编写了桌面捕获程序以引用Internet上的报告。然而,结果是漆黑图片。这是控制台程序的结果还是有其他原因?

#include <stdio.h>
#include <Windows.h>
#include <d3d9.h>

void main()
{
    CoInitialize(NULL);

    LPDIRECT3D9 d3d9;
    LPDIRECT3DDEVICE9 d3ddev;
    d3d9 = Direct3DCreate9(D3D_SDK_VERSION);

    int ww = GetSystemMetrics(SM_CXSCREEN);
    int wh = GetSystemMetrics(SM_CYSCREEN);

    HWND hwnd = GetDesktopWindow();
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = ww;
    d3dpp.BackBufferHeight = wh;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality = 0;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    d3dpp.hDeviceWindow = hwnd;
    d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

    d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

    IDirect3DSurface9* render;
    IDirect3DSurface9* dest;
    d3ddev->CreateOffscreenPlainSurface(ww, wh, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &dest, NULL);
    d3ddev->GetRenderTarget(0, &render);
    d3ddev->GetRenderTargetData(render, dest);

    D3DLOCKED_RECT bits;
    dest->LockRect(&bits, NULL, D3DLOCK_READONLY);

    // If a capture is successful, colors other than black(0x00000000) should enter. 
    for(int i = 0; i < 100; i++){
        printf("%02X ", *((BYTE*)bits.pBits + i));
    }

    dest->UnlockRect();

    render->Release();
    dest->Release();
    d3ddev->Release();
    d3d9->Release();

    CoUninitialize();
}

2 个答案:

答案 0 :(得分:5)

这与应用程序类型无关,如果要获取桌面图像的数据,则应使用以下函数

GetFrontBufferData

所以不要打电话

d3ddev->GetRenderTarget(0, &render);
d3ddev->GetRenderTargetData(render, dest);

你应该致电

d3ddev->GetFrontBufferData(0, dest);

答案 1 :(得分:4)

如果您在Windows 8之前的Windows版本上运行,则GetFrontBufferData API可正常工作,如另一个答案所示。但是,从Windows 8开始,有一个新的desktop duplication API可用于捕获视频内存中的桌面,包括鼠标光标更改以及屏幕的哪些部分实际更改或移动。这比D3D9方法更具性能,并且非常适合将桌面编码为视频流,因为您永远不必将纹理从GPU内存中拉出来。通过枚举DXGI输出并在要捕获的屏幕上调用DuplicateOutput,可以使用新的API。然后,您可以进入一个循环,等待屏幕更新并依次获取每个帧。

如果你想将帧编码为视频,我建议你看看Media Foundation而不是DirectShow,因为Media Foundation有更好的性能,可以使用D3D11而不是D3D9进行编码。它也更容易使用,具体取决于您的场景。请查看Media Foundation的Sink Writer,了解最简单的视频帧编码方法。

为了完全披露,我在微软拥有桌面复制API的团队工作,我个人使用这种技术编写了以60fps的速度将桌面(以及视频,游戏等)捕获到视频文件的应用程序,以及许多其他场景。

相关问题