DXGICaptureSample icon indicating copy to clipboard operation
DXGICaptureSample copied to clipboard

Question

Open Arnold1 opened this issue 8 years ago • 3 comments

Hi, I have a few question to your project. How many fps can you achieve?

i tried to measure how many fps your capture would give. it only gets 6 fps... any idea? i tested it with windows 10 + NVIDIA GeForce GT 720M

// DXGICaptureSample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "DXGIManager.h"
#include <time.h>

DXGIManager g_DXGIManager;

void init() {
    CoInitialize(NULL);
}

int capture() {
    //printf("DXGICaptureSample. Fast windows screen capture\n");
    //printf("Capturing desktop to: capture.bmp\n");
    //printf("Log: logfile.log\n");

    g_DXGIManager.SetCaptureSource(CSDesktop);

    RECT rcDim;
    g_DXGIManager.GetOutputRect(rcDim);

    DWORD dwWidth = rcDim.right - rcDim.left;
    DWORD dwHeight = rcDim.bottom - rcDim.top;

    //printf("dwWidth=%d dwHeight=%d\n", dwWidth, dwHeight);

    DWORD dwBufSize = dwWidth*dwHeight*4;

    BYTE* pBuf = new BYTE[dwBufSize];

    CComPtr<IWICImagingFactory> spWICFactory = NULL;
    HRESULT hr = spWICFactory.CoCreateInstance(CLSID_WICImagingFactory);
    if( FAILED(hr) )
        return hr;

    int i=0;
    do
    {
        hr = g_DXGIManager.GetOutputBits(pBuf, rcDim);
        i++;
    }
    while (hr == DXGI_ERROR_WAIT_TIMEOUT || i < 2);

    if( FAILED(hr) )
    {
        printf("GetOutputBits failed with hr=0x%08x\n", hr);
        return hr;
    }

    //printf("Saving capture to file\n");

    CComPtr<IWICBitmap> spBitmap = NULL;
    hr = spWICFactory->CreateBitmapFromMemory(dwWidth, dwHeight, GUID_WICPixelFormat32bppBGRA, dwWidth*4, dwBufSize, (BYTE*)pBuf, &spBitmap);
    if( FAILED(hr) )
        return hr;

    CComPtr<IWICStream> spStream = NULL;

    hr = spWICFactory->CreateStream(&spStream);
    if (SUCCEEDED(hr)) {
        hr = spStream->InitializeFromFilename(L"capture.bmp", GENERIC_WRITE);
    }

    CComPtr<IWICBitmapEncoder> spEncoder = NULL;
    if (SUCCEEDED(hr)) {
        hr = spWICFactory->CreateEncoder(GUID_ContainerFormatBmp, NULL, &spEncoder);
    }

    if (SUCCEEDED(hr)) {
        hr = spEncoder->Initialize(spStream,WICBitmapEncoderNoCache);
    }

    CComPtr<IWICBitmapFrameEncode> spFrame = NULL;
    if (SUCCEEDED(hr)) {
        hr = spEncoder->CreateNewFrame(&spFrame, NULL);
    }

    if (SUCCEEDED(hr)) {
        hr = spFrame->Initialize(NULL);
    }

    if (SUCCEEDED(hr)) {
        hr = spFrame->SetSize(dwWidth, dwHeight);
    }

    WICPixelFormatGUID format;
    spBitmap->GetPixelFormat(&format);

    if (SUCCEEDED(hr)) {
        hr = spFrame->SetPixelFormat(&format);
    }

    if (SUCCEEDED(hr)) {
        hr = spFrame->WriteSource(spBitmap, NULL);
    }

    if (SUCCEEDED(hr)) {
        hr = spFrame->Commit();
    }

    if (SUCCEEDED(hr)) {
        hr = spEncoder->Commit();
    }

    delete[] pBuf;

    return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
    init();

    clock_t t1 = clock();
    int i;
    int iterations = 100;
    for (i = 0;i < iterations;i++) {
        capture();
    }
    clock_t t2 = clock();
    printf("%d iterations: %0.0f fps\n", iterations, iterations / ((double)(t2 - t1) / CLOCKS_PER_SEC));

    return 0;
}

Arnold1 avatar Oct 21 '16 14:10 Arnold1

Hi,

The main issue I see is that cature() is allocating pBuf every single frame, the same with converting the pBuf to image via gdiplus every frame - it's too much overhead. I would try to rewrite the code so pBuf is allocated only once and then - looked at the code saving picture - I think it has too much overhead as well...

pgurenko avatar Oct 24 '16 03:10 pgurenko

@pgurenko ok, how to improve it so it can record 2 seconds with 30 fps?

Arnold1 avatar Oct 24 '16 03:10 Arnold1

@Arnold1, sorry for the late reply. I would start with simple proof-of-concept like how many fps can we get from just using duplication. The next code gives me about 30 fps so it look like it is possible to achieve it through output duplication.

// DXGICaptureSample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "DXGIManager.h"
#include <time.h>

DXGIManager g_DXGIManager;

int capture(RECT& rcDim, vector<BYTE>& buf, CComPtr<IWICImagingFactory>& spWICFactory) {
  DWORD dwWidth = rcDim.right - rcDim.left;
  DWORD dwHeight = rcDim.bottom - rcDim.top;
  DWORD dwBufSize = buf.size();

  HRESULT hr = g_DXGIManager.GetOutputBits(buf.data(), rcDim);
  if (FAILED(hr))
  {
    printf("GetOutputBits failed with hr=0x%08x\n", hr);
    return hr;
  }
  return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
  CoInitialize(NULL);

  g_DXGIManager.SetCaptureSource(CSDesktop);

  RECT rcDim;
  g_DXGIManager.GetOutputRect(rcDim);

  DWORD dwWidth = rcDim.right - rcDim.left;
  DWORD dwHeight = rcDim.bottom - rcDim.top;

  printf("dwWidth=%d dwHeight=%d\n", dwWidth, dwHeight);

  DWORD dwBufSize = dwWidth*dwHeight * 4;

  vector<BYTE> buf(dwBufSize);

  CComPtr<IWICImagingFactory> spWICFactory = NULL;
  HRESULT hr = spWICFactory.CoCreateInstance(CLSID_WICImagingFactory);
  if (FAILED(hr))
    return hr;

  clock_t t1 = clock();
  int i;
  int iterations = 100;  
  for (i = 0; i < iterations; i++) {
    capture(rcDim, buf, spWICFactory);
  }
  clock_t t2 = clock();
  printf("%d iterations: %0.0f fps\n", iterations, iterations / ((double)(t2 - t1) / CLOCKS_PER_SEC));

  return 0;
}

dwWidth=3840 dwHeight=2160 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 GetOutputBits failed with hr=0x887a0027 100 iterations: 30 fps

I guessed, frame drops are ok - I don't think you really want enforce saving each and every frame.

After that, you will need save the data in buf somewhere and that is another question. There could be a queue keeping few latest frames in the memory and few threads processing this queue and saving frames to JPEG or compressing to video stream....

pgurenko avatar Oct 04 '17 05:10 pgurenko