フィルターの状態

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]

フィルターには、停止、一時停止、実行中の 3 つの状態があります。 一時停止状態の目的は、グラフ内のデータをキューに入れ、実行コマンドがすぐに応答するようにすることです。 フィルター グラフ マネージャーは、すべての状態遷移を制御します。 アプリケーションが IMediaControl::RunIMediaControl::P ause、または IMediaControl::Stop を呼び出すと、Filter Graph Manager はすべてのフィルターで対応する IMediaFilter メソッドを呼び出します。 停止状態と実行中の間の遷移は常に一時停止状態になるため、アプリケーションが停止したグラフで Run を 呼び出すと、フィルター グラフ マネージャーはグラフを実行する前に一時停止します。

ほとんどのフィルターでは、実行中の状態と一時停止中の状態は同じです。 次のフィルター グラフを考えてみましょう。

ソース > 変換 > レンダラー

ここでは、ソース フィルターがライブ キャプチャ ソースではないことを前提としています。 ソース フィルターは、一時停止すると、新しいデータを生成し、できるだけ早くメディア サンプルに書き込むスレッドを作成します。 スレッドは、変換フィルターの入力ピンで IMemInputPin::Receive を呼び出して、サンプルをダウンストリームに "プッシュ" します。 変換フィルターは、ソース フィルターのスレッドでサンプルを受け取ります。 ワーカー スレッドを使用してサンプルをレンダラーに配信することもできますが、通常は同じスレッドでサンプルを配信します。 レンダラーが一時停止している間は、サンプルの受信を待機します。 1 つを受け取った後、そのサンプルを無期限にブロックして保持します。 ビデオ レンダラーの場合は、サンプルをポスター 画像として表示し、必要に応じてイメージを再描画します。

この時点で、ストリームは完全にキューに入り、レンダリングの準備が整います。 グラフが一時停止したままの場合、すべてのフィルターが Receive または IMemAllocator::GetBuffer でブロックされるまで、最初のサンプルの背後にあるグラフにサンプルが "重ねられます"。 ただし、データは失われません。 ソース スレッドのブロックが解除されると、ブロックされた時点から再開されます。

ソース フィルターと変換フィルターは、一時停止から実行中への切り替えを無視します。これらは、データの処理を可能な限り速く続行するだけです。 ただし、レンダラーを実行すると、サンプルのレンダリングが開始されます。 最初に、一時停止中に保持したサンプルをレンダリングします。 次に、新しいサンプルを受け取るたびに、サンプルのプレゼンテーション時間を計算します。 (詳細については、「 DirectShow の時刻と時計」を参照してください)。レンダラーは、プレゼンテーション時まで各サンプルを保持し、その時点でサンプルをレンダリングします。 プレゼンテーション時間を待機している間は、 Receive メソッドをブロックするか、キューを持つワーカー スレッドで新しいサンプルを受信します。 レンダラーの上流にあるフィルターは、スケジュールには関係ありません。

キャプチャ デバイスなどのライブ ソースは、この一般的なアーキテクチャの例外です。 ライブ ソースでは、事前にデータをキューに入れた方が適切ではありません。 アプリケーションでグラフが一時停止され、実行されるまで長時間待つ場合があります。 グラフでは、"古い" サンプルをレンダリングしないでください。 そのため、ライブ ソースでは、実行中にのみ、一時停止中にサンプルは生成されません。 この事実をフィルター グラフ マネージャーに通知するために、ソース フィルターの IMediaFilter::GetState メソッドはVFW_S_CANT_CUEを返します。 このリターン コードは、レンダラーがデータを受信しなかった場合でも、フィルターが一時停止状態に切り替わったことを示します。

フィルターが停止すると、それ以上配信されたサンプルは拒否されます。 ソース フィルターはストリーミング スレッドをシャットダウンし、他のフィルターは作成したワーカー スレッドをすべてシャットダウンします。 ピンでアロケーターのコミットを解除します。

状態遷移

フィルター グラフ マネージャーは、レンダラーから開始し、ソース フィルターに戻って作業を開始し、アップストリームの順序ですべての状態遷移を実行します。 この順序は、サンプルが削除されないようにし、グラフのデッドロックを防ぐために必要です。 最も重要な状態遷移は、一時停止と停止の間です。

  • 一時停止に停止: 各フィルターが一時停止すると、次のフィルターからサンプルを受け取る準備が整います。 ソース フィルターは、最後に一時停止します。 ストリーミング スレッドを作成し、サンプルの配信を開始します。 すべてのダウンストリーム フィルターが一時停止されるため、どのフィルターもサンプルを拒否しません。 フィルター グラフ マネージャーは、グラフ内のすべてのレンダラーがサンプルを受け取るまで遷移を完了しません (前に説明したように、ライブ ソースを除く)。
  • 停止に一時停止: フィルターが停止すると、保持しているサンプルが解放され、 GetBuffer で待機しているアップストリーム フィルターのブロックが解除されます。 フィルターは、 Receive メソッド内のリソースを待機している場合、待機を停止し、呼び出し元のフィルターのブロックを解除する Receive からを返します。 そのため、フィルター グラフ マネージャーが次のアップストリーム フィルターを停止すると、そのフィルターは GetBuffer または Receive でブロックされず、停止コマンドに応答できます。 アップストリーム フィルターでは、stop コマンドを取得する前にいくつかの追加のサンプルが提供される場合がありますが、ダウンストリーム フィルターは既に停止しているため、単にそれらを拒否します。

フィルター グラフのData Flow