c – 使用DirectX捕获屏幕

我知道如何使用GDI捕获屏幕,但它很慢(它几乎没有捕获10 fps)

我已经读过DirectX提供最佳速度.但在我开始学习DirectX之前,我想测试一个样本,看看它是否真的那么快.

我发现这个question提供了一个示例代码来做到这一点:

void dump_buffer()
{
   IDirect3DSurface9* pRenderTarget=NULL;
   IDirect3DSurface9* pDestTarget=NULL;
     const char file[] = "Pickture.bmp";
   // sanity checks.
   if (Device == NULL)
      return;

   // get the render target surface.
   HRESULT hr = Device->GetRenderTarget(0,&pRenderTarget);
   // get the current adapter display mode.
   //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

   // create a destination surface.
   hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width,DisplayMde.Height,DisplayMde.Format,D3DPOOL_SYSTEMMEM,&pDestTarget,NULL);
   //copy the render target to the destination surface.
   hr = Device->GetRenderTargetData(pRenderTarget,pDestTarget);
   //save its contents to a bitmap file.
   hr = D3DXSaveSurfaceToFile(file,D3DXIFF_BMP,pDestTarget,NULL,NULL);

   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();
}

我试图包含所需的文件.然而,并非所有这些都可以包括在内(例如#include< D3dx9tex.h>).

任何人都可以提供一个包含所有必需包含的工作示例,或者指出我应该安装哪些库.

我在Windows 7旗舰版(x64)上使用Visual C 2010 Express.

编辑:

此外,此代码不完整,例如什么是设备标识符?!

解决方法

以下是使用DirectX 9捕获屏幕的一些示例代码.
您不必安装任何SDK(Visual Studio附带的标准文件除外,尽管我没有测试过VS 2010).

只需创建一个简单的Win32控制台应用程序,在stdafx.h文件中添加以下内容:

#include <Wincodec.h>             // we use WIC for saving images
  #include <d3d9.h>                 // DirectX 9 header
  #pragma comment(lib,"d3d9.lib")  // link to DirectX 9 library

以下是示例主要实现

int _tmain(int argc,_TCHAR* argv[])
  {
    HRESULT hr = Direct3D9TakeScreenshots(D3DADAPTER_DEFAULT,10);
    return 0;
  }

这将做的是捕获10倍的屏幕,并将“cap%i.png”图像保存在磁盘上.它还将显示此时间(保存图像不计算在该时间内,仅屏幕捕获).
在我的(台式机Windows 8 – 戴尔Precision M2800 / i7-4810MQ-2.80GHz /英特尔HD 4600这是一台非常糟糕的机器……)机器上,它需要在约4秒内完成100次1920×1080捕获,因此大约需要20/25 fps.

HRESULT Direct3D9TakeScreenshots(UINT adapter,UINT count)
  {
    HRESULT hr = S_OK;
    IDirect3D9 *d3d = nullptr;
    IDirect3DDevice9 *device = nullptr;
    IDirect3DSurface9 *surface = nullptr;
    D3DPRESENT_PARAMETERS parameters = { 0 };
    D3DDISPLAYMODE mode;
    D3DLOCKED_RECT rc;
    UINT pitch;
    SYSTEMTIME st;
    LPBYTE *shots = nullptr;

    // init D3D and get screen size
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    HRCHECK(d3d->GetAdapterDisplayMode(adapter,&mode));

    parameters.Windowed = TRUE;
    parameters.BackBufferCount = 1;
    parameters.BackBufferHeight = mode.Height;
    parameters.BackBufferWidth = mode.Width;
    parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
    parameters.hDeviceWindow = NULL;

    // create device & capture surface
    HRCHECK(d3d->CreateDevice(adapter,D3DDEVTYPE_HAL,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&parameters,&device));
    HRCHECK(device->CreateOffscreenPlainSurface(mode.Width,mode.Height,D3DFMT_A8R8G8B8,&surface,nullptr));

    // compute the required buffer size
    HRCHECK(surface->LockRect(&rc,0));
    pitch = rc.Pitch;
    HRCHECK(surface->UnlockRect());

    // allocate screenshots buffers
    shots = new LPBYTE[count];
    for (UINT i = 0; i < count; i++)
    {
      shots[i] = new BYTE[pitch * mode.Height];
    }

    GetSystemTime(&st); // measure the time we spend doing <count> captures
    wprintf(L"%i:%i:%i.%i\n",st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    for (UINT i = 0; i < count; i++)
    {
      // get the data
      HRCHECK(device->GetFrontBufferData(0,surface));

      // copy it into our buffers
      HRCHECK(surface->LockRect(&rc,0));
      CopyMemory(shots[i],rc.pBits,rc.Pitch * mode.Height);
      HRCHECK(surface->UnlockRect());
    }
    GetSystemTime(&st);
    wprintf(L"%i:%i:%i.%i\n",st.wMilliseconds);

    // save all screenshots
    for (UINT i = 0; i < count; i++)
    {
      WCHAR file[100];
      wsprintf(file,L"cap%i.png",i);
      HRCHECK(SavePixelsToFile32bppPBGRA(mode.Width,pitch,shots[i],file,GUID_ContainerFormatPng));
    }

  cleanup:
    if (shots != nullptr)
    {
      for (UINT i = 0; i < count; i++)
      {
        delete shots[i];
      }
      delete[] shots;
    }
    RELEASE(surface);
    RELEASE(device);
    RELEASE(d3d);
    return hr;
  }

请注意,此代码隐含地链接到WIC(Windows中包含的成像库已有相当长的一段时间)以保存图像文件(因此您不需要需要安装旧版DirectX SDK的着名D3DXSaveSurfaceToFile):

HRESULT SavePixelsToFile32bppPBGRA(UINT width,UINT height,UINT stride,LPBYTE pixels,LPWSTR filePath,const GUID &format)
  {
    if (!filePath || !pixels)
      return E_INVALIDARG;

    HRESULT hr = S_OK;
    IWICImagingFactory *factory = nullptr;
    IWICBitmapEncoder *encoder = nullptr;
    IWICBitmapFrameEncode *frame = nullptr;
    IWICStream *stream = nullptr;
    GUID pf = GUID_WICPixelFormat32bppPBGRA;
    BOOL coInit = CoInitialize(nullptr);

    HRCHECK(CoCreateInstance(CLSID_WICImagingFactory,nullptr,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&factory)));
    HRCHECK(factory->CreateStream(&stream));
    HRCHECK(stream->InitializeFromFilename(filePath,GENERIC_WRITE));
    HRCHECK(factory->CreateEncoder(format,&encoder));
    HRCHECK(encoder->Initialize(stream,WICBitmapEncoderNoCache));
    HRCHECK(encoder->CreateNewFrame(&frame,nullptr)); // we don't use options here
    HRCHECK(frame->Initialize(nullptr)); // we dont' use any options here
    HRCHECK(frame->SetSize(width,height));
    HRCHECK(frame->SetPixelFormat(&pf));
    HRCHECK(frame->WritePixels(height,stride,stride * height,pixels));
    HRCHECK(frame->Commit());
    HRCHECK(encoder->Commit());

  cleanup:
    RELEASE(stream);
    RELEASE(frame);
    RELEASE(encoder);
    RELEASE(factory);
    if (coInit) CoUninitialize();
    return hr;
  }

我使用的一些宏:

#define WIDEN2(x) L ## x
  #define WIDEN(x) WIDEN2(x)
  #define __WFILE__ WIDEN(__FILE__)
  #define HRCHECK(__expr) {hr=(__expr);if(FAILED(hr)){wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" WIDEN(#__expr) L"'\n",hr,__LINE__,__WFILE__);goto cleanup;}}
  #define RELEASE(__p) {if(__p!=nullptr){__p->Release();__p=nullptr;}}

注意:对于Windows 8客户端,应删除所有这些(WIC除外)以支持Desktop Duplication API.

相关文章

一.C语言中的static关键字 在C语言中,static可以用来修饰局...
浅谈C/C++中的指针和数组(二) 前面已经讨论了指针...
浅谈C/C++中的指针和数组(一)指针是C/C++...
从两个例子分析C语言的声明 在读《C专家编程》一书的第三章时...
C语言文件操作解析(一)在讨论C语言文件操作之前,先了解一下...
C语言文件操作解析(三) 在前面已经讨论了文件打开操作,下面...