AV1 specification を読む (デコード処理:フレーム順の制約・確率の補正)


本題のデコード処理です・・・が、まだ画像っぽい話には到達しませんね。

確率変数についての話なので、定義通りやるだけです。


デコード処理

概要

デコーダはすべての面で一致し、ここで規定するデコード処理で生成されたのと同じ出力順で、出力フレームを生成しなければなりません。

この処理の入力は、符号化されたフレームのシーケンスです

この処理の出力は、デコードされたフレームのシーケンスです。

以下の手順で各符号化フレームは処理されます。

  1. 6章と7章で規定されるように、符号化フレームのシンタックス要素を抽出します。関数コールが含まれるシンタックステーブルは、ブロックデコード処理がなされることを示しています。
  2. loop_filter_levelが0ではないならば、8.8節でいていされるループフィルタ処理が、デコードされたフレームに対して1回呼びます。
  3. 以下のすべての条件が真のとき、PrevSegmentIds[row][col] =SegmentIds[row][cos] とします。row = 0..MiRows-1, col=0..MiCosl-1。
    • show_existing_frame == 0
    • segmentation_enabled == 1
    • segmentation_update_map == 1
  4. 8.9節で規定される出力処理を呼びます。
  5. 8.10節で規定される参照フレーム更新処理を呼びます。

フレーム順の制約

本節ではフレームタイプに由来するビットストリームの付加的な制約について説明します。

シーケンスがキーフレームで始まる場合、この付加的な制約は自動的に満たされます。

そうでない場合、シーケンスは非キーフレーム(インターフレーム・イントラオンリーフレーム)で始めることができますが、デコード処理がうまくできるように追加のケアが必要です。
以下を適用することが、ビットストリーム制約の要求です。

  • load_probs(ctx)が呼ばれるとき、初期化された確率のセットをロードしなければなりません。つまり、それ以前にsave_probs(ctx)が存在しなければならないということです。
  • ref_frame_idx[i]がでこどされるとき、初期化された参照フレームを指定しなければなりません。つまり、(refresh_frame_flags»ref_frame_idx[i])&1==1である、それ以前にデコードされたフレームが存在するということです。

注意:
この制約は、最初の符号化フレームはインターフレームになりえないことを意味します。

カウントクリア処理

この処理は、6.1節で説明したフレームのしんったくすでコード内で呼ばれる clear_counts 関数で開始します。

以下の配列には、特定のコンテキストで特定のシンタックス要素が何回デコードされたかを格納します。

角カッコは、配列の各次元のサイズを定義します。
栗アカウント処理が呼ばれたとき、すべてのカウントをゼロにします。

確率補正処理

この節では、様々なシンタックス要素の発生頻度に基づいて、確率を後方更新するための2つの処理を定義します。

これらの処理は、6.1.2節の確率更新シンタックステーブル内の関数定義で呼ばれます。

この処理は、以下で定義する関数merge_prob, merge_probs を使います。

merge prob 処理

この処理入力は以下の通りです。

  • 二値のための、オリジナル確率 preProb
  • 二値が0, 1どちらにデコードされたかの回数を指定する変数 ctx0, ctx1
  • 最大適応には何回デコードが必要かを示す変数 countSat
  • 確率が補正できる最大の回数を指定する変数 maxUpdateFactor

出力は、更新された確率を含む変数 outProbです。
二値がデコードされた合計回数 den = ctx0 + cxx1 とします。

二値が0とデコードされた確率の推定値 prob = (den == 0) ? 128 : Clip3( 1, 255, (ct0 * 256 + (den » 1)) / den )
count = Min( ct0 + ct1, countSat )
factor = maxUpdateFactor * count / countSat
戻り値 outProb = Round2( preProb * (256 - factor) + prob * factor, 8 )

merge probs処理

この処理の入力は以下のとおりです。

  • シンタックス要素のデコードツリーを指定する配列 tree
  • デコードツリーのカレント位置を示す変数 i
  • シンタックス要素をデコードするためのオリジナル確率s probs
  • 各シンタックス要素の各値がが何回デコードされたかを含む配列 counts
  • 最大適応には何回デコードが必要かを示す変数 countSat
  • 確率が補正できる最大の回数を指定する変数 maxUpdateFactor

出力は入力配列 probs を補正したもので、戻り値には二値がデコードされた合計の回数が含まれます。
処理は以下のように定義されます

merge_probs( tree, i, probs, counts, countSat, maxUpdateFactor )
{
    s = tree[i]
    leftCount = (s <= 0) ? counts[-s] : merge_probs( tree, s, probs, counts, countSat, maxUpdateFactor )

    r = tree[i+1]
    rightCount = (r <= 0) ? counts[-r] : merge_probs( tree, r, probs, counts, countSat, maxUpdateFactor )

    probs[i>>1] = merge_prob( probs[i>>1], leftCount, rightCount, countSat, maxUpdateFactor )
    return leftCount + rightCount
}

係数確率適応処理

この処理は、確率更新シンタックステーブルの adapt_coef_probs が呼ばれたときに開始します。
変数 updateFactor は、今のフレームタイプと過去のフレームタイプに従って設定されます。

  • FrameIntra == 1 ならば、updateFactor = 112
  • LastFrameType == KEY_FRAMEならば、updateFactor = 128
  • そうでなければ、updateFacotr = 112

そして、確率変数は以下のように更新します。

for (t=0; t<4; t++)
  for (i=0; i<2; i++)
    for (j=0; j<2; j++)
      for (k=0; k<6; k++) {
        maxL = (k==0) ? 3 : 6;
        for (l=0; l<maxL; l++) {
          merge_probs(small_token_tree, 2, coef_probs[t][i][j][k][l], counts_token[t][i][j][k][l], 24, updateFactor);
          merge_probs(binary_tree, 0, coef_probs[t][i][j][k][l], counts_more_coefs[t][i][j][k][l], 24, updateFactor);
        }
      }

ここで、small_token_treeは以下のように定義します。

small_token_tree[6] = {
  0, 0, // unused
  -ZERO_TOKEN, 4,
  -ONE_TOKEN, -TWO_TOKEN
};

確率以外の確率適応処理

この処理は、確率更新シンタックステーブルの adapt_noncoef_probs が呼ばれたときに開始します。
確率は以下のように更新します。

省略

adapt_probs は以下のように定義します。

adapt_probs(tree, probs, counts) {
  merge_probs(tree, 0, probs, counts, COUNT_SAT, MAX_UPDATE_FACTOR);
}

adapt_prob は以下のように定義します。

adapt_prob(probs, counts) {
  return merge_prob(prob, counts[0], counts[1], COUNT_SAT, MAX_UPDATE_FACTOR);
}