I am using this code to take a series of screen shot using desktop duplication api.
The code is only for a single shot. Thus I am looping over it. However looping the entire code gives fps of 3-4. So I am not looping over the declarations and stuff.
hr = lDesktopResource->QueryInterface(IID_PPV_ARGS(&lAcquiredDesktopImage));
this line only executes once.
On the second loop it breaks. in other words,
2nd loop executes fine until it hits this line, after which the program terminates automatically.
Commenting this line out makes 2nd and further loops work, however the image generated is black. Looping over the entire code in main() fixes the issue but gives terrible performance.
I have tried to replace it with
hr = lDesktopResource->QueryInterface(&lAcquiredDesktopImage);
It does not remove the issue.
I have looked into other similar codes like this. But this code does not work either. It is suppose to do screen capture for 10 seconds, however the program terminates immediately. The output file cant be opened.
I have tried comparing my code with the code given in this question. But i can't figure out the issue.
I have searched for similar codes on the internet, however they are mostly for single shot, not series of shots in quick succession using desktop duplication.
I have tried adding a Sleep(100) in the loop. It does not help. How can I fix this?
int main()
{
int lresult(-1);
D3D_FEATURE_LEVEL lFeatureLevel;
HRESULT hr(E_FAIL);
// Create device
for (UINT DriverTypeIndex = 0; DriverTypeIndex < gNumDriverTypes; ++DriverTypeIndex){
hr = D3D11CreateDevice(
nullptr,
gDriverTypes[DriverTypeIndex],
nullptr,
0,
gFeatureLevels,
gNumFeatureLevels,
D3D11_SDK_VERSION,
&lDevice,
&lFeatureLevel,
&lImmediateContext);
if (SUCCEEDED(hr)){
// Device creation success, no need to loop anymore
break;
}
lDevice.Release();
lImmediateContext.Release();
}
Sleep(100);
// Get DXGI device
CComPtrCustom<IDXGIDevice> lDxgiDevice;
hr = lDevice->QueryInterface(IID_PPV_ARGS(&lDxgiDevice));
// Get DXGI adapter
CComPtrCustom<IDXGIAdapter> lDxgiAdapter;
hr = lDxgiDevice->GetParent(
__uuidof(IDXGIAdapter),
reinterpret_cast<void**>(&lDxgiAdapter));
lDxgiDevice.Release();
UINT Output = 0;
// Get output
CComPtrCustom<IDXGIOutput> lDxgiOutput;
hr = lDxgiAdapter->EnumOutputs(
Output,
&lDxgiOutput);
lDxgiAdapter.Release();
hr = lDxgiOutput->GetDesc(
&lOutputDesc);
// QI for Output 1
CComPtrCustom<IDXGIOutput1> lDxgiOutput1;
hr = lDxgiOutput->QueryInterface(IID_PPV_ARGS(&lDxgiOutput1));
lDxgiOutput.Release();
// Create desktop duplication
hr = lDxgiOutput1->DuplicateOutput(
lDevice,
&lDeskDupl);
lDxgiOutput1.Release();
// Create GUI drawing texture
lDeskDupl->GetDesc(&lOutputDuplDesc);
D3D11_TEXTURE2D_DESC desc;
desc.Width = lOutputDuplDesc.ModeDesc.Width;
desc.Height = lOutputDuplDesc.ModeDesc.Height;
desc.Format = lOutputDuplDesc.ModeDesc.Format;
desc.ArraySize = 1;
desc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET;
desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MipLevels = 1;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
hr = lDevice->CreateTexture2D(&desc, NULL, &lGDIImage);
// Create CPU access texture
desc.Width = lOutputDuplDesc.ModeDesc.Width;
desc.Height = lOutputDuplDesc.ModeDesc.Height;
desc.Format = lOutputDuplDesc.ModeDesc.Format;
desc.ArraySize = 1;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MipLevels = 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
hr = lDevice->CreateTexture2D(&desc, NULL, &lDestImage);
int index_main = 0;
while (index_main< 10) {
CComPtrCustom<IDXGIResource> lDesktopResource;
DXGI_OUTDUPL_FRAME_INFO lFrameInfo;
int lTryCount = 4;
do
{
Sleep(100);
// Get new frame
hr = lDeskDupl->AcquireNextFrame(
0,
&lFrameInfo,
&lDesktopResource);
if (SUCCEEDED(hr))
break;
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
{
continue;
}
else if (FAILED(hr))
break;
} while (--lTryCount > 0);
// QI for ID3D11Texture2D
std::cout << index_main;
hr = lDesktopResource->QueryInterface(IID_PPV_ARGS(&lAcquiredDesktopImage));
//this is beaking the loop
lDesktopResource.Release();
// Copy image into GDI drawing texture
lImmediateContext->CopyResource(lGDIImage, lAcquiredDesktopImage);
// Draw cursor image into GDI drawing texture
CComPtrCustom<IDXGISurface1> lIDXGISurface1;
hr = lGDIImage->QueryInterface(IID_PPV_ARGS(&lIDXGISurface1));
CURSORINFO lCursorInfo = { 0 };
lCursorInfo.cbSize = sizeof(lCursorInfo);
auto lBoolres = GetCursorInfo(&lCursorInfo);
if (lBoolres == TRUE)
{
if (lCursorInfo.flags == CURSOR_SHOWING)
{
auto lCursorPosition = lCursorInfo.ptScreenPos;
auto lCursorSize = lCursorInfo.cbSize;
HDC lHDC;
lIDXGISurface1->GetDC(FALSE, &lHDC);
DrawIconEx(
lHDC,
lCursorPosition.x,
lCursorPosition.y,
lCursorInfo.hCursor,
0,
0,
0,
0,
DI_NORMAL | DI_DEFAULTSIZE);
lIDXGISurface1->ReleaseDC(nullptr);
}
}
// Copy image into CPU access texture
lImmediateContext->CopyResource(lDestImage, lGDIImage);
// Copy from CPU access texture to bitmap buffer
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
lImmediateContext->Map(lDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
index_main = index_main + 1;
}
return lresult;
}