次の方法で共有


DirectShow のソース フィルターを作成する方法

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

このトピックでは、DirectShow のカスタム ソース フィルターを記述する方法について説明します。

注意

このトピックでは、プッシュ ソースについてのみ説明します。非同期リーダー フィルターやプル ソースに接続するスプリッター フィルターなど、プル ソースについては説明しません。 プッシュ ソースとプル ソースの違いについては、「フィルター開発者向けのData Flow」を参照してください。

DirectShow ストリーミング モデル

ソース フィルターを作成するときは、プッシュ ソースがライブ ソースと同じではないことを理解することが重要です。 ライブ ソースは、カメラやネットワーク ストリームなどの一部の外部ソースからデータを取得します。 一般に、ライブ ソースはデータの受信レートを制御できません。 ダウンストリーム フィルターがデータを十分に高速に消費しない場合、ソースはサンプルを削除する必要があります。

ただし、プッシュ ソースはライブ ソースである必要はありません。 たとえば、プッシュ ソースはローカル ファイルからデータを読み取ることができます。 その場合、ダウンストリーム レンダラー フィルターは、参照クロックとサンプル タイム スタンプに基づいて、ソースからのデータを使用する速度を決定します。 ソース フィルターは可能な限り迅速にサンプルを提供しますが、実際のデータ フローはレンダラーによって制限されます。 データ フローを制御するためのメカニズムについては、「フィルター開発者向けのData Flow」を参照してください。

ソース フィルターの各出力ピンは、ストリーミング スレッドと呼ばれる スレッドを作成します。 ピンは、ストリーミング スレッドでサンプルを提供します。 通常、デコード、処理、レンダリングはすべてこのスレッドで行われますが、ダウンストリーム フィルターによっては、出力サンプルをキューに入れる追加のスレッドが作成される場合があります。

ストリーミング スレッドは、次の構造を持つループを実行します。

until (stopped)
  1. Get a media sample from the allocator.
  2. Fill the sample with data.
  3. Time stamp the sample. 
  4. Deliver the sample downstream.

使用可能なサンプルがない場合、ステップ 1 はサンプルが使用可能になるまでブロックします。 手順 4 ではブロックすることもできます。たとえば、グラフが一時停止している間はブロックできます。

ループは可能な限り迅速に実行されますが、レンダラー フィルターが各サンプルをレンダリングする速度によって制限されます。 フィルター グラフに基準クロックがある場合、レートはサンプルの表示時間によって決まります。 参照クロックがない場合、レンダラーは可能な限り迅速にサンプルを使用します。

CSource と CSourceStream の使用

DirectShow 基本クラスには、プッシュ ソースをサポートする CSource と CSourceStream の 2 つのクラスが含 まれています

  • CSource はフィルターの基本クラスであり、 IBaseFilter インターフェイスを実装します。
  • CSourceStream は出力ピンの基本クラスであり、 IPin インターフェイスを実装します。

出力ピン

ソース フィルターには、複数の出力ピンを含めることができます。 フィルターのコンストラクター メソッドで、 CSourceStream から派生した 1 つ以上のピン (出力ストリームごとに 1 つのピン) を作成します。 ピンへのポインターを格納する必要はありません。ピンは、作成時に自動的にフィルターに追加されます。

出力形式

出力ピンは、次の CSourceStream メソッドを使用してフォーマット ネゴシエーションを処理します。

メソッド 説明
GetMediaType 出力ピンからメディアの種類を取得します。
ダウンストリーム フィルターでは型が提案されない可能性があるため、ピンは少なくとも 1 つのメディアタイプを提案する必要があります。 ほとんどの場合、ダウンストリーム フィルターは、ソース フィルターが圧縮データと圧縮されていないデータのどちらを配信するかに応じて、デコーダーまたはレンダラーになります。 レンダラー フィルターには通常、ストリームのレンダリングに必要なすべての形式情報を含む完全なメディアの種類が必要です。 デコーダーの場合、メディアの種類に必要な情報の量は、エンコード形式によって大きく異なります。
CheckMediaType 出力ピンが特定のメディアの種類を受け入れるかどうかを確認します。 GetMediaType の実装方法に応じて、このメソッドのオーバーライドは省略可能です。

GetMediaType メソッドはオーバーロードされています。

  • GetMediaType (1) は、単一のパラメーター ( CMediaType オブジェクトへのポインター) を受け取ります。
  • GetMediaType (2) は、インデックス変数と CMediaType オブジェクトへのポインターを受け取ります。

ソース フィルターの出力ピンで 1 つのメディア形式がサポートされている場合は、(1) をオーバーライドして、その形式で CMediaType オブジェクトを初期化する必要があります。 既定の実装は (2) のままにし、 CheckMediaType の既定の実装はそのままにします。

