Eksperymentowałem ze sposobami przechwytywania ekranu w oknach i w konsekwencji decydowania o najszybszym sposobie. Najbardziej powszechny jest oczywiście sposób GDI. I jest przyzwoity także pod względem wydajności. W zależności od obciążenia systemu i statycznej/niestatycznej zawartości ekranu szybkość przechwytywania ekranu wynosiła od 27-47 fps (Windows 7, Intel [email protected] GHz, 8 GB RAM).Używanie DirectX do przechwytywania ekranu w systemie Windows
Teraz, stosując metodę DirectX Front Buffer (wykorzystującą API GetFrontBufferData()), wydajność była porównywalna, ale nieznacznie wolniejsza (nie mogłem osiągnąć nawet 48 fps).
Przeszedłem przez ten post: Fastest method of screen capturing i wypróbowałem sposób sugerowany w zaakceptowanej odpowiedzi za pomocą getRenderTarget() i getRenderTargetData(), ale jak zasugerowano w komentarzach, dostaję tylko czarny obraz. Oto mój pełny kod w tym wstępne konfiguracje urządzenia:
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();
oraz za część inicjalizacji urządzenie:
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);
Proszę zwrócić uwagę na błąd w powyższym kodzie. Wszelkie sugestie są mile widziane. Próbowałem również funkcji API GetBackBuffer(), ale nie udało mi się uzyskać danych obrazu.
EDIT:
Mój przypadek użycia było przechwytywanie ekranu pulpitu, który wydaje się być dokonana jedynie za pomocą GetFrontBufferData() poprzez DirectX. GetBackBuffer()/GetRenderTargetData() nie jest właściwym interfejsem API do wywoływania tego przypadku. Odniesienia: The desktop capture with DirectX does not work i How to get the screenshot of the desktop from back buffer with DirectX.
Jednak wszelkie sugestie dotyczące szybszej metody przechwytywania ekranu pulpitu lub optymalizacji sposobu GDI są mile widziane.
Czuję, że 'GetRenderTarget' zwróci bufor zwrotny dla urządzenia. Możesz zajrzeć do funkcji 'GetFrontBufferData'. –
Użyłem GetFrontBufferData(), jak wspomniano w pytaniu, działa dobrze. Ale nie ma poprawy wydajności w stosunku do GDI. Szukałem szybszego podejścia, jeśli w ogóle. –
Piszę również aplikację screencapture. [Here] (http://stackoverflow.com/q/31286503/4794952) jest linkiem do mojego problemu. Dostaję czarny ekran, gdy przechwytywam jakąkolwiek grę, podczas gdy dla każdej innej aplikacji zwraca ona właściwy przechwycony ekran. Czy jest jakiś sposób, aby działał z pełnoekranowymi grami? – newbie2015