考察3 - 描画のズレ(動画)

 「黎明」の章で述べた通り、音ズレには「サウンドのズレ」「入力のズレ」「描画のズレ」があります。

 「描画のズレ」についてはすでに垂直帰線同期(VSync)などの要因を述べてきましたが、ここでは、3つのズレすべてに影響を与える動画について述べます。

Video for Windows - Cinepakで始まった動画付き譜面

 動画は、圧縮(エンコード)された画像データを解凍(デコード)しながら画面に描画するという処理を短時間にたくさん繰り返すため、非常に重たい処理となります。パソコンのバッテリーのベンチマークにも「動画の連続再生〇〇時間」と表記されるくらい電力を食う処理でもあります。

 HD動画で高精細!全画面表示!60fps!とは言っても、1 枚の画像を解凍し描画するのに何十㎳ もかかってしまうようでは、音ズレどころか処理落ちしてゲームになりません。

 Windows 95 以降では、動画を再生するためのVideo for Windows (VfW) という機能が標準で搭載されており、動画(BGV)に対応したばかりの DTXMania ではこれを使って動画を再生していました。

 繰り返しますが、とにかく動画の再生は重たい処理なのです。
 今みたいに、CPU をも凌駕する性能で動画の再生を支援してくれる高速な GPU もありませんでした。

 Video for Windows はいろんな形式の圧縮解凍機能(CODEC; コーデック)を使えましたが、DTXMania では、その中から Cinepak と MS-MPEG4v2 を標準のコーデックとして推奨しました。

 Cinepak は、セガサターンなどのコンシューマー機器でも採用されていたコーデックで、とにかく解凍が軽い。軽いんです。その代わり、画質は悪く、圧縮には時間がかかり、データサイズも巨大になります。しかしそれを補って余りある軽さ、シークや巻き戻しの速さは、大きな魅力でした。278×355 という DTXMania の超変則動画サイズにも素のままで対応していました。

 MS-MPEG4v2 は、Microsoft が独自に拡張した MPEG4 コーデックです。データサイズは小さく、圧縮も速く、それでいて画質は綺麗でしたが、当時の DTXMania でスクロールがガタつかないギリギリの重さのコーデックでした。当社比。

 当時は、1 つの DTX 譜面に対して、Cinepak 動画を付けた譜面(演奏用)と、MS-Mpeg4v2 動画を付けた譜面(観賞用)の 両方をわざわざ用意していたものです。

 DivX?
 ああ、インストーラーにスパイウェアが組み込まれていたってんで大騒ぎしてましたね。

DirectShow - Direct になり切れなかった新参

 Video for Windows の後継として登場したのが、ActiveMovie から名を変えて DirectX グループに編入されたものの 2005 年にはあっさり DirectX から除外されてまた独立するハメになったけど開発にはまだ DirectX SDK が必要なんだよという優柔不断さで噂の、あの DirectShow です。

 DTXMania は実に 2015 年までずっと Video for Windows を使い続けていたのですが、そのころには「Video for Windows で対応できないコーデックが増えてきている」「解像度が大きくなると途端に重くなる」「ハードウェアの恩恵を受けられない」などの事情から、DirectShow に乗り換える必要が迫っていました。

 そして、DTXMania 104(2015/12/12)でようやく動画が DirectShow 対応になり、Video for Windows が廃止されました。

 DirectShow による動画の軽量化への貢献は、大きく 2 つ挙げられます。

 ひとつは、解凍した動画フレームを、普通のメモリを介さず、ビデオメモリ(Direct3D)に直接描画できる機能があったことです。さすがは Direct ですね!

 もうひとつは、ffdshow というフリーウェアコーデックの存在です。これをパソコンにインストールしておくと、DirectShow で、多種多様なコーデックを使い、多種多様なフォーマットで出力することができるようになりました。さらに、ffdshow は DXVA(DirectX Video Acceleration)にも対応していたので、コーデック(一部に限られましたが)の重たい処理をハードウェア(GPU)で高速に行うことができました。

 自分でちまちま設定しないと機能しなかった(そして分かりづらかった)のですが、これはいいものでしたね!

☆   ☆   ☆

 しかし、結果として、DirectShow が Direct になることはありませんでした

 DirectShow には、ビデオメモリ(Direct3D)に直接描画するために、VMR(Windows XP 以降)や EVR(Windows Vista 以降)という専用のレンダリング機能(レンダラー)が備わっていたのですが、これがまた当時アホみたいな速さで成長していた Direct3D との相性が悪く、とてもまともに使うことはできませんでした。

 結局、DTXMania では、解凍(デコード)した画像をいったん普通のメモリに出力する MemoryRenderer という DirectShow レンダラーを利用し、それからちまちまと CPU でビデオメモリに転送する仕様に落ち着きました。当然重かったです。

 もし ffdshow が存在していなかったら、DirectShow には手を出さず、まだ Video for Windows で頑張っていたと思います。

