Media foundation transforms (MFTs)的异步数据处理

来源:互联网 发布:如何做淘宝海外买手 编辑:程序博客网 时间:2024/06/10 22:46

原文章 https://msdn.microsoft.com/en-us/library/windows/desktop/dd317909(v=vs.85).aspx

关于异步MFT About Asynchronous MFTs

当在Windows Vista中引入MFT时,其API被设计用于同步数据处理。在这种模型中,MFT总是等待获得输入,或者等待产生输出。
考虑到一个典型的视频解码器。要获得解码的帧,client调用IMFTransform :: ProcessOutput。如果解码器具有足够的数据来解码帧,则在MFT对帧进行解码的同时,处理输出块。否则,ProcessOutput返回MF_E_TRANSFORM_NEED_MORE_INPUT,指示client应调用IMFTransform :: ProcessInput。
如果解码器在一个线程上执行所有的解码操作,这个模型工作良好。但是假设解码器使用多个线程来并行解码帧。为了获得最佳性能,解码器应当在解码线程变得空闲时接收新输入。但线程完成解码操作的速率不会与客户端对ProcessInput和ProcessOutput的调用完全一致,导致线程等待工作。
Windows 7为MFT引入了事件驱动的异步处理。在此模型中,每当MFT需要输入或具有输出时,它向client发送事件。

一般要求 General Requirements

本主题描述异步MFT如何不同于同步MFT。除非本主题中注明,否则两个处理模型是相同的。 (特别是,格式协商是相同的。)
异步MFT必须实现以下接口:
IMFTransform
IMFMediaEventGenerator
IMFShutdown

事件 Event

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

Event Description METransformNeedInput 当MFT可以接受更多输入时发送。 METransformHaveOutput 当MFT输出时发送。 METransformDrainComplete 当排空操作完成时发送。 参见排空。 METransformMarker 标记处理时发送。 请参阅标记。

这些事件是在频带外的。重要的是理解在MFT的上下文中带内和带外事件之间的差异。

