Microsoft DirectX 8.0 |
Microsoft® DirectShow® では、エフェクト フィルタは、エフェクトをメディア データに適用するがメディア タイプを変更しないフィルタとして定義される。
入力と出力のメディア フォーマットが同じで、適用されたエフェクトはフォーマットを変更できないので、エフェクト フィルタがメディア フォーマッティングをチェックするコードを含むこともある。フィルタが変換フィルタの基底クラス (CTransformFilter または CTransInPlaceFilter) のどちらかから派生した場合、そのフィルタは通常、CheckMediaType、CTransformFilter::CheckInputType、および CheckTransform メソッドを使用してフォーマットをチェックする。フィルタが変換フィルタのいずれかの基底クラスから派生したものでない場合、通常は、CBasePin::CheckMediaType メンバ関数を呼び出すことによってピンがフォーマットをチェックする。
エフェクト フィルタ クラスには、必要な最大の機能を提供する基底クラスを選択する必要がある。変換フィルタ基底クラスのいずれかを基底クラスとすることはよくある。必要な機能を上位レベルの基底クラスがいずれもサポートしていない場合は、CBaseFilter または CBasePin を基底クラスとして選択することができる。
エフェクトの状態を GraphEdit に保存したい場合、エフェクト フィルタは IPersistStream インターフェイスを実装しなければならない。このインターフェイスにアクセスするには、CPersistStream からエフェクト フィルタ クラスを派生し、IPersistStream インターフェイスを照会する。設計時にフィルタの状態を保存しても役に立たないが、GraphEdit が閉じたときにエフェクト フィルタがデフォルトの状態に戻るようにしておくと便利である。この場合は、IPersistStream を実装する必要はない。
ユーザーがエフェクトを操作できるようにするには、エフェクト フィルタのプロパティ ページを作成および表示し、さらにユーザーの入力をフィルタに返すためのメカニズムを提供する必要がある。このためには。プロパティ ページ クラス、(プロパティ ページを公開する) ISpecifyPropertyPages インターフェイス、およびプロパティ ページ値を変更するカスタム インターフェイスを実装しなければならない。通常、プロパティ ページは、スライダ、ボタン、チェック ボックスなどのコントロールを使ってユーザー入力を受け取る。また、プロパティ ページにコントロールを表示するリソース ファイルも提供しなければならない。
プロパティ ページ クラスを実装するには、CBasePropertyPage から派生するクラスを作成し、OnReceiveMessage メソッド、CPersistStream::SetDirty メソッド、およびそれぞれのエフェクト パラメータのデータ メンバを実装する。この 2 つのインターフェイスにアクセスするには、エフェクト フィルタ クラスを ISpecifyPropertyPages とカスタム インターフェイスから派生させてインターフェイスを照会する。以下のコード例に示すように、NonDelegatingQueryInterface メソッドをオーバーライドすることによってすべてのインターフェイスを照会することができる (IGargle はカスタム インターフェイス)。
STDMETHODIMP CGargle::NonDelegatingQueryInterface(REFIID riid, void **ppv) { CheckPointer(ppv,E_POINTER); if (riid == IID_IGargle) { return GetInterface((IGargle *) this, ppv); } else if (riid == IID_ISpecifyPropertyPages) { return GetInterface((ISpecifyPropertyPages *) this, ppv); } else if (riid == IID_IPersistStream) { return GetInterface((IPersistStream *) this, ppv); } else { return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv); } }
通常、エフェクト フィルタのカスタム インターフェイスは、それぞれのエフェクト パラメータの put メソッドと get メソッドを提供する。たとえば IGargle カスタム インターフェイスは、put_GargleRate および get_GargleRate メソッドを提供する。Contrast サンプルの IContrast カスタム インターフェイスは、put_ContrastLevel および get_ContrastLevel メソッドを提供する。ユーザーがプロパティ ページのいずれかのコントロールにアクセスすると、ページはウィンドウ メッセージを生成する。プロパティ ページ クラスの OnReceiveMessage メンバ関数がこのメッセージを処理する。Contrast サンプルの以下のコードに、このメッセージ生成および処理を示す。IDB_DEFAULT は、[Default] ボタンのリソース ID である。ユーザーがこのボタンをクリックすると、ビデオのコントラストがデフォルト状態に設定される。CContrastProperties クラスはプロパティ ページを設定し、IContrast::put_DefaultContrastLevel メソッドはコントラスト レベルをデフォルト値に設定する。
BOOL CContrastProperties::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { if (LOWORD(wParam) == IDB_DEFAULT) { pIContrast()->put_DefaultContrastLevel(); SendMessage(m_hwndSlider, TBM_SETPOS, TRUE, 0L); SetDirty(); } return (LRESULT) 1; } ...
エフェクト フィルタは、クリティカル セクションを内部的に使用してグローバル フィルタの状態を保護する。エフェクト フィルタはクリティカル セクションをロックすることによって、フィルタ グラフを通過するデータ フローが直列化され、エフェクトが発生しているときにグローバル フィルタの状態が変化しないことを保証することができる。DirectShow は、CAutoLock クラス オブジェクトを宣言することによってクリティカル セクションをロックする。通常、エフェクト フィルタはエフェクトを適用する関数を入力すると即座にクリティカル セクションをロックする。たとえば以下のコードでエフェクトを適用する関数は MessItAbout である。
// エフェクト フィルタ クラス定義において // クリティカル セクションのデータ メンバ を宣言する。 CCritSec m_GargleLock; void CGargle::MessItAbout(PBYTE pb, int cb) { CAutoLock foo(&m_GargleLock);
通常、エフェクト プロパティの put および get メソッド (たとえば put_GargleRate) はクリティカル セクションをロックするので、エフェクト値は更新の途中で変化しない。