Microsoft DirectX 8.0 |
変換フィルタは、メディア入力を受け取り、それに何らかの変更を加える。変換フィルタを設計する場合、フィルタ クラスはいずれかの変換基底クラス (CTransformFilter、CTransInPlaceFilter、または CVideoTransformFilter) から派生するか、より一般的な CBaseFilter クラスから派生する。どの基底クラスを選択するかは、フィルタがメディア サンプルをコピーする必要があるか、あるいはそのまま変換できるかによって決まる。詳細については、「使用する基底クラスを決める」を参照すること。
フィルタ グラフ マネージャは、フィルタの派生元の基底クラスの関数を使用して、フィルタ グラフにフィルタを挿入し、フィルタ間の接続を自動的に作成する。フィルタ マッパーは、フィルタのレジストリ情報を使用してフィルタ グラフを設定する。
最も単純な変換フィルタ (たとえば、入力ピンと出力ピンが 1 つずつしかないフィルタ) の場合、フィルタ クラスを CTransformFilter から派生して、Transform 関数と CheckInputType 関数だけをオーバーライドすればよい。カスタム機能が必要であれば、他の関数をオーバーライドして独自の接続、ピン、および他のフィルタ機能を作成できる。詳細については、「基底クラス メンバ関数をオーバーライドする」を参照すること。また、フィルタ クラスを CBaseFilter から派生して、そのメソッドをオーバーライドすることもできる。
このセクションでは、以下の方法について説明する。
すべての変換フィルタは、追加インターフェイスへのアクセスを除き、上記のステップをすべて実行するコードを実装しなければならない。
変換フィルタの背景情報については、以下のトピックを参照すること。
フィルタの登録と自己登録化については、「DirectShow オブジェクトの登録方法」を参照すること。
フィルタ クラスを定義してインスタンス化するための手順を以下に示す。
次の例では、フィルタ クラスを CTransInPlaceFilter から派生している。
class CMyFilter :public CTransInPlaceFilter
フィルタ クラス定義のパブリック セクションで CUnknown のインスタンスを作成してから、DECLARE_IUNKNOWN マクロを呼び出す。
public: static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr); DECLARE_IUNKNOWN;
フィルタ クラス定義のプライベート セクションで、コンストラクタを定義する。これは、派生元の変換フィルタ クラスのコンストラクタを呼び出すことで行う。次に、変換を実行して入力タイプをチェックするコードを追加する。次に例を示す。
// CTransInPlaceFilter のコンストラクタを呼び出すことにより、 // コンストラクタを定義する。 CMyFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr) : CTransInPlaceFilter (tszName, punk, CLSID_MyFilter, phr) { } // 変換コードを追加する。 HRESULT Transform(IMediaSample *pSample){ // ここに変換コードが入る。 } // 入力タイプをチェックするコードを追加する。 HRESULT CheckInputType(const CMediaType* mtIn) { // ここに入力チェック コードが入る。 }
CUnknown * WINAPI CMyFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr) { CMyFilter *pNewObject = new CMyFilter(NAME("Description of My Filter"), punk, phr ); if (pNewObject == NULL) { *phr = E_OUTOFMEMORY; } return pNewObject; }
CFactoryTemplate g_Templates[]= { { L"My Filter" , &CLSID_MyFilter , CMyFilter::CreateInstance // クラス ファクトリによって呼び出される関数 , NULL , &sudMyFilter } // AMOVIESETUP_FILTER 構造体のアドレス。 // 構造体が存在しない場合は NULL。 }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
g_cTemplates 変数は、フィルタに対するクラス ファクトリ テンプレート (CFactoryTemplate) の数を定義する。各テンプレートは COM とフィルタの間のリンクを提供し、フィルタのベース オブジェクトを作成するために使用される。フィルタには最低でも 1 つのテンプレートがある。これは、フィルタ独自の CreateInstance 関数のアドレスを提供する。この関数は、呼び出されるとベース オブジェクトを作成する。
CFactoryTemplate テンプレートにパラメータを追加することで、プロパティ ページを追加できる。登録時の CFactoryTemplate の使用法については、「DirectShow オブジェクトの登録方法」を参照すること。
GUID の生成に関する一般的な情報については、Platform SDK の "GUID の作成と最適化" および "uuidgen ユーティリティ" を参照すること。
Microsoft® Visual C++® 5.x で GUID を生成するには、[ツール] メニューから [Create GUID] を選択する。GUID のデフォルトのフォーマットは DEFINE_GUID であり、これをそのまま使用する。[コピー] ボタンをクリックする。ソース ファイルでインクルード文の下にカーソルを置き、[編集] メニューの [貼り付け] を選択する。次の例に示すようなコードが挿入される。ただし、番号と CLSID は固有のものが入る。ヘッダー ファイルまたはメイン ファイルのクラス定義の前にコードを挿入する。
// {3FA5D260-AF2F-11d0-AE9C-00A0C91F0841} DEFINE_GUID(CLSID_MyFilter, 0x3fa5d260, 0xaf2f, 0x11d0, 0xae, 0x9c, 0x0, 0xa0, 0xc9, 0x1f, 0x8, 0x41);
フィルタに対して指定された入力が正しいかどうか確認するために、CheckInputType 関数をオーバーライドする (これは CBaseFilter から派生したフィルタ クラスには適用されない)。実装では、サポートできないメディア タイプに対してエラーを返す必要がある。フィルタがサポートするメディア タイプは、AMOVIESETUP_MEDIATYPE 構造体にリストされる。次に例を示す。
HRESULT CMyFilter::CheckInputType(const CMediaType *pmt) { if (pmt->majortype != MEDIATYPE_Video) { return S_FALSE; } else return S_OK; }
入力メディアに対して必要な変換を実行するために、変換基底クラスの Transform 関数をオーバーライドするか、または独自の変換関数を実装する必要がある (これは CBaseFilter から派生したフィルタ クラスには適用されない)。
たとえば、コントラスト サンプルの以下のコードについて考える。CContrast::Transform 関数を次のようにオーバーライドする。
HRESULT CContrast::Transform(IMediaSample *pIn, IMediaSample *pOut) { HRESULT hr = Copy(pIn, pOut); if (FAILED(hr)) { return hr; } return Transform(pOut); }
最初の CContrast::Transform 関数はメディア データをコピーして、(pOut パラメータが指す) そのコピーを次の Transform 関数に渡す。コントラスト サンプルの最初の Transform 関数はオーバーロードされた関数であり、2 番目の形の Transform 関数は入力メディアのコピーに対してインプレイス変換を行う。これを次のコードに示す。
HRESULT CContrast::Transform(IMediaSample *pMediaSample) { signed char ContrastLevel; ContrastLevel = m_ContrastLevel; AM_MEDIA_TYPE *pAdjustedType = NULL; pMediaSample->GetMediaType(&pAdjustedType); HRESULT hr = Transform(&AdjustedType, ContrastLevel); pMediaSample->SetMediaType(&AdjustedType); return NOERROR; }
2 番目の形のオーバーロードされた Transform 関数は、さらに 3 番目の形のオーバーロードされた Transform 関数を呼び出すことに注意。
フィルタが基底クラスに実装されていないインターフェイスを実装する場合は、NonDelegatingQueryInterface 関数をオーバーライドして、実装されたインターフェイスへのポインタを返す必要がある。
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
// 永続ストリームとプロパティ ページを公開する。 STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv) { if (riid == IID_IPersistStream) { AddRef( ); // 参照カウントを追加する。終了後に解放すること。 *ppv = (void *)(IPersistStream *)this; return NOERROR; } } else if (riid == IID_ISpecifyPropertyPages) { return GetInterface((ISpecifyPropertyPages *) this, ppv); } else { return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv); } }
フィルタ グラフ マネージャは、フィルタのレジストリ エントリを使用して、フィルタとその接続を設定する。フィルタのレジストリ情報は、AMOVIESETUP_MEDIATYPE、AMOVIESETUP_PIN、および AMOVIESETUP_FILTER 構造体に提供する。通常、これらの構造体はフィルタ実装コードの先頭に位置する。これらの構造体の使用法の詳細については、「DirectShow オブジェクトの登録方法」を参照すること。
フィルタの登録に必要な 3 つの構造体を提供するための手順を以下に示す。
const AMOVIESETUP_MEDIATYPE sudPinTypes = { &MEDIATYPE_Video // メジャー タイプ , &MEDIASUBTYPE_NULL} ; // マイナー タイプ
メジャー タイプは、MEDIATYPE_Stream、MEDIATYPE_Video、MEDIATYPE_Audio のいずれかである。
const AMOVIESETUP_FILTER sudMyFilter = { &CLSID_MyFilter // clsID , L"My Filter Description" // strName , MERIT_UNLIKELY // dwMerit , 2 // nPins , sudpPins }; // lpPin