Microsoft DirectX 8.1 (C++)

Building Custom Graphs Using ICaptureGraphBuilder2

Despite its name, the ICaptureGraphBuilder2 interface is useful for building many kinds of custom filter graphs. This article provides a brief overview of how to use this interface.

Creating the Capture Graph Builder

The ICaptureGraphBuilder2 interface is exposed by the Capture Graph Builder object. Call CoCreateInstance to create both the Capture Graph Builder and the Filter Graph Manager. Then call the ICaptureGraphBuilder2::SetFiltergraph method to give the Capture Graph Builder a pointer to the Filter Graph Manager:

IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuilder = NULL;

// Create the Filter Graph Manager.
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
    IID_IGraphBuilder, (void **)&pGraph);

// Create the Capture Graph Builder.
CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, 
    IID_ICaptureGraphBuilder2, (void **)&pBuilder);

pBuilder->SetFiltergraph(pGraph);

Using the RenderStream Method

The ICaptureGraphBuilder2::RenderStream method connects two or three filters together in a chain. Generally, the method works best when each filter has no more than one input pin or output pin of the same type. This discussion begins by ignoring the first two parameters to RenderStream and focusing on the last three parameters. Suppose that A, B, and C are filters, and each filter has one input pin and one output pin. The following call:

RenderStream(NULL, NULL, A, B, C)

connects A to B, and then B to C. The following call:

RenderStream(NULL, NULL, A, NULL, C)

connects A to C. If the last parameter is NULL, the method automatically locates a default renderer. It uses the Video Renderer for video and the DirectSound Renderer for audio. Thus:

RenderStream(NULL, NULL, A, NULL, NULL)

is equivalent to

RenderStream(NULL, NULL, A, NULL, R)

where R is the appropriate renderer. To connect the Video Mixing Renderer filter instead of the Video Renderer, however, you must specify it explicitly.

You can create longer chains by calling the method twice:

RenderStream(NULL, NULL, A, B, C)

RenderStream(NULL, NULL, C, D, E)

All connections are "intelligent," meaning that additional filters are added to the graph as needed. For details, see Intelligent Connect.

The third parameter is an IUnknown pointer; this parameter can specify either a filter (IBaseFilter) or an output pin (IPin). The fourth and fifth parameters specify IBaseFilter pointers. If you specify a filter in the third parameter, you may need to indicate which output pin the method should use for the connection. That is the purpose of the method's first two parameters, as follows:

The first parameter, which applies only to capture filters, is a GUID that indicates a pin category. Two categories are valid for all capture filters:

If a capture filter does not supply separate pins for capture and preview, the RenderStream method inserts a Smart Tee filter, which splits the stream into a capture stream and a preview stream. From the application's standpoint, you can simply treat all capture filters as having separate pins, and ignore the underlying topology of the graph. (For more details about the Smart Tee filter, see Step 4. Render the Streams in Building a Capture Graph.)

For file capture, connect the capture pin to a mux filter. For live preview, connect the preview pin to a renderer. If you switch the two categories, the graph might drop an excessive number of frames during the file capture; if the graph is connected properly, it drops preview frames as needed in order to maintain throughput on the capture stream.

The following example shows how to connect both streams:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, NULL, pCapFilter, NULL, pMux);
// Preview:
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, NULL, pCapFilter, NULL, NULL);

Some capture filters also support closed captions, indicated by PIN_CATEGORY_VBI. To capture the closed captions to a file, render this category to the mux filter. To view the closed captions in your preview window, connect to the renderer:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, pMux);
// Preview on screen:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, NULL);

The second parameter identifies the media type, typically one of the following:

You can use this parameter whenever the filter's output pins support the enumeration of preferred media types. For file sources, the Capture Graph Builder automatically adds a parser filter if needed, and then queries the media types on the parser. (See Recompressing an AVI File for an example.) Also, if the last filter in the chain has several input pins, the method attempts to enumerate their media types. However, not all filters support this functionality.

Using the FindInterface Method

After you build a graph, you will typically need to locate various interfaces exposed by filters and pins in the graph. For example, a capture filter might expose the IAMDroppedFrames interface, while the filter's output pins might expose the IAMStreamConfig interface.

The simplest way to find an interface is to use the ICaptureGraphBuilder2::FindInterface method. This method walks the graph (filters and pins) until it locates the desired interface. You can specify the starting point for the search, and you can limit the search to filters upstream or downstream from the starting point.

Using the FindPin method

Less commonly, you may need to locate an individual pin on a filter, although in most cases the RenderStream and FindInterface methods will save you the trouble. If you do need to find a particular pin on a filter, the ICaptureGraphBuilder2::FindPin helper method is useful. Specify the category, the media type (video or audio), the direction, and whether the pin must be unconnected.

See Also