Building Graphs with the Capture Graph Builder (Windows Embedded CE 6.0)

1/6/2010

Despite its name, the Capture Graph Builder object is useful for building many kinds of custom filter graphs, not only capture graphs.

The Capture Graph Builder exposes the ICaptureGraphBuilder2 Interface. Start by calling CoCreateInstance to create the Capture Graph Builder and the Filter Graph Manager. Then initialize the Capture Graph Builder object by calling ICaptureGraphBuilder2::SetFiltergraph with a pointer to the Filter Graph Manager, as shown in the following code:

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

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

if (SUCCEEDED(hr))
{
    // Create the Capture Graph Builder.
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
        CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
        (void **)&pBuilder);
    if (SUCCEEDED(hr))
    {
        pBuilder->SetFiltergraph(pGraph);
    }
};

Connecting Filters

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 of ICaptureGraphBuilder2::RenderStream and focusing on the last three parameters. The third parameter is an IUnknown pointer, which can specify either a filter (as an IBaseFilter Interface pointer) or an output pin (as an IPin Interface pointer). The fourth and fifth parameters specify IBaseFilter pointers. The ICaptureGraphBuilder2::RenderStream method connects all three filters in a chain. For example, suppose that A, B, and C are filters. Assume for now that each filter has exactly one input pin and one output pin. The following call connects A to B, and then B to C:

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

All connections are "intelligent," meaning that additional filters are added to the graph as needed. For more information, see Graph Building with Intelligent Connect. To connect just two filters, set the middle value to NULL. For example, this call connects A to C:

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

You can create longer chains by calling the method twice:

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

If the last parameter is NULL, the method automatically locates a default renderer. It uses the DirectShow Video Renderer Filter for video and the Audio Renderer (WaveOut) Filter for audio. Thus:

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

is equivalent to

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

where R is the appropriate renderer.

If you specify a filter in the third parameter, rather than a pin, you may need to indicate which output pin should be used for the connection. That is the purpose of the method's first two parameters. The first parameter applies only to capture filters. It specifies a GUID that indicates a pin category. For a complete list of categories, see Pin Property Set. Two of the categories are valid for all capture filters:

  • PIN_CATEGORY_CAPTURE
  • PIN_CATEGORY_PREVIEW

If a capture filter does not supply separate pins for capture and preview, the ICaptureGraphBuilder2::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 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; but if the graph is connected properly, it drops preview frames as needed 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 to ICaptureGraphBuilder2::RenderFile identifies the media type, and is typically one of the following:

  • MEDIATYPE_Audio
  • MEDIATYPE_Video
  • MEDIATYPE_Interleaved (DV)

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. 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.

Finding Interfaces on Filters and Pins

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 in Windows Embedded CE 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.

The following example searches for the IAMStreamConfig Interface on a video preview pin:

IAMStreamConfig *pConfig = NULL;
HRESULT hr = pBuild->FindInterface(
    &PIN_CATEGORY_PREVIEW,
    &MEDIATYPE_Video,
    pVCap,
    IID_IAMStreamConfig,
    (void**)&pConfig
);
if (SUCCESSFUL(hr))
{
    /* ... */
    pConfig->Release();
}

Finding Pins

Less frequently, you may need to locate an individual pin on a filter, although in most cases the ICaptureGraphBuilder2::RenderStream and ICaptureGraphBuilder2::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.

For example, the following code searches for an unconnected video preview pin on a capture filter:

IPin *pPin = NULL;
hr = pBuild->FindPin(
    pCap,                   // Pointer to the filter to search.
    PINDIR_OUTPUT,          // Search for an output pin.
    &PIN_CATEGORY_PREVIEW,  // Search for a preview pin.
    &MEDIATYPE_Video,       // Search for a video pin.
    TRUE,                   // The pin must be unconnected. 
    0,                      // Return the first matching pin (index 0).
    &pPin);                 // This variable receives the IPin pointer.
if (SUCCESSFUL(hr))
{
    /* ... */
    pPin->Release();
}

See Also

Concepts

Video Capture