2017-05-07 41 views
0

Windows APIからDesktop Duplicationを使用しています。 次のフレームにアクセスし、前のフレームから変化したピクセルの矩形を取得するコードです。ここで汚れた矩形を抽出するRGBピクセルバッファーデータ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; 
} 

Frame_Data構造

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; 

はここData->Frame

から変更されているピクセルバッファのデータにアクセスすることが可能です、データにアクセスするための私のコードです:

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; 
} 

ありがとうございます!

答えて

0

複製APIを使用して取得したテクスチャは、個々のピクセルアクセスのためにCPUでアクセスできるとは限りません。テクスチャデータを読み込むには、マッピング可能なステージングテクスチャを作成し、そこで取得したテクスチャをコピーする必要があります。マッピングを実行すると、実際のデータへのポインタが得られます。これは一般に、パフォーマンスに優しい操作ではないことに注意してください。あなたは絶対にCPUのピクセル操作をしなければならないが、それでも加速度の実質的な程度をしたいときにすることができ、それらの時のために

How to work with pixels using Direct2D

あなたは、同様に他の回答の関連情報を検索します独自のマップ可能なD3D11テクスチャを管理します。たとえば、テクスチャリソースをCPUから非同期に操作する場合は、ステージングテクスチャを使用できます。

Transferring textures across adapters in DirectX 11

... ID3D11DeviceContext :: COPYRESOURCEを使用して(同じデバイス上に作成)ステージングリソースにコピーします。私はその後、そのステージングリソースをReadとマップします。

+0

こんにちは、Romanさん、ありがとうございました。私は自分の投稿を編集しましたが、私はどこでも「0」を取得しました...このサンプルから「プロセスフレーム」関数の後に「GetImageData」を呼び出します。https://code.msdn.microsoft.com/windowsdesktop/Desktop-Duplication -Sample-da4c696a/sourcecode?fileId = 42782&pat​​hId = 1384140008 – DevAndroid

+0

更新されたコードスニペットはほぼ正しいです。私は 'CopyResource'が何らかの理由で失敗するかもしれないと思っていましたが、なぜそれがそれを行うのかはコードからは分かりません。 –

+0

はい...問題です。私はそれがなぜ失敗するのかわかりません。たとえmapped.pDataであってもどこでもnull値があります。おそらく私は説明にフラグを追加する必要がありますか? – DevAndroid

関連する問題