我最初遇到了同样的问题。您没有提到如何配置源读取器的输出类型(以及接收器的输入类型),但我发现如果您允许系统处理它(通过选择读取器的输出类型为RGB32) ,性能会很糟糕并且受 CPU 限制。 (为简洁起见,省略了错误检查)
hr = videoMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
hr = videoMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
hr = reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr, videoMediaType);
reader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, true);
文档也同意这一点,表明此配置对于从视频中获取单个快照很有用。因此,如果您将阅读器配置为提供本机媒体类型,性能会非常好,但您现在必须自己转换格式。
reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, videoMode->GetIndex(), videoMediaType);
从这里开始,如果您正在处理简单的颜色转换(例如来自网络摄像头的 YUY2 或 YUV),那么有几个选项。我最初尝试编写自己的转换器,然后使用以下命令将其推送到 GPUHLSL
with DirectCompute
。这非常有效,但就您而言,格式并不那么简单。
最终,创建并配置颜色转换器的实例(作为IMFTransform
)工作完美。
Microsoft::WRL::ComPtr<IMFMediaType> mediaTransform;
hr = ::CoCreateInstance(CLSID_CColorConvertDMO, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMFTransform), reinterpret_cast<void**>(mediaTransform.GetAddressOf());
// set the input type of the transform to the NATIVE output type of the reader
hr = mediaTransform->SetInputType(0u, videoMediaType.Get(), 0u);
创建并配置单独的样本和缓冲区。
IMFSample* transformSample;
hr = ::MFCreateSample(&transformSample);
hr = ::MFCreateMemoryBuffer(RGB_MFT_OUTPUT_BUFFER_SIZE, &_transformBuffer);
hr = transformSample->AddBuffer(transformBuffer);
MFT_OUTPUT_DATA_BUFFER* transformDataBuffer;
transformDataBuffer = new MFT_OUTPUT_DATA_BUFFER();
transformDataBuffer->pSample = _transformSample;
transformDataBuffer->dwStreamID = 0u;
transformDataBuffer->dwStatus = 0u;
transformDataBuffer->pEvents = nullptr;
当从源接收样本时,将它们交给要转换的转换。
hr = mediaTransform->ProcessInput(0u, sample, 0u));
hr = mediaTransform->ProcessOutput(0u, 1u, transformDataBuffer, &outStatus));
hr = transformDataBuffer->pSample->GetBufferByIndex(0, &mediaBuffer);
当然,最后就像今天一样,将转化后的样品交给水槽。我相信这会奏效,你会成为一个非常幸福的人。对我来说,我将 CPU 利用率从 20%(最初实现)降低到 2%(我同时显示视频)。祝你好运。我希望你喜欢你的项目。