捕获Windows桌面并显示为虚幻纹理-像素混乱

时间:2018-12-03 00:26:50

标签: c++ directx unreal-engine4 screen-capture dxgi

正如标题所示,我试图使用DirectX捕获Windows桌面并将结果显示为虚幻中的纹理。但是,生成的纹理是不正确的,因为看起来沿X轴的像素始终重复出现。

下面的代码(成功编译并在UE 4.20 / VS 2017中运行)中捕获了捕获桌面并将其转移到虚幻纹理的基本过程是:

  • 获取桌面的当前框架(g_desks是设备,iDesk是数字。当前使用一台监视器运行,因此iDesk为1)
  • 从设备获取DeviceContext(在底部的初始化代码中显示)
  • 设置存储捕获的ID3D11Texture2D(纹理)的格式
  • 创建过渡纹理以转移
  • 映射过渡纹理
  • 使用Memcpy将数据从映射的暂存纹理复制到虚幻缓冲区中

此外,将像素值硬编码到数组中,然后使用Memcpy到Unreal纹理缓冲区中会产生正确的输出。这使我相信问题出在纹理之间的转换,或者首先是如何捕获桌面。任何帮助将不胜感激!

桌面捕获代码:

    IDXGIResource* resource = nullptr;

    const UINT timeout = 0; // ms

    // acquire current frame of desktop
    HRESULT resultAcquire = CurrentState.g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &CurrentState.g_desks[iDesk].g_frameInfo, &resource);
    if (resultAcquire != S_OK)
    {
        g_needReinit++;
        return;
    }

    CurrentState.g_desks[iDesk].g_isPointerVisible = (CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
    CurrentState.g_desks[iDesk].g_pointerX = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
    CurrentState.g_desks[iDesk].g_pointerY = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;

    // check if resource was correctly acquired
    ID3D11Texture2D* texture;
    HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
    resource->Release();

    if (resultQuery != S_OK)
    {
        g_needReinit++;
        return;
    }

    HRESULT hr;

    // get context from device
    m_Device->GetImmediateContext(&m_DeviceContext);

    //Description for retrieved texture
    D3D11_TEXTURE2D_DESC desc;
    texture->GetDesc(&desc); 

    switch (desc.Format) {
        case DXGI_FORMAT_R8G8B8A8_UNORM:
            std::cout << "Good Format";
            break;
        case DXGI_FORMAT_B8G8R8A8_UNORM:
            std::cout << "Good Format";
            break;
        default:
            std::cout << "Bad Format";
    }

    // set description for the retrieved texture
    D3D11_TEXTURE2D_DESC desc2;
    desc2.Width = desc.Width;
    desc2.Height = desc.Height;
    desc2.MipLevels = desc.MipLevels;
    desc2.ArraySize = desc.ArraySize;
    desc2.Format = desc.Format;
    desc2.SampleDesc = desc.SampleDesc;
    desc2.Usage = D3D11_USAGE_STAGING;
    desc2.BindFlags = 0;
    desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    desc2.MiscFlags = 0;

    // create staging texture
    ID3D11Texture2D* stagingTexture;
    hr = m_Device->CreateTexture2D(&desc2, nullptr, &stagingTexture);
    if (FAILED(hr)) {
        std::cout << "Failed";
    }

    // copy the texture to a staging resource
    m_DeviceContext->CopyResource(stagingTexture, texture);

    D3D11_MAPPED_SUBRESOURCE mapInfo;
    hr = m_DeviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapInfo);

    if (FAILED(hr)) {
        std::cout << "Failed";
    }

    //Use D3D11_MAPPED_SUBRESOURCE to get pointer + size of data
    FTexture2DMipMap& Mip = CurrentState.g_desks[iDesk].g_texture->PlatformData->Mips[0];

    // memcpy into buffer for unreal
    uint8 * Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
    FMemory::Memcpy(Data, (uint8*)mapInfo.pData, mapInfo.RowPitch * desc2.Height);
    Mip.BulkData.Unlock();

    // release staging texture and frame
    m_DeviceContext->Unmap(stagingTexture, 0);
    CurrentState.g_desks[0].g_texture->UpdateResource();
    CurrentState.g_desks[iDesk].g_deskDupl->ReleaseFrame();
}

桌面捕获初始化代码:

void DeskInfo::DesktopCapturePlugin_Initialize() {

g_needReinit = 0;


IDXGIFactory1* factory;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));

IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
    IDXGIOutput* output;
    for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
    {
        DXGI_OUTPUT_DESC outputDesc;
        output->GetDesc(&outputDesc);

        MONITORINFOEX monitorInfo;
        monitorInfo.cbSize = sizeof(MONITORINFOEX);
        GetMonitorInfo(outputDesc.Monitor, &monitorInfo);

        // Maybe in future add a function to identify the primary monitor.
        if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
        {
            int iDesk = DeskAdd();

            CurrentState.g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
            CurrentState.g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

            //TODO: Hacky
            Width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
            Height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

            // Feature levels supported
            D3D_FEATURE_LEVEL FeatureLevels[] =
            {
                D3D_FEATURE_LEVEL_11_0,
                D3D_FEATURE_LEVEL_10_1,
                D3D_FEATURE_LEVEL_10_0,
                D3D_FEATURE_LEVEL_9_1
            };
            UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
            D3D_FEATURE_LEVEL FeatureLevel;
            HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, FeatureLevels, NumFeatureLevels,
                D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
            if (SUCCEEDED(hr))
            {
                // Device creation succeeded, no need to loop anymore
                IDXGIOutput1* output1;
                output1 = reinterpret_cast<IDXGIOutput1*>(output);
                output1->DuplicateOutput(m_Device, &CurrentState.g_desks[iDesk].g_deskDupl);
                break;
            }

        }

        output->Release();
    }
    adapter->Release();
}

factory->Release();

}

0 个答案:

没有答案