Processing Data with DMOs
A version of this page is also available for
4/8/2010
Step 1. Query the DMO
First, query the DMO for the number of streams it supports and the preferred media types for each stream. To retrieve the number of input streams and output streams, call the IMediaObject::GetStreamCount method.
For each stream, the DMO ranks its preferred media types in order of preference and assigns each type an index, starting from zero.
To retrieve a preferred media type for a particular stream, call the IMediaObject::GetInputType or IMediaObject::GetOutputType method. Specify a stream number and a media-type index.
To enumerate all media types on a stream, use a loop that increments the media-type index until the method returns DMO_E_NO_MORE_ITEMS, as shown in the following pseudocode.
DWORD cInputs, cOutputs, type = 0
DMO_MEDIA_TYPE mt
pDMO->GetStreamCount(&cInputs, &cOutputs)
for (DWORD i = 0; i < cInputs; i++)
{
while (pDMO->GetInputType(i, type, &mt) != DMO_E_NO_MORE_ITEMS)
{
if ( this media type is one you want )
break
MoFreeMediaType(&mt)
type++
}
}
The GetInputType and GetOutputType methods return a DMO_MEDIA_TYPE structure with the media type. The following structure members are relevant:
- majortype. A globally unique identifier (GUID) that specifies the major type of the stream. The major type is the general classification, such as video or audio. For a list of major types, see Media Types.
- subtype. A GUID that specifies the subtype of the stream. The subtype further classifies the type. For example, MEDIASUBTYPE_RGB24 specifies 24-bit RGB video. For a list of subtypes, see Media Types.
- pbFormat. Pointer to a structure that describes the format in detail. The format structure specifies information such as the width and height of a video image or the sample rate of an audio sample.
Different media types use different format structures. Most video data uses the VIDEOINFOHEADER structure. Audio data uses the WAVEFORMATEX structure. - formattype. Specifies the format structure contained in pbFormat.
The media type might have a NULL format structure, indicated by a value of GUID_NULL for the formattype member. A NULL format indicates that the DMO can accept a range of formats within the specified media type.
For example, a stream that requires PCM audio might accept a range of sample rates. Therefore, it returns MEDIATYPE_Audio for the major type, MEDIASUBTYPE_PCMAudio for the subtype, and a NULL format.
The application must call the MoFreeMediaType function to free the pbFormat member.
Step 2. Set Media Types
After finding the DMO's preferred media types, set the media type for each stream by calling the IMediaObject::SetInputType and IMediaObject::SetOutputType methods.
Not every combination of media types reported by the DMO is guaranteed to be valid. For example, the output type might need to match the input type.
You can test a media type by calling SetInputType or SetOutputType with the DMO_SET_TYPEF_TEST_ONLY flag. For a decoder, you would generally set the input type and then choose an output type. For an encoder, you would set the output type and then choose an input type.
Because the settings on one stream can affect another stream, you might need to clear a media type that you set previously. To do this, call SetInputType or SetOutputType with the DMO_SET_TYPEF_CLEAR flag.
Step 3. Allocate Buffers
After you set the media types, query the DMO for each stream's buffer requirements. These can change depending on the media type. For each stream, call the IMediaObject::GetInputSizeInfo or IMediaObject::GetOutputSizeInfo method. These methods return three values:
- Minimum buffer size, in bytes.
- Alignment requirements, if any. A buffer is aligned if the start address is a multiple of some specified integer.
- For input buffers, the maximum amount of data that the DMO will hold for a lookahead. Some DMOs need to hold multiple input buffers to process the data; the lookahead value specifies this requirement.
You must allocate sufficient buffers to handle these requirements.
In addition to the size requirements, an input stream might require that each buffer contain only whole samples, contain exactly one sample, or use a fixed sample size. To determine these requirements, call the IMediaObject::GetInputStreamInfo method.
Step 4. Process Input
At this point, you can deliver input buffers to the DMO.
For each input stream, fill one or more input buffers with media data. You can write data directly into a buffer or use an output buffer from another DMO. Call the IMediaObject::ProcessInput method to deliver each buffer.
Typically, the DMO holds a reference count on the buffer. It releases the buffer when it has generated all of the output that it can or when the application flushes the DMO. Do not reuse the buffer until the DMO releases it.
To determine whether an input stream can accept more data, call the IMediaObject::GetInputStatus method. If the stream can accept more data, the method returns the DMO_INPUT_STATUSF_ACCEPT_DATA flag.
Step 5. Process Output
Whereas the ProcessInput method delivers one input buffer at a time, IMediaObject::ProcessOutput generates output for all output streams at once.
The application passes an array of DMO_OUTPUT_DATA_BUFFER structures, with one structure for every output stream. The structure contains a pointer to an output buffer (allocated by the application) and various fields that are filled by the DMO.
In ProcessOutput, the DMO generates as much data as possible, given the size of the output buffers. If it fills an output buffer before it processes all of the data, it sets the DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag in the structure's dwStatus member. When the method returns, check each structure for this flag. If the flag is present, call ProcessOutput again.
After streaming begins, the DMO can always accept input, produce output, or both. Therefore, either GetInputStatus returns the DMO_INPUT_STATUSF_ACCEPT_DATA flag or ProcessOutput returns the DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag. The application keeps data flowing by testing for these flags and calling ProcessInput or ProcessOutput.
Step 6: Signal a Discontinuity
When you have delivered all available input data to a particular input stream, call the IMediaObject::Discontinuity method. The DMO does not accept further input to that stream until you process any remaining output.