Comparison of MFTs and DMOs
Media Foundation transforms (MFTs) are an evolution of the transform model first introduced with DirectX Media Objects (DMOs). This topic summarizes the main ways in which MFTs differ from DMOs. Read this topic if you are already familiar with the DMO interfaces, or if you want to convert an existing DMO into an MFT.
This topic contains the following sections:
- Number of Streams
- Format Negotiation
- Streaming
- Miscellaneous Differences
- Flags
- Error Codes
- Creating Hybrid DMO/MFT Objects
- Related topics
Number of Streams
A DMO has a fixed number of streams, while an MFT can support a dynamic number of streams. The client can add input streams, and the MFT can add new output streams during processing. MFTs are not required to support dynamic streams, however. An MFT can have a fixed number of streams, just like a DMO.
The following methods are used to support dynamic streams on an MFT:
- IMFTransform::AddInputStreams
- IMFTransform::DeleteInputStream
- IMFTransform::GetStreamIDs
- IMFTransform::GetStreamLimits
In addition, the IMFTransform::ProcessOutput method defines the behavior for adding or removing output streams.
Because DMOs have fixed streams, the streams on a DMO are identified using zero-based index values. MFTs, on the other hand, use stream identifiers that do not necessarily correspond to index values. This is because the number of streams on an MFT might change. For example, stream 0 might be removed, leaving stream 1 as the first stream. However, an MFT with a fixed number of streams should observe the same convention as DMOs and use index values for stream identifiers.
Format Negotiation
MFTs use the IMFMediaType interface to describe media types. Otherwise, format negotiation with MFTs works on the same basic principles as with DMOs. The following table lists the format negotiation methods for DMOs and the corresponding methods for MFTs.
Streaming
Like DMOs, MFTs process data through calls to ProcessInput and ProcessOutput methods. Here are the major differences between DMO and MFT processes when streaming data.
Allocating Resources
MFTs do not have the IMediaObject::AllocateStreamingResources and IMediaObject::FreeStreamingResources methods used with DMOs. To handle allocation and deallocation of resources efficiently, an MFT can respond to the following messages in the IMFTransform::ProcessMessage method:
In addition, the client can signal the start and end of a stream by calling ProcessMessage with the following messages:
These two messages have no exact DMO equivalent.
Processing Data
MFTs use media samples to hold input and output data. Media samples expose the IMFSample interface, and contain the following data:
- Time stamp and duration.
- Attributes that contain per-sample information. For a list of attributes, see Sample Attributes.
- Zero or more media buffers. Each media buffer exposes the IMFMediaBuffer interface.
The IMFMediaBuffer interface is similar to the DMO IMediaBuffer interface. To access the underlying memory buffer, call IMFMediaBuffer::Lock. This method is roughly equivalent to IMediaBuffer::GetBufferAndLength for DMOs.
For uncompressed video data, a media buffer might also support the IMF2DBuffer interface. An MFT that processes uncompressed video (either as input or output) should be prepared to use the IMF2DBuffer interface if the buffer exposes it. For more information, see Uncompressed Video Buffers.
Media Foundation provides some standard implementations of IMFMediaBuffer, so it is generally not necessary to write your own implementation. To create a DMO buffer from a Media Foundation buffer, call MFCreateLegacyMediaBufferOnMFMediaBuffer.
Flushing
MFTs do not have a Flush method. To flush an MFT, call IMFTransform::ProcessMessage with the MFT_MESSAGE_COMMAND_FLUSH message.
Stream Discontinuities
MFTs do not have a Discontinuity method. To signal a discontinuity in a stream, set the MFSampleExtension_Discontinuity attribute on the input sample.
Miscellaneous Differences
Here are some additional minor differences between MFTs and DMOs.
There are no MFT equivalents for the following DMO methods:
MFTs are not required to support aggregation.
MFTs support an operation called draining. The purpose of draining is to process any data that remains in the MF, without providing any more input data to the MFT (for example, at the end of the stream). To drain an MFT, call IMFTransform::ProcessMessage with the MFT_MESSAGE_COMMAND_DRAIN message. For more information, see Basic MFT Processing Model.
MFTs can have attributes, including per-stream attributes. Use the following methods to get the attributes from an MFT:
MFTs can process events. To send an event to an MFT, call IMFTransform::ProcessEvent. An MFT can send an event to the client through the ProcessOutput method. For more information, see Basic MFT Processing Model.
Flags
The following tables list the various DMO flags and their MFT equivalents. Whenever a DMO flag maps directly to an MFT flag, both flags have the same numeric value. However, some DMO flags do not have exact MFT equivalents, and vice versa.
ProcessInput Flags
DMOs: _DMO_INPUT_DATA_BUFFER_FLAGS enumeration.
MFTs: No equivalent enumeration.
DMO flag | MFT flag |
---|---|
DMO_INPUT_DATA_BUFFERF_SYNCPOINT | No equivalent flag. Instead, set the MFSampleExtension_CleanPoint attribute on the sample. |
DMO_INPUT_DATA_BUFFERF_TIME | No equivalent flag. Instead, call IMFSample::SetSampleTime on the sample. |
DMO_INPUT_DATA_BUFFERF_TIMELENGTH | No equivalent flag. Instead, call IMFSample::SetSampleDuration on the sample. |
ProcessOutput Flags
DMOs: _DMO_PROCESS_OUTPUT_FLAGS enumeration.
MFTs: _MFT_PROCESS_OUTPUT_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER | MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER |
DMOs: _DMO_OUTPUT_DATA_BUFFER_FLAGS enumeration.
MFTs: _MFT_OUTPUT_DATA_BUFFER_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | No equivalent flag. Instead, check for the MFSampleExtension_CleanPoint attribute on the sample. |
DMO_OUTPUT_DATA_BUFFERF_TIME | No equivalent flag. Instead, call IMFSample::GetSampleTime on the sample. |
DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH | No equivalent flag. Instead, call IMFSample::GetSampleDuration on the sample. |
DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE | MFT_OUTPUT_DATA_BUFFER_INCOMPLETE |
No equivalent flag. | MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE |
No equivalent flag. | MFT_OUTPUT_DATA_BUFFER_STREAM_END |
No equivalent flag. | MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE |
GetInputStatus Flags
DMOs: _DMO_INPUT_STATUS_FLAGS enumeration.
MFTs: _MFT_INPUT_STATUS_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
DMO_INPUT_STATUSF_ACCEPT_DATA | MFT_INPUT_STATUS_ACCEPT_DATA |
GetOutputStatus Flags
DMOs: No equivalent enumeration.
MFTs: _MFT_OUTPUT_STATUS_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
No equivalent flag. | MFT_OUTPUT_STATUS_SAMPLE_READY |
GetInputStreamInfo Flags
DMOs: _DMO_INPUT_STREAM_INFO_FLAGS enumeration.
MFTs: _MFT_INPUT_STREAM_INFO_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
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 |
No equivalent flag. | MFT_INPUT_STREAM_DOES_NOT_ADDREF |
No equivalent flag. | MFT_INPUT_STREAM_REMOVABLE |
No equivalent flag. | MFT_INPUT_STREAM_OPTIONAL |
GetOutputStreamInfo Flags
DMOs: _DMO_OUTPUT_STREAM_INFO_FLAGS enumeration.
MFTs: _MFT_OUTPUT_STREAM_INFO_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
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 |
No equivalent flag. | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES |
No equivalent flag. | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES |
No equivalent flag. | MFT_OUTPUT_STREAM_LAZY_READ |
No equivalent flag. | MFT_OUTPUT_STREAM_REMOVABLE |
SetInputType/SetOutputType Flags
DMOs: _DMO_SET_TYPE_FLAGS enumeration.
MFTs: _MFT_SET_TYPE_FLAGS enumeration.
DMO flag | MFT flag |
---|---|
DMO_SET_TYPEF_TEST_ONLY | MFT_SET_TYPE_TEST_ONLY |
DMO_SET_TYPEF_CLEAR | No equivalent flag. Instead, set the media type to NULL to clear the media type. |
Error Codes
The following table shows how to map DMO error codes to MFT error codes. A hybrid MFT/DMO object should return the DMO error codes from IMediaObject methods and the MFT error codes from IMFTransform methods. The DMO error codes are defined in the header file MediaErr.h. The MFT error codes are defined in the header file mferror.h.
DMO error code | MFT error code |
---|---|
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 |
Creating Hybrid DMO/MFT Objects
The IMFTransform interface is loosely based on IMediaObject, which is the primary interface for DirectX Media Objects (DMOs). It is possible to create objects that expose both interfaces. However, this can lead to naming collisions, because the interfaces have some methods that share the same name. You can solve this problem in one of two ways:
Solution 1: Include the following line at the top of any .cpp file that contains MFT functions:
#define MFT_UNIQUE_METHOD_NAMES
This changes the declaration of the IMFTransform interface so that most of the method names are prefixed with "MFT". Thus, IMFTransform::ProcessInput becomes IMFTransform::MFTProcessInput, while IMediaObject::ProcessInput keeps its original name. This technique is most useful if you are converting an existing DMO to a hybrid DMO/MFT. You can add the new MFT methods without changing the DMO methods.
Solution 2: Use C++ syntax to disambiguate names that are inherited from more than one interface. For example, declare the MFT version of ProcessInput as follows:
CMyHybridObject::IMFTransform::ProcessInput(...)
Declare the DMO version of ProcessInput like this:
CMyHybridObject::IMediaObject::ProcessInput(...)
If you make an internal call to a method within the object, you can use this syntax, but doing so will override the virtual status of the method. A better way to make calls from inside the object is the following:
hr = ((IMediaObject*)this)->ProcessInput(...)
That way, if you derive another class from CMyHybridObject and override the CMyHybridObject::IMediaObject::ProcessInput method, the correct virtual method is called. The DMO interfaces are documented in the DirectShow SDK documentation.
Related topics