Captura de tela DirectX e saída como vídeo
Estou capturando a tela da área de trabalho e queria que a saída fosse um arquivo de vídeo. Atualmente, tenho códigos provenientes deaqui para gerar imagens png. Modifiquei um pouco o código para alterar a saída para o arquivo JPEG e, em seguida, converti-o para saída de vídeo avi usando o openCV 3.0.0. O motivo pelo qual eu preciso do arquivo JPEG é que a saída é porque estou executando no Windows 8.1 e OpenCV VideoWriter :: fourcc ('M', 'J', 'P', 'G') são as únicas opções que funcionam para mim.
A saída da imagem PNG funciona perfeitamente, mas não o JPEG. Existem linhas verticais na imagem e o tempo para gerar as saídas JPEG é relativamente longe, r que PNG.
Eu tenho 2 opções aqui:
Melhore a saída do arquivo JPEG para trabalhar mais rápido e ter uma imagem nítida.
Livre-se do problema do OpenCV 3.0.0 para aceitar a entrada de arquivo PNG e capaz de gerar um arquivo de vídeo (de preferência no formato de arquivo AVI / MP4)
Qualquer solução servirá para mim. Por favor ajude. Obrigado.
Meu código:
#include "stdafx.h"
#include <Wincodec.h> // we use WIC for saving images
#include <d3d9.h> // DirectX 9 header
#include <opencv\cv.h>
#include <opencv\cxcore.hpp>
#include <opencv2\highgui\highgui.hpp>
#pragma comment(lib, "d3d9.lib") // link to DirectX 9 library
using namespace cv;
#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;}}
HRESULT Direct3D9TakeScreenshots(UINT adapter, UINT count);
HRESULT SavePixelsToFile32bppPBGRA(UINT width, UINT height, UINT stride, LPBYTE pixels, LPWSTR filePath, const GUID &format);
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = Direct3D9TakeScreenshots(D3DADAPTER_DEFAULT, 10);
return 0;
}
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"START Capture--> %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"END Capture--> %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.jpg", i);
HRCHECK(SavePixelsToFile32bppPBGRA(mode.Width, mode.Height, pitch, shots[i], file, GUID_ContainerFormatJpeg));
}
cleanup:
if (shots != nullptr)
{
for (UINT i = 0; i < count; i++)
{
delete shots[i];
}
delete[] shots;
}
RELEASE(surface);
RELEASE(device);
RELEASE(d3d);
return hr;
}
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();
//This part do encode JPEG file to video file
VideoCapture in_capture("cap%d.jpg");
Mat img;
VideoWriter out_capture("video.avi", CV_FOURCC('M','J','P','G'), 1, Size(1920,1080));
while (true)
{
in_capture >> img;
if(img.empty())
break;
out_capture.write(img);
}
return hr;
}