ピンが複数の形式をサポートしている場合は、オーバーライド (2) します。 インデックス変数の値に従って CMediaType オブジェクトを初期化します。 ピンは、形式を順序付きリストとして返す必要があります。 この場合は、CheckMediaType をオーバーライドして、形式の一覧に対してメディアの種類をチェックする必要もあります。

圧縮されていないビデオ形式の場合は、ダウンストリーム フィルターでさまざまなストライド値を持つ形式を提案できることに注意してください。 フィルターは、有効なストライド値を受け入れる必要があります。 詳細については、「 BITMAPINFOHEADER」を参照してください。

また、pure-virtual CBaseOutputPin::D ecideBufferSize メソッドもオーバーライドする必要があります。 サンプル バッファーのサイズを設定するには、このメソッドを使用します。

ストリーム

CSourceStream クラスは、ピンのストリーミング スレッドを作成します。 スレッド プロシージャは CSourceStream::D oBufferProcessingLoop メソッドに 実装されます。 このメソッドは、派生クラスがオーバーライドする必要がある純粋仮想 CSourceStream::FillBuffer メソッドを呼び出します。 このメソッドは、ピンがバッファーにデータを入力する場所です。 たとえば、フィルターで圧縮されていないビデオが配信される場合、ここでビデオ フレームを描画します。

基本クラスは、フィルターが一時停止または停止したときに、適切なタイミングでスレッド ループを自動的に開始および停止します。 この場合、 CSourceStream クラスは一部のメソッドを呼び出して派生クラスに通知します。

特別な処理を追加する必要がある場合は、これらのメソッドをオーバーライドできます。 それ以外の場合、既定の実装は 単にS_OKを返します。

求めて

1 つの出力ピンを持つソース フィルターがある場合は、シークを実装するための開始点として CSourceSeeking クラスを使用できます。 CSourceStreamCSourceSeeking の両方から pin クラスを継承します。

Note

CSourceSeeking は、複数の出力ピンを持つフィルターには推奨されません。 メインの問題は、要求のシークに 1 つのピンだけが応答する必要があるということです。 通常、これにはピンとフィルター間の通信が必要です。

CSourceSeeking クラスは、再生速度、開始時刻、停止時間、および継続時間を管理します。 派生クラスでは、最初の停止時間と継続時間を設定する必要があります。 これらの値のいずれかが変更されるたびに、 CSourceSeeking::ChangeRateCSourceSeeking::ChangeStart、または CSourceSeeking::ChangeStop メソッドが必要に応じて呼び出されます。 メソッドはすべて純粋な仮想メソッドです。 派生 pin クラスは、次の操作を行うためにこれらのメソッドをオーバーライドします。

  1. ダウンストリーム ピンで IPin::BeginFlush を呼び出します。 これにより、ダウンストリーム フィルターは、保持しているサンプルを解放し、新しいサンプルを拒否します。
  2. CSourceStream::Stop を呼び出してストリーミング スレッドを停止します。 ソース フィルターは、新しいデータの生成を中断します。
  3. ダウンストリーム ピンで IPin::EndFlush を呼び出します。 これにより、ダウンストリーム フィルターが新しいデータを受け入れるように通知されます。
  4. 新しい開始時刻と停止時刻とレートを使用して IPin::NewSegment を呼び出します。
  5. 次のサンプルで不連続性プロパティを設定します。

詳細については、「 ソース フィルターでのシークのサポート」を参照してください。

フィルターでシークがサポートされている場合、ストリームの位置はプレゼンテーション時間に依存しません。 シーク後、タイムスタンプは 0 にリセットされます。 タイム スタンプの一般的な数式は次のとおりです。

  • サンプル開始時刻 = 経過時間 / 再生速度
  • sample end time = sample start time + (time per frame / playback rate)

ここで 、経過時間 は、フィルターの実行が開始されてから、または最後の seek コマンド以降に経過した時間です。

シークの時間形式

既定では、seek コマンドの単位は 100 ナノ秒です。 ソース フィルターでは、フレーム番号によるシークなど、追加の時間形式をサポートできます。 各時刻形式は GUID によって識別されます。 「時刻形式 GUID」を参照してください。

追加の時間形式をサポートするには、出力ピンに次のメソッドを実装する必要があります。

アプリケーションで新しい時刻形式が設定されている場合、 IMediaSeeking メソッド内のすべての位置パラメーターは、新しい時刻形式の観点から解釈されます。 たとえば、時間形式がフレームの場合、 IMediaSeeking::GetDuration メソッドは期間をフレーム単位で返す必要があります。

実際には、追加の時間形式をサポートする DirectShow フィルターはほとんどなく、その結果、この機能を利用する DirectShow アプリケーションはほとんどありません。

ソース フィルターの作成