Windows MFT(媒体基础转换)解码器未返回正确的采样时间或持续时间

Posted

技术标签:

【中文标题】Windows MFT(媒体基础转换)解码器未返回正确的采样时间或持续时间【英文标题】:Windows MFT (Media Foundation Transform) decoder not returning proper sample time or duration 【发布时间】:2016-09-26 05:16:56 【问题描述】:

要使用 Windows Media Foundation Transform 解码 H264 流,目前的工作流程是这样的:

IMFSample sample;
sample->SetTime(time_in_ns);
sample->SetDuration(duration_in_ns);
sample->AddBuffer(buffer);

// Feed IMFSample to decoder
mDecoder->ProcessInput(0, sample, 0);

// Get output from decoder.
/* create outputsample that will receive content */  ... 
MFT_OUTPUT_DATA_BUFFER output = 0;
output.pSample = outputsample;
DWORD status = 0;
HRESULT hr = mDecoder->ProcessOutput(0, 1, &output, &status);
DWORD status = 0;
hr = mDecoder->ProcessOutput(0, 1, &output, &status);
if (output.pEvents) 
  // We must release this, as per the IMFTransform::ProcessOutput()
  // MSDN documentation.
  output.pEvents->Release();
  output.pEvents = nullptr;


if (hr == MF_E_TRANSFORM_STREAM_CHANGE) 
  // Type change, probably geometric aperture change.
  // Reconfigure decoder output type, so that GetOutputMediaType()
 else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) 
  // Not enough input to produce output.
 else if (!output.pSample) 
  return S_OK;
 else 
  // Process output

当我们将所有数据输入到 MFT 解码器后,我们必须将其排空:

mDecoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);

现在,WMF H264 解码器的一件事是,无论 h264 滑动窗口的大小如何,它通常在使用超过 30 个压缩的 h264 帧调用之前不会输出任何内容。延迟非常高...

我遇到了一个非常麻烦的问题。 对于仅由关键帧组成的视频,并且只有 15 帧,每帧长 2 秒,第一帧的呈现时间非零(此流来自实时内容,因此第一帧通常在 epos 时间) 因此,在没有耗尽解码器的情况下,解码器将不会输出任何内容,因为它没有接收到足够的帧。

但是,一旦解码器耗尽,解码的帧就会出来。但是,MFT 解码器仅将所有持续时间设置为 33.6 毫秒,并且第一个样本的呈现时间始终为 0。 原始时长和演示时间已丢失。

如果您向 h264 解码器提供超过 30 帧,则持续时间和 pts 都有效...

我还没有找到让 WMF 解码器输出具有正确值的样本的方法。 看来,如果您必须在解码器本身输出任何样本之前排空解码器,那么它就完全坏了……

有没有人遇到过这样的问题?你是怎么解决的?

提前谢谢你

编辑:http://people.mozilla.org/~jyavenard/mediatest/fragmented/1301869.mp4 上提供了视频样本 由于上述问题,使用 Firefox 播放此视频会导致播放速度极快。

【问题讨论】:

你应该试试CODECAPI_AVLowLatencyMode [1, 2]。 低延迟仅适用于 Window 8 及更高版本。此外,与任何包含 B 帧的东西都不兼容。此外,启用时会出现大量驱动程序崩溃......低延迟在这里会有所帮助,但如果我有 恐怕你提到的只是设计行为。输出帧是异步可用的(尤其是在 DXVA 模式下),Windows 8+ 中的低延迟可以稍微改善一些事情,当 H.264 嵌入时间相关数据时改变了时间。当然,驱动程序崩溃需要驱动程序更新。我想,纯软件解码器可能具有更可预测的行为。 所以 MFT 返回错误的时间戳和错误的持续时间是设计使然?我觉得这很难相信:) 如果您考虑 H.264 比特流中的时序信息,则不一定是错误的。它可能比您的时间戳更受欢迎。 【参考方案1】:

我不确定您的工作流程是否正确。我认为你应该这样做:

do

    ...
    hr = mDecoder->ProcessInput(0, sample, 0);
    if(FAILED(hr))
      break;
    ...
    hr = mDecoder->ProcessOutput(0, 1, &output, &status);
    if(FAILED(hr) && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
      break;

while(hr == MF_E_TRANSFORM_NEED_MORE_INPUT);

if(SUCCEEDED(hr))

    // You have a valid decoded frame here

这个想法是在 ProcessOutput 返回 MF_E_TRANSFORM_NEED_MORE_INPUT 时继续调用 ProcessInput/ProcessOutut。 MF_E_TRANSFORM_NEED_MORE_INPUT 表示解码器需要更多输入。我认为有了这个循环,你就不需要耗尽解码器了。

【讨论】:

你所描述的和我所拥有的没有什么不同。我只介绍了 ONE 框架的工作流程。当然,如果您有多个帧,您将循环......但是问题是,如果您调用 ProcessInput 的次数少于 30 次,则通常不会从 ProcessOutput 中输出任何内容。这是需要排水的地方。 “MF_E_TRANSFORM_NEED_MORE_INPUT 意味着解码器需要更多输入”当然...但是如果您在到达流的末尾时没有什么可以提供给解码器怎么办? 是的,ProcessOutput 在返回第一个样本之前确实返回了 MF_E_TRANSFORM_STREAM_CHANGE。进一步提到了那里的 h264 时序,我开始深入研究 SPS,确实这个麻烦的视频将timing_info_present_flag 设置为 true,且 fixed_frame_rate_flag = true 也是如此。然后我找到了这个 MS 文档:msdn.microsoft.com/en-us/library/windows/desktop/…,其中提到如果在 SPS 中找不到任何内容,则默认使用 29.976fps。 SPS 确实有 num_units_in_tick = 1 和 time_scale = 50 是的,第一帧在字节流中同时包含 SPS 和 PPS。这是自动添加的,因为 MFT 需要附件 B 内容。将 SPS 和 PPS 复制到字节流是作为 AVCC -> AnnexB 转换的一部分完成的......我也玩过 MFSampleExtension_Discontinuity,它没有区别 “为避免初始格式更改,请在输入类型中提供尽可能多的信息”

以上是关于Windows MFT(媒体基础转换)解码器未返回正确的采样时间或持续时间的主要内容,如果未能解决你的问题,请参考以下文章

媒体基础 - 如何在 MFT(媒体基础转换)中更改帧大小

商业媒体基础过滤器

如何通过媒体基础使用英特尔 Quicksync 进行解码?

使用 C# 的 Microsoft 媒体基础转换 (MFT)?

如何在媒体会话解析的拓扑末尾添加我的 MFT?

媒体基础自定义拓扑 E_FAIL