API дублирования рабочего стола Windows занимает много времени - PullRequest
0 голосов
/ 09 февраля 2019

Я использую API дублирования рабочего стола Windows для записи своего экрана в Windows 10. У меня, однако, есть некоторые проблемы с производительностью.При воспроизведении видео с использованием Google Chrome и попытке записать время, необходимое для записи экрана, колеблется от 15 мс до 45 мс.Я хотел иметь возможность записывать как минимум 30 кадров в секунду, и я знаю, что 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;
    }

Важно отметить, что это особый раздел, который занимает 15 мс-45 мс для завершения каждого цикла.Цикл memcpy в нижней части обычно занимает около 2 мс этого времени, поэтому я знаю, что он не отвечает за время, которое он занимает здесь.Также тайм-аут AcquireNextFrame установлен в ноль, поэтому он возвращается почти сразу.Любая помощь будет принята с благодарностью!Вставленный здесь код был адаптирован из этого: https://gist.github.com/Xirexel/a69ade44df0f70afd4a01c1c9d9e02cd

1 Ответ

0 голосов
/ 09 февраля 2019

Вы не используете API оптимальным способом. Прочитайте примечания в документации к API ReleaseFrame:

По соображениям производительности мы рекомендуем освободить кадр непосредственно перед вызовом метода IDXGIOutputDuplication :: AcquireNextFrame для получения следующего кадра.Когда клиент не владеет фреймом, операционная система копирует все обновления рабочего стола на поверхность.Это может привести к потере циклов графического процессора, если операционная система обновляет один и тот же регион для каждого кадра.

Вы не делаете то, что там написано, вы освобождаете кадры, как только копируете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...