Microsoft DirectX 8.0 |
ここでは、Microsoft® DirectShow® フィルタ グラフにおけるデータの流れについて説明する。内容は次のとおりである。
2 つのピンを接続すると、データは出力ピンから入力ピンへ移動する。出力ピンはデータを送信し、入力ピンはデータを受信する。出力から入力へというデータ フローの方向はダウンストリームと呼ばれ、その逆の方向はアップストリームと呼ばれる。
2 つのピンの間を移動するデータのタイプは、ピンの実装によって異なる。最も一般的なケースでは、ピンはメイン メモリに格納されたメディア データを使用して動作する。ただし、これ以外の配置も可能である。たとえば、2 つのフィルタがビデオ ハードウェアを制御する場合は、ハードウェアがすべてのビデオ データを処理し、ピンは制御情報を交換する。データのタイプ、およびピンの間をデータが移動する方法は、転送と呼ばれる。ここでは、メディア データがメイン メモリに格納されているローカル メモリ転送と呼ばれる転送について説明する。
ローカル メモリ転送では、データはメディア サンプルと呼ばれる圧縮された個別のオブジェクトである。メディア サンプルは、割り当てられたメモリ バッファへのポインタを格納する COM オブジェクトである。メディア サンプルは IMediaSample インターフェイスをサポートし、IMediaSample2 インターフェイスをサポートすることも可能である。
バッファの割り当てとメディア サンプルの作成を行うもう 1 つの COM オブジェクトがメモリ アロケータである。接続時、アロケータはバッファのためのメモリを予約する。さらにアロケータはメディア サンプルの集合を作成し、メモリ ブロック内のアドレスへのポインタを各サンプルに渡す。バッファが解放されるまで、アロケータはどのサンプルが使用可能かを示すリストを維持する。フィルタは、新しいサンプルが必要になると、アロケータにサンプルを要求する。サンプルは、処理された後リストに戻される。
このメカニズムではフィルタが同じバッファを再利用するため、メモリ割り当ての量が減る。また、アロケータは使用可能なサンプルのリストを保持しているため、まだ処理の済んでいないデータがフィルタによって誤ってオーバーライドされることを防止できる。さらに、グラフ内のデータ移動を効率よく実行できる。出力ピンは、サンプルを送信するとき、サンプルの IMediaSample インターフェイスへのポインタを渡す。データをコピーする必要はない。
次の図は、アロケータ、メディア サンプル、およびフィルタの関係を示している。
接続された複数のピンが 1 つのメモリ アロケータを共有する。フィルタは入力用と出力用に異なるアロケータを使用できる。これは、デコンプレッサ フィルタのように、データを展開するフィルタで一般的である。出力が入力より大きくない場合は、フィルタはデータを新しいバッファに移動せず、元の場所で処理できる。その場合、2 つ以上のピン接続で 1 つのアロケータを共有できる。
ローカル メモリをサポートする入力ピンは IMemInputPin インターフェイスを公開する。出力ピンは、入力ピンに対して IMemInputPin::Receive メソッドを呼び出すことによって、サンプルを送信する。入力ピンは次のいずれかの処理を実行する。
IMemInputPin::ReceiveCanBlock メソッドは、入力ピンが Receive の呼び出しをブロックするかどうかを判別する。出力ピンはこのメソッドを呼び出し、適切なスレッド処理方法を決定できる。ワーカー スレッドを作成し、ほかの作業を実行しながらバックグラウンドでサンプルを送信できるフィルタもある。あるいは、ダウンストリーム フィルタが次のサンプルを受け取る準備ができるまでブロックするフィルタもある。
また、一度に複数のサンプルを送信する IMemInputPin::ReceiveMultiple というメソッドもある。このメソッドは Receive と同様に動作するが、サンプルの配列を処理する。
フィルタには、停止、ポーズ、および実行中という 3 つの状態がある。ほとんどのフィルタでは、ポーズと実行中は等しい。
レンダリング フィルタは例外である。レンダリング フィルタが停止状態からポーズ状態に移る場合、メディア サンプルを 1 つ受け取った時点で移行が完了する。その時点で、レンダリング フィルタはサンプルを保留し、Receive の呼び出しをブロックする。ビデオ レンダラはサンプルを静止フレームとして描画する。オーディオ レンダラは実行状態になってからサンプルをレンダリングする。オーディオでは "静止フレーム" に相当するものは存在しない。いずれの場合も、レンダラはポーズから実行中に切り替わるまで次のサンプルを受け取らない。
フィルタ グラフ マネージャはフィルタ グラフ全体の状態を制御する。有効な状態移行として、停止とポーズ、およびポーズと実行中の間の移行がある。停止と実行中の間の移行は、ポーズを経由する必要がある。停止状態のグラフに対して IMediaControl::Run、または実行中のグラフに対して IMediaControl::Stop を呼び出すと、フィルタ グラフ マネージャは最初にグラフをポーズする。
フィルタ グラフが停止からポーズに移る場合、次の手順が実行される。
これらのイベントが完了するまでの時間は一定ではない。通常は長くかからないが、圧縮解除を要するソースの場合は特に遅延が顕著なことがある。ただし、グラフはポーズ状態が終了すると、直ちにデータのレンダリングを開始できる。したがって、グラフのポーズにはデータを "挿入" する効果がある。アプリケーションでは、これをあらかじめ実行し、次にユーザーからのコマンドに応じてすばやくグラフを実行中の状態に切り替えることができる。
ライブ キャプチャ フィルタは、ほかのソース フィルタと異なり、ポーズ状態のときにサンプルを送信しない。pause コマンドと run コマンドの間にどれぐらいの時間が経過するかは特定できない。pause コマンドの時点で送信されたサンプルは最新ではない可能性がある。ユーザーが run コマンドを発行するまでに 1 時間が経過した場合、1 時間前にキャプチャしたビデオ フレームではなく新しいビデオ フレームをグラフで生成する必要がある。そのため、キャプチャ フィルタは実行中のときだけサンプルを送信する。
ただし、この動作によってグラフに問題が発生する場合がある。フィルタ グラフ マネージャは、すべてのフィルタがポーズするまで待機してからグラフを実行する。しかし、レンダラはキャプチャ フィルタからのサンプルを待機するため、この移行は完了しない。この問題を回避するために、キャプチャ フィルタの IMediaFilter::GetState メソッドは VFW_S_CANT_CUE を返す。この戻りコードはフィルタ グラフ マネージャに対して、キャプチャ フィルタがサンプルを送信していないことを知らせ、レンダラを待機しないように指示する。
データ フローの詳細については、「フィルタ開発者が使用するデータ フロー」を参照すること。