Theora では、ブロックノイズの低減のため、Loop Filter が実装されている。
Theora の Loop Filter には、ブロックの境界画素 (縦、横の辺) に近接画素 から求めた値を、加算、減算することで、境界の不連続性を滑らかにする働きがある。
高ビットレートでのエンコーディングでは、Loop Filter が、高忠実度性を損なうことがあるので、 フィルターの利き具合や、フィルター適用の有無を調整することが可能になっている。
近傍画素から、フィルタリング値を計算する。
7.10 Loop Filtering で定義されている関数 lflim(R, L) で画素差分値を計算する。
パラメータ L は、フレーム毎に定められる値である。
差分値を、境界画素 p[-1], p[0] へ、それぞれ加算、減算し、8 bit unsigned へ飽和演算 して、画素値を変更する。
ブロックは、8x8 画素単位なので、1回のフィルター操作で、8画素分の処理が行われる。
16 bit 精度の演算を行うため、MMX では、4画素単位、SSE2 では、8画素単位で処理できる。
SIMD 実装で問題なのは、lflim 関数の計算で、C の実装では、条件分岐を避けるためルックアップテーブル を使用したが、SIMD 演算では、ルックアップテーブルの使用は不効率である。
ルックアップテーブルを使用せず直接計算することになるが、この場合問題になるのは、条件分岐である。
MMX, SSE2 では、条件分岐の必要な処理に使用できる比較用の命令を次の2種類備えている。
PCMPEQW, PCMPGTW
これらの命令では、それぞれの値が、等しいか大ききかによって、マスクパターンを作成する。
このマスクパターンを使用すると、それぞれの条件での全ての計算結果を求めておき、マスクパターンに よるビット演算で、条件に該当する計算結果のみを抽出することができる。結果として、条件分岐 を行うことなく、計算を実行することができる。
また、MMX, SSE2 には、
PANDN
という命令があり、マスクパターンの反転との AND 演算が1命令で実行できる。
MMX によるコード例は、以下の通りになる。
- __m64 r1 = _mm_sub_pi16(l->L2, R);
- __m64 r2 = _mm_sub_pi16(l->NL2, R);
- __m64 m1 = _mm_cmpgt_pi16(R, l->L); /* R > L */
- __m64 m2 = _mm_cmpgt_pi16(l->NL, R ); /* R < -L */
- __m64 m3 = _mm_cmpgt_pi16(R, l->L2); /* R > 2 * L */
- __m64 m4 = _mm_cmpgt_pi16(l->NL2, R ); /* R < -2 * L */
- __m64 r = R;
- r = _mm_or_si64(_mm_andnot_si64(m1, r), _mm_and_si64(r1, m1));
- r = _mm_or_si64(_mm_andnot_si64(m2, r), _mm_and_si64(r2, m2));
- r = _mm_andnot_si64(m3, r);
- r = _mm_andnot_si64(m4, r);
構造体 l には、パック済みの L の値が与えられているものとする。
l->L = L l->L2 = 2*L l->NL = -L l->NL2 = -2*L
上記のコードでは、条件式の境界条件 <, <= に仕様との相違が生じているが、この場合は計算上どちらの 結果を採用しても、同じ計算結果になるため、実装としては問題はない。
上辺へのフィルター適用については、画素のメモリーイメージを、そのまま MMX, SSE2 レジスター にロードして処理することができるが、右辺への適用については、近傍4画素を1ラスターづつ読み出し、 転置処理を行う必要がある。また、適用結果のストアについても、2画素単位に分解して行う。
[PageInfo]
LastUpdate: 2009-07-14 17:30:29, ModifiedBy: noumiakira
[License]
Creative Commons 2.1 Attribution-ShareAlike
[Permissions]
view:all, edit:members, delete/config:members