Media Foundation - 這い寄りすぎた混沌

 Media Foundation は、Windows Vista で登場し、やがては DirectShow を置き換えるであろうと登場時から延々言われ続けているにも関わらず未だに陽が当たってない現役のマルチメディア(死語)API です。多機能である代わりに複雑すぎるんですこれ。

 H.264 フォーマットの爆発的な普及により、動画と言えば mp4 、という時代が来ていました。

 DTXMania が未だに Direct でない DirectShow を使って 275×355 という変則サイズの動画で頑張っていた中、DTXMania の派生版である DTXHD では、とうとう HD 動画の全画面表示が実現されました。

 この辺りから私も、DTXMania での「1280×720p, 60fps の H.264 動画の全画面再生」を目標にし始めていました。

 これを実現することは、DirectShow には荷が重すぎました。そこで、すでに名前は耳にしていたものの「ffdshowがあればええやん」とか思って敢えて見ないようにしていた Media Foundation の学習を始めることになります。

 Media Foundation は、Windows XP では動作しませんが、Windows Vista や Windows 7 では動作するので問題ない。

 と、そう思っていました。

ビデオプロセッシングという名の混沌

 Media Foundation の最大の特徴は、DXVA 2.0 に対応し、H.264 動画をハードウェア(GPU)で高速に解凍(デコード)できるという点と、解凍された画像データを普通のメモリを介して Direct3D にちまちま転送しなくても、GPU の内部だけで高速に転送してくれるという点でした。

 ところが、ffdshow ではできたことが、Media Foundation ではできませんでした。それは、解凍後の画像を RGB フォーマットで出力するということです。(正確には RGBX 32bit フォーマット。)

 Media Foundation が標準で搭載する Microsoft の H.264 コーデックは、解凍後の画像を NV12 フォーマットでしか出力できませんでした。いや確かに映像業界じゃ RGB よりも YUV なんでしょうけども(※ NV12 は YUV フォーマットの中の 1 つです)。Direct3D では RGB なんです。(※ Direct3D で NV12 がまともに使えるようになったのは、Direct3D11.4 からでした。つまり、実質は Direct3D12 です。)

 VfW や DirectShow のように出力が RGB で得られる場合は、画像をビデオメモリに転送するためには 1 ピクセルを読み込んでそのまま 1 ピクセルとして出力するという作業を行えば済みます。面積画素分だけ行うので数は膨大ですが。

 一方 NV12 では、Y, U, V という別々のプレーン(領域)からそれぞれ 1要素ずつ合計 12 ビットの情報を読み出し、RGBに変換するための行列演算を行い、さらに隣接ピクセルとの補間処理やインターレース解除処理などを行ってからようやく 1 ピクセルとして出力する、という非常にめんどくさい手続きを行う必要があります。しかも、こちらも面積画素分だけ行いますので数は膨大です。これはもう、GPU でプログラマブルピクセルシェーダを使って行うレベルの重たい処理です。

 実際には、Direct3D には Video Processing 機能というものがあり、これを使えば先ほどのような定型処理をハードウェアで行えるということは知っていました。ですが、実際にやってみると、その手順は非常に複雑でした。NV12 は何とかなりましたが、それ以外が出てきたらもうお手上げです。

 これには、かなりの期間悩みました。

☆   ☆   ☆

 いろいろ試行錯誤する中で、Media Foundation に直接 RGB フォーマットで出力させる方法がようやく見つかりました。

 それは、Media Foundation で画像データを出力する IMFSourceReader を拡張した IMFSourceReaderEx という機能を使うだけでした。前者は NV12 でしか出力できませんでしたが、いろいろと検証するうちに、後者では RGBA32 で出力する(Video Processing 機能を有効にして自動変換させる)こともできる、ということが判りました。RGBX32 ではなく RGBA32 なので、出力された動画の透明度も簡単に変えることができました。

 これで、DXVA2.0 を使った 1280×720p 60fps の動画の滑らかな表示が、現実のものとなりました。

 ただし、この IMFSourceReaderEx は Windows 8 以降でなければ利用できません。
 これは大きな壁でした。

 結果的に、DirectShow から Media Foundation への移行は、Windows 7 のサポートを続ける無印版の DTXMania ではなく、Windows 10 のみをサポートする DTXmatixx のほうで実現されることになりました。

マルチスレッドの壁

 実は、Media Foundation には、もっと大きな壁がありました。それは、Media Foundation は「MTAThread でしか動作を保証しない」ということです。簡単に言えば非同期処理(マルチスレッド)での動作が前提になるということです。(もう少し詳しく言えば、非同期のリアルタイムメッセージを大量に発出するから自分専用のメッセージキューを持たせてくれないと処理が間に合わないかもよということ。) これは、Direct3D との連携も非同期になるということを意味していました。

 Media Foundation は、RGBA32 画像を Direct3D に直接出力できます。しかし同期が取れなければ、例えば Media Foundation が画像を描画している最中に Direct3D がその画像を表示してしまうような事態も発生してしまいます。GPU は、このような競合(異常処理)が起きたときに例外を発生させて停止するような律儀な作法は持っていないので、同期に失敗した結果がどうなるかは不明です。

 そして、Media Foundation との同期は、Direct3D10 以降でしか行えません。Direct3D9 はマルチスレッドに対応していないためです

 結局、Media Foundation を使い、DXVA2.0 の恩恵を得て GPU 軽量にH.264動画を描画したいのであれば、Windows 10 と Direct3D11 の組み合わせへ移行することが必然となったのでした。