Processing Data in a DMO
This section explains how to process a stream of data using a DMO. The steps listed in this section are the default behavior; all DMOs must support the methods described here. These methods use separate buffers for input and output. Some DMOs also support in-place processing, using a single buffer. For more information about in-place processing, see In-Place Processing.
The client is responsible for all buffer allocation. After you set the media types on the DMO, 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 the following information:
- Minimum buffer size, in bytes.
- Alignment requirements, if any. A buffer is aligned if the start address is a multiple of some specified integer.
- The maximum amount of data the DMO will hold for lookahead. This number applies only to input streams. For some kinds of data (for example, MPEG encoding), a DMO might need to look forward in the stream. The lookahead value indicates how much input data the DMO will require before it can produce output.
The client must allocate buffers that match these requirements. In addition, the DMO might have requirements about how the client packages the input data. For example, the DMO might require each buffer to contain exactly one sample (or video frame). To determine these requirements, call the IMediaObject::GetInputStreamInfo method. The IMediaObject::GetOutputStreamInfo method returns similar information about an output stream.
In the default streaming model, the client does not pass raw buffer pointers to the DMO. Instead, it uses a lightweight COM object that exposes the IMediaBuffer interface. The IMediaBuffer interface acts as a COM wrapper for a block of memory. Because it is a COM object, it supports reference counting, which helps to ensure that buffers are not released while still in use.
The IMediaBuffer interface serves a function similar to the IMediaSample interface in DirectShow.
The client must implement the IMediaBuffer object. For more information, see Implementing IMediaBuffer.
Processing the Data
To process data, do the following:
- For each input stream, fill a buffer with input data.
- Call IMediaObject::ProcessInput to deliver each buffer.
- Call IMediaObject::ProcessOutput to process the data. This method takes an array of buffers, one for each output stream.
- Repeat until there is no more input data.
The ProcessInput method accepts input for one stream at a time. Typically the method returns immediately, and the DMO holds a reference count on the IMediaBuffer object. It releases the object after it processes all of the data in the buffer, or when the application flushes the DMO. Do not re-use a buffer until the DMO has released it. To determine whether an input stream can accept more data, call the IMediaObject::GetInputStatus method. This method returns the DMO_INPUT_STATUSF_ACCEPT_DATA flag if the stream can accept more input.
The ProcessOutput method generates output for all of the output streams at once. The application passes in an array of DMO_OUTPUT_DATA_BUFFER structures, one for each output stream. Each structure in the array has a pointer to an IMediaBuffer object. The DMO writes as much output data as it can into the buffers. It also sets various flags to report the status of the operation. The DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag indicates the DMO can produce more output from the existing input. In that case, the client can call ProcessOutput again. Otherwise, it should call ProcessInput with more input data. The DMO never modifies the data in the input buffers; it writes only to the output buffers.
After you have delivered all of the data to an input stream, call the IMediaObject::Discontinuity method. The DMO does not accept further input to that stream until you process the remaining output (or flush the DMO).
At any point after streaming begins, the DMO is able to receive input or produce output, or both. Therefore, either GetInputStatus returns DMO_INPUT_STATUSF_ACCEPT_DATA, or ProcessOutput returns DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE. The application keeps data flowing by testing for these flags and calling ProcessInput or ProcessOutput accordingly. To interrupt the data flow, call the IMediaObject::Flush method. This method causes the DMO to discard any buffers it is holding internally.