Windows桌面复制API需要很长时间

时间:2019-02-08 21:39:56

标签: c++ windows visual-c++

我正在使用Windows桌面复制API在Windows 10中记录我的屏幕。但是,我在性能方面遇到了一些问题。使用谷歌浏览器播放视频并尝试记录屏幕录制时间从15毫秒波动到45毫秒。我希望能够至少以30fps的速度录制,并且我知道桌面复制api能够做到这一点。无论如何,这是我用来实际捕获屏幕的代码:

processor->hr = processor->lDeskDupl->AcquireNextFrame(0, &processor->lFrameInfo, &processor->lDesktopResource);

    if (processor->hr == DXGI_ERROR_WAIT_TIMEOUT) {
        processor->lDeskDupl->ReleaseFrame();
        return false;
    }

    if (FAILED(processor->hr)) {
        processor->lDeskDupl->ReleaseFrame();
        return false;
    }

    // QI for ID3D11Texture2D
    processor->hr = processor->lDesktopResource->QueryInterface(IID_PPV_ARGS(&processor->lAcquiredDesktopImage));
    if (FAILED(processor->hr)) {
        processor->lDeskDupl->ReleaseFrame();
        return false;
    }

    processor->lDesktopResource.Release();
    if (processor->lAcquiredDesktopImage == nullptr) {
        processor->lDeskDupl->ReleaseFrame();
        return false;
    }

    processor->lImmediateContext->CopyResource(processor->lGDIImage, processor->lAcquiredDesktopImage);

    processor->lAcquiredDesktopImage.Release();
    processor->lDeskDupl->ReleaseFrame();

    // Copy image into CPU access texture
    processor->lImmediateContext->CopyResource(processor->lDestImage, processor->lGDIImage);

    // Copy from CPU access texture to bitmap buffer
    D3D11_MAPPED_SUBRESOURCE resource;
    processor->subresource = D3D11CalcSubresource(0, 0, 0);
    processor->lImmediateContext->Map(processor->lDestImage, processor->subresource, D3D11_MAP_READ_WRITE, 0, &resource);

    BYTE* sptr = reinterpret_cast<BYTE*>(resource.pData);
    BYTE* dptr = processor->pBuf;
    UINT lRowPitch = min(processor->lBmpRowPitch, resource.RowPitch);

    for (int i = 0; i < processor->lOutputDuplDesc.ModeDesc.Height; i++) {
        memcpy_s(dptr, processor->lBmpRowPitch, sptr, lRowPitch);
        sptr += resource.RowPitch;
        dptr += processor->lBmpRowPitch;
    }

重要的是要注意,这是一个特定的部分,需要花费15ms-45ms的时间来完成每个周期。底部的memcpy循环通常占该时间的2毫秒左右,因此我知道这并不占用这里的时间。另外AcquireNextFrame的超时设置为零,因此几乎立即返回。任何帮助将不胜感激!此处粘贴的代码改编自:https://gist.github.com/Xirexel/a69ade44df0f70afd4a01c1c9d9e02cd

1 个答案:

答案 0 :(得分:0)

您没有以最佳方式使用API​​。 Read remarks在ReleaseFrame API文档中:

出于性能原因,我们建议您在调用IDXGIOutputDuplication :: AcquireNextFrame方法以获取下一个帧之前释放该帧。当客户端不拥有框架时,操作系统会将所有桌面更新复制到表面。如果操作系统为每个出现的帧更新相同的区域,则可能导致GPU周期浪费。

您没有执行此处写的内容,而是在复制后立即释放框架。