圧縮フィルタの選択

次に示すように、ビデオまたはオーディオの圧縮を実行できるソフトウェア コンポーネントは数種類ある。

  • ネイティブ DirectShow フィルタ
  • ビデオ圧縮マネージャ (VCM) CODEC
  • オーディオ圧縮マネージャ (ACM) CODEC
  • DirectX Media Object(DMO)

DirectShow では、VCM CODEC は AVI コンプレッサ フィルタによってラップされており、ACM CODEC は ACM ラッパー フィルタによってラップされている。DMO は、DMO ラッパー フィルタによってラップされている。System Device Enumerator が提供する、これらのコンプレッサ タイプを列挙したり作成したりする方法は一貫性があり、基盤となるモデルについて心配する必要はない。

System Device Enumerator の詳細については、「System Device Enumerator の使い方」を参照すること。簡単に説明すると、すべての DirectShow フィルタはカテゴリ別に分類され、各カテゴリは GUID で識別される。ビデオ コンプレッサの場合、カテゴリ GUID は CLSID_VideoCompressorCategory である。オーディオ コンプレッサの場合は、CLSID_AudioCompressorCategory である。System Device Enumerator は、特定のカテゴリを列挙するために、IEnumMoniker インターフェイスをサポートする "列挙子オブジェクト" を作成する。アプリケーションはこのインターフェイスを使って、デバイス モニカを取得する。各デバイス モニカは、DirectShow フィルタのインスタンスを表す。モニカを使ってフィルタを作成するか、または、フィルタを作成しないでデバイスのフレンドリ名を取得する。

ユーザーのシステムで利用可能なビデオ コンプレッサまたはオーディオ コンプレッサを列挙するには、次の作業を行う。

  1. CoCreateInstance を呼び出して、クラス ID が CLSID_SystemDeviceEnum の System Device Enumerator を作成する。
  2. フィルタ カテゴリ GUID を指定して ICreateDevEnum::CreateClassEnumerator を呼び出す。このメソッドは、IEnumMoniker インターフェイス ポインタを返す。
  3. IEnumMoniker::Next メソッドを使って、デバイス モニカを列挙する。このメソッドは、モニカを表す IMoniker インターフェイスを返す。

モニカからフレンドリ名を取得するには、次の作業を行う。

  1. IMoniker::BindToStorage メソッドを呼び出す。このメソッドは、IPropertyBag インターフェイス ポインタを返す。
  2. IPropertyBag::Read メソッドを使って、FriendlyName プロパティを読み取る。

通常、アプリケーションはコンプレッサの一覧を表示するので、ユーザーはその一覧の中から選択できる。たとえば、次のコードは利用できるビデオ コンプレッサの名前をリスト ボックスに設定する。

void OnInitDialog(HWND hDlg)
{
    HRESULT hr;
    ICreateDevEnum *pSysDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    IMoniker *pMoniker = NULL;

    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
        CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, 
        (void**)&pSysDevEnum);
    if (FAILED(hr))
    {
        // エラーを処理する。
    }    

    hr = pSysDevEnum->CreateClassEnumerator(
             CLSID_VideoCompressorCategory, &pEnum, 0);
    if (hr == S_OK)  // S_FALSE はこのカテゴリでは何も意味しない。
    {
        while (S_OK == pEnum->Next(1, &pMoniker, NULL))
        {
            IPropertyBag *pPropBag = NULL;
            pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 
                (void **)&pPropBag);
            VARIANT var;
            VariantInit(&var);
            hr = pPropBag->Read(L"FriendlyName", &var, 0);
            if (SUCCEEDED(hr))
            {
                LRESULT iSel = AddString(GetDlgItem(hDlg, 
                    IDC_CODEC_LIST), var.bstrVal);
            }   
            VariantClear(&var); 
            pPropBag->Release();
            pMoniker->Release();
        }
    }

    SendDlgItemMessage(hDlg, IDC_CODEC_LIST, 
                       LB_SETCURSEL, 0, 0);
    pSysDevEnum->Release();
    pEnum->Release();
}

モニカからフィルタ インスタンスを作成するには、IMoniker::BindToObject メソッドを呼び出す。このメソッドは、IBaseFilter ポインタを返す。

IBaseFilter *pFilter = NULL;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, 
                                       (void**)&pFilter);
if (SUCCEEDED(hr))
{
    // フィルタを使う。
    // 忘れずに IBaseFilter インターフェイスを解放すること。
}

VCM CODEC の場合、すべての CODEC は同じ AVI 圧縮フィルタにラップされているが、各モニカは特定の CODEC を表す。BindToObject を呼び出すと、その CODEC 用に初期化された、このフィルタのインスタンスが作成される。このため、AVI 圧縮フィルタに対して CoCreateInstance を直接呼び出すことはできない。必ず System Device Enumerator を経由する必要がある。