5

因为D3DPOOL_SCRATCH处理比较慢,所以自己写了桌面抓包程序,供网上的报告参考。然而,结果是一幅漆黑的画面。这是控制台程序的结果还是有其他原因?

#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();
}
4

2 回答 2

5

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

获取前端缓冲区数据

所以而不是打电话

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

你应该打电话

d3ddev->GetFrontBufferData(0, dest);
于 2012-10-12T16:14:28.730 回答
4

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

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

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

于 2014-03-06T07:41:04.450 回答