2010年11月26日金曜日

mod16

およそ動画系の話題を扱うforumであればたまに出てくる話題に"mod16"なるものがある。
そう、「動画の解像度は縦横ともに16の倍数にすべきである」ってやつですな。
これは正しいといえば正しいが、正しくないといえば正しくない。
とりあえず事実だけを言うのであれば「(mpeg系のエンコーダーは)解像度が16の倍数でないと圧縮出来ない」になるだろう。

mpeg系エンコーダー(そしてこれらの影響を受けているH.263とかVPxとか)は、まず映像を左上を原点にとって16x16のMB(マクロブロック)の集まりに分割してから動き検索やらDCT(離散コサイン変換)やらを行う。
規格によっては16x16のMBをさらに4x4に分割したり8x8とか8x16とかにも分割したりするが(SMB:サブマクロブロック)、とりあえず一回16x16で分割しないことには何も始まらない。
さあ、16x16の集まりに分割するのだ。

でも、たとえば642x484なんていう解像度を圧縮する場合はどうすればいいのよ?
右端の2x16とか下端の16x4とか一番右下の2x4は処理できないじゃん。
困るよ、おい。

これを何とかするため、16の倍数になっていないものの場合はエンコーダーの内部でpadding(パディング)なるものが行われるようになっている。
paddingを英和辞典で引けば「詰め物」とかそういった感じの意味で載っているだろう。
つまり、本来存在しない映像をを付け足して、16の倍数になるようにするわけだ。642x484であれば、映像の右端に幅14ピクセル、下端に幅12ピクセルのダミーをくっつけて656x496にしてしまう。
よーし、これで圧縮にとりかかれますな。

ところでこのpaddingされる映像ってどんなものなのか、知ってます?
黒ベタ? 灰色ベタ?
正解は右端および下端の縁の色です。
つまり、こんな感じ。
なんでこんな絵の具が垂れたみたいな感じに?
それは、このようにpaddingを行うのが一番、本来の映像に影響を与えずに圧縮できるから。
単色ベタ塗りは色々とまずいことがあるのですよ。色々ね。
もし自分でこのようなpaddingをしてみたければ、AviUtlなら「"縁塗りつぶし"を"縁の色で塗る"にチェックを入れて値をマイナスに設定」、AviSynthなら「"AddBorders"と"BorderControl"または"FillMargins"を併用」で可能です。
#padding.avs
AVISource("642x484.avi")
AddBorders(0,0,14,12)

#BorderControlの場合
LoadPlugin("BorderControl.dll")
BorderControl(XRS=14,YBS=12)

#FillMarginsの場合
LoadPlugin("FillMargins.dll")
FillMargins(0,0,14,12)

さて、これで圧縮は出来たけど、いざ動画を再生するときに、こんな変な部分まで表示されたら、それはそれで嫌ではないかな?
本来存在しないはずのものまで見えるのってうざいと思うよっつーかうざいんだよボケ。心霊写真じゃあるまいし。
そういう文句が出ることは分かりきっているので、paddingされたデータはまともなデコーダーならデコード時にはcropしてしまうようになっています。つまりさっきくっつけた右端14ピクセルと下端12ピクセルは表示されず、もとの642x484として表示される。
やれやれ、これにて一件落着。

でもね。
影響の少ないダミーによる水増しとはいえ、映像は642x484ではなく656x496の状態で圧縮されてるわけですよ。
解像度が大きければ、その分ファイルサイズも当然大きくなります。
もし640x480だったならばpaddingも必要なく、ファイルサイズも小さくなるだろうに…。
表示されない屑データのために膨れるなんて、そんな贅肉見苦しいんだよ、メタボだよ、ああむかつくこんちくしょう、うーんと、えーっと、そもそも水平2ピクセル、垂直4ピクセルくらいなら、削っちゃっても問題なくね?フフフそうだよそれくらい削っても気にならないだろ普通は、っつーかむしろ気にするやつのほうがおかしいだろ頭悪いだろキ○○イだろフヒヒヒヒええい削ってしまえバカヤローウギャー…orz

というわけで、やたら圧縮率にこだわる人であれば16の倍数になるようにするでしょう。
これが「動画の解像度は縦横ともに16の倍数にするべきである」の正体です。
まあ、もともと16の倍数になるように絵が作られていれば、こんな葛藤も起こらないわけで、それにこしたことはないんですが…はぁ(ため息)。

ちなみにたまに「mod16に出来ないならば、次善の策としてmod8(8の倍数)にするべきである」という人がいますが、これは迷信の類です。
mod16でなければpaddingは起こります。
そしてpaddingされるデータ量は、解像度を16で割った余りが16に近ければ近いほど小さくなります。
644x484、648x488、652x492という3種類の映像があったとすれば、ファイルサイズに対してpadding分のデータ量の占める割合は、644x484 > 648x488 > 652x492です。
つまりpaddingは少ないほどよいってことですね。
「652x492か。縦横12ずつ削るってのはさすがに嫌だよなあ…でも縦横4ずつくらいならそれほど嫌じゃないぞ。よし、648x488でmod8にしよう」
「それはつまり、大事な映像をわざわざ削った挙句に無駄になるデータを増やそうってことですかそーですか…手前の馬鹿さ加減にゃあ父ちゃん情けなくって涙出てくらぁ!!」(CV:東野英心)

あと、「mod16じゃないと、映像の端がゆがむ」という人もいますが、これもどうなんでしょうかね。
よっぽどひどいエンコーダーでもない限り、前述したような適切なpaddingを行っていれば、まず人間の目ではソースと並べて見比べてもなかなか視認出来るものではないはずなんですが。