Microsoft DirectX 8.0

DMO Sample

Description

DMO Sample is a sample Microsoft® DirectX® Media Object (DMO). It takes MPEG-1 video packets as input and produces two output streams. The first output stream contains video frames in RGB 565 format. Each frame displays the time code taken from the MPEG-1 video, and is otherwise blank. The second output stream is an optional text stream with the time code.

DMO Sample uses the IMediaObjectImpl base-class template to implement the IMediaObject interface. For information about using this template, see Using the DMO Base Class. The Active Template Library (ATL) handles various COM details, including registration, aggregation, IUnknown, and the DLL entry points.

Path

Source: (SDK root)\Samples\Multimedia\DirectShow\DMO\DMOSample

User's Guide

The project workspace builds a DLL named Dmosample.dll. Use the Regsvr32 utility to register the DLL. To see the DMO in action, you can use the Microsoft® DirectShow® GraphEdit utility. You will need an MPEG-1 video file. Perform the following steps:

  1. Run GraphEdit.
  2. Render an MPEG-1 file:
  3. Remove the MPEG-1 Video Decoder filter from the filter graph by selecting the filter and pressing DELETE.
  4. Insert the DMO Sample in the graph:
  5. Connect the MPEG-1 Stream Splitter to the DMO Sample by dragging the mouse from the small box labeled Video on the MPEG-1 Stream Splitter to the box labeled in0 on the DMO Sample. (See illustration.)
  6. Connect the DMO Sample to the Video Renderer:
    • Drag the mouse from the box labeled out0 on the DMO Sample to the box labeled Input on the Video Renderer
    • .
    • GraphEdit might automatically insert a Color Space Converter filter to convert between RGB types.
  7. Press the play button on the GraphEdit toolbar, or click Play from the Graph menu.

When the graph runs, a video window appears that displays the time codes.

Connecting the DMO Sample filter.

Programming Notes

The DMO Sample contains the following source and header files:

The DMO Sample also uses the following resource files:

The following remarks describe the implementation in greater detail.

Dmosample.cpp

The file contains the object map that ATL uses to create and register the DMO object. It also contains the exported DLL functions. These include the entry-point function (DllMain), and the functions that COM requires (DllCanUnloadNow, DllGetClassObject, DllRegisterServer, and DllUnregisterServer).

The ATL COM AppWizard automatically generates most of the code contained in this file. Two things are added:

Resource.h

The one constant declared in this header file, IDR_SAMPLE, is used by ATL's self-registration mechanism. The constant IDR_SAMPLE identifies a text resource, which is defined in the resource file Sample.rgs and imported by the resource file Dmosample.rc. The header file Sample.h contains the line:

DECLARE_REGISTRY_RESOURCEID(IDR_SAMPLE)  

which causes ATL to use the registration information declared in the IDR_SAMPLE resource.

Sample.h

The DEFINE_GUID macro declares the class identifier (CLSID) of the DMO.

The CSample class derives from the following classes:

CSample aggregates the Free Threaded Marshaler, which is an object that performs custom marshaling. If the COM library marshals a CSample pointer across threads within the sample process, the exact same pointer is returned. If the COM library tries to marshal the object across processes or across machines, it fails. ATL adds all of the code need to aggregrate the Free Threaded Marshaler. This code appears in the FinalConstruct and FinalRelease methods. The COM_INTERFACE_ENTRY_AGGREGATE entry in the COM map delegates the IMarshal interface to the Free Threaded Marshaler.

The CSample class declares the following member variables:

m_pUnkMarshalerPointer to the Free Threaded Marshaler object.
m_pBufferPointer to the input buffer. The DMO holds a reference count on the buffer until it processes all of the input.
m_pbDataPointer to the next byte in the input buffer.
m_cbDataNumber of bytes remaining to process.
m_rtFrameTime stamp from the most recent output frame.
m_StreamStateInstance of the CStreamState helper class, which parses MPEG data.
m_bPictureBoolean flag that indicates whether the DMO has picture information to output.

Sample.cpp

This file implements the methods in the CSample class.

InternalGetInputStreamInfo

The DMO can process any number of bytes, aligned on any boundary, so this method returns zero flags.

InternalGetOutputStreamInfo

The first output stream produces whole fixed-sized samples, one at a time, which is typical for video decoders. The second output stream is optional. The returned flags indicate these attributes.

InternalCheckInputType

The input type must be MPEG-1 Video Payload, with a format type of FORMAT_MPEGVideo. After the input type is set, the method rejects format changes.

InternalCheckOutputType

This method validates output formats. There are two output streams:

  • Stream 0. The only media type supported by this stream is RGB-565. A real video decoder would typically support a range of formats. Also, the frame size of the output must match the frame size of the input—which is generally the case for real video decoders. This stream cannot be set unless the input type is set.
  • Stream 1. The media type must be MEDIATYPE_Text.

After the types are set, the method fails unless the new type matches the current type. If a DMO cannot handle format changes while streaming, it should include similar code. In fact, the sample DMO could easily accept format changes, because it generates output one frame at a time.

InternalGetInputType

This method returns no types. Therefore, any index value is out of range, and the return value is DMO_E_NO_MORE_ITEMS. For more information, see IMediaObject::GetInputType.

InternalGetOutputType

If the input type is not set, this method returns no types. Otherwise, it returns one type for each stream. For stream 0, it returns RGB-565 with a frame size equal to the input size. For stream 1, it returns MEDIATYPE_Text.

InternalGetInputSizeInfo

The minimum buffer size for the input stream is one byte, with no alignment requirements. The stream does not perform lookahead.

InternalGetOutputSizeInfo

For stream 0, the buffers must be large enough to hold an output sample. For stream 1, the buffers must be large enough to hold a text string with a time stamp.

InternalFlush

This method releases the input buffer by setting m_pBuffer (an ATL smart pointer) to NULL. It also calls the InternalDiscontinuity method, which resets the CStreamState object.

InternalProcessInput

This method processes as much input data as possible. It performs the following steps:

  • Calls the IMediaBuffer::GetBufferAndLength method to retrieve a pointer to the input data and the size of the input.
  • Holds a reference count on the input buffer. The m_pBuffer variable is an ATL smart pointer, so assigning to the variable has the effect of calling the IUnknown::AddRef method
  • .
  • Passes the time stamp to the CStreamState object. If the sample does not have a time stamp, the method uses the value INVALID_TIME.
  • Calls the Process helper method to process the data.

InternalProcessOutput

If there is no data to output, this method returns S_FALSE. Otherwise, it generates output data. For stream 0, it performs the following steps:

  • Checks whether the output buffer is large enough to hold the output data. If not, the method returns an error.
  • Calls the OurFillRect method to draw the background, and the DrawOurText method to draw the text.
  • Sets the time stamp. If there is a valid time stamp for this frame, it is used. Otherwise, the previous time stamp is incremented by the average frame rate.
  • Calls the Process method again to process any data that might remain in the input buffer. If this results in more output data, the DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag is set.

Stream 1 is optional, so the caller might not allocate a buffer for that stream. Assuming that stream 1 does have an output buffer, however, the DMO writes the time code as a text string. The time stamps and processing flags are taken from stream 0.

InternalAcceptingInput

If the DMO is still holding a reference count on the previous input buffer, it does not accept any more input.

Process

This private method steps through the input data one byte at a time, updating the CStreamState object. If the CStreamState object finds a picture boundary before the input data is exhausted, the Process method returns S_OK. Otherwise, it returns S_FALSE.