Home | History | Annotate | Download | only in common
      1 /*
      2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <stdlib.h>
     12 #include "loopfilter.h"
     13 #include "onyxc_int.h"
     14 
     15 typedef unsigned char uc;
     16 
     17 static signed char vp8_signed_char_clamp(int t) {
     18   t = (t < -128 ? -128 : t);
     19   t = (t > 127 ? 127 : t);
     20   return (signed char)t;
     21 }
     22 
     23 /* should we apply any filter at all ( 11111111 yes, 00000000 no) */
     24 static signed char vp8_filter_mask(uc limit, uc blimit, uc p3, uc p2, uc p1,
     25                                    uc p0, uc q0, uc q1, uc q2, uc q3) {
     26   signed char mask = 0;
     27   mask |= (abs(p3 - p2) > limit);
     28   mask |= (abs(p2 - p1) > limit);
     29   mask |= (abs(p1 - p0) > limit);
     30   mask |= (abs(q1 - q0) > limit);
     31   mask |= (abs(q2 - q1) > limit);
     32   mask |= (abs(q3 - q2) > limit);
     33   mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 > blimit);
     34   return mask - 1;
     35 }
     36 
     37 /* is there high variance internal edge ( 11111111 yes, 00000000 no) */
     38 static signed char vp8_hevmask(uc thresh, uc p1, uc p0, uc q0, uc q1) {
     39   signed char hev = 0;
     40   hev |= (abs(p1 - p0) > thresh) * -1;
     41   hev |= (abs(q1 - q0) > thresh) * -1;
     42   return hev;
     43 }
     44 
     45 static void vp8_filter(signed char mask, uc hev, uc *op1, uc *op0, uc *oq0,
     46                        uc *oq1) {
     47   signed char ps0, qs0;
     48   signed char ps1, qs1;
     49   signed char filter_value, Filter1, Filter2;
     50   signed char u;
     51 
     52   ps1 = (signed char)*op1 ^ 0x80;
     53   ps0 = (signed char)*op0 ^ 0x80;
     54   qs0 = (signed char)*oq0 ^ 0x80;
     55   qs1 = (signed char)*oq1 ^ 0x80;
     56 
     57   /* add outer taps if we have high edge variance */
     58   filter_value = vp8_signed_char_clamp(ps1 - qs1);
     59   filter_value &= hev;
     60 
     61   /* inner taps */
     62   filter_value = vp8_signed_char_clamp(filter_value + 3 * (qs0 - ps0));
     63   filter_value &= mask;
     64 
     65   /* save bottom 3 bits so that we round one side +4 and the other +3
     66    * if it equals 4 we'll set it to adjust by -1 to account for the fact
     67    * we'd round it by 3 the other way
     68    */
     69   Filter1 = vp8_signed_char_clamp(filter_value + 4);
     70   Filter2 = vp8_signed_char_clamp(filter_value + 3);
     71   Filter1 >>= 3;
     72   Filter2 >>= 3;
     73   u = vp8_signed_char_clamp(qs0 - Filter1);
     74   *oq0 = u ^ 0x80;
     75   u = vp8_signed_char_clamp(ps0 + Filter2);
     76   *op0 = u ^ 0x80;
     77   filter_value = Filter1;
     78 
     79   /* outer tap adjustments */
     80   filter_value += 1;
     81   filter_value >>= 1;
     82   filter_value &= ~hev;
     83 
     84   u = vp8_signed_char_clamp(qs1 - filter_value);
     85   *oq1 = u ^ 0x80;
     86   u = vp8_signed_char_clamp(ps1 + filter_value);
     87   *op1 = u ^ 0x80;
     88 }
     89 void vp8_loop_filter_horizontal_edge_c(unsigned char *s, int p, /* pitch */
     90                                        const unsigned char *blimit,
     91                                        const unsigned char *limit,
     92                                        const unsigned char *thresh, int count) {
     93   int hev = 0; /* high edge variance */
     94   signed char mask = 0;
     95   int i = 0;
     96 
     97   /* loop filter designed to work using chars so that we can make maximum use
     98    * of 8 bit simd instructions.
     99    */
    100   do {
    101     mask = vp8_filter_mask(limit[0], blimit[0], s[-4 * p], s[-3 * p], s[-2 * p],
    102                            s[-1 * p], s[0 * p], s[1 * p], s[2 * p], s[3 * p]);
    103 
    104     hev = vp8_hevmask(thresh[0], s[-2 * p], s[-1 * p], s[0 * p], s[1 * p]);
    105 
    106     vp8_filter(mask, hev, s - 2 * p, s - 1 * p, s, s + 1 * p);
    107 
    108     ++s;
    109   } while (++i < count * 8);
    110 }
    111 
    112 void vp8_loop_filter_vertical_edge_c(unsigned char *s, int p,
    113                                      const unsigned char *blimit,
    114                                      const unsigned char *limit,
    115                                      const unsigned char *thresh, int count) {
    116   int hev = 0; /* high edge variance */
    117   signed char mask = 0;
    118   int i = 0;
    119 
    120   /* loop filter designed to work using chars so that we can make maximum use
    121    * of 8 bit simd instructions.
    122    */
    123   do {
    124     mask = vp8_filter_mask(limit[0], blimit[0], s[-4], s[-3], s[-2], s[-1],
    125                            s[0], s[1], s[2], s[3]);
    126 
    127     hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]);
    128 
    129     vp8_filter(mask, hev, s - 2, s - 1, s, s + 1);
    130 
    131     s += p;
    132   } while (++i < count * 8);
    133 }
    134 
    135 static void vp8_mbfilter(signed char mask, uc hev, uc *op2, uc *op1, uc *op0,
    136                          uc *oq0, uc *oq1, uc *oq2) {
    137   signed char s, u;
    138   signed char filter_value, Filter1, Filter2;
    139   signed char ps2 = (signed char)*op2 ^ 0x80;
    140   signed char ps1 = (signed char)*op1 ^ 0x80;
    141   signed char ps0 = (signed char)*op0 ^ 0x80;
    142   signed char qs0 = (signed char)*oq0 ^ 0x80;
    143   signed char qs1 = (signed char)*oq1 ^ 0x80;
    144   signed char qs2 = (signed char)*oq2 ^ 0x80;
    145 
    146   /* add outer taps if we have high edge variance */
    147   filter_value = vp8_signed_char_clamp(ps1 - qs1);
    148   filter_value = vp8_signed_char_clamp(filter_value + 3 * (qs0 - ps0));
    149   filter_value &= mask;
    150 
    151   Filter2 = filter_value;
    152   Filter2 &= hev;
    153 
    154   /* save bottom 3 bits so that we round one side +4 and the other +3 */
    155   Filter1 = vp8_signed_char_clamp(Filter2 + 4);
    156   Filter2 = vp8_signed_char_clamp(Filter2 + 3);
    157   Filter1 >>= 3;
    158   Filter2 >>= 3;
    159   qs0 = vp8_signed_char_clamp(qs0 - Filter1);
    160   ps0 = vp8_signed_char_clamp(ps0 + Filter2);
    161 
    162   /* only apply wider filter if not high edge variance */
    163   filter_value &= ~hev;
    164   Filter2 = filter_value;
    165 
    166   /* roughly 3/7th difference across boundary */
    167   u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7);
    168   s = vp8_signed_char_clamp(qs0 - u);
    169   *oq0 = s ^ 0x80;
    170   s = vp8_signed_char_clamp(ps0 + u);
    171   *op0 = s ^ 0x80;
    172 
    173   /* roughly 2/7th difference across boundary */
    174   u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7);
    175   s = vp8_signed_char_clamp(qs1 - u);
    176   *oq1 = s ^ 0x80;
    177   s = vp8_signed_char_clamp(ps1 + u);
    178   *op1 = s ^ 0x80;
    179 
    180   /* roughly 1/7th difference across boundary */
    181   u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7);
    182   s = vp8_signed_char_clamp(qs2 - u);
    183   *oq2 = s ^ 0x80;
    184   s = vp8_signed_char_clamp(ps2 + u);
    185   *op2 = s ^ 0x80;
    186 }
    187 
    188 void vp8_mbloop_filter_horizontal_edge_c(unsigned char *s, int p,
    189                                          const unsigned char *blimit,
    190                                          const unsigned char *limit,
    191                                          const unsigned char *thresh,
    192                                          int count) {
    193   signed char hev = 0; /* high edge variance */
    194   signed char mask = 0;
    195   int i = 0;
    196 
    197   /* loop filter designed to work using chars so that we can make maximum use
    198    * of 8 bit simd instructions.
    199    */
    200   do {
    201     mask = vp8_filter_mask(limit[0], blimit[0], s[-4 * p], s[-3 * p], s[-2 * p],
    202                            s[-1 * p], s[0 * p], s[1 * p], s[2 * p], s[3 * p]);
    203 
    204     hev = vp8_hevmask(thresh[0], s[-2 * p], s[-1 * p], s[0 * p], s[1 * p]);
    205 
    206     vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p,
    207                  s + 2 * p);
    208 
    209     ++s;
    210   } while (++i < count * 8);
    211 }
    212 
    213 void vp8_mbloop_filter_vertical_edge_c(unsigned char *s, int p,
    214                                        const unsigned char *blimit,
    215                                        const unsigned char *limit,
    216                                        const unsigned char *thresh, int count) {
    217   signed char hev = 0; /* high edge variance */
    218   signed char mask = 0;
    219   int i = 0;
    220 
    221   do {
    222     mask = vp8_filter_mask(limit[0], blimit[0], s[-4], s[-3], s[-2], s[-1],
    223                            s[0], s[1], s[2], s[3]);
    224 
    225     hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]);
    226 
    227     vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2);
    228 
    229     s += p;
    230   } while (++i < count * 8);
    231 }
    232 
    233 /* should we apply any filter at all ( 11111111 yes, 00000000 no) */
    234 static signed char vp8_simple_filter_mask(uc blimit, uc p1, uc p0, uc q0,
    235                                           uc q1) {
    236   /* Why does this cause problems for win32?
    237    * error C2143: syntax error : missing ';' before 'type'
    238    *  (void) limit;
    239    */
    240   signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 <= blimit) * -1;
    241   return mask;
    242 }
    243 
    244 static void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0,
    245                               uc *oq1) {
    246   signed char filter_value, Filter1, Filter2;
    247   signed char p1 = (signed char)*op1 ^ 0x80;
    248   signed char p0 = (signed char)*op0 ^ 0x80;
    249   signed char q0 = (signed char)*oq0 ^ 0x80;
    250   signed char q1 = (signed char)*oq1 ^ 0x80;
    251   signed char u;
    252 
    253   filter_value = vp8_signed_char_clamp(p1 - q1);
    254   filter_value = vp8_signed_char_clamp(filter_value + 3 * (q0 - p0));
    255   filter_value &= mask;
    256 
    257   /* save bottom 3 bits so that we round one side +4 and the other +3 */
    258   Filter1 = vp8_signed_char_clamp(filter_value + 4);
    259   Filter1 >>= 3;
    260   u = vp8_signed_char_clamp(q0 - Filter1);
    261   *oq0 = u ^ 0x80;
    262 
    263   Filter2 = vp8_signed_char_clamp(filter_value + 3);
    264   Filter2 >>= 3;
    265   u = vp8_signed_char_clamp(p0 + Filter2);
    266   *op0 = u ^ 0x80;
    267 }
    268 
    269 void vp8_loop_filter_simple_horizontal_edge_c(unsigned char *s, int p,
    270                                               const unsigned char *blimit) {
    271   signed char mask = 0;
    272   int i = 0;
    273 
    274   do {
    275     mask = vp8_simple_filter_mask(blimit[0], s[-2 * p], s[-1 * p], s[0 * p],
    276                                   s[1 * p]);
    277     vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p);
    278     ++s;
    279   } while (++i < 16);
    280 }
    281 
    282 void vp8_loop_filter_simple_vertical_edge_c(unsigned char *s, int p,
    283                                             const unsigned char *blimit) {
    284   signed char mask = 0;
    285   int i = 0;
    286 
    287   do {
    288     mask = vp8_simple_filter_mask(blimit[0], s[-2], s[-1], s[0], s[1]);
    289     vp8_simple_filter(mask, s - 2, s - 1, s, s + 1);
    290     s += p;
    291   } while (++i < 16);
    292 }
    293 
    294 /* Horizontal MB filtering */
    295 void vp8_loop_filter_mbh_c(unsigned char *y_ptr, unsigned char *u_ptr,
    296                            unsigned char *v_ptr, int y_stride, int uv_stride,
    297                            loop_filter_info *lfi) {
    298   vp8_mbloop_filter_horizontal_edge_c(y_ptr, y_stride, lfi->mblim, lfi->lim,
    299                                       lfi->hev_thr, 2);
    300 
    301   if (u_ptr) {
    302     vp8_mbloop_filter_horizontal_edge_c(u_ptr, uv_stride, lfi->mblim, lfi->lim,
    303                                         lfi->hev_thr, 1);
    304   }
    305 
    306   if (v_ptr) {
    307     vp8_mbloop_filter_horizontal_edge_c(v_ptr, uv_stride, lfi->mblim, lfi->lim,
    308                                         lfi->hev_thr, 1);
    309   }
    310 }
    311 
    312 /* Vertical MB Filtering */
    313 void vp8_loop_filter_mbv_c(unsigned char *y_ptr, unsigned char *u_ptr,
    314                            unsigned char *v_ptr, int y_stride, int uv_stride,
    315                            loop_filter_info *lfi) {
    316   vp8_mbloop_filter_vertical_edge_c(y_ptr, y_stride, lfi->mblim, lfi->lim,
    317                                     lfi->hev_thr, 2);
    318 
    319   if (u_ptr) {
    320     vp8_mbloop_filter_vertical_edge_c(u_ptr, uv_stride, lfi->mblim, lfi->lim,
    321                                       lfi->hev_thr, 1);
    322   }
    323 
    324   if (v_ptr) {
    325     vp8_mbloop_filter_vertical_edge_c(v_ptr, uv_stride, lfi->mblim, lfi->lim,
    326                                       lfi->hev_thr, 1);
    327   }
    328 }
    329 
    330 /* Horizontal B Filtering */
    331 void vp8_loop_filter_bh_c(unsigned char *y_ptr, unsigned char *u_ptr,
    332                           unsigned char *v_ptr, int y_stride, int uv_stride,
    333                           loop_filter_info *lfi) {
    334   vp8_loop_filter_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride, lfi->blim,
    335                                     lfi->lim, lfi->hev_thr, 2);
    336   vp8_loop_filter_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride, lfi->blim,
    337                                     lfi->lim, lfi->hev_thr, 2);
    338   vp8_loop_filter_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride, lfi->blim,
    339                                     lfi->lim, lfi->hev_thr, 2);
    340 
    341   if (u_ptr) {
    342     vp8_loop_filter_horizontal_edge_c(u_ptr + 4 * uv_stride, uv_stride,
    343                                       lfi->blim, lfi->lim, lfi->hev_thr, 1);
    344   }
    345 
    346   if (v_ptr) {
    347     vp8_loop_filter_horizontal_edge_c(v_ptr + 4 * uv_stride, uv_stride,
    348                                       lfi->blim, lfi->lim, lfi->hev_thr, 1);
    349   }
    350 }
    351 
    352 void vp8_loop_filter_bhs_c(unsigned char *y_ptr, int y_stride,
    353                            const unsigned char *blimit) {
    354   vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride,
    355                                            blimit);
    356   vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride,
    357                                            blimit);
    358   vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride,
    359                                            blimit);
    360 }
    361 
    362 /* Vertical B Filtering */
    363 void vp8_loop_filter_bv_c(unsigned char *y_ptr, unsigned char *u_ptr,
    364                           unsigned char *v_ptr, int y_stride, int uv_stride,
    365                           loop_filter_info *lfi) {
    366   vp8_loop_filter_vertical_edge_c(y_ptr + 4, y_stride, lfi->blim, lfi->lim,
    367                                   lfi->hev_thr, 2);
    368   vp8_loop_filter_vertical_edge_c(y_ptr + 8, y_stride, lfi->blim, lfi->lim,
    369                                   lfi->hev_thr, 2);
    370   vp8_loop_filter_vertical_edge_c(y_ptr + 12, y_stride, lfi->blim, lfi->lim,
    371                                   lfi->hev_thr, 2);
    372 
    373   if (u_ptr) {
    374     vp8_loop_filter_vertical_edge_c(u_ptr + 4, uv_stride, lfi->blim, lfi->lim,
    375                                     lfi->hev_thr, 1);
    376   }
    377 
    378   if (v_ptr) {
    379     vp8_loop_filter_vertical_edge_c(v_ptr + 4, uv_stride, lfi->blim, lfi->lim,
    380                                     lfi->hev_thr, 1);
    381   }
    382 }
    383 
    384 void vp8_loop_filter_bvs_c(unsigned char *y_ptr, int y_stride,
    385                            const unsigned char *blimit) {
    386   vp8_loop_filter_simple_vertical_edge_c(y_ptr + 4, y_stride, blimit);
    387   vp8_loop_filter_simple_vertical_edge_c(y_ptr + 8, y_stride, blimit);
    388   vp8_loop_filter_simple_vertical_edge_c(y_ptr + 12, y_stride, blimit);
    389 }
    390