Microsoft DirectX 8.0

キャプチャ フォーマットと圧縮フォーマットの公開

ここでは、IAMStreamConfig::GetStreamCaps メソッドを使用してキャプチャ フォーマットと圧縮フォーマットを返す方法を説明する。このメソッドを使うと、受け付けられるメディア タイプに関して、ピンのメディア タイプを列挙する従来の方法に比べてより多くの情報を取得することができるので、通常はこのメソッドを使用すべきである。従来のメディア タイプを列挙する方法については、「メディア タイプ接続の確立」を参照すること。GetStreamCaps は、オーディオやビデオに許された各種フォーマットに関する情報を返す。またここでは、フィルタが特定の出力を生成できるように変換フィルタ入力ピンを再接続するためのコード例を示す。

GetStreamCaps メソッドは、メディア タイプ構造体と能力構造体のペアを要素とする配列を返す。メディア タイプは AM_MEDIA_TYPE 構造体で、能力は AUDIO_STREAM_CONFIG_CAPS 構造体または VIDEO_STREAM_CONFIG_CAPS 構造体で表される。ここでは最初にビデオの例を示し、次にオーディオの例を示す。

このトピックは、以下のセクションを含んでいる。

ビデオ能力

IAMStreamConfig::GetStreamCaps メソッドは、AM_MEDIA_TYPE 構造体と VIDEO_STREAM_CONFIG_CAPS 構造体のペアの配列でビデオ能力を示す。以下に説明するように、このメソッドを使用すると、ピンでサポートされているすべてのフォーマットと解像度を公開することができる。

GetStreamCaps のオーディオ関連の例については、「オーディオ能力」を参照すること。

使用しているキャプチャ カードが、160 × 120 ピクセルから 320 × 240 ピクセルの間のすべての解像度で JPEG フォーマットをサポートしているとする。この場合、サポートされている解像度間の違いは 1 である。なぜなら、サポートされている各解像度に対して 1 ピクセル加算または減算することによって、次のサポートされている解像度を得ているからである。サポートされている解像度間におけるこの差は、細分度と呼ばれる。

カードが 640 × 480 のサイズもサポートしているとする。以下の図に、この単独の解像度と、上記の解像度範囲 (160 × 120 ピクセルから 320 × 240 ピクセルまでの範囲のすべての解像度) を示す。

160 × 120 ピクセルから 320 × 240 ピクセルまでの範囲のすべてのサイズ、および 640 × 480 での JPEG サポート

さらに、細分度が 8 で 160 × 120 から 320 × 240 までの範囲の解像度で 24 ビット カラーの RGB フォーマットをサポートしているとする。以下の図に、この場合の有効サイズのいくつかを示す。

細分度が 8 で 160 × 120 から 320 × 240 までの範囲のサイズでの RGB サポート

具体的には、有効な解像度として以下の解像度がある。

GetStreamCaps を使用して、最小能力 160 × 120、最大能力 320 × 240、細分度 1 を組み合わせた 320 × 240 JPEG (これがデフォルトまたは希望サイズの場合) のメディア タイプを提供することによって、これらのカラー フォーマットおよびディメンジョン能力を公開する。GetStreamCaps を使って次に公開するペアは、最小能力 640 × 480、最大能力 640 × 480、細分度 0 を組み合わせた 640 × 480 JPEG のメディア タイプとなる。3 番目のペアは、最小能力 160 × 120、最大能力 320 × 240、細分度 8 を持つ、 320 × 240 の 24 ビット RGB のメディア タイプである。このように、カードがサポートするほとんどすべてのフォーマットおよび能力を公開することができる。どのような圧縮フォーマットが提供されるかを知らなければならないアプリケーションは、すべてのペアを取得して、メディア タイプの一意なサブタイプのリストを作成することができる。

フィルタは、 VIDEOINFOHEADER 構造体の rcSource および rcTarget メンバからメディア タイプの転送元矩形および転送先矩形をそれぞれ取得する。フィルタは、転送元矩形および転送先矩形をサポートする必要はない。

