异步 MRT

本主题介绍媒体基础转换 (MRT) 的异步数据处理。

注意

本主题适用于 Windows 7 或更高版本。

 

关于异步 MRT

在 Windows Vista 中引入 MCT 时,该 API 设计用于 同步 数据处理。 在该模型中,MFT 始终在等待获取输入或等待生成输出。

考虑一个典型的视频解码器。 为了获取解码的帧,客户端调用 IMFTransform::P rocessOutput。 如果解码器有足够的数据来解码帧,则当 MFT 解码帧时 ,ProcessOutput 会阻止。 否则, ProcessOutput 返回 MF_E_TRANSFORM_NEED_MORE_INPUT,指示客户端应调用 IMFTransform::P rocessInput

如果解码器在一个线程上执行其所有解码操作,则此模型非常有效。 但假设解码器使用多个线程并行解码帧。 为了获得最佳性能,解码器应在解码线程空闲时接收新输入。 但是,线程完成解码操作的速率与客户端对 ProcessInputProcessOutput 的调用不完全一致,导致线程等待工作。

Windows 7 为 MCT 引入了事件驱动的 异步 处理。 在此模型中,每当 MFT 需要输入或具有输出时,它就会向客户端发送事件。

一般要求

本主题介绍异步 MFT 与同步 MFT 的区别。 除非本主题中另有说明,否则这两个处理模型是相同的。 特别是 (,格式协商是相同的。)

异步 MFT 必须实现以下接口:

事件

异步 MFT 使用以下事件来指示其数据处理状态:

事件 说明
METransformNeedInput 当 MFT 可以接受更多输入时发送。
METransformHaveOutput 在 MFT 具有输出时发送。
METransformDrainComplete 在排出操作完成时发送。 请参阅 清空
METransformMarker 处理标记时发送。 请参阅 标记

 

这些事件在带外发送。 了解 MFT 上下文中带内事件和带外事件之间的差异非常重要。

原始 MFT 设计支持 带内 事件。 带内事件包含有关数据流的信息,例如有关格式更改的信息。 客户端通过调用 IMFTransform::P rocessEvent 将带内事件发送到 MFT。 MFT 可以在 ProcessOutput 方法中将带内事件发送回客户端。 (具体而言,事件在 MFT_OUTPUT_DATA_BUFFER structure 的 pEvents 成员中传达。)

MFT 通过 IMFMediaEventGenerator 接口发送带外事件,如下所示:

  1. MFT 实现 IMFMediaEventGenerator 接口,如 媒体事件生成器中所述。
  2. 客户端在 MFT 上为 IMFMediaEventGenerator 接口调用 IUnknown::QueryInterface。 异步 MFT 必须公开此接口。 同步 MRT 不应公开此接口。
  3. 客户端调用 IMFMediaEventGenerator::BeginGetEventIMFMediaEventGenerator::EndGetEvent 以接收来自 MFT 的带外事件。

ProcessInput

IMFTransform::P rocessInput 方法的修改如下:

  1. 当流式处理启动时,客户端发送 MFT_MESSAGE_NOTIFY_START_OF_STREAM 消息。
  2. 在流式处理期间,MFT 通过发送 METransformNeedInput 事件来请求数据。 事件数据是流标识符。
  3. 对于每个 METransformNeedInput 事件,客户端为指定的流调用 ProcessInput
  4. 在流式处理结束时,客户端可能会使用MFT_MESSAGE_NOTIFY_END_OF_STREAM消息调用 ProcessMessage

实现说明:

ProcessOutput

IMFTransform::P rocessOutput 方法的修改如下:

  1. 每当 MFT 具有输出时,它就会发送 METransformHaveOutput 事件。
  2. 对于每个 METransformHaveOutput 事件,客户端调用 ProcessOutput

实现说明:

  • 如果客户端在任何其他时间调用 ProcessOutput ,该方法将返回 E_UNEXPECTED
  • 异步 MFT 绝不应从 ProcessOutput 方法返回MF_E_TRANSFORM_NEED_MORE_INPUT。 如果 MFT 需要更多输入,它将发送 METransformNeedInput 事件。

正在清空

清空 MFT 会导致 MFT 从已发送的任何输入数据中生成尽可能多的输出。 清空异步 MFT 的工作原理如下:

  1. 客户端发送 MFT_MESSAGE_COMMAND_DRAIN 消息。
  2. MFT 继续发送 METransformHaveOutput 事件,直到没有更多要处理的数据。 在此期间,它不会发送 METransformNeedInput 事件。
  3. MFT 发送最后一个 METransformHaveOutput 事件后,会发送 METransformDrainComplete 事件。

清空完成后,MFT 不会发送另一个 METransformNeedInput 事件,直到收到来自客户端 的MFT_MESSAGE_NOTIFY_START_OF_STREAM 消息。

