Microsoft DirectX 8.0 |
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:
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 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.
To safely remove this filter and reconnect the graph, the application must perform the following steps:
Three interfaces support these operations:
The following sections describe the process in greater detail:
To block the data flow, call IPinFlowControl::Block on the upstream output pin (pin A). You can call this method either asynchronously or synchronously:
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent); WaitForSingleObject(hEvent, dwMilliseconds);
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.
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 methodfor example, if you use the IGraphConfig::Reconfigure methodyou 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:
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.
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.
A filter chain is a sequence of filters that meets the following conditions:
For example, in the following diagram, filters AB, CD, and FGH are filter chains. Each subchain in FGH (FG and GH) 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.
The IFilterChain interface provides the following methods for controlling filter chains:
IFilterChain::StartChain | Starts a chain. |
IFilterChain::StopChain | Stops a chain. |
IFilterChain::PauseChain | Pauses a chain. |
IFilterChain::RemoveChain | Removes 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.
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:
For example, in the previous diagram, filter B must complete any data processing calls from filter A, and filter E must finish any calls from filter D. If the pins expose the IPinFlowControl and IPinConnection interfaces, you can push the data through the graph by calling the IPinFlowControl::Block and IGraphConfig::PushThroughData methods, as described in Dynamic Reconnection. Filters might also support private methods for pushing the data.