2017-05-07 1 views
0

Ich verwende Desktop-Duplizierung von Windows-API. Hier ist der Code, um auf den nächsten Frame zuzugreifen und das Rechteck der Pixel zu erhalten, die sich vom vorherigen Frame geändert haben.Extrahieren Sie fehlerhafte Rekruten RGB-Pixel Pufferdaten DirectX

// 
// Get next frame and write it into Data 
// 
_Success_(*Timeout == false && return == DUPL_RETURN_SUCCESS) 
DUPL_RETURN DUPLICATIONMANAGER::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Timeout) 
{ 
IDXGIResource* DesktopResource = nullptr; 
DXGI_OUTDUPL_FRAME_INFO FrameInfo; 

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

if (FAILED(hr)) 
{ 
    return ProcessFailure(m_Device, L"Failed to acquire next frame in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); 
} 

// If still holding old frame, destroy it 
if (m_AcquiredDesktopImage) 
{ 
    m_AcquiredDesktopImage->Release(); 
    m_AcquiredDesktopImage = nullptr; 
} 

// QI for IDXGIResource 
hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage)); 
DesktopResource->Release(); 
DesktopResource = nullptr; 
if (FAILED(hr)) 
{ 
    return ProcessFailure(nullptr, L"Failed to QI for ID3D11Texture2D from acquired IDXGIResource in DUPLICATIONMANAGER", L"Error", hr); 
} 

// Get metadata 
if (FrameInfo.TotalMetadataBufferSize) 
{ 
    // Old buffer too small 
    if (FrameInfo.TotalMetadataBufferSize > m_MetaDataSize) 
    { 
     if (m_MetaDataBuffer) 
     { 
      delete [] m_MetaDataBuffer; 
      m_MetaDataBuffer = nullptr; 
     } 
     m_MetaDataBuffer = new (std::nothrow) BYTE[FrameInfo.TotalMetadataBufferSize]; 
     if (!m_MetaDataBuffer) 
     { 
      m_MetaDataSize = 0; 
      Data->MoveCount = 0; 
      Data->DirtyCount = 0; 
      return ProcessFailure(nullptr, L"Failed to allocate memory for metadata in DUPLICATIONMANAGER", L"Error", E_OUTOFMEMORY); 
     } 
     m_MetaDataSize = FrameInfo.TotalMetadataBufferSize; 
    } 

    UINT BufSize = FrameInfo.TotalMetadataBufferSize; 

    // Get move rectangles 
    hr = m_DeskDupl->GetFrameMoveRects(BufSize, reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(m_MetaDataBuffer), &BufSize); 
    if (FAILED(hr)) 
    { 
     Data->MoveCount = 0; 
     Data->DirtyCount = 0; 
     return ProcessFailure(nullptr, L"Failed to get frame move rects in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); 
    } 
    Data->MoveCount = BufSize/sizeof(DXGI_OUTDUPL_MOVE_RECT); 

    BYTE* DirtyRects = m_MetaDataBuffer + BufSize; 
    BufSize = FrameInfo.TotalMetadataBufferSize - BufSize; 

    // Get dirty rectangles 
    hr = m_DeskDupl->GetFrameDirtyRects(BufSize, reinterpret_cast<RECT*>(DirtyRects), &BufSize); 
    if (FAILED(hr)) 
    { 
     Data->MoveCount = 0; 
     Data->DirtyCount = 0; 
     return ProcessFailure(nullptr, L"Failed to get frame dirty rects in DUPLICATIONMANAGER", L"Error", hr, FrameInfoExpectedErrors); 
    } 
    Data->DirtyCount = BufSize/sizeof(RECT); 

    Data->MetaData = m_MetaDataBuffer; 
} 

Data->Frame = m_AcquiredDesktopImage; 
Data->FrameInfo = FrameInfo; 

//Here I would like to access pixel data from Data->Frame. A buffer of RGBA pixel 

return DUPL_RETURN_SUCCESS; 
} 

Hier ist Frame_Data Struktur

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; 

Ist es möglich, Pixelpufferdaten zuzugreifen, die von Data->Frame

Hier wurden geändert wird meine Codedaten zuzugreifen:

