x264のYUV4:4:4/RGB、AviUtlのYC48とYUY2入出力の仕様

 2ちゃんねるのx264 rev32スレッドが珍しく賑わっているので元を辿ってみると、どうやらx264にRGBやYUV4:4:4(以下コロン省略)エンコーディングがサポートされた事による書き込みだったようです。

 RGBやYUV444エンコーディングは、RGB/YUV444データとして私たちが入手可能なもの(身近なものではゲーム機の映像をRGBまたはYUV444キャプチャ)をそのままの画素情報で処理するという点において最大の効果を発揮します。YUV422/YUV420といった色差情報の間引きでゲームグラフィックスの色が抜けたり滲んだりする現象をピクセルデータ的には防げます(それ故にYUV420(YV12等)と比べるとピクセルデータ量が多いため、圧縮後のサイズが大きくなりやすい)。 

 AviUtlのプレビューはYC48をRGB変換しているため、若干綺麗なプレビューを見られるものの、それはあくまで「YC48上のデータをRGB各8bitに変換した映像」を見ているに過ぎず、このあたりはきっちり把握しておく必要があります(裏を返せばYC48のアドバンテージでもあり、H.264@High10といった各8bit以上(10bit等)を要求されるシーンで威力を発揮しやすい。例えばx264guiExなど)。

