動的再接続
多くの DirectShow フィルタでは、グラフがアクティブにデータをストリーミングしている間はピンを再接続できない。アプリケーションは、ピンを再接続する前にグラフを停止する必要がある。ただし、一部のフィルタでは、グラフの実行中のピンの再接続をサポートしている。この処理を "動的再接続" と呼ぶ。この処理は、アプリケーションまたはグラフ内のフィルタによって実行される。
例として、次のようなグラフを考えてみる。
動的再接続のシナリオの 1 つとして、グラフの実行中に、グラフからフィルタ 2 を削除し、別のフィルタに置換する場合がある。このシナリオが機能するには、次の条件を満たす必要がある。
- フィルタ 3 の入力ピン (ピン D) が IPinConnection インターフェイスをサポートしている必要がある。このインターフェイスは、フィルタを停止せずにピンを再接続できるようにする。
- フィルタ 1 の出力ピン (ピン A) は、再接続が行われているときに、メディア データのフローをブロックできる必要がある。再接続中は、ピン A とピン D の間でデータを受け渡しできない。一般的に、このことは出力ピンが IPinFlowControl インターフェイスをサポートしている必要があることを意味する。ただし、フィルタ 1 が再接続を開始するフィルタである場合、それ自体のデータ フローをブロックする何らかの内部的なメカニズムを持っていることもある。
動的再接続は、次のような手順で行われる。
- ピン A からのデータ ストリームをブロックする。
- 通常、新しい中間フィルタを介して、ピン A とピン D を再接続する。
- フローが再開するように、ピン A のブロックを解除する。
手順 1. データ ストリームのブロック
データ ストリームをブロックするために、ピン A で IPinFlowControl::Block を呼び出す。このメソッドは、非同期的にも、同期的にも呼び出すことができる。このメソッドを "非同期的" に呼び出すには、Win32 イベント オブジェクトを作成し、イベント ハンドルを Block メソッドに渡す。このメソッドは直ちに戻る。WaitForSingleObject のような関数を使って、イベントが通知済みになるまで待機する。ピンは、データ フローをブロックすると、イベントを送信する。以下に例を示す。
// イベントを作成する
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent != NULL)
{
// データ フローをブロックする。
hr = pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent);
if (SUCCEEDED(hr))
{
// ピンが完了するまで待機する。
DWORD dwRes = WaitForSingleObject(hEvent, dwMilliseconds);
}
}
このメソッドを "同期的" に呼び出すには、イベント ハンドルの代わりに NULL 値を渡すだけでよい。これで、メソッドは処理が完了するまでブロックする。ピンが新しいサンプルを出力する用意ができるまで、この処理は行われない可能性がある。フィルタがポーズ状態である場合、任意の長さの時間がかかる可能性がある。そのため、アプリケーションのメイン スレッドから、同期的に呼び出してはならない。ワーカー スレッドを使うか、このメソッドを非同期的に呼び出すこと。
手順 2. ピンの再接続
ピンを再接続するために、フィルタ グラフ マネージャは IGraphConfig インターフェイスを照会し、IGraphConfig::Reconnect または IGraphConfig::Reconfigure のいずれかを呼び出す。Reconnect メソッドの使い方は単純である。このメソッドは次の処理を行う。
- 中間フィルタ (例ではフィルタ 2) を停止し、グラフからそのフィルタを削除する。
- 必要に応じて、新しい中間フィルタを追加する。
- すべてのピンを接続する。
- グラフの状態に合わせて、新しいフィルタをポーズまたは実行する。
Reconnect メソッドには、ピン接続のメディア タイプおよび使用する中間フィルタを指定するために使えるオプションのパラメータがいくつかある。以下に例を示す。
pGraph->AddFilter(pNewFilter, L"New Filter for the Graph");
pConfig->Reconnect(
pPinA, // この出力ピンを...
pPinD, // ... この入力ピンに再接続する。
pMediaType, // このメディア タイプを使用する。
pNewFilter, // このフィルタを介して接続する。
NULL,
0);
詳細については、リファレンス ページを参照すること。Reconnect メソッドの柔軟性が十分ではない場合は、Reconfigure メソッドを使える。このメソッドは、アプリケーション定義のコールバック メソッドを使ってピンを再接続する。このメソッドを使うには、アプリケーションで IGraphConfigCallback インターフェイスを実装する。
Reconfigure を呼び出す前に、前に説明したように、出力ピンからのデータ フローをブロックする。次に、再接続しているグラフのセクションでペンディング状態になっているデータを、次のようにプッシュする。
- 再接続チェーンの最もダウンストリームの入力ピン (例ではピン D) で IPinConnection::NotifyEndOfStream を呼び出す。ハンドルを Win32 イベントに渡す。
- データ フローをブロックした出力ピンのすぐ次にあるダウンストリームの入力ピンで IPin::EndOfStream を呼び出す。この例では、データ フローはピン A でブロックされているので、ピン B で EndOfStream を呼び出す。
- イベントが通知済み状態になるのを待つ。入力ピン (ピン D) は、エンドオブストリーム通知を受信すると、イベントを送信する。これは、ピン間でデータの受け渡しがないこと、および呼び出し側が安全にピンを再接続できることを示す。
IGraphConfig::Reconnect メソッドは自動的に前の手順を処理する。これらの手順を手動で実行する必要があるのは、Reconfigure メソッドを使う場合だけである。
グラフ内でデータがプッシュされた後、Reconfigure を呼び出して、IGraphConfigCallback コールバック インターフェイスへのポインタを渡す。フィルタ グラフ マネージャは、指定された IGraphConfigCallback::Reconfigure メソッドを呼び出す。
手順 3. データ フローのブロック解除
ピンを再接続したら、最初のパラメータに 0 を渡して IPinFlowControl::Block を呼び出し、データ フローのブロックを解除する。
注 フィルタが動的再接続を行う場合、いくつかのスレッドの問題に注意しなければならない。フィルタ グラフ マネージャがフィルタを停止しようとした場合、グラフはフィルタが停止するのを待ち、同時にフィルタはデータがグラフにプッシュされるのを待つので、デッドロックが発生することがある。このようなデッドロックを回避するために、ここで説明したメソッドのいくつかは Win32 イベントへのハンドルを使う。フィルタは、フィルタ グラフ マネージャがフィルタを停止しようとすると、イベントを送信する。詳細については、「IGraphConfig インターフェイス」および「IPinConnection インターフェイス」を参照すること。