桌面复制API返回空框架

问题描述 投票:1回答:1

我知道已经有几个问题要问这个问题或类似问题,因此我深入其中几个问题,但没有成功。

我尝试使用桌面复制API捕获显示器的“屏幕快照”并处理其像素数据。后来我想至少每秒执行30次,但这是另一种情况。现在,我尝试使用Microsoft的示例:https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/master/Official%20Windows%20Platform%20Sample/DXGI%20desktop%20duplication%20sample我成功保存了屏幕图片,并使用该代码访问了像素数据。

    DirectX::ScratchImage image;
    hr = DirectX::CaptureTexture(m_Device, m_DeviceContext, m_AcquiredDesktopImage, image);
    hr = DirectX::SaveToDDSFile(image.GetImages(), image.GetImageCount(), image.GetMetadata(), DirectX::DDS_FLAGS_NONE, L"test.dds");

    uint8_t* pixels;
    pixels = image.GetPixels();

现在,我想将示例代码分解为所需的基本内容。由于我不熟悉DirectX,因此很难。我想出了以下代码,该代码运行无误,但产生了空白图片。我在“调试模式”下检查hr,我知道这是不正确的做法,很脏!

int main()
{
    HRESULT hr = S_OK;

    ID3D11Device* m_Device;
    ID3D11DeviceContext* m_DeviceContext;


        // Driver types supported
    D3D_DRIVER_TYPE DriverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT NumDriverTypes = ARRAYSIZE(DriverTypes);

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

    // Create device
    for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
    {
        hr = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels, NumFeatureLevels,
            D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
        if (SUCCEEDED(hr))
        {
            // Device creation success, no need to loop anymore
            break;
        }
    }


    IDXGIOutputDuplication* m_DeskDupl;
    IDXGIOutput1* DxgiOutput1 = nullptr;
    IDXGIOutput* DxgiOutput = nullptr;
    IDXGIAdapter* DxgiAdapter = nullptr;
    IDXGIDevice* DxgiDevice = nullptr;
    UINT Output = 0;

    hr = m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice));

    hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter));
    DxgiDevice->Release();
    DxgiDevice = nullptr;

    hr = DxgiAdapter->EnumOutputs(Output, &DxgiOutput);
    DxgiAdapter->Release();
    DxgiAdapter = nullptr;

    hr = DxgiOutput->QueryInterface(__uuidof(DxgiOutput1), reinterpret_cast<void**>(&DxgiOutput1));
    DxgiOutput->Release();
    DxgiOutput = nullptr;

    hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl);




    IDXGIResource* DesktopResource = nullptr;
    DXGI_OUTDUPL_FRAME_INFO FrameInfo;

    hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);

    ID3D11Texture2D* m_AcquiredDesktopImage;

    hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&m_AcquiredDesktopImage));
    DesktopResource->Release();
    DesktopResource = nullptr;

    DirectX::ScratchImage image;
    hr = DirectX::CaptureTexture(m_Device, m_DeviceContext, m_AcquiredDesktopImage, image);
    hr = DirectX::SaveToDDSFile(image.GetImages(), image.GetImageCount(), image.GetMetadata(), DirectX::DDS_FLAGS_NONE, L"test.dds");

    uint8_t* pixels;
    pixels = image.GetPixels();


    hr = m_DeskDupl->ReleaseFrame();
}

任何人都可以给我提示此代码有什么问题吗?

编辑:刚刚在下面找到了代码片断,并将其集成到我的代码中。现在可以了!得到教训:-)实际输出/处理小时!-)AcquireNextFrame可能在第一次尝试时无法使用(?)

我可能会使用功能更好的循环,用更好的代码再次更新此帖子。

    int lTryCount = 4;

    do
    {
        Sleep(100);

        hr = m_DeskDupl->AcquireNextFrame(250, &FrameInfo, &DesktopResource);

        if (SUCCEEDED(hr))
            break;

        if (hr == DXGI_ERROR_WAIT_TIMEOUT)
        {
            continue;
        }
        else if (FAILED(hr))
            break;

    } while (--lTryCount > 0);
directx desktop-duplication
1个回答
0
投票

AcquireNextFrame acquires a new desktop frame when the operating system either updates the desktop bitmap image or changes the shape or position of a hardware pointer.

当您开始获取帧时,您显然将很快获得第一张桌面图像,但是在图像之前,您也可能会有一些指针通知。

您不应以4次尝试来限制自己,也不需要在循环中睡觉。只需继续轮询图像即可。为了避免死循环,更有意义的是跟踪在循环中花费的总时间并将其限制为例如一秒。

另请参见:

AcquireNextFrame() never grabs an updated image, always blank

© www.soinside.com 2019 - 2024. All rights reserved.