Microsoft DirectX 8.0

Dynamic Graph Building

If you need to modify an existing filter graph, you can stop the graph, make the changes, and restart the graph. This is usually the best approach. However, under some circumstances, you might want to alter a graph while it is still running. For example:

These are all examples of dynamic graph building, a term that covers any kind of change to a filter graph while the graph continues to run. Dynamic graph building can be initiated by an application or by a filter in the graph. Three distinct scenarios are possible:

This article contains the following sections:

Dynamic Format Change

If a filter switches output formats, it may be possible for the downstream filter to accept the new format without reconnecting any pins, stopping the graph, or replacing any filters. To determine whether the pin can accept the new media type while the graph is running, the filter (or an application) calls IPinConnection::DynamicQueryAccept on the input pin connected to the filter's output pin. This method differs from the IPin::QueryAccept method, because QueryAccept does not guarantee that the pin will accept a media type once the filter starts running.

If the new format cannot be accepted with the current connection, the next solution is a dynamic reconnection, described in the following section.

Dynamic Reconnection

Dynamic reconnection is a change to the topology of the graph. In order not to lose data, an application or filter that initiates dynamic reconnection must be careful about the sequence of events. The section of the graph being reconfigured must not have any media data flowing through it. For example, suppose that an application dynamically replaces Filter 2 in the following filter graph.

Dynamic Graph Building Diagram

To safely remove this filter and reconnect the graph, the application must perform the following steps:

  1. Block the data flow on Pin A.
  2. Push pending data through the filter graph, from Pin B to Pin D.
  3. Reconfigure the graph by removing Filter 2 and inserting a new filter.
  4. Unblock pin A so that data starts flowing again.

Three interfaces support these operations:

The following sections describe the process in greater detail:

Blocking the Data Flow

To block the data flow, call IPinFlowControl::Block on the upstream output pin (pin A). You can call this method either asynchronously or synchronously:

After the graph is reconfigured, unblock the data flow by calling IPinFlowControl::Block with a value of zero for the first parameter.

If an upstream filter initiates the reconnection, it might be able to control the data flow internally, rather than by calling IPinFlowControl::Block.

Pushing Data Through the Graph

By default, the filter graph manager automatically pushes data through the graph when you call the IGraphConfig::Reconnect method, which is described in the next section. However, if you do not use this method—for example, if you use the IGraphConfig::Reconfigure method—you must handle this operation yourself. In any case, it is useful to understand the process.

To push the data through the graph, perform the following steps:

  1. Call IPinConnection::NotifyEndOfStream on the downstream input pin (pin D). This method requests notification from the pin when the next end-of-stream condition occurs. The pin will notify the caller by signaling an event.
  2. Call IPin::EndOfStream on the input pin immediately connected to the upstream output pin (pin B). As the remaining data travels downstream through any intermediate filters, those filters propagate the end-of-stream notification. In this example, the only intermediate filter is Filter 2.
  3. Wait for the event. When the downstream input pin (pin D) receives the end-of-stream notification, it signals the event. At this point, there is no more pending data and it is safe for the caller to reconfigure the graph.

Reconfiguring the Graph

To reconfigure the graph, call the IGraphConfig::Reconnect method. This method performs the following actions:

If the IGraphConfig::Reconnect method is not suitable for some reason, you can reconfigure the graph in a callback method. Implement the IGraphConfigCallback interface, and then call the IGraphConfig::Reconfigure method, which calls your callback method. In that case, you are responsible for pushing the data through the filter graph. Call the IGraphConfig::PushThroughData method.

Example Code

The following example shows an outline of how an application might insert an effect filter, pointed to by the variable pFX, between a source filter and a renderer filter. Other scenarios are possible, and the IGraphConfig::Reconnect method takes several parameters that control its behavior. See the IGraphConfig reference for more information.

// Assume the graph is running.
    IGraphConfig *pConfig;
    pGraph->QueryInterface(IID_IGraphConfig, (void **)&pConfig);

    // Block the data flow.
    IPinFlowControl *pFlowControl;
    pOutPin->QueryInterface(IID_IPinFlowControl, (void **)&pFlowControl);
    pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, NULL); 

    // Reconfigure the graph.
    pGraph->AddFilter(pFX, L"Effect Filter");
    pConfig->Reconnect(
            pOutPin,    // Start from this output pin.
            NULL,       // Search downstream for a suitable input pin.
            NULL,       // First connection is unspecified.
            pFX,        // Use this filter.
            NULL, 
            0);     

    pFlowControl->Block(0, NULL);   // Unblock the data flow.

Note  pOutPin is assumed to be a pointer to an output pin on the source filter. For information on retrieving pointers to pins on a filter, see Enumerating Pins.

If dynamic reconnection is performed by a filter, rather than an application, there are potential threading issues. Specifically, if another process tries to stop the filter, it can deadlock while the graph waits for the filter to stop, and the filter waits for data to be pushed through the graph. To prevent this situation, some methods described previously take a handle to an event, which the filter should signal if it receives a call to its IMediaFilter::Stop method. For more information, see IGraphConfig and IPinConnection.

Filter Chains

A filter chain is a sequence of filters that meets the following conditions:

For example, in the following diagram, filters A–B, C–D, and F–G–H are filter chains. Each subchain in F–G–H (F–G and G–H) is also a filter chain. A filter chain can consist of a single filter, so filters A, B, C, D, F, G, and H are also distinct filter chains. Filter E has two input connections, so any sequence of filters that includes filter E is not a filter chain.

Filter Chain (Example 1)

The IFilterChain interface provides the following methods for controlling filter chains:

IFilterChain::StartChainStarts a chain.
IFilterChain::StopChainStops a chain.
IFilterChain::PauseChainPauses a chain.
IFilterChain::RemoveChainRemoves a chain from the graph.

There is no specific method for adding a chain. To add a chain, insert the new filters using the IFilterGraph::AddFilter method. Then connect the filters by calling IGraphBuilder::Connect, IGraphBuilder::Render, or similar methods.

When the graph is running, a filter chain can switch between running and stopped. When the graph is paused, it can switch between paused and stopped. These are the only state transitions possible with filter chains.

Filter Chain Guidelines

When you use IFilterChain methods, it is important to make sure that the filters in the graph can support filter chaining operations. Otherwise, you might cause deadlocks or graph errors. Filters connected to the chain must function correctly after the chain changes state.

The best way to use IFilterChain is with a set of filters that you have designed specifically for chaining. Use the following guidelines to ensure that your filters are safe for filter chain operations. These points refer to the following diagram:

Filter Chain (Example 2)