Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access pixels data from ID3D11Texture2D?

I'm using Windows Desktop Duplication API to make my own mirroring protocol. I have this piece of code :

// Get new frame
HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
{
    *Timeout = true;
    return DUPL_RETURN_SUCCESS;
}

Here is the FrameInfo structure :

`typedef struct _FRAME_DATA {
ID3D11Texture2D* Frame;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
_Field_size_bytes_((MoveCount * sizeof(DXGI_OUTDUPL_MOVE_RECT)) +    (DirtyCount * sizeof(RECT))) BYTE* MetaData;
UINT DirtyCount;
UINT MoveCount;
 } FRAME_DATA;`

I would like to extract the pixel buffer from ID3D11Texture2D* Frame; How can I extract on a BYTE * or unsigned char * and have a RGB sequence ? Thank you !

like image 381
X6Entrepreneur Avatar asked Apr 26 '17 09:04

X6Entrepreneur


2 Answers

You need to create a second texture of the same size with CPU read access using ID3D11Device::CreateTexture2D, copy whole frame or just updated parts to this texture on GPU using ID3D11DeviceContext::CopyResource or ID3D11DeviceContext::CopySubresourceRegion (it is possible to retrieve which parts were updated using IDXGIOutputDuplication::GetFrameDirtyRects and IDXGIOutputDuplication::GetFrameMoveRects), map second texture to make it accessible by CPU using ID3D11DeviceContext::Map which gives you D3D11_MAPPED_SUBRESOURCE struct containing pointer to buffer with frame data and it's size, that is what you are looking for.

Microsoft provides a rather detailed Desktop Duplication API usage sample implementing all the steps mentioned above.

There is also a straight sample demonstrating how to save ID3D11Texture2D data to file.

like image 188
user7860670 Avatar answered Nov 14 '22 22:11

user7860670


Hi here is the code which helps for your requirement. output will be in UCHAR buffer g_iMageBuffer

//Variable Declaration
IDXGIOutputDuplication* IDeskDupl;
IDXGIResource*          lDesktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO IFrameInfo;
ID3D11Texture2D*        IAcquiredDesktopImage;
ID3D11Texture2D*        lDestImage;
ID3D11DeviceContext*    lImmediateContext;
UCHAR*                  g_iMageBuffer=nullptr;

//Screen capture start here
hr = lDeskDupl->AcquireNextFrame(20, &lFrameInfo, &lDesktopResource);

// >QueryInterface for ID3D11Texture2D
hr = lDesktopResource->QueryInterface(IID_PPV_ARGS(&lAcquiredDesktopImage));
lDesktopResource.Release();

// Copy image into GDI drawing texture
lImmediateContext->CopyResource(lDestImage,lAcquiredDesktopImage);
lAcquiredDesktopImage.Release();
lDeskDupl->ReleaseFrame();  

// Copy GPU Resource to CPU
D3D11_TEXTURE2D_DESC desc;
lDestImage->GetDesc(&desc);
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
lImmediateContext->Map(lDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);

std::unique_ptr<BYTE> pBuf(new BYTE[resource.RowPitch*desc.Height]);
UINT lBmpRowPitch = lOutputDuplDesc.ModeDesc.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 < lOutputDuplDesc.ModeDesc.Height; ++h)
{
    memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
    sptr += resource.RowPitch;
    dptr -= lBmpRowPitch;
}

lImmediateContext->Unmap(lDestImage, subresource);
long g_captureSize=lRowPitch*desc.Height;
g_iMageBuffer= new UCHAR[g_captureSize];
g_iMageBuffer = (UCHAR*)malloc(g_captureSize);

//Copying to UCHAR buffer 
memcpy(g_iMageBuffer,pBuf,g_captureSize);
like image 36
Krish Avatar answered Nov 14 '22 22:11

Krish