« ニコエンコ v0.77を使う場合の注意点 | トップページ | ffdshow tryoutsにRGB24出力が復活。更に10bit/16bitのYUV出力も追加。 »

2011年11月25日 (金)

HuffyuvS(末尾にSがつくもの)は基本的に使わないほうが良いというお話

可逆圧縮コーデックとして有名なものに「Huffyuv」があります。

それを独自に改造したコーデックに「HuffyuvS」というものがあります。
本家と間違えやすいですが、末尾に「S」がつく別物です。
(おそらくこの「S」は「ストレート」の「S」だと思われます。)

※最後のSを小文字にして「Huffyuvs」と表記されることもありますが
  ここでは最後のSを大文字にした「HuffyuvS」という表記に統一します。
  (そもそもコーデックの設定画面などでも両方の表記が使われており統一されていません)

比較的初期のニコニコ動画まとめWikiでは、可逆圧縮コーデックの定番として
この「HuffyuvS」を勧めていましたが、現在では取り消されています。

aviutlを使ったVP6 2pass - ニコニコ動画まとめwiki
 
可逆圧縮コーデック「Huffyuv」を、コーデック内部のRGB-YUV変換が
ストレート変換になるように改造したもの。
この改造の意味がわからないまま使うと映像の色が大きく変わるという
結果を招くことがあるので、基本的には使うべきではない。

このページに書いてあるように、HuffyuvSの仕組みを理解しないまま使うと
映像の色が大きく変わるという結果を招くことがあるので、
動画編集ではHuffyuvSを使うのはやめたほうがよいでしょう。

また、現在入手できるHuffyuvS(huffyuvs_0.6_-_left_origin_-_base2.1.1-ccesp_dll.zip)は、
   「Huffyuv 2.1.1 CCESP Patch v0.2.2」
という、本家Huffyuv 2.1.1にパッチを当てたものをベースにしていますが、
このパッチ自体にも欠陥がありますので、あまり使うべきではありません。

以下、調べたことを書いていきます。

 
■色変化とその理由について

   実際にどのような色変化が起きるのかを示したのが下の画像です。
   上半分がオリジナル画像、下半分がHuffyuvSを使って色変化が起きた画像です。
   (画像クリックで別ウィンドウで開きます)

Huffyuvscolorchange

   
   下半分に黄色文字で示したのが、変化後のRGB値です。
     (0,0,0) → (16,16,16)
     (255,255,255) → (235,235,235)
     (16,180,16) → (28,171,27)
   など、色が変わってしまっていることがわかります。
   コントラストが低くなっている感じですね。
   デフォルト設定のままAviUtlでHuffyuvSを使ってAVI出力し、
   そのAVIをプレイヤーで再生したり、NiVEやMMDの背景AVI読み込みで使ったりすると、
   このような色変化が発生してしまうことになります。
   
   色変化が起きるのは、
     「HuffyuvSのコーデック内部でのRGB⇔YCbCr変換はフルレンジ変換になっている」
   という仕様が原因です。

   RGB⇔YCbCr変換を行なう場合、一般的には

      RGB[0~255] ⇔ YCbCr [Y:16~235、Cb,Cr:16~240]

   という「YCbCr圧縮レンジ」での計算が行なわれます。

   これに対し、HuffyuvSの内部処理では、

      RGB[0~255] ⇔ YCbCr [Y:0~255、Cb,Cr:0~255]

   という「YCbCrフルレンジ」での計算が行なわれるようになっています。

     ※「圧縮レンジ」を「TVスケール」と表現したり
       「フルレンジ」を「フルスケール」「PCスケール」と表現することもあります。
       また、フルレンジへの計算のことを「ストレート変換」と呼ぶことがあり、
       おそらくそれがHuffyuvSの「S」の由来だと思われるのですが、
       この記事では「圧縮レンジ」「フルレンジ」という表現に統一します。

   例を上げて考えてみましょう。
   
     1.AviUtlの「環境設定→コーデックの設定」のHuffyuvSのところで
       「YUY2圧縮する」のチェックが入っているとする。
   
     2.RGBデータを読み込んでHuffyuvSでAVI出力する際、
       AviUtlはRGBデータをYUY2に変換し、そのデータをHuffyuvSに渡す。
       この時のRGB→YCbCr変換は、「圧縮レンジ」での変換となる。
       例えば、RGB(0,0,0)は、YCbCr(16,128,128)となる。
   
     3.HuffyuvSは受け取ったYUY2データをそのまま圧縮する。
   
     4.出力したAVIを再生すると、HuffyuvSがデコード時にYUY2→RGB変換を行いRGBで出力する。
       この時のYCbCr→RGB変換は、「フルレンジ」での変換となる。
       この変換により、YCbCr(16,128,128)は、RGB(16,16,16)となる。
   
   このような流れにより、本来は圧縮レンジであるデータをフルレンジとしてデコードしてしまうため、
   RGB(0,0,0)がRGB(16,16,16)に変化してしまうことになります。

   問題が発生する重要なポイントは画像や上の説明にも書いたとおり、
      「圧縮レンジのYUY2データをHuffyuvSがフルレンジデータと解釈してRGBに変換している」
   というところです。
   仕組みを理解していれば、このようなことがないように扱えばよいだけですが、
   うっかりすると色変化が起きてしまうリスクがあるわけですので、基本的に使わないほうが良いでしょう。

