Hi I am trying to combine the given code with mine to output an array of pixels from the image, but the problem is 1) It outputs an empty array 2) memcpy fails with "unique_ptr to const void * ERROR" How to access pixels data from ID3D11Texture2D?
To be honest, I don't understand what the problem might be, because I did everything as it says. Help please, maybe I missed something.
#include "D3D9.h"
#include <Wincodec.h>
#include <chrono>
#include <shellapi.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <Atlbase.h>
#include <comdef.h>
#include <windows.h>
#include <shlobj.h>
#include <shellapi.h>
#include <dxgi1_2.h>
#include <d3d11.h>
#include <memory>
#include <algorithm>
#include <string>
#include <iostream>
#pragma comment(lib, "D3D11.lib")
#pragma comment(lib, "D3d9.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "gdi32.lib")
//using namespace System;
#define EXIT(hr) { if (FAILED(hr)) \
{std::cout<<"ERROR"<<std::endl; return -1; } }
HBITMAP GetPix(ID3D11Texture2D* d3dtex, ID3D11Device* pDevice)
{
HRESULT hr;
HBITMAP hBitmapTexture = NULL;
HGDIOBJ hBitmap;
D3D11_TEXTURE2D_DESC desc;
ID3D11Texture2D* pNewTexture = NULL;
D3D11_TEXTURE2D_DESC description;
d3dtex->GetDesc(&desc);
d3dtex->GetDesc(&description);
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
description.MiscFlags = 0;
if (FAILED(pDevice->CreateTexture2D(&description, NULL, &pNewTexture)))
{
return NULL;
}
ID3D11DeviceContext* ctx = NULL;
pDevice->GetImmediateContext(&ctx);
ctx->CopyResource(pNewTexture, d3dtex);
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
ctx->Map(pNewTexture, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
// Copy from texture to bitmap buffer.
std::unique_ptr<BYTE> pBuf(new BYTE[resource.RowPitch * desc.Height]);
UINT lBmpRowPitch = desc.Width * 4;
BYTE* sptr = reinterpret_cast<BYTE*>(resource.pData);
BYTE* dptr = pBuf.get() + resource.RowPitch * desc.Height - lBmpRowPitch;
UINT lRowPitch = std::min<UINT>(lBmpRowPitch, resource.RowPitch);
for (size_t h = 0; h < desc.Height; ++h)
{
memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
sptr += resource.RowPitch;
dptr -= lBmpRowPitch;
}
ctx->Unmap(pNewTexture, subresource);
long g_captureSize = lRowPitch * desc.Height;
UCHAR* g_iMageBuffer = nullptr;
g_iMageBuffer = new UCHAR[g_captureSize];
g_iMageBuffer = (UCHAR*)malloc(g_captureSize);
//Copying to UCHAR buffer
//memcpy(g_iMageBuffer, pBuf, g_captureSize);
std::cout << pBuf<< std::endl;
}
int main()
{
HRESULT hr;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1
};
D3D_FEATURE_LEVEL d3dFeatLvl;
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pImmediateContext = nullptr;
hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE,
NULL, D3D11_CREATE_DEVICE_DEBUG, featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&pDevice,
&d3dFeatLvl,
&pImmediateContext);
EXIT(hr);
IDXGIDevice* DxgiDevice = nullptr;
hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice));
IDXGIAdapter* DxgiAdapter = nullptr;
hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter));
EXIT(hr);
DxgiDevice->Release();
DxgiDevice = nullptr;
IDXGIOutput* DxgiOutput = nullptr;
hr = DxgiAdapter->EnumOutputs(0, &DxgiOutput);
EXIT(hr);
DxgiAdapter->Release();
DxgiAdapter = nullptr;
DXGI_OUTPUT_DESC OutputDesc;
DxgiOutput->GetDesc(&OutputDesc);
IDXGIOutput1* DxgiOutput1 = nullptr;
hr = DxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&DxgiOutput1));
EXIT(hr);
DxgiOutput->Release();
DxgiOutput = nullptr;
IDXGIOutputDuplication* DeskDupl = nullptr;
hr = DxgiOutput1->DuplicateOutput(pDevice, &DeskDupl);
EXIT(hr);
DxgiOutput1->Release();
DxgiOutput1 = nullptr;
DXGI_OUTDUPL_DESC OutputDuplDesc;
DeskDupl->GetDesc(&OutputDuplDesc);
ID3D11Texture2D* AcquiredDesktopImage = nullptr;
IDXGIResource* DesktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
hr = DeskDupl->AcquireNextFrame(20, &FrameInfo, &DesktopResource);
EXIT(hr);
hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&AcquiredDesktopImage));
EXIT(hr);
DesktopResource->Release();
DesktopResource = nullptr;
GetPix(AcquiredDesktopImage, pDevice);
//GETRGB(AcquiredDesktopImage, pDevice);
return 0;
}
There are a few problems in your code, specifically you need to match AcquireFrame
/ReleaseFrame
calls and accept the fact that you don't necessarily get the picture in the first call. I explained this earlier in DXGI API: AcquireNextFrame() never grabs an updated image, always blank question.
I edited your code to make it work, see ADDED and REMOVED comments.
IDXGIResource* DesktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
// <<--- BEGIN ADDED
for(; ; )
{
hr = DeskDupl->AcquireNextFrame(20, &FrameInfo, &DesktopResource);
EXIT(hr);
if(FrameInfo.LastPresentTime.QuadPart == 0)
{
DesktopResource->Release();
hr = DeskDupl->ReleaseFrame();
EXIT(hr);
continue;
}
hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&AcquiredDesktopImage));
GetPix(AcquiredDesktopImage, pDevice);
break;
}
// <<--- END ADDED
EXIT(hr);
DesktopResource->Release();
DesktopResource = nullptr;
//GetPix(AcquiredDesktopImage, pDevice); // <<--- REMOVED
//GETRGB(AcquiredDesktopImage, pDevice);
You can set a breakpoint after sptr
line and see the data is there: