Share via


Selecting a Decoder in DirectShow Editing Services

 
Microsoft DirectShow 9.0

Selecting a Decoder in DirectShow Editing Services

When DirectShow Editing Services (DES) renders a video editing project, the Rendering Engine automatically selects the necessary decoders. This may happen inside the IRenderEngine::ConnectFrontEnd method, or else dynamically during rendering.

A user might install several decoders that are capable of decoding a particular file. This is particularly true for MPEG-2 content, because DirectShow does not provide an MPEG-2 decoder, so users often install third-party decoders. When multiple decoders are available, DES uses the Intelligent Connect algorithm to select the decoder.

There is no way for the application to specify directly which decoder to use. However, you can choose the decoder indirectly through the IAMGraphBuilderCallback callback interface. By implementing this interface in your application, you can receive notifications during the graph-building process and reject certain filters from the graph.

Start by implementing a class that exposes the IAMGraphBuilderCallback interface:

class GraphBuilderCB : public IAMGraphBuilderCallback
{
public:
     // Method declarations (not shown).
};

Then create an instance of the Filter Graph Manager and register your class to receive callback notifications:

// Declare an instance of the callback object.
GraphBuilderCB GraphCB; 

// Create the Filter Graph Manager.
CComPtr<IGraphBuilder> pGraph;
hr = pGraph.CoCreateInstance(CLSID_FilterGraph);
if (FAILED(hr))
{
    // Handle error (not shown).
}
// Register to receive the callbacks.
CComQIPtr<IObjectWithSite> pSite(pGraph);
if (pSite)
{
    hr = pSite->SetSite((IUnknown*)&GraphCB);
}

Next, create the Render Engine and call the IRenderEngine::SetFilterGraph method with a pointer to the Filter Graph Manager. This ensures that the Render Engine does not create its own Filter Graph Manager, but instead uses the instance that you have configured for callbacks.

CComPtr<IRenderEngine> pRender;
hr = pRender.CoCreateInstance(CLSID_RenderEngine);
if (FAILED(hr))
{
    // Handle error (not shown).
}

hr = pRender->SetFilterGraph(pGraph);

When the project is rendered, the application's IAMGraphBuilderCallback::SelectedFilter method is called immediately before the Filter Graph Manager creates a new filter. The SelectedFilter method receives a pointer to an IMoniker interface that represents a moniker for the filter. Examine the moniker, and if you decide to reject the filter, return a failure code from the SelectedFilter method.

The difficult part is to identify which monikers represent decoders — and in particular, which monikers represent decoders that you want to reject. One solution is the following:

  • Before rendering the project, use the IFilterMapper2::EnumMatchingFilters method to create a list of filters that are registered as accepting the desired input type. For video or audio compression types, this list should map to a set of decoders. 

  • The EnumMatchingFilters method returns a collection of monikers. For each moniker in the collection, get the DisplayName property, as described in Using the Filter Mapper.

  • Store a list of the display names, but omit the display name that matches the filter you want to use for decoding. Display names for software filters have the following form:

    OLESTR("@device:sw:{CategoryGUID}{FilterCLSID}");
    

    where CategoryGUID is the GUID of the filter category, and FilterCLSID is the filter's CLSID. For DMOs, the format is the same, but change sw to dmo.

    The list now contains display names for every filter that outputs the desired media type but is not your preferred filter.

  • In the SelectedFilter method, get the DisplayName property on the proposed moniker and check it against the stored list. If the display name matches an entry in the list, reject that filter. Otherwise, accept it by returning S_OK.