Microsoft DirectX 8.1 (C++)

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.

Asynchronously: Call the CreateEvent function to create an event object and pass the event handle to the Block method. The method returns immediately, and the pin signals the event when the operation has completed. Call a wait function such as WaitForSingleObject to wait for the event, as shown in the following code:

HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent); 
WaitForSingleObject(hEvent, dwMilliseconds);

Synchronously: Pass NULL instead of an event handle. The method does not return until the operation completes. This might not happen until the pin is ready to deliver a sample; and if the filter is paused, the method might block indefinitely. Therefore, do not call Block synchronously from your main application thread.

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.