IMFSinkWriter 中的错误?

Posted

技术标签:

【中文标题】IMFSinkWriter 中的错误?【英文标题】:Bug in IMFSinkWriter? 【发布时间】:2015-04-29 05:57:50 【问题描述】:

我以两种方式实现了编码器。

1) 基于 SDK Transcoder 示例,使用拓扑和转码配置文件

2) 基于 IMFSourceReader 和 IMFSinkWriter,Sinkwriter 将样本传送到 Sourcewriter 进行转码

我在 Windows 8.1 上使用 Nvidia (Quadro K2200) 和 Intel GPU (P4600/P4700) 测试了这两种实现

但奇怪的是,只有拓扑实现使用 GPU(两者都使用)。

在 2)我都设置了“MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS”,我猜它不必设置,因为 1)在为容器类型设置和不设置此标志的情况下与 GPU 一起工作。

是否有使用 IMFSinkWriter 启用 GPU 的技巧,或者这是媒体基础中的错误?

【问题讨论】:

涉及的格式有哪些(源/汇)? 为简单起见,我始终使用 2 个测试 Szenarios 运行我的测试:1) PAL WMV -> 1920x1080 H264 Mp4 8 Mbit 2) 1920x1080 H264 Mp4 4 Mbit -> 1920x1080 H264 Mp4 8 Mbit 在瞬间出现第二个问题:使用 source->sink 方法时,上方出现一条绿线,图片的某些部分似乎不正常 绿线是将解码器媒体类型设置为 nv12 而不是 YUY2 时出现问题。硬件解码/编码仍然不起作用 【参考方案1】:

我最初遇到了同样的问题。您没有提及如何配置源阅读器的输出类型(以及接收器的输入类型),但我发现如果您允许系统处理它(通过选择阅读器的输出类型为 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),那么有几个选项。我最初尝试编写自己的转换器,并使用HLSLDirectCompute 将其推送到GPU。这很好用,但在你的情况下,格式并不是那么简单。

最终,创建和配置颜色转换器的实例(作为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);

当然,最后就像今天一样将转换后的样本交给水槽。我相信这会奏效,你会是一个非常幸福的人。对我来说,我从 20% 的 CPU 利用率(最初的实现)下降到 2%(我同时显示视频)。祝你好运。我希望你喜欢你的项目。

【讨论】:

以上是关于IMFSinkWriter 中的错误?的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows Media Foundation 中使用 Sink Writer 添加到视频的音频示例

通过 ICodecAPI 为 H.264 IMFSinkWriter 编码器设置属性

IMFSinkWriter::BeginWriting 未初始化,因为 IMFMediaEventGenerator 有未决事件

使用 IMFSinkWriter 更改标题、作者等元数据

使用 IMFSinkWriter 编码的视频的播放速度根据宽度变化

媒体基础 MP4 编码:IMFSinkWriter 不接受 PCM 输入