Проблемы с пониманием DXGI DirectX 11 Дублирование рабочего стола для получения буфера или массива

Я хочу понять DXGI Desktop Duplication. Я много читал, и этот код я скопировал из частей образца DesktopDupplication на веб-сайте Microsoft. Мой план состоит в том, чтобы получить буфер или массив из DesktopImage, потому что я хочу создать новую текстуру для другой программы. Я надеюсь, что кто-нибудь может объяснить мне, что я могу сделать, чтобы получить его.

void DesktopDublication::GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Timeout)
{
    IDXGIResource* DesktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo;

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

    }
    *Timeout = false;

    if (FAILED(hr))
    {

    }

    // 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))
    {

    }

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

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

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

        }
        Data->DirtyCount = BufSize / sizeof(RECT);

        Data->MetaData = m_MetaDataBuffer;
    }

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

person Boke    schedule 29.11.2014    source источник


Ответы (2)


Если я вас правильно понимаю, вы хотите получить текущее изображение рабочего стола, продублировать его в частную текстуру, а затем отобразить эту частную текстуру в своем окне. Я бы начал с чтения Direct3D 11 и изучения того, как визуализировать сцену, так как вам понадобится D3D, чтобы делать что-либо с объектом текстуры, который вы получаете из DXGI. Это, это и < href="https://rads.stackoverflow.com/amzn/click/com/1936420228" rel="nofollow noreferrer" rel="nofollow noreferrer">это поможет вам начать работу с D3D11. Я бы также потратил некоторое время на чтение исходного кода примера, из которого вы скопировали свой код, так как он полностью объясняет, как это сделать. Вот ссылка на полный исходный код этого примера .

Чтобы на самом деле получить данные текстуры и отрендерить их, вам нужно сделать следующее:

1). Создайте объект устройства D3D11 и контекст устройства.

2). Напишите и скомпилируйте шейдер Vertex и Pixel для видеокарты, а затем загрузите их в свое приложение.

3). Создайте объект Input Layout и установите его для устройства.

4). Инициализируйте необходимые состояния Blend, Depth-Stencil и Rasterizer для устройства.

5). Создайте объект «Текстура» и объект «Представление ресурсов шейдера».

6). Получите текстуру дублирования рабочего стола, используя приведенный выше код.

7). Используйте CopyResource, чтобы скопировать данные в вашу текстуру.

8). Отобразите эту текстуру на экране.

Это перенесет все данные, отображаемые на одном из рабочих столов, в вашу текстуру. Он не обрабатывает грязные прямоугольники рабочего стола. Он не выполняет обработку перемещенных областей. Это голый код «захватить рабочий стол и отобразить его в другом месте».

Если вы хотите получить более подробную информацию, прочитайте связанные ресурсы и изучите пример кода, так как образец в основном делает то, о чем вы просите.

person Alex    schedule 02.12.2014
comment
Здравствуйте Алексей! Большое спасибо! Но я не хочу отображать дублирование рабочего стола в окно или сцену. Мне нужна текстура в другом приложении. Мне нужны только данные изображения рабочего стола в массиве байтов или буфере или что-то еще, например, красный, зеленый, синий и альфа для каждого пикселя. Может ли кто-нибудь сказать мне, как это работает? - person Boke; 04.12.2014
comment
Итак, что вы действительно просите, так это способ поместить данные в файл, чтобы их можно было получить позже. - person Alex; 04.12.2014

Поскольку добавление этого к моему последнему ответу было не совсем правильным, я решил создать второй.

Если вы хотите прочитать данные рабочего стола в файл, вам нужен объект устройства D3D11, объект текстуры с установленным флагом D3D11_USAGE_STAGING и метод преобразования данных пикселей RGBA текстуры рабочего стола в желаемое. Основная процедура представляет собой упрощенную версию той, что была в моем исходном ответе:

1). Создайте объект устройства D3D11 и контекст устройства.

2). Создайте промежуточную текстуру того же формата, что и текстура рабочего стола.

3). Используйте CopyResource, чтобы скопировать текстуру рабочего стола в промежуточную текстуру.

4). Используйте ID3D11DeviceContext::Map(), чтобы получить указатель на данные, содержащиеся в промежуточной текстуре.

Убедитесь, что вы знаете, как работает Map, и убедитесь, что вы можете записывать файлы изображений из одного двоичного потока. В буфере изображения также может быть отступ, поэтому имейте в виду, что вам также может потребоваться отфильтровать его. Кроме того, убедитесь, что вы Unmap вызываете буфер, а не free, так как предоставленный вам буфер почти наверняка не принадлежит CRT.

person Alex    schedule 03.12.2014
comment
Привет, Алекс, я попробовал это вчера, я получил адрес памяти, но он был пуст, я опубликую новый код позже сегодня. Большое спасибо! - person Boke; 04.12.2014