Microsoft DirectX 8.0 |
既存のフィルタ グラフを変更する必要がある場合は、グラフを停止し、変更を加えてから、グラフを再起動することができる。普通はこれが最良の方法だが、以下のような状況では、実行中にグラフを変更したい場合もある。
これらはすべて"動的グラフ作成"の例である。動的グラフ作成とは、実行中にフィルタ グラフに加えられるさまざまな変更をすべて含む用語である。動的グラフ作成は、アプリケーションまたはグラフ内のフィルタによって開始される。以下の 3 種類のシナリオが考えられる。
このトピックは、以下のセクションで構成される。
フィルタが出力フォーマットを切り換える場合、ピンを再接続したり、グラフをポーズまたは停止したり、フィルタを置換したりしなくても、ダウンストリーム フィルタが新しいフォーマットを受け入れられることもある。グラフの実行中に、ピンが新しいメディア タイプを受け入れられるかどうかを判定するために、フィルタ (またはアプリケーション) は、フィルタの出力ピンに接続された入力ピンの IPinConnection::DynamicQueryAccept を呼び出す。このメソッドは、IPin::QueryAccept メソッドとは異なる。QueryAccept は、フィルタが実行を開始していると、ピンがメディア タイプを受け入れることを保証しない。
現在の接続で新しいフォーマットが受け入れられない場合、次に考えられる解決方法は、以下のセクションで説明する動的再接続である。
動的再接続とは、グラフのトポロジを変更することである。データを失わないために、動的再接続を開始するアプリケーションまたはフィルタは、イベントのシーケンスに注意しなければならない。再設定されるグラフのセクションには、メディア データが流れていてはならない。例として、次の図のフィルタ グラフのフィルタ 2 をアプリケーションが動的に置換する場合を考えてみよう。
このフィルタを安全に削除してグラフを再接続するために、アプリケーションは以下の操作を行わなければならない。
3 つのインターフェイスが、これらの操作をサポートしている。
以下のセクションで、処理内容を詳しく説明する。
データ フローをブロックするには、アップストリームの出力ピン (ピン A) の IPinFlowControl::Block を呼び出す。このメソッドは、非同期または同期させて呼び出すことができる。
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, hEvent); WaitForSingleObject(hEvent, dwMilliseconds);
グラフを再設定したら、最初のパラメータに 0 を渡して IPinFlowControl::Block を呼び出し、データ フローのブロックを解除する。
アップストリーム フィルタで再接続を開始する場合は、IPinFlowControl::Block を呼び出さなくても、データ フローを内部で制御できることがある。
デフォルトでは、次のセクションで説明する IGraphConfig::Reconnect メソッドを呼び出すと、フィルタ グラフ マネージャがデータを自動的にグラフに送り出す。しかし、このメソッドを使わずに IGraphConfig::Reconfigure メソッドを使う場合などは、この処理を自分で扱わなければならない。いずれの場合も、この処理を理解しておけば役に立つ。
データをグラフに送り出すには、以下の操作を行う。
グラフを再設定するには、IGraphConfig::Reconnect メソッドを呼び出す。このメソッドは以下の処理を行う。
何らかの理由で IGraphConfig::Reconnect メソッドが適当でない場合は、コールバック メソッドでグラフを再設定することができる。IGraphConfigCallback インターフェイスを実装し、IGraphConfig::Reconfigure メソッドを呼び出す。これがコールバック メソッドを呼び出す。この場合は、データを自分でフィルタ グラフに送り出す必要がある。IGraphConfig::PushThroughData メソッドを呼び出す。
以下の例に、ソース フィルタとレンダリング フィルタの間に変数 pFX が指すエフェクト フィルタを挿入する方法を示す。ほかのシナリオも考えられるので、IGraphConfig::Reconnect メソッドは動作を制御するパラメータをいくつか受け取る。詳細については、IGraphConfig のリファレンスを参照すること。
// グラフが実行中と仮定する。 IGraphConfig *pConfig; pGraph->QueryInterface(IID_IGraphConfig, (void **)&pConfig); // データ フローをブロックする。 IPinFlowControl *pFlowControl; pOutPin->QueryInterface(IID_IPinFlowControl, (void **)&pFlowControl); pFlowControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, NULL); // グラフを再設定する。 pGraph->AddFilter(pFX, L"Effect Filter"); pConfig->Reconnect( pOutPin, // この出力ピンから開始する。 NULL, // ダウンストリーム側から適当な入力ピンを捜す。 NULL, // 最初の接続は指定しない。 pFX, // このフィルタを使用する。 NULL, 0); pFlowControl->Block(0, NULL); // データ フローのブロックを解除する。
注 : pOutPin は、ソース フィルタの出力ピンへのポインタであると仮定されている。フィルタのピンへのポインタの取得については、「ピンの列挙」を参照すること。
アプリケーションではなくフィルタが動的再接続を行う場合は、スレッドに問題が発生する可能性がある。特に、別のプロセスがフィルタを停止しようとした場合、フィルタが停止するのをグラフが待ち、データがグラフに送り出されるのをフィルタが待っている間にデッドロックが発生することがある。前に説明したいくつかのメソッドでは、これを防ぐためにイベントへのハンドルを受け取る。フィルタは、自分の IMediaFilter::Stop メソッドへの呼び出しを受け取ると、このイベントをシグナル状態にする。詳細については、「IGraphConfig インターフェイス」および「IPinConnection インターフェイス」を参照すること。
"フィルタ チェイン"とは、以下の条件に合致するフィルタの集まりである。
たとえば、次の図のフィルタ A–B、C–D、および F–G–H がフィルタ チェインである。F–G–H 内のサブチェイン (F–G および G–H) もフィルタ チェインである。フィルタ チェインは 1 つのフィルタで構成してもよいので、フィルタ A、B、C、D、F、G、および H も別々のフィルタ チェインである。フィルタ E には入力接続が 2 つあるので、フィルタ E を含むフィルタの集まりはフィルタ チェインではない。
IFilterChain インターフェイスは、フィルタ チェインを制御するために以下のメソッドを提供している。
IFilterChain::StartChain | チェインを開始する。 |
IFilterChain::StopChain | チェインを停止する。 |
IFilterChain::PauseChain | チェインをポーズする。 |
IFilterChain::RemoveChain | チェインをグラフから削除する。 |
チェインを追加するための専用のメソッドはない。チェインを追加するには、IFilterGraph::AddFilter メソッドを使って新しいフィルタを挿入し、IGraphBuilder::Connect、IGraphBuilder::Render、または同様なメソッドを呼び出してそれらのフィルタを接続する。
グラフの実行中、フィルタ チェインは実行と停止の間で切り替わることができる。グラフがポーズしているとき、フィルタ チェインはポーズと停止の間で切り替わることができる。フィルタ チェインで可能な状態の変化はこれだけである。
IFilterChain メソッドを使用するときは、グラフ内のフィルタがフィルタ チェインの操作をサポートしていることを確認しなければならない。サポートしていない場合、デッドロックやグラフ エラーが発生することがある。 チェインに接続されたフィルタは、チェインの状態が変化しても正しく機能しなければならない。
IFilterChain を使用する場合は、チェイン処理専用にデザインしたフィルタを使用するのが最良である。以下のガイドラインを使って、フィルタ チェイン処理の間にフィルタが安全であることを確実にすること。それらのポイントを次の図に示す。
たとえば、上の図のフィルタ B は、フィルタ A からのデータ処理の呼び出しを完了しなければならず、フィルタ E は、フィルタ D からの呼び出しを完了しなければならない。ピンが IPinFlowControl および IPinConnection インターフェイスを公開している場合は、「動的再接続」で説明したように、IPinFlowControl::Block および IGraphConfig::PushThroughData メソッドを呼び出してデータをグラフに送り出すことができる。フィルタが、データを送り出すためのプライベート メソッドをサポートしている場合もある。