BYTE* DISPLAYMANAGER::GetImageData(ID3D11Texture2D* texture2D, D3D11_TEXTURE2D_DESC Desc) 
{ 
if (texture2D != NULL) 
{ 
    D3D11_TEXTURE2D_DESC description; 
    texture2D->GetDesc(&description); 
    description.BindFlags = 0; 
    description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 
    description.Usage = D3D11_USAGE_STAGING; 
    description.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 

    ID3D11Texture2D* texTemp = NULL; 
    HRESULT hr = m_Device->CreateTexture2D(&description, NULL, &texTemp); 
    if (FAILED(hr)) 
    { 
     if (texTemp) 
     { 
      texTemp->Release(); 
      texTemp = NULL; 
     } 
     return NULL; 
    } 
    m_DeviceContext->CopyResource(texTemp, texture2D); 

    D3D11_MAPPED_SUBRESOURCE mapped; 
    unsigned int subresource = D3D11CalcSubresource(0, 0, 0); 
    hr = m_DeviceContext->Map(texTemp, subresource, D3D11_MAP_READ_WRITE, 0, &mapped); 
    if (FAILED(hr)) 
    { 
     texTemp->Release(); 
     texTemp = NULL; 
     return NULL; 
    } 

    unsigned char *captureData = new unsigned char[Desc.Width * Desc.Height * 4]; 
    RtlZeroMemory(captureData, Desc.Width * Desc.Height * 4); 
    const int pitch = mapped.RowPitch; 
    unsigned char *source = static_cast<unsigned char*>(mapped.pData); 
    unsigned char *dest = captureData; 
    for (int i = 0; i < Desc.Height; i++) { 
     memcpy(captureData, source, Desc.Width * 4); 
     source += pitch; 
     captureData += Desc.Width * 4; 
    } 
    for (int i = 0; i < Desc.Width * Desc.Height * 4; i++) { 
     //trace(L"Pixel[%d] = %x\n", i, dest[i]); 
    } 

    m_DeviceContext->Unmap(texTemp, 0); 
    return dest; 
} 
else 
    return NULL; 
} 

Vielen Dank für Ihre Hilfe!

Antwort

0

Die Texturen, die Sie über die Duplizierungs-API erhalten, sind für den einzelnen Pixelzugriff nicht unbedingt für die CPU zugänglich. Um die Texturdaten zu lesen, müssen Sie möglicherweise eine mappable Staging-Textur erstellen und die erhaltene Textur dorthin kopieren. Wenn Sie dann das Mapping durchführen, erhalten Sie einen Zeiger auf die tatsächlichen Daten. Beachten Sie, dass dies im Allgemeinen kein leistungsfreundlicher Vorgang ist.

Sie finden relevante Informationen in anderen Antworten auch:

How to work with pixels using Direct2D:

Für jene Zeiten, in denen Sie absolut Manipulation CPU Pixel zu tun haben, aber immer noch ein hohes Maß an Beschleunigung möchten, können Sie Verwalten Sie Ihre eigenen mappbaren D3D11-Texturen. Sie können beispielsweise Staging-Texturen verwenden, wenn Sie Ihre Texturressourcen asynchron von der CPU aus bearbeiten möchten.

Transferring textures across adapters in DirectX 11:

... kopiert sie in einem Staging-Ressource (auf dem gleichen Gerät erstellt) ID3D11DeviceContext :: CopyResource verwenden. Ich kartieren dann diese Aufstellungsressource mit gelesenem ...

+0

Hallo römisches danke für Ihre Hilfe. Ich habe meinen Post mit dem bearbeitet, was ich gemacht habe, aber ich habe überall '0' ... Ich rufe "GetImageData" nach der "Process Frame" -Funktion aus diesem Beispiel https://code.msdn.microsoft.com/windowsdesktop/Desktop-Duplication -Sample-da4c696a/sourcecode? FileId = 42782 & pathId = 1384140008 – DevAndroid

+0

Das aktualisierte Code-Snippet ist ungefähr richtig. Ich dachte "CopyResource" könnte aus irgendeinem Grund fehlschlagen, aber es ist nicht klar, nur aus dem Code, warum es das tun würde. –

+0

Ja ... Es ist ein Problem. Ich weiß nicht, warum das fehlschlägt. Sogar mapped.pData hat überall Nullwerte. Vielleicht sollte ich eine Flagge auf die Beschreibung hinzufügen? – DevAndroid