■「Huffyuv CCESP Patch」について

   CCESPとは、「Cinema Craft Encoder SP」というMPEG2エンコードソフトです。
   当時(2002年頃?)は、キャプチャしたデータをHuffyuvで圧縮し、
   それをCCESPに読み込んでMPEG2にエンコードする人が多かったようです。
   当時198000円もするソフトだったようですが、当時のログを読むと
   クラック版(いわゆる「割れ」)を使う人もいたようですね・・・。

   まあそれはおいとくとして、オリジナルのHuffyuv 2.1.1とCCESPは相性が悪かったらしく、
   YUY2圧縮したデータをYUY2のままCCE-SPに渡すと映像がおかしくなってしまっていたようです。
   それに対処するついでに機能追加なども盛り込んだパッチが「CCESP Patch」だったようですね。

■Huffyuv CCESP Patch 0.2.2の問題点

   最初に書いたように、現在入手できるHuffyuvSは、
      「Huffyuv 2.1.1 CCESP Patch v0.2.2」
   という、本家Huffyuv 2.1.1にパッチを当てたものをベースにしています。

   このパッチでの修正内容の1つに、
     「Field Thresholdの設定機能の追加」
   という項目があります。
   Field Thresholdというのはフィールド閾値といって、
     「縦解像度がこの値を超えてる場合はインターレース映像と判断してエンコードしますよ(※1)」
   という数値のことです。
   本家Huffyuv 2.1.1ではこの値は内部で288に固定されていたのですが、
   CCESP Patch v0.2.2では自由に設定できるようになったわけですね。

     ※1・・・インターレースと判断した場合、フィールド毎に映像をまとめてから圧縮し、
          圧縮効率を高めているようです。
          分離したフィールドを横並びにして圧縮しているという感じですかね。
          詳細についてはMultiedia Wikiの解説がわかりやすいです。
          要するに、インターレース映像の場合はField Thresholdの値を縦解像度より小さくし、
          プログレッシブ映像の場合はField Thresholdの値を縦解像度の値より大きくすれば
          圧縮効率が高まるだろうということです。
          UtVideoコーデックでも「インターレース映像として圧縮する」という
          設定がありますが、これも同じような処理だと思われます。

   しかし、CCESP Patch v0.2.2では、このField Thresholdの扱いに問題があります。
   設定したField Thresholdの値は、システムフォルダの中にある「huffyuvs.ini」というファイルに
   保存されるようになっており、エンコード時もデコード時も、このファイルに書かれている
   Field Thresholdの値を参照して、「インターレースかどうか」の判断を行なっているのです。
   これにより
     「エンコード時とデコード時とで異なるField Threshold値を設定していると
      まともにデコードできないことがある。」

   という問題が発生します。
   
   例えば、上でサンプルとして使った解像度640x360のカラーバー画像を
   Field Thresholdを288に設定してエンコードし、それを

     「コーデックの設定でField Thresholdの設定値を480とした状態」

   で再生すると、下のように完全に崩壊した画像になります。