IAMStreamConfig の解説で説明したクロッピング矩形は、出力ピンVIDEOINFOHEADER 構造体の rcSource 矩形と同じである。

IAMStreamConfig の解説で説明した出力矩形は、出力ピンの BITMAPINFOHEADER 構造体の biWidth および biHeight メンバと同じである。

フィルタの出力ピンが、空でない転送元矩形および転送先矩形を持つメディア タイプに接続されている場合、フィルタは、入力フォーマットの転送元サブ矩形を出力フォーマットの転送先サブ矩形に伸縮する必要がある。転送元サブ矩形は、VIDEO_STREAM_CONFIG_CAPS 構造体の InputSize メンバに格納される。

たとえば、以下のようなビデオ コンプレッサ シナリオを考えてみよう。入力イメージは RGB フォーマットで、160 × 120 ピクセルのサイズを持つ。転送元矩形の左上隅の座標は (20,20) で、その右下隅の座標は (30,30) である。出力イメージは、サイズが 320 × 240 の MPEG フォーマットである。転送先矩形の左上隅の座標は (0,0) で、その右下隅の座標は (100,100) である。この場合、フィルタは、160 × 120 RGB の転送元ビットマップの 10 × 10 部分を取り出して、それを 320 × 240 のビットマップの最初の 100 × 100 領域に埋め、320 × 240 ビットマップの残りの領域はそのままにしておかなければならない。以下の図にこの操作を示す。

転送元矩形と転送先矩形の間でイメージのサブ矩形を伸縮するビデオ コンプレッサ

フィルタがこのような操作をサポートしていない場合、rcSourcercTarget が空でないメディア タイプへの接続は失敗する。

VIDEOINFOHEADER 構造体は、フィルタのデータ レート能力に関する情報を公開する。たとえば、あるメディア タイプを持つ次のフィルタに (直接的に、または CMediaType::SetFormat 関数から渡されたメディア タイプを使用して) 出力ピンを接続したとする。そのメディア タイプの VIDEOINFOHEADER フォーマット構造体の dwBitRate メンバを見ると、ビデオの圧縮に使用すべきデータ レートがわかる。VIDEOINFOHEADER 構造体の AvgTimePerFrame メンバ内のフレームあたりのタイム単位数に dwBitRate メンバ内のデータ レートを掛け、その結果を 10,000,000 (1 秒あたりの単位数) で割ると、フレームあたりのバイト数を求めることができる。小さなサイズのフレームを生成することはできるが、大きなサイズのフレームは生成できない。ビデオ コンプレッサまたはキャプチャ フィルタのフレーム レートを求めるには、出力ピンのメディア タイプの AvgTimePerFrame を使用する。

オーディオ能力

オーディオ能力に関して、IAMStreamConfig::GetStreamCapsAM_MEDIA_TYPE 構造体と AUDIO_STREAM_CONFIG_CAPS 構造体のペアの配列を返す。ビデオの場合と同様に、これを使用してピンのすべての種類のオーディオ能力 (たとえばデータ レートやモノラルまたはステレオのサポートの有無) を公開することができる。

GetStreamCaps のビデオ関連の例については、「ビデオ能力」を参照すること。

毎秒 11,025、22,050、および 44,100 サンプルのサンプリング レート、8 ビットまたは 16 ビット モノラルまたはステレオの PCM (pulse code modulation) wave フォーマット (Microsoft® Win32® PCMWAVEFORMAT 構造体で示される) をサポートする場合を考えてみる。この場合、2 つの構造体ペアを提供する。1 番目のペアは、AUDIO_STREAM_CONFIG_CAPS 能力構造体を持ち、毎秒 11,025 サンプルの細分度 (細分度は、サポートされている値の差) で 1 秒あたり最小 11,025 〜 最大 22,050 サンプル、1 サンプルあたり 8 ビットの細分度で 1 サンプルあたり最小 8 〜 最大 16 ビット、最小 1 チャンネル、最大 2 チャンネルをサポートすることを示す。1 番目のペアのメディア タイプは、その範囲内のデフォルト PCM フォーマットとなり、22kHz、16 ビット ステレオとなる。2 番目のペアは、1 秒あたりの最小および最大サンプル数が 44,100、1 サンプルあたり 8 ビットの細分度で 1 サンプルあたり 8 ビット (最小) および 16 ビット (最大)、最小 1 チャンネル、最大 2 チャンネルを表す。このメディア タイプは、デフォルトの 44kHz フォーマットとなり、44kHz 16 ビット ステレオとなる。

