有没有更快的方法从 IMFSample 读取 ReadSample?

Is there a faster way to ReadSample from an IMFSample?

我正在为我的应用程序设置一个 VideoRenderer,它使用 Direct3D9Ex 接口,但是当我使用大纹理(桌面分辨率)时,视频开始变慢。

我使用的是 DirectShow,但我发现 H264 存在一些问题,因此我决定使用 Media Foundation。我已经搜索了很多关于它的内容,但我没有得到如何使用 DXVA 渲染视频,因此,我使用 MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING 和 MFVideoFormat_RGB32 阅读了一个带有 IMFSourceReader(异步)的示例所以我可以复制到我的表面然后渲染它正常。

这就是我创建 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);

然后我 post 一个 ReadSample 并在我的更新方法中,我这样做:

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 吗?我可以将当​​前代码调整到 运行 更快吗?我在哪里可以找到一些关于它的好样本?

此处与速度相关的主要因素是能够在 GPU 上解码为纹理,然后在不将数据下载到系统内存的情况下使用该纹理(如果可能)。

您正在做 MF_SOURCE_READER_D3D_MANAGER,最终您从纹理中读取了数据。所以 DXVA 已经在为你工作了,它应该会很快地工作(也就是说,你不需要加速 ReadSample 本身)。 IDirect3DSurface9::LockRect 并且访问位可能很慢,您可能需要禁用读取纹理步骤并比较性能以进行验证。