手順 6. COM のサポートを追加する
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]
これは、 変換フィルターの記述に関するチュートリアルの手順 6 です。
最後の手順では、COM のサポートを追加します。
参照カウント
IUnknown::AddRef または IUnknown::Release を実装する必要はありません。 すべてのフィルター クラスとピン クラスは、参照カウントを処理する CUnknown から派生します。
QueryInterface
すべてのフィルター クラスとピン クラスは、継承するすべての COM インターフェイスに IUnknown::QueryInterface を実装します。 たとえば、CTransformFilter はIBaseFilter を (CBaseFilter 経由で) 継承します。 フィルターで追加のインターフェイスが公開されない場合は、他の操作を行う必要はありません。
追加のインターフェイスを公開するには、 CUnknown::NonDelegatingQueryInterface メソッドを オーバーライドします。 たとえば、フィルターが IMyCustomInterface という名前のカスタム インターフェイスを実装するとします。 このインターフェイスをクライアントに公開するには、次の操作を行います。
- そのインターフェイスからフィルター クラスを派生させます。
- DECLARE_IUNKNOWN マクロをパブリック宣言セクションに配置します。
- NonDelegatingQueryInterface をオーバーライドしてインターフェイスの IID をチェックし、フィルターへのポインターを返します。
これらの手順を示すコードは次のようになります。
CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
if (riid == IID_IMyCustomInterface) {
return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}
詳細については、「 IUnknown を実装する方法」を参照してください。
オブジェクトの作成
DLL にフィルターをパッケージ化し、他のクライアントで使用できるようにする場合 は、CoCreateInstance および他の関連 COM 関数をサポートする必要があります。 基底クラス ライブラリは、このほとんどを実装します。フィルターに関する情報を入力するだけです。 このセクションでは、実行する操作の概要について簡単に説明します。 詳細については、「 DirectShow フィルター DLL を作成する方法」を参照してください。
まず、フィルターの新しいインスタンスを返す静的クラス メソッドを記述します。 このメソッドには任意の名前を付けることができますが、シグネチャは次の例に示されているものと一致している必要があります。
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
次に、g_Templatesという名前の CFactoryTemplate クラス インスタンスのグローバル配列 を宣言します。 各 CFactoryTemplate クラスには、1 つのフィルターのレジストリ情報が含まれています。 複数のフィルターを 1 つの DLL に配置できます。追加の CFactoryTemplate エントリを含めるだけです。 プロパティ ページなど、他の COM オブジェクトを宣言することもできます。
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
g_Templates配列の長さと等しい値を持つ g_cTemplates という名前のグローバル整数を定義します。
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
最後に、DLL 登録関数を実装します。 次の例は、これらの関数の最小限の実装を示しています。
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
レジストリ エントリのフィルター処理
前の例では、COM 用にフィルターの CLSID を登録する方法を示します。 多くのフィルターでは、これで十分です。 その後、クライアントは CoCreateInstance を使用してフィルターを作成し、 IFilterGraph::AddFilter を呼び出してフィルター グラフに追加する必要があります。 ただし、場合によっては、レジストリでフィルターに関する追加情報を提供することが必要な場合があります。 この情報では、次の処理が行われます。
- クライアントがフィルター マッパー または システム デバイス列挙子を使用してフィルターを検出できるようにします。
- フィルター グラフ マネージャーで、グラフの自動作成中にフィルターを検出できるようにします。
次の例では、RLE エンコーダー フィルターをビデオ コンプレッサー カテゴリに登録します。 詳細については、「 DirectShow フィルターを登録する方法」を参照してください。 フィルター登録の推奨されるプラクティスについて説明 している「フィルターの登録に関するガイドライン」セクションを必ずお読みください。
// Declare media type information.
FOURCCMap fccMap = FCC('MRLE');
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };
// Declare pin information.
REGFILTERPINS sudPinReg[] = {
// Input pin.
{ 0, FALSE, // Rendered?
FALSE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudInputTypes // Media types.
},
// Output pin.
{ 0, FALSE, // Rendered?
TRUE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudOutputTypes // Media types.
}
};
// Declare filter information.
REGFILTER2 rf2FilterReg = {
1, // Version number.
MERIT_DO_NOT_USE, // Merit.
2, // Number of pins.
sudPinReg // Pointer to pin information.
};
STDAPI DllRegisterServer(void)
{
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_RLEFilter, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_VideoCompressorCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2FilterReg // Filter information.
);
pFM2->Release();
}
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_RLEFilter);
pFM2->Release();
}
return hr;
}
また、フィルターを DLL 内にパッケージ化する必要はありません。 場合によっては、特定のアプリケーション専用に設計された特殊なフィルターを記述する場合があります。 その場合は、次の例に示すように、フィルター クラスをアプリケーションで直接コンパイルし、 演算子を使用 new
して作成できます。
#include "MyFilter.h" // Header file that declares the filter class.
// Compile and link MyFilter.cpp.
int main()
{
IBaseFilter *pFilter = 0;
{
// Scope to hide pF.
CMyFilter* pF = new MyFilter();
if (!pF)
{
printf("Could not create MyFilter.\n");
return 1;
}
pF->QueryInterface(IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));
}
/* Now use pFilter as normal. */
pFilter->Release(); // Deletes the filter.
return 0;
}
関連トピック