非 PCM wave フォーマットをサポートする場合、このメソッドから返されるメディア タイプは、サポートする非 PCM フォーマット (デフォルトのサンプリング レート、ビット レート、およびチャンネル) を示し、そのメディア タイプに伴う能力構造体は、サポートするサンプリング レート、ビット レート、およびチャンネルを示す。

特定の出力タイプを保証するために入力を再接続する

フィルタは、ピンが接続される前にオーディオまたはビデオ ストリームのフォーマットを設定するために、IAMStreamConfig::SetFormat メソッドを実装する。また、出力ピンが既に接続されていて新しいタイプを提供できる場合は、ピンを再接続する。フィルタが接続されている先のピンがメディア タイプを使用できない場合、この呼び出しは失敗し、接続はそのままになる。

ピンがどのような出力タイプを提供するかわからない変換フィルタは、入力ピンが接続されるまで、すべての SetFormat 呼び出しおよび IAMStreamConfig::GetStreamCaps 呼び出しをエラー コード VFW_E_NOT_CONNECTED で拒否しなければならない。

入力が接続されていなくても、ピンが提供できるタイプがわかっている場合は、通常どおりにタイプを提示したり受け付けることができる。詳細については、「変換フィルタの接続」を参照すること。

場合によっては、確立済みの接続に対してフォーマットを提示するときにピンを再接続した方が便利なこともある。たとえば、24 ビットの RGB 入力があるときだけビデオをフォーマット X に圧縮できる一方で、8 ビット RGB 入力を圧縮フォーマット Y に圧縮できる場合、次の選択肢がある。

  1. GetStreamCaps および SetFormat を使用して常に X と Y の両方を提示および受け付ける。
  2. 入力が 24 として接続された場合だけフォーマット X を提示し、入力が 8 として接続された場合だけフォーマット Y を提示する。入力が接続されていない場合は、GetStreamCaps および SetFormat の両方を失敗させる。

どちらの方法を選んだとしても、次のような再接続を行うコードが必要になる。

