MPEG デコーダの前処理変換
レターボックスとパン-スキャン
4x3 イメージを作成するには、イメージの上下をパディングするか (レターボックス イメージと呼ばれる)、イメージの 4x3 部分を抽出する (パン-スキャン イメージと呼ばれる)。メニューとサブピクチャ ストリームは最終ビデオ イメージの上にオーバーレイされる。16x9 アスペクト比のイメージは 4x3 変形フォーマットで保存される。変形 4x3 アスペクト比の 720x480 ソース ビデオを 16x9 アスペクト比に引き延ばすと、元の 16x9 アスペクト比のイメージになる。
次に、各モードとそのハイライト領域を正しく表示する方法について記述する。
- ワイドスクリーン : 出力ウィンドウの最大の 16x9 領域に引き延ばされたソース ビデオ。ハイライト領域は 16x9 領域の内側に比例する。ブラック バーを上下または左右に追加して 16x9 領域を保持する必要がある。
- パン-スキャン : 16x9 ビデオから MPEG2 ストリームで提供されている水平オフセットを使い、4x3 サブウィンドウを抽出する。4x3 サブウィンドウを出力クライアント ウィンドウの最大の 4x3 領域に置く。ハイライト領域の座標は、4x3 出力ウィンドウに比例し、16x9 ソース ビデオとは関係ない。ブラック バーを上下または左右に追加して 4x3 領域を保持する必要がある。
- レターボックス : 出力ウィンドウの最大の 4x3 領域を計算する。ブラック バーを上下または左右に追加して 4x3 領域を保持する必要がある。変形 4x3 ソース ビデオ (16x9 イメージを表す) は、4x3 領域内部の最大の 16x9 領域に置く。ブラック バーをサブウィンドウの上下に追加して 16x9 領域を保持する必要がある。ハイライト領域の座標は、4x3 領域に比例し、16x9 ソース ビデオとは関係ない。ディスクで、16x9 領域の外ではあるが、4x3 ウィンドウの中にハイライト領域が表示されるように指定することが可能である。4x3 ビデオの場合は、ビデオを出力クライアント ウィンドウの最大の 4x3 出力領域に表示する。ブラック バーを上下または左右に追加して 4x3 領域を保持する必要がある。
DVD ナビゲータと VMR を使った MPEG 前処理
現在、デコーダには FORMAT_MPEG2_VIDEO メディア タイプ (フォーマット ブロックは MPEG2VIDEOINFO 構造体を指す) が渡される。出力ピンにデコーダは FORMAT_VideoInfo2 メディア タイプを生成する。そのフォーマット ブロックは VIDEOINFOHEADER2 構造体を指す。VIDEOINFOHEADER2 の dwReserved フィールドは dwControls フラグに名前が変更される。新しい定義 (dvdmedia.h 内) は次のようになる。
typedef struct tagVIDEOINFOHEADER2 {
RECT rcSource;
RECT rcTarget;
DWORD dwBitRate;
DWORD dwBitErrorRate;
REFERENCE_TIME AvgTimePerFrame;
DWORD dwInterlaceFlags; // AMINTERLACE_* 定義を使う。
// 未定義ビットが 0 ではない場合、接続を拒否する。
DWORD dwCopyProtectFlags; // AMCOPYPROTECT_* 定義を使う。
// 未定義ビットが 0 ではない場合、接続を拒否する。
DWORD dwPictAspectRatioX; // 画像のアスペクト比の X ディメンジョン。
// たとえば 16x9 表示の 16。
DWORD dwPictAspectRatioY; // 画像のアスペクト比の Y ディメンジョン。
// たとえば 16x9 表示の 9。
union {
DWORD dwControlFlags; // AMCONTROL_* 定義を使う。
// 以降はこの値を使う。
DWORD dwReserved1; // 下位互換性のため。
//(必ず 0 にする。それ以外の場合、
// 接続は拒否される。)
};
DWORD dwReserved2; // 必ず 0 にする。それ以外の場合、接続は拒否される。
BITMAPINFOHEADER bmiHeader;
} VIDEOINFOHEADER2;
VIDEOINFOHEADER2.dwControlFlags には新しいビットが含まれる。
AMCONTROL_USED | 0x00000001 |
AMCONTROL_PAD_TO_4x3 | 0x00000002 |
AMCONTROL_PAD_TO_16x9 | 0x00000004 |
AMCONTROL_USED は、これらの新しいフラグがサポートされているかどうかを確認するときに使う。ソース フィルタは AMCONTROL_USED フラグを設定し、QueryAccept(MediaType) がダウンストリーム ピンで成功しているかどうかを調べる必要がある。拒否された場合、AMCONTROL フラグは使えず、dwReserved1 は 0 に設定する必要がある。
AMCONTROL_PAD_TO_4x3 は、イメージをパディングし、4x3 領域に表示することを示す。
AMCONTROL_PAD_TO_16x9 は、イメージをパディングし、16x9 領域に表示することを示す。
デコーダはビットをそのままコピーするか、または処理する。デコーダ自体がレターボックス化する場合は、ピクセル アスペクト比を変更し、イメージをパディングして、対応する AMCONTROL_* ビットを削除する必要がある。
MPEG2VIDEOINFO.dwFlags には、コンテンツの表示方法を制御する 3 つのフラグを含まれている。
AMMPEG2_DoPanScan (0x00000001)
: このフラグを設定すると、MPEG-2 ビデオ デコーダは picture_display_extension のパン-スキャン ベクトルに基づき、出力イメージをトリミングし、画像のアスペクト比を 4x3 に変更する。このフラグでは、VMR は 16x9 サンプルを受け取らない。簡単な実装によって転送元矩形を変更し、左端が picture_display_extension のディスプレイ オフセットに等しい、540 ワイド ソース領域を示せる。AMMPEG2_LetterboxAnalogOut (0x00000020)
: ハードウェア デコーダがこのストリームをビデオ出力 (通常はカード上の SVIDEO コネクタ) に表示するとき、4x3 ディスプレイに 16x9 サンプルを表示する規則が適用される。ソフトウェア デコーダ (または VMR に送信される出力を生成するハードウェア デコーダ) には、イメージを処理するとき、次の 2 つのオプションがある。
- 1) このフラグを無視し、VideoInfoHeader2 のコンテンツを VMR に渡す (サンプルでは、DVD ナビゲータにより AMCONTROL_PAD_TO_4x3 フラグがあらかじめ設定される)。VMR は、AMCONTROL_PAD_TO_4x3 フラグが設定された 16x9 ビデオ サンプル、および 4x3 サブピクチャ ストリームを取得する。アプリケーションは、2 つのストリームの正規化した出力転送先矩形が同じ幅になるように設定する必要がある。
- 2) イメージの上下をパディングし、イメージのアスペクト比を 4x3 に設定し (上記のレターボックスを参照すること)、VIDEOINFOHEADER2 から AMCONTROL_PAD_TO_4x3 ビットを削除して、変形ストリームを 4x3 イメージに変換する。
ビデオとサブピクチャ ストリームをブレンドする DirectXVA デコーダは、このフラグを処理する必要がある。ハードウェアがブレンドされたサブピクチャをスケールできない場合、デコーダは VMR がビデオとブレンドするように、別のサブピクチャ ストリームを生成する必要がある。
AMMPEG2_WidescreenAnalogOut (0x00000200)
: ハードウェア デコーダがこのストリームをビデオ出力 (通常はカード上の SVIDEO コネクタ) に表示する場合は、16x9 (変形) 表示を想定する。ソフトウェア デコーダ (または VMR に送信される出力を生成するハードウェア デコーダ) には、変形イメージを処理するとき、次の 2 つのオプションがある。
- このフラグを無視し、VideoInfoHeader2 のコンテンツを VMR にコピーする。AMCONTROL_PAD_TO_16x9 が設定されている場合、VMR は 4x3 イメージを 16x9 にパディングする。
- 出力イメージを 16x9 イメージにパディングし、AMCONTROL_PAD_TO_16x9 ビットを削除する。
ほとんどのデコーダは GetMediaType を使って、入力ピンのメディアの変更を検出し、VIDEOINFOHEADER2 のコンテンツ (MPEG2INFOHEADER に含まれる) を出力ピンにコピーする。パン-スキャン ビットのみを処理することが多い。
次のサンプル コードは、VIDEOINFOHEADER2 のコンテンツを入力ピンから出力ピンにコピーする方法を示している。
#include <dvdmedia.h>
HRESULT CopyMPeg2ToVideoInfoHeader2(CMediaSample* pInSample, CMediaSample* pOutSample)
{
HRESULT hr = S_OK;
// 入力サンプルのメディア タイプを調べる。
AM_MEDIA_TYPE* pInType;
if (pInSample->GetMediaType(&pInType) == S_OK)
{
// MPEG2 ビデオ フォーマットであることを確認する。
if ((pInType->formattype == FORMAT_MPEG2_VIDEO) &&
(pInType->cbFormat >= sizeof(MPEG2VIDEOINFO)))
{
hr = S_OK; // CMediaType コンストラクタの hr を初期化する。
CMediaType outType(*pInType, &hr);
if (FAILED(hr))
{
DeleteMediaType( pInType );
return hr;
}
// フォーマット タイプ GUID を設定する。
outType.SetFormatType(&FORMAT_VideoInfo2);
// VIDEOINFOHEADER 部分のみを含むようにフォーマット ブロックを切り詰める。
MPEG2VIDEOINFO *pMPeg2Header = (MPEG2VIDEOINFO*)pInType->pbFormat;
BYTE *pVIH = (BYTE*)&pMPeg2Header->hdr;
hr = (outType.SetFormat(pVIH, sizeof(VIDEOINFOHEADER2)) ? S_OK : E_OUTOFMEMORY);
if (SUCCEEDED(hr))
{
hr = pOutSample->SetMediaType(&outType);
}
}
else
{
ASSERT(FALSE); // MPEG2 ヘッダーではない。
hr = VFW_E_INVALIDMEDIATYPE;
}
DeleteMediaType( pInType );
}
return hr;
}