Huffyuvsthresholderror

 
   エンコード時は
     「縦解像度360はField Threshold値の288より大きいからインターレースだな」
   と解釈してエンコードしたのに、デコード時には
     「縦解像度360はField Threshold値の480より小さいからプログレッシブだな」
   と解釈してデコードするため、結果がおかしくなるわけですね。
   
   まあField Thresholdの値を変えずに使っていれば問題はないのですが、
   欠陥には違いないのでなるべく使わないに越したことはないでしょう。
   
   なお、その後リリースされた
     「Huffyuv 2.1.1 CCESP Patch 0.2.5」
   では、Field Thresholdのiniファイルへの保存をやめ、そのかわり圧縮データ内に
   インターレースフラグを設定するようになっており、この問題は発生しなくなっているようです。
   このパッチをあてたHuffyuvは、Doom9からダウンロードすることができます。
   
   これとは別にHuffyuv 2.2.0というのもありますが、RGB圧縮に致命的なバグがあるので使わないほうがよいでしょう。
   また、ffmpeg系ではHuffyuvを独自に拡張し、YV12での圧縮もサポートしているようです。
   
   もっとも、今なら可逆圧縮コーデックにはUtVideo Codec Suiteを使うのが良いでしょうから、
   あえてHuffyuvシリーズを使う必要はあまりないでしょうけど。

■「HuffyuvS」が作られた経緯など

   HuffyuvSは、2002/11/27に、2ちゃんねるの「CCE-SP情報スレ2のレス182」で
   vmaker氏によって公開されたコーデックのようです。
   元々は本家Huffyuv 2.1.1ベースでしたが、2003/02/14に別のスレ
   CCESP Patch v0.2.2ベースのものもリリースされました。
   ただ、残念ながらHuffyuvSを公開していたvmaker氏のサイトは
   2003年5月頃に閉鎖してしまったようです。
   公開期間はわずか半年ほどだったのですね。

   当時、CCE-SPでMPEG2にエンコードするまでの編集過程では、
   TMPGEncやAviUtl 0.98dなどが利用されていたようです。

   当時のTMPGEncはRGB入力しか受け付けなかったようです。
   (現在のTMPGEncがどうなっているのかはよく知りませんが。)
   また、AviUtl 0.98dは、
     「出力時にYC48→YUY2変換をする際、YCbCrの値をY:16~235、
      Cb,Cr:16~240の範囲に飽和させる(範囲外の値は境界値にされる)」
   という仕様になっており、この飽和処理はあまり歓迎されていなかったようです。
   (0.99以降はこの飽和処理をするかどうかを「システムの設定」で設定できるようになっています)
   
   そのあたりの事情もあって、どうしても編集途中でRGB⇔YCbCr変換をはさむことがあり、
   そのあたりの改善を求めてフルレンジ変換を行なうHuffyuvSが登場したようなのですが、
   当時のスレのログを読んでみたものの、なんだか混沌としておりよくわからず、
   vmaker氏のサイトにあったという解説文も今では見つかりませんでしたので、
   いまいち有用性が理解できませんでした。

   HuffyuvSを作った目的について、作者のvmaker氏は以下のように発言しています。

★◆キャプチャ&エンコード 質問、情報交換スレ◆4
 

