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 Ultimate(x64)でVisual C++ 2010 Expressを使用しています。
編集:
また、このコードは完全ではありません。たとえば、Device
識別子は何ですか?!
これは、DirectX 9で画面をキャプチャするためのサンプルコードです。SDKをインストールする必要はありません(VS 2010をテストしていませんが、Visual Studioに付属する標準ファイルを除きます)。
単純な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-Dell Precision M2800/i7-4810MQ-2.80GHz/Intel HD 4600これはかなりくだらないマシンです...)マシンでは、1920x1080のキャプチャが100秒かかるため、約4秒で、約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, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &device));
HRCHECK(device->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, nullptr));
// compute the required buffer size
HRCHECK(surface->LockRect(&rc, NULL, 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, NULL, 0));
CopyMemory(shots[i], rc.pBits, rc.Pitch * mode.Height);
HRCHECK(surface->UnlockRect());
}
GetSystemTime(&st);
wprintf(L"%i:%i:%i.%i\n", st.wHour, st.wMinute, st.wSecond, 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, mode.Height, 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, nullptr, &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, hr, __LINE__,__WFILE__);goto cleanup;}}
#define RELEASE(__p) {if(__p!=nullptr){__p->Release();__p=nullptr;}}
注:Windows 8以降のクライアントの場合、これらすべて(WICを除く)は Desktop Duplication API を優先して削除する必要があります。
ターゲットのWindowsバージョンの要件を指定していません。 Windows 7をサポートする必要がない場合、Windows 8には、新しいDXGIインターフェイス IDXGIOutputDuplication が含まれています。これにより、ビデオアダプターの出力を複製し、CPUからビデオメモリへのアクセスを提供するCOMオブジェクトを作成できます。 IDXGIOutputDuplication :: MapDesktopSurface 。 MSDNには非常に優れた sample があり、これを使用してデスクトップをキャプチャし、フォーム内に描画してスムーズに動作します。したがって、Windows 7が必須ではない場合は、これを確認することをお勧めします。
DirectX SDKはMicrosoft.com/en-ca/download/details.aspx?id=6812(@ymsによる投稿)から入手できます。このSDKは、XPを含むすべてのバージョンのWindowsと互換性があります。 D3D9をインクルード/リンクする方法については、そのドキュメントを参照してください。
あなたの例ではDevice
はIDirect3DDevice9
です。すべてのD3D9アプリケーションは、これらのいずれかを作成する必要があります。コードの作成方法に関するサンプルコードを見つけるのは非常に簡単です(例 https://msdn.Microsoft.com/en-us/library/windows/desktop/bb204867%28v=vs.85%29.aspx )。
サンプルコードでは、DirectXでレンダリングされているコンテンツのみがキャプチャされていますが、これはあなたの意図ではないと思います。画面全体をキャプチャするには(私が目標としている)、IDirect3DDevice9::GetRenderTarget
を使用する代わりに、このチュートリアルのようにIDirect3DDevice9::GetFrontBufferData
を使用する必要があります( http:// dim-i .net/2008/01/29/taking-screenshots-with-directx-and-dev-cpp / )。速度を求める場合は、例とこのチュートリアルの両方のように、フレームごとにオフスクリーンサーフェスを再作成しないでください。この場合、メモリプールはD3DPOOL_SYSTEMMEM
ではなくD3DPOOL_SCRATCH
である必要があります。画面のサイズに応じて、ボトルネックがイメージをディスクに書き込むことになります。
また、ここからキャプチャされた画面は、IDirect3DDevice9
を作成するために使用されるアダプタ用であることに注意してください。これはIDirect3D9::CreateDevice
の最初のパラメータです。これは、複数のモニターをキャプチャする可能性がある場合にのみ問題になります。