Date

独自フィルタを作成するために SDK に付属している BaseClasses (DirectShow クラスライブラリ)をコンパイルする。BaseClasses とは、簡単に DirectShow フィルタを作成できるクラスライブラリである。フィルタは IBaseFilter を継承した独自クラスを実装していく必要があるが、これをスクラッチから書くと非常に大変である。BaseClasses は、Windows SDK に付属している。(以前は DirectX SDK に付属していたが移行した。)

コンパイル方法

C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\Multimedia\DirectShow\BaseClasses を開く。 baseclasses.sln というファイルがあるので Visual Studio で開く。

プロジェクトのプロパティページを開き、構成を[全ての構成]にする。[64 ビット移植への対応]を[いいえ]にする。[はい]のままでは警告やエラーが表示されることがある。

[ビルド]-[バッチビルド] 全て選択して、 [リビルド] をクリックする。

BaseClasses はやや古いソースコードであるため、Visual Studio 2005 でコンパイルすると_CRT_SECURE_NO_DEPRECATE を使え というような警告が表示されますが、最終的には、なんら問題なくライブラリが作成される。気になる方はヘッダファイルなどに当該マクロを define すると良い。

コンパイルできたか確認する

C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\Multimedia\DirectShow\BaseClasses に、Debug, Debug_MBCS, Release, Release_MBCS という 4つのフォルダが新しく作成され、 strmbase.lib または strmbasd.lib が作成されていれば成功。

フィルタプロジェクトを作成

フィルタは DLL として作成する

新規プロジェクトを作成し、プロジェクトタイプは [win32 プロジェクト]にする。アプリケーションの種類は [DLL] を選ぶ。プロジェクト名を入力する。

プロジェクトのプロパティを表示させる。[全ての構成]を表示させて、[構成プロパティ]-[C/C++]-[全般]を開く。追加のインクルードディレクトリに BaseClasses のディレクトリを指定する。64 ビット移植への対応を[いいえ]にする。

[リンカ]-[追加のライブラリディレクトリ]を次のように設定する。

Releaseビルド C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\Multimedia\DirectShow\BaseClasses\release
Debugビルド C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\Multimedia\DirectShow\BaseClasses\debug

インクルードファイルとライブラリのリンク

stdafx.h を書きかえる。strmbase.lib (strmbasd.lib) をインポートし、streams.h, initguid.h をインクルードしている。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#pragma once
#define WIN32_LEAN_AND_MEAN        // Windows ヘッダーから使用されていない部分を除外する。
#define _WIN32_DCOM
#define _CRT_SECURE_NO_DEPRECATE
#pragma warning(disable : 4995)
#pragma comment(lib, "strmiids.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "winmm.lib")
#ifdef _DEBUG
#pragma comment(lib, "strmbasd.lib")
#else
#pragma comment(lib, "strmbase.lib")
#endif
#include <streams.h>
#include <initguid.h>

フィルタを OS へ登録できるようにする

フィルタを OS へ登録・解除する際に呼び出される関数を定義する。

DllSetup.cpp を新規作成しプロジェクトに追加する。

(CMyFilterは、作成するフィルタのクラス名。)

AMovieDllRegisterServer2, AMovieDllRegisterServer2は、COM をレジストリに登録・解除する際に呼ぶ関数で、BaseClasses クラスライブラリに実装されている。

DllMain関数内で DbgSetModuleLevelを呼び出しデバッグログを出力するようにしている。Visual Studio 2005 の[出力]ウィンドウに表示されるようになる。

CFactoryTemplate g_Templates は、CoCreateInstanceが呼び出され、定義したフィルタクラスのインスタンスが作成されたときに使用する配列である。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include "stdafx.h"
#define LOGING_LEVEL 5
extern "C" {
    BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
};
CFactoryTemplate g_Templates [] = {
     { TEMPLATE_NAME , &CLSID_MySource, CMySource::CreateInstance, NULL, &afFilterInfo}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
STDAPI DllRegisterServer() {
    return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer() {
    return AMovieDllRegisterServer2(FALSE);
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved) {
    DbgSetModuleLevel(LOG_TRACE,LOGING_LEVEL);
    DbgSetModuleLevel(LOG_ERROR,LOGING_LEVEL);
    return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

モジュール定義ファイルを作成

モジュール定義ファイル module.def を作成する。 DLL として公開する関数を指定している。プロジェクトのプロパティを再び開いて、 [全ての構成]-[構成プロパティ]-[リンカ]-[入力]を開き、[モジュール定義ファイル] に module.def を入力する。

1
2
3
4
5
6
LIBRARY "MyFilter"
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow     PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

フィルタ情報の定義

MyFilter.h のように適当なヘッダーファイルを作成し、stdafx.h の末尾にインクルードする。

DllSetup.cpp で使われていた CFactoryTemplate g_Templates を初期化する TEMPLATE_NAME, フィルタ名, 出力ピンの名前を define で定義する。

1
2
3
#define TEMPLATE_NAME (L"My Filter")
#define FILTER_NAME (TEMPLATE_NAME)
#define OUTPUT_PIN_NAME (L"Output")

フィルタのクラス ID を決める。Playform SDK に付属している guidgen.exe を使って GUID を生成する。すると次のような書式でクリップボードにコピーできる。

1
2
3
// {78A3788B-F360-45f9-8E1D-443D3C63BD0B}
DEFINE_GUID(CLSID_MyFilter,  // ← クラス ID は CLSID_XXXXX の書式が使われる。
0x78a3788b, 0xf360, 0x45f9, 0x8e, 0x1d, 0x44, 0x3d, 0x3c, 0x63, 0xbd, 0xb);

AMOVIESETUP_FILTER構造体 afFilterInfoを定義する。(設定した値は仮の値。)

1
2
3
4
5
6
7
8
9
// フィルタ情報
const AMOVIESETUP_FILTER afFilterInfo=
{
    &CLSID_MyFilter,        // フィルタのCLSID
    FILTER_NAME,            // フィルタ名 ( FILTER_NAME で呼び出させるようにしている )
    MERIT_DO_NOT_USE,       // メリット値
    0,                      // ピン数
    NULL                    // ピン情報
};

最後に、フィルタクラスの定義を追記する。全体のソースコードは次のとおり。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#pragma once
#define TEMPLATE_NAME    (L"My Filter")
#define FILTER_NAME        (TEMPLATE_NAME)
#define OUTPUT_PIN_NAME (L"Output")
// {78A3788B-F360-45f9-8E1D-443D3C63BD0B}
DEFINE_GUID(CLSID_MyFilter,
0x78a3788b, 0xf360, 0x45f9, 0x8e, 0x1d, 0x44, 0x3d, 0x3c, 0x63, 0xbd, 0xb);
// フィルタ情報
const AMOVIESETUP_FILTER afFilterInfo=
{
    &CLSID_MyFilter,        // フィルタのCLSID
    FILTER_NAME,            // フィルタ名
    MERIT_DO_NOT_USE,       // メリット値
    0,                      // ピン数
    NULL                    // ピン情報
};
// TODO : ここにフィルタクラスの定義を記述する

Comments

comments powered by Disqus