MFT 和 DMO 的比较
媒体基础转换(MFT)是 DirectX 媒体对象(DMO)首次引入的转换模型的演变。 本主题总结了 MFT 与 DMO 的不同主要方式。 如果已熟悉 DMO 接口,或者想要将现有 DMO 转换为 MFT,请阅读本主题。
本主题包含以下部分:
流数
DMO 具有固定数量的流,而 MFT 可以支持动态数量的流。 客户端可以添加输入流,MFT 可以在处理过程中添加新的输出流。 但是,不支持动态流不需要 MFT。 MFT 可以具有固定数量的流,就像 DMO 一样。
以下方法用于支持 MFT 上的动态流:
- IMFTransform::AddInputStreams
- IMFTransform::D eleteInputStream
- IMFTransform::GetStreamIDs
- IMFTransform::GetStreamLimits
此外,IMFTransform::P rocessOutput 方法定义添加或删除输出流的行为。
由于 DMO 具有固定流,因此使用从零开始的索引值标识 DMO 上的流。 另一方面,MFT 使用不一定对应于索引值的流标识符。 这是因为 MFT 上的流数可能会更改。 例如,可能会删除流 0,将流 1 保留为第一个流。 但是,具有固定数量的流的 MFT 应遵守与 DMO 相同的约定,并使用流标识符的索引值。
格式协商
MFT 使用 IMFMediaType 接口来描述媒体类型。 否则,与 MFT 进行格式协商的工作方式与 DMO 具有相同的基本原则。 下表列出了 DMO 的格式协商方法和 MFT 的相应方法。
流
与 DMO 一样,MFT 通过调用 ProcessInput 和 ProcessOutput 方法来处理数据。 下面是流式处理数据时 DMO 和 MFT 进程之间的主要差异。
分配资源
MFT 没有 IMediaObject::AllocateStreamingResources 和 IMediaObject::FreeStreamingResources 与 DMO 一起使用的方法。 若要高效处理资源的分配和解除分配,MFT 可以响应 IMFTransform::P rocessMessage 方法中的以下消息:
此外,客户端还可以通过使用以下消息调用 ProcessMessage 来发出流的开始和结束信号:
这两条消息没有确切的 DMO 等效项。
处理数据
MFT 使用媒体示例来保存输入和输出数据。 媒体示例公开 IMFSample 接口,并包含以下数据:
- 时间戳和持续时间。
- 包含每个样本信息的属性。 有关属性列表,请参阅 示例属性。
- 零个或多个媒体缓冲区。 每个媒体缓冲区都公开 IMFMediaBuffer 接口。
IMFMediaBuffer 接口类似于 DMO IMediaBuffer 接口。 若要访问基础内存缓冲区,请调用 IMFMediaBuffer::Lock。 此方法大致相当于适用于 DMO 的 IMediaBuffer::GetBufferAndLength。
对于未压缩的视频数据,媒体缓冲区还可能支持 IMF2DBuffer 接口。 处理未压缩的视频(输入或输出)的 MFT 应准备好在缓冲区公开视频时使用 IMF2DBuffer 接口。 有关详细信息,请参阅 未压缩的视频缓冲区。
媒体基础提供了 IMFMediaBuffer的一些标准实现,因此通常不需要编写自己的实现。 若要从 Media Foundation 缓冲区创建 DMO 缓冲区,请调用 MFCreateLegacyMediaBufferOnMFMediaBuffer。
冲洗
MFT 没有 Flush 方法。 若要刷新 MFT,请使用 MFT_MESSAGE_COMMAND_FLUSH 消息调用 IMFTransform::P rocessMessage。
流中断性
MFT 没有 非连续 方法。 若要在流中发出不连续信号,请对输入示例设置 MFSampleExtension_Discontinuity 属性。
其他差异
下面是 MFT 和 DMO 之间的一些附加细微差异。
以下 DMO 方法没有 MFT 等效项:
不支持聚合时不需要 MFT。
MFT 支持名为 排水的作。 清空的目的是处理在 MF 中保留的任何数据,而无需向 MFT 提供更多输入数据(例如,在流末尾)。 若要清空 MFT,请使用 MFT_MESSAGE_COMMAND_DRAIN 消息调用 IMFTransform::P rocessMessage。 有关详细信息,请参阅 基本 MFT 处理模型。
MFT 可以具有属性,包括每个流属性。 使用以下方法从 MFT 获取属性:
MFT 可以处理事件。 若要将事件发送到 MFT,请调用 IMFTransform::P rocessEvent。 MFT 可以通过 ProcessOutput 方法将事件发送到客户端。 有关详细信息,请参阅 基本 MFT 处理模型。
标志
下表列出了各种 DMO 标志及其 MFT 等效项。 每当 DMO 标志直接映射到 MFT 标志时,这两个标志具有相同的数值。 但是,某些 DMO 标志没有确切的 MFT 等效项,反之亦然。
ProcessInput 标志
DMO:_DMO_INPUT_DATA_BUFFER_FLAGS 枚举。
MFT:无等效枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_INPUT_DATA_BUFFERF_SYNCPOINT | 无等效标志。 而是在示例中设置 MFSampleExtension_CleanPoint 属性。 |
DMO_INPUT_DATA_BUFFERF_TIME | 无等效标志。 相反,请对示例调用 IMFSample::SetSampleTime。 |
DMO_INPUT_DATA_BUFFERF_TIMELENGTH | 无等效标志。 相反,请对示例调用 IMFSample::SetSampleDuration。 |
ProcessOutput 标志
DMO:_DMO_PROCESS_OUTPUT_FLAGS 枚举。
MFT:_MFT_PROCESS_OUTPUT_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER | MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER |
DMO:_DMO_OUTPUT_DATA_BUFFER_FLAGS 枚举。
MFT:_MFT_OUTPUT_DATA_BUFFER_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | 无等效标志。 而是检查示例上的 MFSampleExtension_CleanPoint 属性。 |
DMO_OUTPUT_DATA_BUFFERF_TIME | 无等效标志。 相反,请对示例调用 IMFSample::GetSampleTime。 |
DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH | 无等效标志。 相反,请对示例调用 IMFSample::GetSampleDuration。 |
DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE | MFT_OUTPUT_DATA_BUFFER_INCOMPLETE |
无等效标志。 | MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE |
无等效标志。 | MFT_OUTPUT_DATA_BUFFER_STREAM_END |
无等效标志。 | MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE |
GetInputStatus 标志
DMO:_DMO_INPUT_STATUS_FLAGS 枚举。
MFT:_MFT_INPUT_STATUS_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_INPUT_STATUSF_ACCEPT_DATA | MFT_INPUT_STATUS_ACCEPT_DATA |
GetOutputStatus 标志
DMO:无等效枚举。
MFT:_MFT_OUTPUT_STATUS_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
无等效标志。 | MFT_OUTPUT_STATUS_SAMPLE_READY |
GetInputStreamInfo 标志
DMO:_DMO_INPUT_STREAM_INFO_FLAGS 枚举。
MFT:_MFT_INPUT_STREAM_INFO_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_INPUT_STREAMF_WHOLE_SAMPLES | MFT_INPUT_STREAM_WHOLE_SAMPLES |
DMO_INPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
DMO_INPUT_STREAMF_FIXED_SAMPLE_SIZE | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE |
DMO_INPUT_STREAMF_HOLDS_BUFFERS | MFT_INPUT_STREAM_HOLDS_BUFFERS |
无等效标志。 | MFT_INPUT_STREAM_DOES_NOT_ADDREF |
无等效标志。 | MFT_INPUT_STREAM_REMOVABLE |
无等效标志。 | MFT_INPUT_STREAM_OPTIONAL |
GetOutputStreamInfo 标志
DMO:_DMO_OUTPUT_STREAM_INFO_FLAGS 枚举。
MFT:_MFT_OUTPUT_STREAM_INFO_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_OUTPUT_STREAMF_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE |
DMO_OUTPUT_STREAMF_DISCARDABLE | MFT_OUTPUT_STREAM_DISCARDABLE |
DMO_OUTPUT_STREAMF_OPTIONAL | MFT_OUTPUT_STREAM_OPTIONAL |
无等效标志。 | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES |
无等效标志。 | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES |
无等效标志。 | MFT_OUTPUT_STREAM_LAZY_READ |
无等效标志。 | MFT_OUTPUT_STREAM_REMOVABLE |
SetInputType/SetOutputType 标志
DMO:_DMO_SET_TYPE_FLAGS 枚举。
MFT:_MFT_SET_TYPE_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_SET_TYPEF_TEST_ONLY | MFT_SET_TYPE_TEST_ONLY |
DMO_SET_TYPEF_CLEAR | 无等效标志。 相反,将媒体类型设置为 NULL 清除媒体类型。 |
错误代码
下表显示了如何将 DMO 错误代码映射到 MFT 错误代码。 混合 MFT/DMO 对象应从 IMediaObject 方法返回 DMO 错误代码,以及来自 IMFTransform 方法的 MFT 错误代码。 DMO 错误代码在头文件 MediaErr.h 中定义。 MFT 错误代码在头文件 mferror.h 中定义。
DMO 错误代码 | MFT 错误代码 |
---|---|
DMO_E_INVALIDTYPE | MF_E_INVALIDTYPE |
DMO_E_INVALIDSTREAMINDEX | MF_E_INVALIDSTREAMNUMBER |
DMO_E_NOTACCEPTING | MF_E_NOTACCEPTING |
DMO_E_NO_MORE_ITEMS | MF_E_NO_MORE_TYPES |
DMO_E_TYPE_NOT_ACCEPTED | MF_E_INVALIDMEDIATYPE |
DMO_E_TYPE_NOT_SET | MF_E_TRANSFORM_TYPE_NOT_SET |
创建混合 DMO/MFT 对象
IMFTransform 接口基于 IMediaObject,这是 DirectX 媒体对象(DMO)的主要接口。 可以创建公开这两个接口的对象。 但是,这可能会导致命名冲突,因为接口具有共享相同名称的一些方法。 可以通过以下两种方式之一解决此问题:
解决方案 1:在包含 MFT 函数的任何.cpp文件的顶部包含以下行:
#define MFT_UNIQUE_METHOD_NAMES
这会更改 IMFTransform 接口的声明,以便大多数方法名称的前缀为“MFT”。 因此,IMFTransform::P rocessInput 变为 IMFTransform::MFTProcessInput,而 IMediaObject::P rocessInput 保留其原始名称。 如果将现有 DMO 转换为混合 DMO/MFT,此方法最有用。 无需更改 DMO 方法,即可添加新的 MFT 方法。
解决方案 2:使用C++语法消除从多个接口继承的名称的歧义。 例如,按如下所示声明 ProcessInput 的 MFT 版本:
CMyHybridObject::IMFTransform::ProcessInput(...)
声明 ProcessInput 的 DMO 版本,如下所示:
CMyHybridObject::IMediaObject::ProcessInput(...)
如果对对象内的方法进行内部调用,则可以使用此语法,但这样做将替代方法的虚拟状态。 从对象内部发出调用的更好方法是:
hr = ((IMediaObject*)this)->ProcessInput(...)
这样,如果从 CMyHybridObject 派生另一个类 并重写 CMyHybridObject::IMediaObject::P rocessInput 方法,则会调用正确的虚拟方法。 DMO 接口记录在 DirectShow SDK 文档中。
相关主题