348 : ◆S/VMAKER3c :03/04/29 00:04
huffyuvSは、当初 ConvertYUY の為だけに存在してたんだったりします。
つまり、TMPGEnc の出力を YUY2で保存して中間ファイルにする時に、
何度でも通せるようにしたかったのです(ぉぃ

 
   まるもさんのITU-R BT.601の解説ページの「PCでの取り扱い方」によると
   フルスケール変換(当記事で言うフルレンジ変換)は、
   
     YUV -> RGB -> YUV -> RGB と変換を繰り返した場合の画質の変化が
     最小限に抑えられるという利点もあります。

   
   とのことです。
   また、当時まるもさんが検証を行なって書き込んでおられたようですので、そちらも貼っておきます。
   (検証データは現在は消滅しているようです)

YC伸張する?しない?総合スレッド

381 : ◆XPRMtj3vAA :03/05/01 17:38
>>375
http://ime.nu/www.marumo.ne.jp/bt601/yuvcheck.lzh
ストレートでの YUV->RGB->YUV の誤差とか RGB->YUV->RGBの誤差とか
圧縮・伸張での YUV->RGB->YUV の誤差とか RGB->YUV->RGB の誤差とか
 
RGB 変換後オーバーフローしない範囲内ならば、ストレートも圧縮・伸張も
YUV->RGB->YUV 共に誤差 0。オーバーフローするケースだと、ストレートが有利。
 
とまあ、そんな結果になります。
 
アーカイブの中のプログラムは浮動小数点で精度を最大限取れるように
計算 してるから、Huffyuv/HuffyuvS の MMX 実装でどうなるかは不明です。
多分傾向は変わらないんじゃないかと思いますけど。
 
YUV 絶対主義の方(多分居ないと思うけど)はそもそも 234 の言うように
RGB になんて変換してはいけません。どっちでもオーバーフローしますから。
 
382 :381 ◆47o/marumo :03/05/01 17:41
トリップミスかっこ悪ぃ。

 
■備考

   ●HuffyuvSの設定画面の「RGB compression method」で「Convert to YUY2」を選び、
     RGBのデータを渡すと、HuffyuvSは内部でRGB→YUY2変換を行なってから
     そのYUY2データを圧縮します。
     オリジナルのHuffyuv 2.1.1では、この時の処理は

        ・色差は左右のピクセルの平均値を採用
        ・YCbCr圧縮レンジに変換

     という内容になっていますが、HuffyuvSでは

        ・色差は左ピクセルの値を採用(left origin)
        ・YCbCrフルレンジに変換

     という処理になっています。
     フルレンジになっているのは上に書いたとおりですが、
     色差のサンプリングがleft originになっているのもHuffyuvSの特徴です。

   ●HuffyuvSに限った話ではありませんが、Huffyuvシリーズをインストールする時に使う
     infファイルは、
       ・64bit環境などに対応していない(まあ古い物ですし仕方ない)
       ・アンインストールがうまくいかない
        (修正方法が書かれているサイトは色々あるけどどれが正しいのかよくわからない)
     という欠点があるようです。
     記事内にも書きましたが、いまさらHuffyuvシリーズを使うメリットはないと思うので、
     インストーラ付きで64bitやMacにも対応しているUtVideo Codec Suiteなどを使ったほうがよいでしょう。

 
■関連リンク

  CCE-SP情報スレ2みみずん検索過去ログ

  ◆キャプチャ&エンコード 質問、情報交換スレ◆4みみずん検索過去ログ

  ★YC伸張する?しない?総合スレッドみみずん検索過去ログ
  
  huffyuvで劣化知らず

  huffyuvs、huffyuvの改良版
  
  CINEMA CRAFT ENCODER BasicのFAQ

 

|

« ニコエンコ v0.77を使う場合の注意点 | トップページ | ffdshow tryoutsにRGB24出力が復活。更に10bit/16bitのYUV出力も追加。 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1278146/43140219

この記事へのトラックバック一覧です: HuffyuvS(末尾にSがつくもの)は基本的に使わないほうが良いというお話:

« ニコエンコ v0.77を使う場合の注意点 | トップページ | ffdshow tryoutsにRGB24出力が復活。更に10bit/16bitのYUV出力も追加。 »