// 手の込んだ再接続を行うためのオーバーライド。
//
HRESULT MyOutputPin::CheckMediaType(const CMediaType *pmtOut)
{
HRESULT hr;
    CMediaType *pmtEnum;
    BOOL fFound = FALSE;
    IEnumMediaTypes *pEnum;

    if (!m_pFilter->m_pInput->IsConnected()) {
return VFW_E_NOT_CONNECTED;
    }

    // メディア タイプが不正ではないことをすばやくチェックする。
    //
   
    // SetFormat があらかじめ呼び出されている場合、メディア タイプが一致
    // しなければこの呼び出しを失敗させる。
   
    // 通常どおりにこの出力タイプを受け付ける。特別な操作は必要ない。
    hr = m_pFilter->CheckTransform(&m_pFilter->m_pInput->CurrentMediaType(),
        pmtOut);
if (hr == NOERROR)
return hr;

    DbgLog((LOG_TRACE,3,TEXT("Can't accept this output media type")));
    DbgLog((LOG_TRACE,3,TEXT(" But how about reconnecting the input...")));
    
    // 入力ピンを再接続して、使用可能なタイプを探す。
    // 入力ピンに接続されるピンにより、必要なタイプに変換可能な
    // タイプがわかる場合もある。
    hr = m_pFilter->m_pInput->GetConnected()->EnumMediaTypes(&pEnum);
if (hr != NOERROR)
        return E_FAIL;
    while (1) {
        hr = pEnum->Next(1, (AM_MEDIA_TYPE **)&pmtEnum, &j);

    // すべて列挙型から。
    if (hr == S_FALSE || j == 0) {
break;
    }

    // ピンはこれらのタイプ間で変換を行えるか?
    hr = m_pFilter->CheckTransform(pmtEnum, pmtOut);

if (hr != NOERROR) {
DeleteMediaType(pmtEnum);
continue;
    }

    // OK。使用可能なタイプが提示された。いますぐ受け入れるか?
    hr = m_pFilter->m_pInput->GetConnected()->QueryAccept(pmtEnum);
    // No。
if (hr != NOERROR) {
DeleteMediaType(pmtEnum);
continue;
    }
    // OK。
    fFound = TRUE;
    DbgLog((LOG_TRACE,2,TEXT("This output type is only acceptable after
                                reconnecting the input.")));

    // すべて完了。
DeleteMediaType(pmtEnum);
break;
    }
    pEnum->Release();

    if (!fFound)
        DbgLog((LOG_TRACE,3,TEXT("*NO! Reconnecting the input won't help")));
    
    return fFound ? NOERROR : VFW_E_INVALIDMEDIATYPE;
}



HRESULT MyOutputPin::SetFormat(AM_MEDIA_TYPE *pmt)
{
HRESULT hr;
    LPWAVEFORMATEX lpwfx;
    DWORD dwSize;

    if (pmt == NULL)
return E_POINTER;


    // ストリーミングが開始/停止の途中でないことを確認する。
    CAutoLock cObjectLock(&m_pFilter->m_csFilter);

    if (m_pFilter->m_State != State_Stopped)
    return VFW_E_NOT_STOPPED;

    // 可能な出力フォーマットは入力フォーマットに依存する。
    if (!m_pFilter->m_pInput->IsConnected())
return VFW_E_NOT_CONNECTED;

    // このフォーマットは既に使用している。
    if (IsConnected() && CurrentMediaType() == *pmt)
return NOERROR;

    // このタイプが使用可能かどうかを調べる。
    if ((hr = CheckMediaType((CMediaType *)pmt)) != NOERROR) {
    DbgLog((LOG_TRACE,2,TEXT("IAMStreamConfig::SetFormat rejected")));
return hr;
    }

    // 別のフィルタに接続する場合は、そのフィルタが当該タイプを受け付けるか確認する。
    if (IsConnected()) {
    hr = GetConnected()->QueryAccept(pmt);
if (hr != NOERROR)
        return VFW_E_INVALIDMEDIATYPE;
    }

    // 以降、これが唯一許されるフォーマットであり、これ以外の
    // フォーマットは上記の CheckMediaType コードで拒否することに注意。

    // フォーマットの変更は、必要に応じて再接続することを意味する。
    if (IsConnected())
        m_pFilter->m_pGraph->Reconnect(this);

return NOERROR;
}


// 手の込んだ再接続を完了するためにオーバーライド。
//
HRESULT MyWrapper::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
{
HRESULT hr;

    // OUTPUT タイプを設定する。
    if (direction == PINDIR_OUTPUT) {

    // 手の込んだ再接続の一部として、入力ピンは、
    // 別のタイプに再接続せずには提供できないメディア タイプを
    // 提供するように要求される。
    if (m_pInput && m_pInput->IsConnected()) {

        // ピンがこのタイプを今実際に提供できる場合は問題ない。
            hr = CheckTransform(&m_pInput->CurrentMediaType(),
                    &m_pOutput->CurrentMediaType());
if (hr == NOERROR)
return hr;
    
                DbgLog((LOG_TRACE,2,TEXT("*Set OUTPUT requires RECONNECT of INPUT!")));

        // 入力ピンを再接続する。
        return m_pGraph->Reconnect(m_pInput);

    }

return NOERROR;
    }

return NOERROR;
}