有没有更快的方法从 IMFSample 读取样本?
Posted
技术标签:
【中文标题】有没有更快的方法从 IMFSample 读取样本?【英文标题】:Is there a faster way to ReadSample from an IMFSample? 【发布时间】:2018-12-24 01:47:27 【问题描述】:我正在为使用 Direct3D9Ex 接口的应用程序设置 VideoRenderer,但是当我使用大纹理(桌面分辨率)时,视频开始变慢。
我使用的是 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);
然后我发布一个 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 吗?我可以调整当前代码以更快地运行吗?我在哪里可以找到一些关于它的好样本?
【问题讨论】:
不相关,但您确实应该使用 RAII 而不是goto Quit
的东西。
我明白了,谢谢你提醒我。
【参考方案1】:
这里与速度相关的主要因素是能够在 GPU 上解码为纹理,然后在不将数据下载到系统内存的情况下使用此纹理。
你正在做MF_SOURCE_READER_D3D_MANAGER
,最终你从纹理中读取数据。所以 DXVA 已经为你工作了,它应该很快就能工作(也就是说,你不需要加速 ReadSample
本身)。 IDirect3DSurface9::LockRect
并且访问位可能很慢,您可能需要禁用读取纹理步骤并比较性能以验证。
【讨论】:
怎么样?我的意思是,我不必阅读纹理然后将其放在另一个上呈现吗? 这很典型,例如"I profiled and found that copying memory from GPU to CPU is very expensive. I am looking for your inputs to alleviate this performance loss." - 你会发现很多。 很抱歉,我没有找到这与我的问题之间的联系。显然他在 FPS 方面也有一些问题,但他使用的是不同的媒体 api。我应该使用 IOPattern 来读取样本吗? 连接是我建议您停止从视频内存(从纹理)读取并比较代码的性能。我希望您的速度更快,这将证明ReadSample
没问题,并且您从纹理读取到系统内存的速度很慢。我之前评论中的链接实际上表明这是一项基本挑战,适用于所有 API。您会发现在 Media Foundation 上的类似讨论要少得多,因为它不是一个流行的 API,但是如果您查看 DirectShow、Direct3D、供应商 SDK,您会发现每个人都在处理这个问题。
知道了,但是考虑到这一点,我应该如何将它渲染到我的设备上?这是我发现的唯一方法。以上是关于有没有更快的方法从 IMFSample 读取样本?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 H.264 NV12 IMFSample 输出渲染到 DirectX11 纹理?
如何为 WindowsMediaFoundation H.264 编码器 MFT 创建 IMFSample
处理来自 IMFSourceReader 和 IMFSample 的图像数据