非インターレースの設定
Video Mixing Renderer (VMR) はハードウェアによってアクセラレートされる非インターレースをサポートする。この機能は、インターレースされたビデオのレンダリング品質を改善する。実際に利用できる機能の詳細は、基になるハードウェアによって異なる。アプリケーションは IVMRDeinterlaceControl インターフェイス (VMR-7) または IVMRDeinterlaceControl9 インターフェイス (VMR-9) を介し、ハードウェアの非インターレース機能を問い合わせ、非インターレースを設定できる。非インターレースはストリーム単位で実行される。
注 : ここでは IVMRDeinterlaceControl9 のメソッドについて説明するが、VMR-7 の場合もほとんど同じである。
ビデオ ストリームの非インターレース機能を取得するには、次の作業を行う。
- VMR9VideoDesc 構造体にビデオ ストリームの説明を格納する。この構造体にデータを格納する方法については、後で説明する。
- IVMRDeinterlaceControl9::GetNumberOfDeinterlaceModes メソッドにこの構造体を渡す。メソッドを 2 回呼び出す。最初の呼び出しでは、ハードウェアが指定されたフォーマットにサポートしている非インターレース モードの数を返す。このサイズの GUID の配列を割り当て、配列のアドレスを渡してもう一度メソッドを呼び出す。2 回目の呼び出しにより、配列に GUID を入れる。各 GUID は 1 つの非インターレース モードを識別する。
- 特定のモードの機能を取得するには、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 に設定し、dwDenominator を AvgTimePerFrame に設定する。しかし、よく知られたフレーム レートを調べることもできる。
フレームあたりの平均時間 フレーム レート (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.dwDenominator を InputSampleFreq.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; // インターレースされていない。
}
}