MFT 和 DMO 的比较
媒体基础转换 (MMT) 是首次随 DirectX 媒体对象 (MDO) 引入的转换模型的演变。 本主题总结了 MMT 与 MTO 的区别main方式。 如果你已经熟悉 DMO 接口,或者想要将现有 DMO 转换为 MFT,请阅读本主题。
本主题包含以下各节:
流数
DMO 具有固定数量的流,而 MFT 可以支持动态数量的流。 客户端可以添加输入流,MFT 可以在处理期间添加新的输出流。 但是,不需要 MRT 即可支持动态流。 MFT 可以有固定数量的流,就像 DMO 一样。
以下方法用于支持 MFT 上的动态流:
- IMFTransform::AddInputStreams
- IMFTransform::D eleteInputStream
- IMFTransform::GetStreamIDs
- IMFTransform::GetStreamLimits
此外, IMFTransform::P rocessOutput 方法定义添加或删除输出流的行为。
由于 DMO 具有固定流,因此使用从零开始的索引值标识 DMO 上的流。 另一方面,MRT 使用不一定对应于索引值的流标识符。 这是因为 MFT 上的流数可能会更改。 例如,可能会删除流 0,将流 1 保留为第一个流。 但是,具有固定流数的 MFT 应遵循与 DSO 相同的约定,并将索引值用于流标识符。
格式协商
MRT 使用 IMFMediaType 接口来描述媒体类型。 否则,与 MMT 的格式协商遵循与 MDO 相同的基本原则。 下表列出了 MDO 的格式协商方法和 MMT 的相应方法。
流式处理
与 MDO 一样,MMT 通过调用 ProcessInput 和 ProcessOutput 方法来处理数据。 以下是流式处理数据时 DMO 和 MFT 进程之间的主要差异。
分配资源
MMT 没有用于 DMO 的 IMediaObject::AllocateStreamingResources 和 IMediaObject::FreeStreamingResources 方法。 为了有效地处理资源的分配和解除分配,MFT 可以在 IMFTransform::P rocessMessage 方法中响应以下消息:
此外,客户端可以通过使用以下消息调用 ProcessMessage 来发出流的开始和结束信号:
这两条消息没有完全等效的 DMO。
处理数据
MRT 使用媒体样本来保存输入和输出数据。 媒体示例公开 IMFSample 接口,并包含以下数据:
- 时间戳和持续时间。
- 包含每个示例信息的属性。 有关属性的列表,请参阅 示例属性。
- 零个或多个媒体缓冲区。 每个媒体缓冲区都公开 IMFMediaBuffer 接口。
IMFMediaBuffer 接口类似于 DMO IMediaBuffer 接口。 若要访问基础内存缓冲区,请调用 IMFMediaBuffer::Lock。 此方法大致等效于适用于 DMO 的 IMediaBuffer::GetBufferAndLength 。
对于未压缩的视频数据,媒体缓冲区可能还支持 IMF2DBuffer 接口。 处理未压缩视频 (作为输入或输出) 的 MFT 应准备好使用 IMF2DBuffer 接口(如果缓冲区公开该接口)。 有关详细信息,请参阅 未压缩的视频缓冲区。
媒体基础提供 IMFMediaBuffer 的一些标准实现,因此通常不需要编写自己的实现。 若要从媒体基础缓冲区创建 DMO 缓冲区,请调用 MFCreateLegacyMediaBufferOnMFMediaBuffer。
冲洗
MRT 没有 Flush 方法。 若要刷新 MFT,请使用MFT_MESSAGE_COMMAND_FLUSH消息调用IMFTransform::P rocessMessage。
流不连续
MRT 没有 非连续方法 。 若要指示流中的不连续性,请在输入样本上设置 MFSampleExtension_Discontinuity 属性。
其他差异
下面是 MMT 和 MTO 之间的一些其他细微差异。
以下 DMO 方法没有 MFT 等效项:
不需要 MRT 即可支持聚合。
MRT 支持名为 “清空”的操作。 清空的目的是处理保留在 MF 中的任何数据,而无需向 MFT (提供更多输入数据,例如,在流) 末尾。 若要清空 MFT,请使用MFT_MESSAGE_COMMAND_DRAIN消息调用 IMFTransform::P rocessMessage。 有关详细信息,请参阅 基本 MFT 处理模型。
MRT 可以具有属性,包括每流属性。 使用以下方法从 MFT 获取属性:
MRT 可以处理事件。 若要将事件发送到 MFT,请调用 IMFTransform::P rocessEvent。 MFT 可以通过 ProcessOutput 方法将事件发送到客户端。 有关详细信息,请参阅 基本 MFT 处理模型。
Flags
下表列出了各种 DMO 标志及其 MFT 等效项。 每当 DMO 标志直接映射到 MFT 标志时,这两个标志都具有相同的数值。 但是,某些 DMO 标志没有确切的 MFT 等效项,反之亦然。
ProcessInput 标志
DMO: _DMO_INPUT_DATA_BUFFER_FLAGS 枚举。
MCT:无等效枚举。
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 枚举。
MRT: _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 枚举。
MRT: _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 枚举。
MCT: _MFT_INPUT_STATUS_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
DMO_INPUT_STATUSF_ACCEPT_DATA | MFT_INPUT_STATUS_ACCEPT_DATA |
GetOutputStatus 标志
DMO:无等效枚举。
MCT: _MFT_OUTPUT_STATUS_FLAGS 枚举。
DMO 标志 | MFT 标志 |
---|---|
无等效标志。 | MFT_OUTPUT_STATUS_SAMPLE_READY |
GetInputStreamInfo 标志
DMO: _DMO_INPUT_STREAM_INFO_FLAGS 枚举。
MCT: _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 枚举。
MCT: _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 标志
DSO: _DMO_SET_TYPE_FLAGS 枚举。
MMFT: _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,IMediaObject 是 DirectX 媒体对象 (DMC) 的主要接口。 可以创建公开这两个接口的对象。 但是,这可能会导致命名冲突,因为接口的某些方法具有相同的名称。 可以通过以下两种方式之一来解决此问题:
解决方案 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 方法,则会调用正确的虚拟方法。 DirectShow SDK 文档中记录了 DMO 接口。
相关主题