Capturar janela via DirectX (C++)

5 respostas
P

Eu estava tentando entender/editar um codigo para capturar uma janela especifica pelo DirectX, como o “Capturar jogo” do OBS Studio faz, porém não consegui entender nenhum exemplo que encontrei na internet.

Eu encontrei esse codigo no github que duplica o Desktop pelo DirectX: https://github.com/arBmind/desktop-duplication-cpp, porém não faço ideia de como fazê-lo capturar uma janela específica ao invés do desktop, é totalmente diferente dos metodos que eu utilizava (PrintWindow\BitBlt).

Outro exemplo que eu encontrei foi esse, porém também não consegui entendê-lo:

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

5 Respostas

K

Tentou com GetFrontBufferData() em lugar ou antes de GetRenderTargetData()?

E, acho que se você usar D3D9 não vai conseguir capturar tela de contextos D3D10, ou D3D11.

P

Obrigado pela resposta Kronal, eu não tentei o GetFrontBufferData() pois não sei como utilizar tal codigo, nunca tive experiencia com DirectX antes, o que eu creio que esteja faltando no código seja criar o “Device”, porém não faço ideia de como fazer isso. E sobre o D3D11, voce teria um exemplo de como eu faria?

K

Aqui nesse thread tem codigo que parece funcionar (o problema do cara é só com cores 16bits):

Sobre uso de D3D11 eu já vi fazerem captura de tela mas é muito mais complexo, até D3D10 já é bem mais complexo no geral que o 9, e sinceramente ta fora da minha alçada.

P

O codigo dele está incompleto, foi postado somente a parte da dúvida.

ViniGodoy

O D3DX foi deprecated desde o DX9.

No lugar, a MS recomenda o uso da biblioteca DirectXTex. Nele existe um módulo chamado ScreenGrab que torna o processo realmente simples.

using namespace DirectX;
using namespace Microsoft::WRL;

ComPtr<ID3D11Texture2D> backBuffer;
HRESULT hr = swapChain->GetBuffer( 0,
__uuidof( ID3D11Texture2D ),
   reinterpret_cast<LPVOID*>( backBuffer.GetAddressOf() ) );
if ( SUCCEEDED(hr) )
{
hr = SaveWICTextureToFile( immContext.Get(), backBuffer.Get(),
            GUID_ContainerFormatJpeg, L"SCREENSHOT.JPG" );
}
DX::ThrowIfFailed(hr);

Aproveite e também instale o DirectXTK que já inclui o ScreenGrab e várias outras funções bastante úteis para lidar com o DirectX. Observe que todos esses módulos são da própria Microsoft.

Criado 28 de dezembro de 2019
Ultima resposta 24 de jan. de 2020
Respostas 5
Participantes 3