次の方法で共有


非インターレースの設定

Video Mixing Renderer (VMR) はハードウェアによってアクセラレートされる非インターレースをサポートする。この機能は、インターレースされたビデオのレンダリング品質を改善する。実際に利用できる機能の詳細は、基になるハードウェアによって異なる。アプリケーションは IVMRDeinterlaceControl インターフェイス (VMR-7) または IVMRDeinterlaceControl9 インターフェイス (VMR-9) を介し、ハードウェアの非インターレース機能を問い合わせ、非インターレースを設定できる。非インターレースはストリーム単位で実行される。

 :  ここでは IVMRDeinterlaceControl9 のメソッドについて説明するが、VMR-7 の場合もほとんど同じである。

ビデオ ストリームの非インターレース機能を取得するには、次の作業を行う。

  1. VMR9VideoDesc 構造体にビデオ ストリームの説明を格納する。この構造体にデータを格納する方法については、後で説明する。
  2. IVMRDeinterlaceControl9::GetNumberOfDeinterlaceModes メソッドにこの構造体を渡す。メソッドを 2 回呼び出す。最初の呼び出しでは、ハードウェアが指定されたフォーマットにサポートしている非インターレース モードの数を返す。このサイズの GUID の配列を割り当て、配列のアドレスを渡してもう一度メソッドを呼び出す。2 回目の呼び出しにより、配列に GUID を入れる。各 GUID は 1 つの非インターレース モードを識別する。
  3. 特定のモードの機能を取得するには、IVMRDeinterlaceControl9::GetDeinterlaceModeCaps メソッドを呼び出す。同じ VMR9VideoDesc 構造体および配列の GUID の 1 つを渡す。このメソッドは VMR9DeinterlaceCaps 構造体にモード機能を格納する。

次のコードにこれらの手順を示す。

VMR9VideoDesc VideoDesc; 
DWORD dwNumModes = 0;
// VideoDesc 構造体にデータを入れる (省略)。
hr = pDeinterlace->GetNumberOfDeinterlaceModes(&VideoDesc, 
    &dwNumModes, NULL);
if (SUCCEEDED(hr) && (dwNumModes != 0))
{
    // モードを識別する GUID の配列を割り当てる。
    GUID *pModes = new GUID[dwNumModes];
    if (pModes)
    {
        // 配列にデータを入れる。
        hr = pDeinterlace->GetNumberOfDeinterlaceModes(&VideoDesc, 
            &dwNumModes, pModes);
        if (SUCCEEDED(hr))
        {
            // 各アイテムをループし、機能を取得する。
            for (int i = 0; i < dwNumModes; i++)
            {
                VMR9DeinterlaceCaps Caps;
                hr = pDeinterlace->GetDeinterlaceModeCaps(pModes + i, 
                    &VideoDesc, &Caps);
                if (SUCCEEDED(hr))
                {
                    // Caps 構造体を調べる。
                }
            }
        }
        delete [] pModes;
    }
}

アプリケーションは、次のメソッドを使ってストリームの非インターレース モードを設定できるようになった。

  • SetDeinterlaceMode メソッドは優先モードを設定する。非インターレースを無効にするには、GUID_NULL を使う。
  • 要求されたモードが利用できない場合、SetDeinterlacePrefs メソッドは動作を指定する。
  • GetDeinterlaceMode メソッドは設定された優先モードを返す。
  • GetActualDeinterlaceMode メソッドは実際に使用中のモードを返す。優先モードが利用できない場合は、フォールバック モードになることがある。

メソッドのリファレンス ページには、さらに詳しい説明が掲載されている。

VMR9VideoDesc 構造体の使い方

前に説明した手順で、最初に VMR9VideoDesc 構造体にビデオ ストリームの説明を格納した。初めに、ビデオ ストリームのメディア タイプを取得する。それには、VMR フィルタの入力ピンの IPin::ConnectionMediaType を呼び出す。次に、ビデオ ストリームがインターレースされているかどうかを確認する。VIDEOINFOHEADER2 フォーマットのみインターレースできる。フォーマット タイプが FORMAT_VideoInfo である場合は、必ずプログレッシブ フレームである。フォーマット タイプが FORMAT_VideoInfo2 である場合は、dwInterlaceFlags フィールドで AMINTERLACE_IsInterlaced フラグの有無を調べる。このフラグがある場合、ビデオはインターレース化されている。

変数 pBMI がフォーマット ブロックの BITMAPINFOHEADER 構造体へのポインタであると想定する。VMR9VideoDesc 構造体に次の値を設定する。

  • dwSize: このフィールドを sizeof(VMR9VideoDesc) に設定する。

  • dwSampleWidth: このフィールドを pBMI->biWidth に設定する。

  • dwSampleHeight: このフィールドを abs(pBMI->biHeight) に設定する。

  • SampleFormat: このフィールドはメディア タイプのインターレース特性について記述する。VIDEOINFOHEADER2 構造体の dwInterlaceFlags フィールドを調べ、SampleFormat を同等の VMR9_SampleFormat フラグに設定する。この処理を行うヘルパー関数を後で示す。

  • InputSampleFreq: このフィールドは入力周波数を示す。この値は VIDEOINFOHEADER2 構造体の AvgTimePerFrame フィールドの値から計算できる。一般には、dwNumerator を 10000000 に設定し、dwDenominatorAvgTimePerFrame に設定する。しかし、よく知られたフレーム レートを調べることもできる。

    フレームあたりの平均時間 フレーム レート (fps) 分子 分母
    166833 59.94 (NTSC) 60000 1001
    333667 29.97 (NTSC) 30000 1001
    417188 23.97 (NTSC) 24000 1001
    200000 50.00 (PAL) 50 1
    400000 25.00 (PAL) 25 1
    416667 24.00 (フィルム) 24 1
  • OutputFrameFreq: このフィールドは出力周波数を示す。この値は InputSampleFreq 値と入力ストリームのインタリーブ特性から計算できる。

    • OutputFrameFreq.dwDenominatorInputSampleFreq.dwDenominator と等しい値に設定する。
    • 入力ビデオがインターリーブされる場合は、OutputFrameFreq.dwNumerator を 2 × InputSampleFreq.dwNumerator に設定する (非インターレース化の後、フレーム レートは 2 倍になる)。それ以外の場合は、値を InputSampleFreq.dwNumerator に設定する。
  • dwFourCC: このフィールドを pBMI->biCompression に設定する。

次のヘルパー関数は AMINTERLACE_X フラグを VMR9_SampleFormat 値に変換する。

#define IsInterlaced(x) ((x) & AMINTERLACE_IsInterlaced)
#define IsSingleField(x) ((x) & AMINTERLACE_1FieldPerSample)
#define IsField1First(x) ((x) & AMINTERLACE_Field1First)

VMR9_SampleFormat ConvertInterlaceFlags(DWORD dwInterlaceFlags)
{
    if (IsInterlaced(dwInterlaceFlags)) {
        if (IsSingleField(dwInterlaceFlags)) {
            if (IsField1First(dwInterlaceFlags)) {
                return VMR9_SampleFieldSingleEven;
            }
            else {
                return VMR9_SampleFieldSingleOdd;
            }
        }
        else {
            if (IsField1First(dwInterlaceFlags)) {
                return VMR9_SampleFieldInterleavedEvenFirst;
             }
            else {
                return VMR9_SampleFieldInterleavedOddFirst;
            }
        }
    }
    else {
        return VMR9_SampleProgressiveFrame;  // インターレースされていない。
    }
}