冲洗

客户端可以通过发送 MFT_MESSAGE_COMMAND_FLUSH 消息来刷新 MFT。 MFT 会删除它保存的所有输入和输出样本。

MFT 在收到来自客户端的MFT_MESSAGE_NOTIFY_START_OF_STREAM消息之前,不会发送另一个 METransformNeedInput 事件。

标记

客户端可以通过发送 MFT_MESSAGE_COMMAND_MARKER 消息来标记流中的点。 MFT 的响应如下所示:

  1. MFT 会从现有输入数据生成尽可能多的输出样本,为每个输出样本发送 METransformHaveOutput 事件。
  2. 生成所有输出后,MFT 将发送 METransformMarker 事件。 必须在所有 METransformHaveOutput 事件之后发送此事件。

例如,假设解码器有足够的输入数据来生成四个输出样本。 如果客户端发送 MFT_MESSAGE_COMMAND_MARKER 消息,MFT 会将四个 METransformHaveOutput 事件排入队列, (每个输出示例) 一个,后跟 一个 METransformMarker 事件。

标记消息类似于排出消息。 但是,排水被视为流中的中断,而标记则不被视为中断。 排水和标记具有以下差异。

排水:

  • 排出时,MFT 不会发送 METransformNeedInput 事件。
  • MFT 会丢弃任何不能用于创建输出示例的输入数据。
  • 某些 MMFT 在数据末尾生成“尾部”。 例如,音频效果(如混响或回声)在输入数据停止后会生成额外的数据。 生成尾部的 MFT 应在排水操作结束时执行此操作。
  • MFT 完成清空后,它会使用 MFSampleExtension_Discontinuity 属性标记下一个输出示例,以指示流中的不连续。

标记:

  • MFT 在发送标记事件之前继续发送 METransformNeedInput 事件。
  • MFT 不会放弃任何输入数据。 如果有部分数据,则应在标记点之后进行处理。
  • MFT 不会在标记点生成尾部。
  • MFT 不会在标记点之后设置不连续标志。

格式更改

异步 MFT 必须支持动态格式更改,如 处理流更改中所述。

特性

异步 MFT 必须实现 IMFTransform::GetAttributes 方法才能返回有效的属性存储。 以下属性适用于异步 MCT:

Attribute 说明
MF_TRANSFORM_ASYNC MFT 必须将此属性设置为 TRUE (1) 。 客户端可以查询此属性,以发现 MFT 是否为异步。
MF_TRANSFORM_ASYNC_UNLOCK
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE MFT 必须将此属性设置为 TRUE (1) 。 客户端可以假定已设置此属性。

 

解锁异步 MCT

异步 MFT 与原始 MFT 数据处理模型不兼容。 为了防止异步 MCT 破坏现有应用程序,定义了以下机制:

客户端在 MFT 上调用 IMFTransform::GetAttributes 。 客户端查询此 MF_TRANSFORM_ASYNC 属性的 。 对于异步 MFT,此属性的值为 “TRUE”。 若要解锁 MFT,客户端必须将 MF_TRANSFORM_ASYNC_UNLOCK 属性设置为 “TRUE”。

在客户端解锁 MFT 之前,所有 IMFTransform 方法都应返回 MF_E_TRANSFORM_ASYNC_LOCKED,但以下情况除外:

以下代码演示如何解锁异步 MFT:

HRESULT UnlockAsyncMFT(IMFTransform *pMFT)
{
    IMFAttributes *pAttributes = NULL;

    HRESULT hr = hr = pMFT->GetAttributes(&pAttributes);

    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
        pAttributes->Release();
    }
    
    return hr;
}

关闭 MFT

异步 MCT 必须实现 IMFShutdown 接口。

  • 关闭:MFT 必须关闭其事件队列。 如果使用标准事件队列,请调用 IMFMediaEventQueue::Shutdown。 (可选)MFT 可能会释放其他资源。 客户端在调用 Shutdown 后不得使用 MFT。
  • GetShutdownStatus:调用 Shutdown 后,MFT 应返回 pStatus 参数中的值MFSHUTDOWN_COMPLETED。 它不应返回 MFSHUTDOWN_INITIATED的值。

注册和枚举

若要注册异步 MFT,请调用 MFTRegister 函数并在 Flags 参数中设置MFT_ENUM_FLAG_ASYNCMFT标志。 (以前保留此标志。)

若要枚举异步 MFT,请调用 MFTEnumEx 函数并在 Flags 参数中设置 MFT_ENUM_FLAG_ASYNCMFT 标志。 为了向后兼容, MFTEnum 函数不枚举异步 MMT。 否则,在用户计算机上安装异步 MFT 可能会中断现有应用程序。

Media Foundation 转换