Stavo sperimentando modi per acquisire lo schermo su Windows e di conseguenza decidere il modo più veloce per farlo. Il più comune è ovviamente il modo GDI. Ed è decente anche nelle prestazioni. A seconda del carico del sistema e del contenuto dello schermo statico/non statico, la velocità di acquisizione dello schermo variava da 27 a 47 fps (Windows 7, Intel [email protected],6 GHz, 8 GB di RAM).Utilizzo di DirectX per acquisire lo schermo su Windows
Ora, con l'approccio del front-buffer DirectX (utilizzando l'API GetFrontBufferData()), le prestazioni erano paragonabili ma leggermente più lente (non riuscivo a raggiungere i 48 fps).
Ho passato questo post: Fastest method of screen capturing e ho provato il modo suggerito nella risposta accettata usando getRenderTarget() e getRenderTargetData(), ma come suggerito nei commenti, tutto quello che ottengo è un'immagine nera. Qui è il mio codice completo incluse le configurazioni iniziali per il dispositivo:
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();
E per la parte di inizializzazione del dispositivo:
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);
Si prega di segnalare l'errore nel codice di cui sopra. Qualsiasi suggerimento è benvenuto. Ho anche provato l'API GetBackBuffer() ma non ho potuto ottenere i dati dell'immagine.
EDIT:
mio caso d'uso è stato quello di bloccare lo schermo del desktop che sembra essere fatto solo utilizzando GetFrontBufferData() tramite DirectX. GetBackBuffer()/GetRenderTargetData() non è l'API corretta per chiamare questo caso. Riferimento: The desktop capture with DirectX does not work e How to get the screenshot of the desktop from back buffer with DirectX.
Tuttavia, qualsiasi suggerimento per un metodo più veloce per l'acquisizione dello schermo del desktop o l'ottimizzazione del modo GDI sono i benvenuti.
Mi sembra che 'GetRenderTarget' restituirà il buffer posteriore per il dispositivo. Si potrebbe voler esaminare la funzione 'GetFrontBufferData'. –
Ho usato GetFrontBufferData() come menzionato nella domanda, funziona perfettamente. Ma, non c'è alcun guadagno in termini di prestazioni rispetto al modo GDI. Stavo cercando un approccio più veloce, se esiste. –
Sto anche scrivendo un'applicazione per screencapture. [Qui] (http://stackoverflow.com/q/31286503/4794952) è il link al mio problema. Ottengo uno schermo nero quando catturo qualsiasi gioco, mentre per qualsiasi altra applicazione, restituisce lo schermo catturato giusto. C'è un modo per farlo funzionare con i giochi a schermo intero? – newbie2015