次の方法で共有


サンプルとアロケータ

ピンが別のピンにメディア データを送る場合、ピンはメモリ バッファへの直接のポインタを渡すわけではない。その代わりに、メモリを管理する COM オブジェクトへのポインタを渡す。このオブジェクトは、"メディア サンプル" と呼ばれ、IMediaSample インターフェイスを公開する。受信ピンは、IMediaSample::GetPointerIMediaSample::GetSize、および IMediaSample::GetActualDataLength などの IMediaSample メソッドを呼び出すことによってメモリ バッファにアクセスする。

サンプルは、常に、出力ピンから入力ピンへとダウンストリームへと移動する。プッシュ モデルでは、出力ピンは、入力ピンに対して IMemInputPin::Receive メソッドを呼び出すことによって、サンプルを送信する。入力ピンは、データを同期的に (つまり完全に Receive メソッド内で) 処理するか、ワーカー スレッドで非同期的に処理する。入力ピンは、リソースを待つ必要がある場合は、Receive メソッド内でブロックできる。

メディア サンプルの作成と管理を行うもう 1 つの COM オブジェクトが "アロケータ" である。アロケータは IMemAllocator インターフェイスを公開する。フィルタはバッファが空のメディア サンプルが必要になると、IMemAllocator::GetBuffer メソッドを呼び出す。このメソッドはサンプルへのポインタを返す。各ピン接続は 1 つのアロケータを共有する。2 つのピンを接続する場合、どちらのフィルタがアロケータを提供するかが決定される。ピンは、バッファの数や各バッファのサイズなど、アロケータに関するプロパティも設定する。詳細については、「フィルタの接続」および「アロケータの調整」を参照すること。

次の図は、アロケータ、メディア サンプル、フィルタの関係を示している。

メディア サンプルとアロケータ

メディア サンプルの参照カウント

アロケータは有限のサンプルのプールを作成する。ある時点で、使用中であるサンプルもあれば、GetBuffer の呼び出しで利用できるサンプルもある。アロケータは参照カウントを使ってサンプルを追跡する。GetBuffer メソッドは、参照カウントを 1 にしてサンプルを返す。参照カウントが 0 になると、サンプルはアロケータのプールに戻り、次の GetBuffer の呼び出しで利用できる。参照カウントが 0 よりも大きい限り、サンプルは GetBuffer で利用できない。アロケータに属するすべてのサンプルが使用中である場合、GetBuffer メソッドはサンプルが利用可能になるまでブロックする。

たとえば、入力ピンがサンプルを受け取る場合を考えてみる。入力ピンがサンプルを Receive メソッド内で同期的に処理する場合、入力ピンは参照カウントをインクリメントしない。Receive が戻ると、出力ピンはサンプルを解放し、参照カウントは 0 になり、サンプルはアロケータのプールに戻る。一方、入力ピンがワーカー スレッド上でサンプルを処理する場合、入力ピンは Receive メソッドを離れる前に参照カウントをインクリメントする。このとき参照カウントは 2 になる。出力ピンがサンプルを解放すると、カウントは 1 になるが、サンプルはまだプールに戻らない。ワーカー スレッドは、サンプルの処理を終了すると、Release を呼び出してサンプルを解放する。このときサンプルはプールに戻る。

ピンは、サンプルを受け取ると、データを別のサンプルにコピーしたり、元のサンプルを変更して次のフィルタに送ったりすることができる。潜在的に、サンプルはグラフ全体を移動する可能性があり、各フィルタは順に AddRefRelease を呼び出す。したがって、出力ピンは Receive を呼び出した後でサンプルを再利用しないようにしなければならない。ダウンストリームのフィルタがサンプルを使っている場合があるからである。出力ピンは常に GetBuffer を呼び出して新しいサンプルを取得する必要がある。

このメカニズムではフィルタが同じバッファを再利用するため、メモリ割り当ての量が少なくて済む。また、アロケータは使用可能なサンプルのリストを保持しているため、まだ処理の済んでいないデータがフィルタによって誤って上書きされることを防止できる。

フィルタが入力用と出力用に異なるアロケータを使うことも可能である。フィルタは入力データを展開する (データの圧縮解除など) 場合に、このような処理を行うことがある。出力が入力より大きくない場合、フィルタはデータを新しいサンプルにコピーせず、元の場所で処理できる。その場合、2 つ以上のピン接続で 1 つのアロケータを共有できる。

アロケータのコミットとデコミット

フィルタが最初にアロケータを作成する場合、アロケータはメモリ バッファを何も予約していない。この時点では、GetBuffer メソッドを呼び出すと失敗する。ストリーミングが始まると、出力ピンは IMemAllocator::Commit を呼び出し、アロケータを "コミット" してメモリを割り当てる。これでピンは GetBuffer を呼び出すことができる。

ストリーミングが終了すると、ピンは IMemAllocator::Decommit を呼び出して、アロケータを "デコミット" する。アロケータが再びコミットされるまで、これ以降の GetBuffer の呼び出しはすべて失敗する。また、現在、サンプルを待ってブロックしている GetBuffer の呼び出しがある場合、その呼び出しは直ちにエラー コードを返す。Decommit メソッドは、実装によって、メモリを解放する場合と解放しない場合がある。たとえば、CMemAllocator クラスは、デコンストラクタ メソッドがメモリを解放するまで待機する。