次の方法で共有


サンプルとアロケーター

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

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

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

アロケーターと呼ばれる別の 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::D ecommit を呼び出し、アロケーターをデコミットします。 GetBuffer に対する後続のすべての呼び出しは、アロケーターが再度コミットされるまで失敗します。 また、 GetBuffer への呼び出しが現在、サンプルの待機中にブロックされている場合は、すぐにエラー コードが返されます。 実装によっては、 Decommit メソッドによってメモリが解放される場合と解放されない場合があります。 たとえば、 CMemAllocator クラスは、デストラクター メソッドがメモリを解放するまで待機します。

フィルター グラフのData Flow