0

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;
}
TEARLESS
  • 31
  • 1
  • 6

1 Answers1

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:

enter image description here

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Good afternoon, but you didn't help with the main problem, it doesn't display pixels. – TEARLESS Nov 29 '20 at 21:21
  • `sptr` holds valid pixels values representing monitor image, can't you take care of the pixels from there? – Roman R. Nov 29 '20 at 21:25
  • https://pix.my/o/0bdULh?1606685706 That's what I'm trying to do, but it displays zeros, so i think it cannot scan the screen. – TEARLESS Nov 29 '20 at 21:35
  • My mistake, I saw it was displaying pixels correctly. Please help me set it up, how can I display a pixel from certain coordinates? – TEARLESS Nov 29 '20 at 21:44
  • I don't understand the question. Here on StackOverflow there are questions and answers, you had an empty array and this is hopefully resolved. Please ask another question and explain how exactly you are trying to display pixels, what you are doing for this and where you get stuck. – Roman R. Nov 29 '20 at 22:00
  • https://stackoverflow.com/questions/65065765/dxgi-fails-to-scan-60-fps-pixels – TEARLESS Nov 29 '20 at 22:13
  • https://stackoverflow.com/questions/65065765/dxgi-fails-to-scan-60-fps-pixels new team – TEARLESS Nov 29 '20 at 22:13
  • I did mention that your responsibility is to match `AcquireNextFrame` and `ReleaseFrame` calls. I edited code so that you have match for the first acquired image, to make sure captured pixels are valid. In your further edit you fail to match the calls. – Roman R. Nov 29 '20 at 22:20
  • Good afternoon. Thank you very much for helping me, but I have a new problem. I'm counting on you.)) https://stackoverflow.com/questions/65066779/dxgi-scans-pixels-at-10-fps-and-uses-more-memory – TEARLESS Nov 30 '20 at 00:46
  • Hi @RomanR. I am running into problems as well with this. Map function returns with success but when i am trying to convert BYTE* to HBITMAP and dumping it everything is black. @ TEARLESS can you please share your piece of code. I see that page is no longer present – Illuminati Jul 17 '23 at 12:59