AV1 specification を読む (デコード処理の概要1:参考)


まだ本題に入ってきませんが、読み物としてよい出来だと思います。
codecについての一般的な理解の助けになると思います。


デコード処理の概要(参考)

本章の目的は、機能の簡単な紹介と、ビデオコーデックにあまり詳しくない読者のためのAV1仕様の説明です。
本章は、背景の説明をするだけで、仕様の必須部分ではありません。

AV1 の目的

この仕様は、ビデオシーケンスを蓄積・伝送する方法としてバンド幅効率が高い
AV1ビデオ圧縮フォーマットを定義します。
ビデオデータは非常に高バンド幅です。
例えば、幅1920高さ1080画素の秒間30フレームの動画です。
各ピクセルはおよそ12bit必要なので、そのバンドはbは1920 * 1080 * 30 * 12 = 746Mbits/sec になります。
AV1の目的は、このようなビデオを数桁小さいビットに圧縮して格納する方法を提供することです。

本仕様は、圧縮されたフレームのシーケンスを得るためのデコード処理について記述し、それを表示可能な伸長したビデオフレーム列に変換します。
AV1に適合するすべてのデコーダは、厳密に同じ方法で圧縮されたフレームをデコードしなければなりません。

ここではエンコード処理については記述しないことに注意してください。
フレームをエンコードする方法の選択肢はたくさん存在します。
元画像がどれだけ変更され人間の視覚に影響し、どれだけのビットを消費するのかは、その方法によって良くも悪くもなります。

画像データの圧縮

8bitの画像データを圧縮することを考えよう。
まずは、4x4グリッドの個々の画素について注目します。
とりあえず色については無視して、各画素は 0(黒)から255(白)の単一の値で表現します。

162 160 160 158
161 160 161 160
159 161 160 159
160 160 162 160

ここには16個の8bit値があるので、RAWデータとして 16*8=128bit が必要です。
しかし、この画像はとても平坦なので、この平坦な領域を160という1つの値で表現してしまっても、視聴者はそれほど違いを感じないかもしれません。
これなら8bitだけになります。

同様に、以下のような領域を考えてみましょう。

10 20 30 40
10 20 30 40
10 20 30 40
10 20 30 40

この場合、画像は左から右に少しずつ明るくなっていくので、何らかの方法でスロープを規定してやれば、16個すべての値をより少ないビットで表現できるでしょう。

AV1は、可逆変換を使って大部分の数値を小さくし、少数の数値を大きくしようとします。
このアプローチの要点は、2つの値(例えば162と160)について、その値の和と差(162+160=322, 162-160=2)をとることです。
デコーダが322と2という値を与えられたら、画素ペアの和と差は、2の除算 (322+2)/2=162, (322-2)/2=160 で得られます。
完全な変換では、画素ペアの和と差を取り、同様の演算を行にも列にも適用します。

この結果、16個の元画素は、16個の変換された値になります。
変換された値は正方形状ですが、その縦横軸は周波数を表現します。
もし、画像が平坦であれば、変換によって左上角(DC成分と呼びます)にだけ非ゼロ係数が存在します。
この変換は、似ている画素落ちを少数の非ゼロ変換係数にまとめられるので便利です。
そして、変換された係数は、通常元画像よりも少ないビットで表現できます。

量子化と非可逆圧縮

上の例では、ほとんど平坦な画像が、1つの大きなDC係数と、小さな他の係数(AC係数と呼びます)に変換されます。
これだけでも改善しているのですが、係数を量子化することでもっと圧縮することができます。
これは、係数を符号化する前に量子化因数で係数を除算し、デコード処理ではその量子化因数で乗算することを意味します。

例えば、量子化因子を10とします。
322と2という数値を送信するのではなく、322/10=32と2/10=0を送ります(数値が整数となるように切り捨てます)。
デコード処理では32*10=320, 0*10=0と計算してから変換 (320+0)/2=160, (320-0)/2=160します。

デコードして得られた2つの値(160, 160)は、32と0という数値だけを伝送すればよいという利点と引き換えに、元画像と似ていますが厳密には一致しません。
元画像と厳密に一致するデータをデコードすることは不可能で、これは非可逆圧縮と呼ばれます。

