動画圧縮を1から — 動き補償とGOP
1秒30枚の写真を別々に圧縮していては、いまの配信帯域にはまるで届きません。フレーム差分がなぜ破綻するのか、動き補償は何を送っているのか、I/P/BフレームとGOP、CBR・VBR・CRFが何を一定に保つのか。最後は配信担当が実際に決めるキーフレーム間隔まで降りていきます。
比喩: 「さっきと同じ、ただし左の人が一歩右へ」
防犯カメラの映像を電話越しに実況する仕事を想像してください。1秒に30回も画面全体を説明し直す人はいません。最初に一度「駐車場、白い車が3台」と伝えたら、あとは「さっきと同じ、ただし左の人が一歩右へ動いた」で済む。動画圧縮も突き詰めればこれだけです。
素朴に桁を確かめましょう。1920×1080は約207万画素。RGBなら1フレーム約6.2MB、30fpsで毎秒約186MB——約1.5Gbpsです。各フレームを独立にJPEGにして10分の1になるとしても150Mbps前後。実際の1080p配信は、多くの場合それより2桁ほど細い帯域に収まります。JPEGを何枚並べても、まるで足りない。
足りない分を埋めるのが時間方向の冗長性です。隣り合うフレームは30分の1秒しか離れておらず、ほとんどの画素は前と同じ値のまま残ります。静止画の圧縮が1枚の絵の中の冗長性を削るのに対し、動画はここを削る。削れる量は桁違いに大きい。
差分を送る、という発想
いちばん素朴な手は、前のフレームとの引き算を送ることです。
つまりこの式は、画素の位置ごとに「いまの値から、1フレーム前の同じ位置の値を引く」と言っているだけです。送るのは、引いて残った分だけでいい。
は時刻 のフレーム、 がその差分——「前回から何が変わったか」だけを描いた絵です。三脚のカメラで人が一人歩いているだけなら、絵はほぼ真っ黒で、人のまわりだけが光る。0ばかりの数列はよく縮みます。
ところがこの手は、カメラが動いた瞬間に破綻します。パンで画面が1画素ずれただけで、画面じゅうの輪郭が差分に現れる。被写体が動けば、元の場所と新しい場所の両方が差分に出ます。中身は同じで、ずれているだけです。
動き補償: 「どこから来たか」を送る
ずれているだけなら、ずらしてから引けばいい。これが動き補償です。
フレームをブロックに分け(H.264では16×16画素のマクロブロックが基本単位)、ブロックごとに「前のフレームのどこにいちばん似た絵があるか」を探します。そのずれが動きベクトル です。
つまり、引き算の相手を「前フレームの同じ位置の画素」から「そこから だけずらした位置の画素」に取り替えた、ということです。ブロックの中身が直前にいた場所から引くので、残るのは「ずらしただけでは説明しきれなかった分」になります。
右辺の第2項が「ずらして持ってきた予測」、左辺の が残差です。256画素のブロックが、2つの数字とわずかな残差で表せます。
大事なのは、ベクトルをどう探すかが規格の外側にある点です。規格が定めるのは伝え方と小数位置の補間だけ(多くのコーデックは2分の1・4分の1画素の精度で予測します)。探索半径を とすれば全探索は1ブロックあたり 回の比較——すぐ非現実的に膨らむので(計算量の記事でいう二乗の壁)、実装は階層探索や近傍ベクトルからの局所探索で削ります。同じ規格・同じビットレートでもエンコーダで画質が違うのは、主にここの差です。
残差もまた画像である
残差 とは、ただの画像です。予測が当たっていれば、ほとんどの画素が0付近に張り付いたのっぺりした絵になります。
ならば画像の道具がそのまま使えます。残差はブロック単位で周波数変換され(H.264以降は、エンコーダとデコーダで結果がずれないよう整数演算で定義されたDCT近似の変換)、量子化で丸められ、エントロピー符号化で詰められる。JPEGの記事と同じ道筋です。
違うのは入力だけです。動画の圧縮率が高いのは、変換や符号化が優れているからではなく、変換に入る前の絵がすでに空っぽに近いからです。
コメント
コメントにはログインが必要です