可逆・不可逆に関しては、元データの色空間やピクセルフォーマットを維持(して圧縮・展開)できるか否かであるため──

  • オリジナルデータがRGB24の場合
  • > UtVideoを使いRGB24で圧縮・展開→可逆
    > 無(非)圧縮RGB24で入出力→可逆
    > UtVideoを使いYUV420で圧縮・展開→非可逆(YUVへの色空間変換が入り、更にYUV420変換で色差情報が1/4に損失)

  • オリジナルデータがYUV420(YV12等)の場合
  • > UtVideoを使いRGB24で圧縮・展開→非可逆(色空間変換によるもの)
    > 無(非)圧縮YUV420で入出力→可逆
    > UtVideoを使いYUV420で圧縮・展開→可逆

    という具合に「元映像が何であるか」によって異なります。ゲーム映像をRGBキャプチャしたデータならx264のYUV420ロスレスでも非可逆データになりますし、放送映像やBD等のYUV420を元とするなら可逆になります(圧縮codecは、圧縮による可逆・非可逆性なのか、色空間変換等によるものか切り分けないと話が噛み合わなくなる)。

    AviUtl入出力の特徴と内部フォーマットの可逆性

     AviUtlはYUV色空間の入出力にYUY2しか扱えません。YUV420(YV12)等のアクセスは外部codecにYUY2変換を要求します。例えば、YV12 Codecの映像をAviUtlに放り込むと、

  • YV12ファイル→CodecがYUY2へ変換(YV12→YUY2)→AviUtl(YUY2入力)
     
  • 出力時は逆で

  • AviUtl(YUY2出力)→CodecがYV12へ変換(YUY2→YV12)→YV12ファイル
  • という、処理行程を辿ります。もしもYV12 CodecがYUY2入出力をサポートしていない(もしくは対応Codecがシステムにインストールされていない)と、このように正常な表示ができません(このあたりがAviUtlの若干ややこしい部分であり、どういったcodecをインストールしアクセスされているか把握しないといけない部分。ただし、プラグインによる映像入出力では、内部形式YC48間の変換さえ実装できれば外部Codecに頼らずYV12を扱ったりYC48をそのまま受けたりもできる)。そして──

  • YUY2⇔YC48 / RGB⇔YC48 AviUtl内部のピクセルフォーマット変換は可逆
  • YV12→YUY2→YV12 外部codec依存だが、ピクセルフォーマット変換だけなのでcodec側が変な処理をしなければ可逆
  • ですので、「YUY2やYV12をAviUtlに通すとデータが変わる・劣化する」というのは誤りです。YUY2やYV12においても、入出力の色変換指定でミスをしなければ出力データの同一性は保たれます(プログレッシブ映像の場合)。

     ただし、インタレースなYUV420(YV12等)に限り、Codecがインタレースをサポートしていなければなりません。UtVideoがそれにあたりますが、可逆圧縮CodecであるためRawストリームの受け渡しはできませんし、aviコンテナに対して圧縮・展開できるのみです。例えば、AviSynthスクリプトをインタレースYV12で出力しても、インタレースYV12⇔インタレースYUY2で受け渡すRaw Codecが存在しないため、AviUtlではRawなインタレースYUV420(Raw Interlaced YV12等)を正常に受けられません。そのため、インタレースな生YUV420映像を受けるときに限り、予めInterlaced YUY2変換しておく必要があります(AviUtlでインタレースYUV420映像を扱うときのややこしい部分ですが、大抵はデコード側のフィルタがInterlaced YUY2変換をサポートしているので、あまり気にする事はありませんが)。

     以下に、カラーベクトルを可視化した元映像(UtVideoでYUV420圧縮)と、その元映像をAviUtlに入力・YV12保存(ストリームコピーではない)を10回繰り返した映像データがあります。プレビュー画像/映像データともにハッシュ値が完全一致し、AviUtlにYV12/YUY2映像を入出力してもピクセル情報が変化しない可逆性を証明しています(輪郭のジャギーに見える異なる色はYUV420化した際に抜け落ちたクロマ成分によるものですので、このテストにおいては気にしないでください)。



    ↑YV12の元映像
     


    ↑AviUtlで入力・保存を10回繰り返した映像


    ↑ハッシュ値。ファイル名末尾10が10回処理したデータ。
  • ダウンロード
  • AViUtl処理データ(末尾10が10回処理したもの。BT.709 ColorMatrix)
    UtVideo(可逆圧縮codec)

    MPEG-2 VIDEO VFAPI Plug-In の縦方向クロマ補間

    更新(2011/07/15):茂木氏より指摘のあった誤植を訂正

     茂木氏が公開している「MPEG-2 VIDEO VFAPI Plug-In」は、拡張子を aui に変更し、入力プラグインモードで動作させると出力がYUY2になります。VFAPIのまま使用すると問答無用でRGBにされるため、色空間変換による誤差を生じますが、入力プラグインモードであればYUV色空間のままMPEG-2のデコードデータが得られます。

     しかし、MPEG-2 VIDEO VFAPI Plug-In は、YUV420をYUV422(YUY2)にピクセルフォーマット変換する際、とくにインタレース映像で上下2ライン毎に互いのクロマ成分が入り込む現象を起こします。DGMPGDecもupConv=1でYUY2出力をすると同様なのですが、upConv=0でYV12出力してからAviSynthのConvertToYUY2(interlaced=true)、もしくはAutoYUY2()にてYUY2変換をすればそれなりに改善効果はあります。上下の色がハッキリと異なる領域でないと判りにくいため、殆どの映像ではパッと見気付かないレベルですが、方々で指摘されているとおり、今のところこういった状況にあるのは事実です(かといって、このYUY2変換が間違っているかというとそうではないため、誤解なさらぬよう)。以下に、テレビ埼玉のARIBカラーバーをデコードしたスクリーンショットを載せておきます。



    ↑DGMPGDecにてデコード(BT.709)。YV12出力後、AutoYUY2()


    ↑MPEG-2 VIDEO VFAPI Plug-In ver0.7.5(入力プラグインモード)でデコード(BT.709)。


    ↑カラーバーの右端(赤・青)部分をトリミングしてx2ズーム。MPEG-2 VIDEO VFAPI Plug-Inは、赤と青の境目で互いのクロマ成分が上下2ライン毎に潜り込んでいる。AviUtlであれば4:2:0補間フィルタで縦補間をすれば若干改善できる。

    これは、MPEG-2 VIDEO VFAPI Plug-In 側のYUY2変換であるため、AviSynth・AviUtlどちらで受けても同様の結果になります(デコーダ側のピクセルフォーマット変換であるためAviSynthやAviUtl側の問題ではない)。改善には、MPEG-2 VIDEO VFAPI Plug-In のYUY2変換改良、もしくはYUV420(YV12)出力機能の追加(AviSynthへの対応として)が考えられますが、このあたりは茂木氏の所思次第、といったところでしょうか。

    最後に、本文についての誤植や情報の誤りなどがございましたら、コメントにてご指摘いただけますと幸いです。

  • リンク
  • AviSynth
    AviUtl
    MPEG-2 VIDEO VFAPI Plug-In(まるも製作所)
    AviUtlの内部形式について

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    32 ÷ 8 =