非可逆圧縮は、巨大なバンド幅を削減できるため、大部分の放送ビデオで使われています。
しかし、アプリケーション(例えば、ビデオ編集)によっては、可逆圧縮のほうが 便利なこともあります。
可逆圧縮は何度適用しても小さな誤差が拡大することはありませんが、非可逆圧縮では繰り返し伸長・再圧縮を繰り返すと誤差が拡大してしまいます。

AV1では、非可逆と可逆符号化をサポートします。
可逆符号化は最も小さな量子化因子で表現され、自動的にWalsh-Hadamard変換として知られる完全に可逆は変換を使うように切り替わります。

画像データの予測

画像のデコードの途中で、以下のような画素がデコードされたとします。

160 160 160 200 200
160 ? ? ? ?
160 ? ? ? ?
160 ? ? ? ?
160 ? ? ? ?

緑のセルはすでにデコードされた画素を示していて、?マークは今デコードしようとしている4x4ブロックの画素を示しています。

未知の画素のうち左のほうは160に近い値で、右のほうは200に近い値になるのが自然と思われます。
しかし、画像は以下のようにも

160 160 160 200 200
160 160 160 200 200
160 160 160 200 200
160 160 160 200 200
160 160 160 200 200

そして以下のようにもなるかもしれません。

160 160 160 200 200
160 160 160 200 200
160 160 160 200 200
160 160 160 160 200
160 160 160 160 160
160 160 160 160 160

AV1では、最初の場合のような縦方向、次の場合のような45度方向を規定するイントラモードがあります。
ブロックをデコードするときに、デコーダはまずイントラモードを読み、カレントフレームですでにデコードした画素をフィルタしてブロックkの内容を予測するために使います。
これは、イントラ予測として知られ、この方法はイントラブロックのデコードと呼びます。

もちろん、我々の元画像データは、その予測と厳密に一致はしにくいです。

実際の内容が以下のようであるとすると、

160 160 200 200
160 160 200 200
170 170 210 210
170 170 210 210

残差ブロックを考えます。
これは、予測(垂直方向の予測をすると仮定します)と、元画像との差分として定義されます。

0 0 0 0
0 0 0 0
10 10 10 10
10 10 10 10

残差は小さな数値しか含まれないので、元の内容よりも安価に表現できます。

AV1では、すべてのブロックはそのブロックの内容をどう予測するか(この場合はイントラモード)と、残差ブロックの変換係数で表現されます。
デコーダはまず予測値を計算し、変なkン係数を逆変換した結果(残差)をこの予測値に加算します。

この処理は、まだ画素をデコードしていない最初のブロックについても適用します。
この場合、デコーダは画面買いに固定値がデコードされているみなします。

インター予測

さて、ビデオシーケンス全体を圧縮してみましょう。

過去の画像から次の画像を予測できるかどうかを考えます。
背景に静止した物体があるかもしれません、このため阿古過去のフレームと内容が一致するブロックがあるかもしれません。
同様に、カメラが動く物体をパンしているならば、過去のフレームの一部をシフトしたものと非常に似ているブロックがあるかもしれません。

AV1では、これらの場合にインターブロックを利用します。
インターブロックにはブロックを予測するために使う過去のフレームの一部を指すオフセットを指定する動きベクトルが含まれます。
例えば、静止したブロックはゼロ動きベクトルとして表現します。
動きベクトルは、水平垂直方向の動きに対応するために、水平垂直オフセットが含まれます。

イントラブロックと同様に、デコード処理では最初に予測値を計算してから、変換係数を逆変換した結果(残差)を予測値に加算します。

動きベクトルは、1画素単位あるいは小数画素の移動をして指定することもできます。
小数画素の移動が使われるとき、より正確な予測をするために、過去のフレームはフィルタリングされます。

このフィルタリングに使う保管フィルタのタイプを選ぶこともできます。
主な違いはフィルタのバンド幅です。
ソースフレームがノイジーならば、ノイズを除去するために狭帯域なフィルタを使うのが適切で、ソースがきれいならば広帯域なフィルタを使って高周波なテクスチャを保存するのがよいでしょう。
この選択は、フレーム内のすべてのブロックに適用することもできますし、ブロックごとに指定することもできます。