Есть ли более быстрый способ чтения образца из образца IMFS? - PullRequest
0 голосов
/ 24 декабря 2018

Я настраиваю VideoRenderer для своего приложения, которое использует интерфейсы Direct3D9Ex, но когда я использую большую текстуру (разрешение рабочего стола), видео начинает замедляться.

Я использовал DirectShow, но обнаружил некоторые проблемы сH264, и я решил пойти на Media Foundation.Я много об этом искал, но я не понял, как отобразить видео с помощью DXVA, и поэтому я читаю образец с помощью IMFSourceReader (Async), используя MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING и MFVideoFormat_RGB32, чтобы я мог скопировать его на мою поверхность, а затемсделать его нормальным.

Вот как я создаю SourceReader.

    MFCreateAttributes(&m_Attributes, 4);

    m_Attributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, GRAPHICSDEVICE->GetDeviceManager());
    m_Attributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
    m_Attributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
    m_Attributes->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE);

    MFCreateSourceReaderFromURL(L"Video.mp4", m_Attributes, &m_SourceReader);
    MFCreateMediaType(&m_MediaType);
    MFSetAttributeSize(m_MediaType, MF_MT_FRAME_SIZE, m_VideoWidth, m_VideoHeight);

    m_MediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    m_MediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);

Затем я публикую один ReadSample, и в моем методе Update я делаю это:

if (WaitForSingleObject(m_SampleEvent, 0) == WAIT_OBJECT_0)
    {
        if (m_SourceReader)
        {
            m_SourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, nullptr, nullptr, nullptr, nullptr);
        }
    }

Это часть моего обратного вызова OnReadSample, который просто копирует одну поверхность на другую.

IDirect3DSurface9 * pSampleSurface = nullptr;

if (SUCCEEDED(GetD3DSurfaceFromSample(Sample, &pSampleSurface)))
{
    D3DLOCKED_RECT SampleRect;
    if (FAILED(pSampleSurface->LockRect(&SampleRect, nullptr, D3DLOCK_READONLY)))
    {
        pSampleSurface->Release();
        goto Quit;
    }

    BYTE * pVideo = (BYTE*)SampleRect.pBits;

    D3DLOCKED_RECT TextureRect;
    if (FAILED(m_Texture->LockRect(0, &TextureRect, nullptr, D3DLOCK_DISCARD)))
    {
        pSampleSurface->UnlockRect();
        pSampleSurface->Release();
        goto Quit;
    }

    BYTE * pDest = (BYTE*)TextureRect.pBits;

    for (unsigned int i = 0; i < m_VideoHeight; i++)
    {
        CopyMemory(pDest, pVideo, m_VideoWidth * 4);
        pDest += TextureRect.Pitch;
        pVideo += SampleRect.Pitch;
    }

    m_Texture->UnlockRect(0);
    pSampleSurface->UnlockRect();
    pSampleSurface->Release();
}

Итак, мои фактические результаты приемлемы для среды отладки, но когда я меняю разрешение своего приложения на настольное(от 800x600 до 1366x768) все становится намного медленнее.

Нужно ли использовать что-то в качестве DXVA?Могу ли я настроить текущий код, чтобы он работал быстрее?Где я могу найти хорошие образцы об этом?

1 Ответ

0 голосов
/ 24 декабря 2018

Основной фактор, связанный со скоростью, заключается в том, чтобы иметь возможность декодировать на GPU в текстуру, а затем использовать эту текстуру, не выгружая данные в системную память, если это возможно.

Вы выполняете MF_SOURCE_READER_D3D_MANAGER и в конечном итоге вычитать данные из текстуры.Таким образом, DXVA уже работает для вас, и он должен работать прилично быстро (то есть вам не нужно ускорять ReadSample как таковое).IDirect3DSurface9::LockRect и доступ к битам, по-видимому, выполняется медленно, вы можете отключить шаг чтения текстуры и сравнить производительность для проверки.

...