原始的MFT设计支持带内事件。 带内事件包含有关数据流的信息,例如有关格式更改的信息。 client通过调用IMFTransform :: ProcessEvent将带内事件发送到MFT。 MFT可以在ProcessOutput方法中将带内事件发送回client。 (具体来说,事件在MFT_OUTPUT_DATA_BUFFER结构的pEvents成员中传递。

  • MFT实现IMFMediaEventGenerator接口,如媒体事件生成器中所述。
  • client在MFT上为IMFMediaEventGenerator接口调用IUnknown :: QueryInterface。
    异步MFT必须暴露此接口。 同步MFT不应暴露此接口。
  • client调用IMFMediaEventGenerator ::
    BeginGetEvent和IMFMediaEventGenerator :: EndGetEvent从MFT接收带外事件。

输入处理 ProcessInput

IMFTransform :: ProcessInput方法修改如下:
- 流开始时,client发送MFT_MESSAGE_NOTIFY_START_OF_STREAM消息。
- 在流式传输期间,MFT通过发送一个METransformNeedInput事件来请求数据。 事件数据是流标识符。
- 对于每个METransformNeedInput事件,client为指定的流调用ProcessInput。
- 在流式处理结束时,client可以使用MFT_MESSAGE_NOTIFY_END_OF_STREAM消息调用ProcessMessage。

实施注意事项:
- MFT不能发送任何METransformNeedInput事件,直到它收到MFT_MESSAGE_NOTIFY_START_OF_STREAM消息。
- 在流传输期间,MFT可以随时发送METransformNeedInput事件。MFT应该维护等待中的METransformNeedInput事件的计数。
任何对不与METransformNeedInput事件对应的ProcessInput的调用必须返回MF_E_NOTACCEPTING。
- 当MFT接收到MFT_MESSAGE_NOTIFY_END_OF_STREAM消息时,它将将待处理的METransformNeedInput事件的计数重置为零。在接收到MFT_MESSAGE_NOTIFY_END_OF_STREAM消息后,MFT不得发送任何METransformNeedInput事件。
- 如果在MFT_MESSAGE_NOTIFY_START_OF_STREAM之前或在MFT_MESSAGE_NOTIFY_END_OF_STREAM之后调用ProcessInput,则该方法必须返回MF_E_NOTACCEPTING。

输出处理 ProcessOutput

IMFTransform :: ProcessOutput方法修改如下:

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

实施注意事项:

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

排空 Draining

排空MFT导致MFT从已经发送的任何输入数据产生尽可能多的输出。 排空异步MFT的过程如下:

  1. client发送MFT_MESSAGE_COMMAND_DRAIN消息。
  2. MFT继续发送METransformHaveOutput事件,直到它没有更多的数据要处理。
    在此期间不会发送METransformNeedInput事件。
  3. 在MFT发送最后一个METransformHaveOutput事件之后,它发送一个METransformDrainComplete事件。
  4. 排空完成后,MFT不会发送另一个METransformNeedInput事件,直到它从客户端接收到MFT_MESSAGE_NOTIFY_START_OF_STREAM消息。

刷新 Flushing

client可以通过发送MFT_MESSAGE_COMMAND_FLUSH消息来刷新MFT。 MFT丢弃其保存的所有输入和输出样本。
MFT不会发送另一个METransformNeedInput事件,直到它从客户端接收到MFT_MESSAGE_NOTIFY_START_OF_STREAM消息。

标记 Markers

client可以通过发送MFT_MESSAGE_COMMAND_MARKER消息在流中标记一个点。 MFT响应如下:

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

例如,假设解码器具有足够的输入数据以产生四个输出样本。如果客户端发送MFT_MESSAGE_COMMAND_MARKER消息,MFT将排队4个METransformHaveOutput事件(每个输出样本一个),随后是一个METransformMarker事件。
标记消息类似于排空消息。然而,排空被认为是流中的中断,而标记不是。排出和标记有以下差异。
排空:

  • 排空时,MFT不发送METransformNeedInput事件。
  • MFT丢弃不能用于创建输出样本的任何输入数据。
  • 一些MFT在数据的结尾产生“尾部”。例如,混响或回声等音频效果会在输入数据停止后产生额外的数据。产生尾部的MFT在排空操作结束时应该这样做。
  • 在MFT完成排空之后,它用MFSampleExtension_Discontinuity属性标记下一个输出样本,以指示流中的不连续性。

标记:

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

格式更改 Format Changes

异步MFT必须支持动态格式更改,如Handling Stream Changes中所述。

属性 Attributes

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

Attribute Description MF_TRANSFORM_ASYNC MFT必须将此属性设置为TRUE(1)。 client可以查询此属性以发现MFT是否是异步的。 MF_TRANSFORM_ASYNC_UNLOCK MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE MFT必须将此属性设置为TRUE(1)。 client可以假定该属性已设置。

解锁异步MFT Unlocking Asynchronous MFTs

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

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

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

  • IMFTransform :: GetAttributes(所有异步MFT)
  • IMFTransform :: GetInputAvailableType(所有异步MFT)
  • IMFTransform :: GetOutputCurrentType(仅限编码器)
  • IMFTransform :: SetOutputType(仅限编码器)
  • IMFTransform :: GetStreamCount(所有异步MFT)
  • IMFTransform :: GetStreamIDs(所有异步MFT)

以下代码显示如何解锁异步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 Shutting Down the MFT

异步MFT必须实现IMFShutdown接口。

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

注册和枚举 Registration and Enumeration

要注册异步MFT,请调用MFTRegister函数,并在Flags参数中设置MFT_ENUM_FLAG_ASYNCMFT标志。 (以前此标志已保留。)
要枚举异步MFT,请调用MFTEnumEx函数并在Flags参数中设置MFT_ENUM_FLAG_ASYNCMFT标志。 为了向后兼容,MFTEnum函数不枚举异步MFT。 否则,在用户计算机上安装异步MFT可能会破坏现有应用程序。

Media Foundation Transforms

0 0