Home | History | Annotate | Download | only in encoder
      1 /*
      2  *  Copyright (c) 2012 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 <limits.h>
     12 
     13 #include "denoising.h"
     14 
     15 #include "vp8/common/reconinter.h"
     16 #include "vpx/vpx_integer.h"
     17 #include "vpx_mem/vpx_mem.h"
     18 #include "vp8_rtcd.h"
     19 
     20 static const unsigned int NOISE_MOTION_THRESHOLD = 25 * 25;
     21 /* SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming
     22  * var(noise) ~= 100.
     23  */
     24 static const unsigned int SSE_DIFF_THRESHOLD = 16 * 16 * 20;
     25 static const unsigned int SSE_THRESHOLD = 16 * 16 * 40;
     26 static const unsigned int SSE_THRESHOLD_HIGH = 16 * 16 * 60;
     27 
     28 /*
     29  * The filter function was modified to reduce the computational complexity.
     30  * Step 1:
     31  * Instead of applying tap coefficients for each pixel, we calculated the
     32  * pixel adjustments vs. pixel diff value ahead of time.
     33  *     adjustment = filtered_value - current_raw
     34  *                = (filter_coefficient * diff + 128) >> 8
     35  * where
     36  *     filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3));
     37  *     filter_coefficient += filter_coefficient /
     38  *                           (3 + motion_magnitude_adjustment);
     39  *     filter_coefficient is clamped to 0 ~ 255.
     40  *
     41  * Step 2:
     42  * The adjustment vs. diff curve becomes flat very quick when diff increases.
     43  * This allowed us to use only several levels to approximate the curve without
     44  * changing the filtering algorithm too much.
     45  * The adjustments were further corrected by checking the motion magnitude.
     46  * The levels used are:
     47  * diff       adjustment w/o motion correction   adjustment w/ motion correction
     48  * [-255, -16]           -6                                   -7
     49  * [-15, -8]             -4                                   -5
     50  * [-7, -4]              -3                                   -4
     51  * [-3, 3]               diff                                 diff
     52  * [4, 7]                 3                                    4
     53  * [8, 15]                4                                    5
     54  * [16, 255]              6                                    7
     55  */
     56 
     57 int vp8_denoiser_filter_c(unsigned char *mc_running_avg_y, int mc_avg_y_stride,
     58                           unsigned char *running_avg_y, int avg_y_stride,
     59                           unsigned char *sig, int sig_stride,
     60                           unsigned int motion_magnitude,
     61                           int increase_denoising)
     62 {
     63     unsigned char *running_avg_y_start = running_avg_y;
     64     unsigned char *sig_start = sig;
     65     int sum_diff_thresh;
     66     int r, c;
     67     int sum_diff = 0;
     68     int adj_val[3] = {3, 4, 6};
     69     int shift_inc1 = 0;
     70     int shift_inc2 = 1;
     71     int col_sum[16] = {0, 0, 0, 0,
     72                        0, 0, 0, 0,
     73                        0, 0, 0, 0,
     74                        0, 0, 0, 0};
     75     /* If motion_magnitude is small, making the denoiser more aggressive by
     76      * increasing the adjustment for each level. Add another increment for
     77      * blocks that are labeled for increase denoising. */
     78     if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD)
     79     {
     80       if (increase_denoising) {
     81         shift_inc1 = 1;
     82         shift_inc2 = 2;
     83       }
     84       adj_val[0] += shift_inc2;
     85       adj_val[1] += shift_inc2;
     86       adj_val[2] += shift_inc2;
     87     }
     88 
     89     for (r = 0; r < 16; ++r)
     90     {
     91         for (c = 0; c < 16; ++c)
     92         {
     93             int diff = 0;
     94             int adjustment = 0;
     95             int absdiff = 0;
     96 
     97             diff = mc_running_avg_y[c] - sig[c];
     98             absdiff = abs(diff);
     99 
    100             // When |diff| <= |3 + shift_inc1|, use pixel value from
    101             // last denoised raw.
    102             if (absdiff <= 3 + shift_inc1)
    103             {
    104                 running_avg_y[c] = mc_running_avg_y[c];
    105                 col_sum[c] += diff;
    106             }
    107             else
    108             {
    109                 if (absdiff >= 4 + shift_inc1 && absdiff <= 7)
    110                     adjustment = adj_val[0];
    111                 else if (absdiff >= 8 && absdiff <= 15)
    112                     adjustment = adj_val[1];
    113                 else
    114                     adjustment = adj_val[2];
    115 
    116                 if (diff > 0)
    117                 {
    118                     if ((sig[c] + adjustment) > 255)
    119                         running_avg_y[c] = 255;
    120                     else
    121                         running_avg_y[c] = sig[c] + adjustment;
    122 
    123                     col_sum[c] += adjustment;
    124                 }
    125                 else
    126                 {
    127                     if ((sig[c] - adjustment) < 0)
    128                         running_avg_y[c] = 0;
    129                     else
    130                         running_avg_y[c] = sig[c] - adjustment;
    131 
    132                     col_sum[c] -= adjustment;
    133                 }
    134             }
    135         }
    136 
    137         /* Update pointers for next iteration. */
    138         sig += sig_stride;
    139         mc_running_avg_y += mc_avg_y_stride;
    140         running_avg_y += avg_y_stride;
    141     }
    142 
    143     for (c = 0; c < 16; ++c) {
    144       // Below we clip the value in the same way which SSE code use.
    145       // When adopting aggressive denoiser, the adj_val for each pixel
    146       // could be at most 8 (this is current max adjustment of the map).
    147       // In SSE code, we calculate the sum of adj_val for
    148       // the columns, so the sum could be upto 128(16 rows). However,
    149       // the range of the value is -128 ~ 127 in SSE code, that's why
    150       // we do this change in C code.
    151       // We don't do this for UV denoiser, since there are only 8 rows,
    152       // and max adjustments <= 8, so the sum of the columns will not
    153       // exceed 64.
    154       if (col_sum[c] >= 128) {
    155         col_sum[c] = 127;
    156       }
    157       sum_diff += col_sum[c];
    158     }
    159 
    160     sum_diff_thresh= SUM_DIFF_THRESHOLD;
    161     if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH;
    162     if (abs(sum_diff) > sum_diff_thresh) {
    163       // Before returning to copy the block (i.e., apply no denoising), check
    164       // if we can still apply some (weaker) temporal filtering to this block,
    165       // that would otherwise not be denoised at all. Simplest is to apply
    166       // an additional adjustment to running_avg_y to bring it closer to sig.
    167       // The adjustment is capped by a maximum delta, and chosen such that
    168       // in most cases the resulting sum_diff will be within the
    169       // accceptable range given by sum_diff_thresh.
    170 
    171       // The delta is set by the excess of absolute pixel diff over threshold.
    172       int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1;
    173       // Only apply the adjustment for max delta up to 3.
    174       if (delta < 4) {
    175         sig -= sig_stride * 16;
    176         mc_running_avg_y -= mc_avg_y_stride * 16;
    177         running_avg_y -= avg_y_stride * 16;
    178         for (r = 0; r < 16; ++r) {
    179           for (c = 0; c < 16; ++c) {
    180             int diff = mc_running_avg_y[c] - sig[c];
    181             int adjustment = abs(diff);
    182             if (adjustment > delta)
    183               adjustment = delta;
    184             if (diff > 0) {
    185               // Bring denoised signal down.
    186               if (running_avg_y[c] - adjustment < 0)
    187                 running_avg_y[c] = 0;
    188               else
    189                 running_avg_y[c] = running_avg_y[c] - adjustment;
    190               col_sum[c] -= adjustment;
    191             } else if (diff < 0) {
    192               // Bring denoised signal up.
    193               if (running_avg_y[c] + adjustment > 255)
    194                 running_avg_y[c] = 255;
    195               else
    196                 running_avg_y[c] = running_avg_y[c] + adjustment;
    197               col_sum[c] += adjustment;
    198             }
    199           }
    200           // TODO(marpan): Check here if abs(sum_diff) has gone below the
    201           // threshold sum_diff_thresh, and if so, we can exit the row loop.
    202           sig += sig_stride;
    203           mc_running_avg_y += mc_avg_y_stride;
    204           running_avg_y += avg_y_stride;
    205         }
    206 
    207         sum_diff = 0;
    208         for (c = 0; c < 16; ++c) {
    209           if (col_sum[c] >= 128) {
    210             col_sum[c] = 127;
    211           }
    212           sum_diff += col_sum[c];
    213         }
    214 
    215         if (abs(sum_diff) > sum_diff_thresh)
    216           return COPY_BLOCK;
    217       } else {
    218         return COPY_BLOCK;
    219       }
    220     }
    221 
    222     vp8_copy_mem16x16(running_avg_y_start, avg_y_stride, sig_start, sig_stride);
    223     return FILTER_BLOCK;
    224 }
    225 
    226 int vp8_denoiser_filter_uv_c(unsigned char *mc_running_avg_uv,
    227                              int mc_avg_uv_stride,
    228                              unsigned char *running_avg_uv,
    229                              int avg_uv_stride,
    230                              unsigned char *sig,
    231                              int sig_stride,
    232                              unsigned int motion_magnitude,
    233                              int increase_denoising) {
    234     unsigned char *running_avg_uv_start = running_avg_uv;
    235     unsigned char *sig_start = sig;
    236     int sum_diff_thresh;
    237     int r, c;
    238     int sum_diff = 0;
    239     int sum_block = 0;
    240     int adj_val[3] = {3, 4, 6};
    241     int shift_inc1 = 0;
    242     int shift_inc2 = 1;
    243     /* If motion_magnitude is small, making the denoiser more aggressive by
    244      * increasing the adjustment for each level. Add another increment for
    245      * blocks that are labeled for increase denoising. */
    246     if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD_UV) {
    247       if (increase_denoising) {
    248         shift_inc1 = 1;
    249         shift_inc2 = 2;
    250       }
    251       adj_val[0] += shift_inc2;
    252       adj_val[1] += shift_inc2;
    253       adj_val[2] += shift_inc2;
    254     }
    255 
    256     // Avoid denoising color signal if its close to average level.
    257     for (r = 0; r < 8; ++r) {
    258       for (c = 0; c < 8; ++c) {
    259         sum_block += sig[c];
    260       }
    261       sig += sig_stride;
    262     }
    263     if (abs(sum_block - (128 * 8 * 8)) < SUM_DIFF_FROM_AVG_THRESH_UV) {
    264       return COPY_BLOCK;
    265     }
    266 
    267     sig -= sig_stride * 8;
    268     for (r = 0; r < 8; ++r) {
    269       for (c = 0; c < 8; ++c) {
    270         int diff = 0;
    271         int adjustment = 0;
    272         int absdiff = 0;
    273 
    274         diff = mc_running_avg_uv[c] - sig[c];
    275         absdiff = abs(diff);
    276 
    277         // When |diff| <= |3 + shift_inc1|, use pixel value from
    278         // last denoised raw.
    279         if (absdiff <= 3 + shift_inc1) {
    280           running_avg_uv[c] = mc_running_avg_uv[c];
    281           sum_diff += diff;
    282         } else {
    283           if (absdiff >= 4 && absdiff <= 7)
    284             adjustment = adj_val[0];
    285           else if (absdiff >= 8 && absdiff <= 15)
    286             adjustment = adj_val[1];
    287           else
    288             adjustment = adj_val[2];
    289           if (diff > 0) {
    290             if ((sig[c] + adjustment) > 255)
    291               running_avg_uv[c] = 255;
    292             else
    293               running_avg_uv[c] = sig[c] + adjustment;
    294             sum_diff += adjustment;
    295           } else {
    296             if ((sig[c] - adjustment) < 0)
    297               running_avg_uv[c] = 0;
    298             else
    299               running_avg_uv[c] = sig[c] - adjustment;
    300             sum_diff -= adjustment;
    301           }
    302         }
    303       }
    304       /* Update pointers for next iteration. */
    305       sig += sig_stride;
    306       mc_running_avg_uv += mc_avg_uv_stride;
    307       running_avg_uv += avg_uv_stride;
    308     }
    309 
    310     sum_diff_thresh= SUM_DIFF_THRESHOLD_UV;
    311     if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH_UV;
    312     if (abs(sum_diff) > sum_diff_thresh) {
    313       // Before returning to copy the block (i.e., apply no denoising), check
    314       // if we can still apply some (weaker) temporal filtering to this block,
    315       // that would otherwise not be denoised at all. Simplest is to apply
    316       // an additional adjustment to running_avg_y to bring it closer to sig.
    317       // The adjustment is capped by a maximum delta, and chosen such that
    318       // in most cases the resulting sum_diff will be within the
    319       // accceptable range given by sum_diff_thresh.
    320 
    321       // The delta is set by the excess of absolute pixel diff over threshold.
    322       int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1;
    323       // Only apply the adjustment for max delta up to 3.
    324       if (delta < 4) {
    325         sig -= sig_stride * 8;
    326         mc_running_avg_uv -= mc_avg_uv_stride * 8;
    327         running_avg_uv -= avg_uv_stride * 8;
    328         for (r = 0; r < 8; ++r) {
    329           for (c = 0; c < 8; ++c) {
    330             int diff = mc_running_avg_uv[c] - sig[c];
    331             int adjustment = abs(diff);
    332             if (adjustment > delta)
    333               adjustment = delta;
    334             if (diff > 0) {
    335               // Bring denoised signal down.
    336               if (running_avg_uv[c] - adjustment < 0)
    337                 running_avg_uv[c] = 0;
    338               else
    339                 running_avg_uv[c] = running_avg_uv[c] - adjustment;
    340               sum_diff -= adjustment;
    341             } else if (diff < 0) {
    342               // Bring denoised signal up.
    343               if (running_avg_uv[c] + adjustment > 255)
    344                 running_avg_uv[c] = 255;
    345               else
    346                 running_avg_uv[c] = running_avg_uv[c] + adjustment;
    347               sum_diff += adjustment;
    348             }
    349           }
    350           // TODO(marpan): Check here if abs(sum_diff) has gone below the
    351           // threshold sum_diff_thresh, and if so, we can exit the row loop.
    352           sig += sig_stride;
    353           mc_running_avg_uv += mc_avg_uv_stride;
    354           running_avg_uv += avg_uv_stride;
    355         }
    356         if (abs(sum_diff) > sum_diff_thresh)
    357           return COPY_BLOCK;
    358       } else {
    359         return COPY_BLOCK;
    360       }
    361     }
    362 
    363     vp8_copy_mem8x8(running_avg_uv_start, avg_uv_stride, sig_start,
    364                     sig_stride);
    365     return FILTER_BLOCK;
    366 }
    367 
    368 void vp8_denoiser_set_parameters(VP8_DENOISER *denoiser, int mode) {
    369   assert(mode > 0);  // Denoiser is allocated only if mode > 0.
    370   if (mode == 1) {
    371     denoiser->denoiser_mode = kDenoiserOnYOnly;
    372   } else if (mode == 2) {
    373     denoiser->denoiser_mode = kDenoiserOnYUV;
    374   } else if (mode == 3) {
    375     denoiser->denoiser_mode = kDenoiserOnYUVAggressive;
    376   } else {
    377     denoiser->denoiser_mode = kDenoiserOnAdaptive;
    378   }
    379   if (denoiser->denoiser_mode != kDenoiserOnYUVAggressive) {
    380     denoiser->denoise_pars.scale_sse_thresh = 1;
    381     denoiser->denoise_pars.scale_motion_thresh = 8;
    382     denoiser->denoise_pars.scale_increase_filter = 0;
    383     denoiser->denoise_pars.denoise_mv_bias = 95;
    384     denoiser->denoise_pars.pickmode_mv_bias = 100;
    385     denoiser->denoise_pars.qp_thresh = 0;
    386     denoiser->denoise_pars.consec_zerolast = UINT_MAX;
    387     denoiser->denoise_pars.spatial_blur = 0;
    388   } else {
    389     denoiser->denoise_pars.scale_sse_thresh = 2;
    390     denoiser->denoise_pars.scale_motion_thresh = 16;
    391     denoiser->denoise_pars.scale_increase_filter = 1;
    392     denoiser->denoise_pars.denoise_mv_bias = 60;
    393     denoiser->denoise_pars.pickmode_mv_bias = 60;
    394     denoiser->denoise_pars.qp_thresh = 100;
    395     denoiser->denoise_pars.consec_zerolast = 10;
    396     denoiser->denoise_pars.spatial_blur = 20;
    397   }
    398 }
    399 
    400 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height,
    401                           int num_mb_rows, int num_mb_cols, int mode)
    402 {
    403     int i;
    404     assert(denoiser);
    405     denoiser->num_mb_cols = num_mb_cols;
    406 
    407     for (i = 0; i < MAX_REF_FRAMES; i++)
    408     {
    409         denoiser->yv12_running_avg[i].flags = 0;
    410 
    411         if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width,
    412                                         height, VP8BORDERINPIXELS)
    413             < 0)
    414         {
    415             vp8_denoiser_free(denoiser);
    416             return 1;
    417         }
    418         vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0,
    419                    denoiser->yv12_running_avg[i].frame_size);
    420 
    421     }
    422     denoiser->yv12_mc_running_avg.flags = 0;
    423 
    424     if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
    425                                    height, VP8BORDERINPIXELS) < 0)
    426     {
    427         vp8_denoiser_free(denoiser);
    428         return 1;
    429     }
    430 
    431     vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
    432                denoiser->yv12_mc_running_avg.frame_size);
    433 
    434     if (vp8_yv12_alloc_frame_buffer(&denoiser->yv12_last_source, width,
    435                                     height, VP8BORDERINPIXELS) < 0) {
    436       vp8_denoiser_free(denoiser);
    437       return 1;
    438     }
    439     vpx_memset(denoiser->yv12_last_source.buffer_alloc, 0,
    440                denoiser->yv12_last_source.frame_size);
    441 
    442     denoiser->denoise_state = vpx_calloc((num_mb_rows * num_mb_cols), 1);
    443     vpx_memset(denoiser->denoise_state, 0, (num_mb_rows * num_mb_cols));
    444     vp8_denoiser_set_parameters(denoiser, mode);
    445     denoiser->nmse_source_diff = 0;
    446     denoiser->nmse_source_diff_count = 0;
    447     denoiser->qp_avg = 0;
    448     // QP threshold below which we can go up to aggressive mode.
    449     denoiser->qp_threshold_up = 80;
    450     // QP threshold above which we can go back down to normal mode.
    451     // For now keep this second threshold high, so not used currently.
    452     denoiser->qp_threshold_down = 128;
    453     // Bitrate thresholds and noise metric (nmse) thresholds for switching to
    454     // aggressive mode.
    455     // TODO(marpan): Adjust thresholds, including effect on resolution.
    456     denoiser->bitrate_threshold = 200000;  // (bits/sec).
    457     denoiser->threshold_aggressive_mode = 35;
    458     if (width * height > 640 * 480) {
    459       denoiser->bitrate_threshold = 500000;
    460       denoiser->threshold_aggressive_mode = 100;
    461     } else if (width * height > 960 * 540) {
    462       denoiser->bitrate_threshold = 800000;
    463       denoiser->threshold_aggressive_mode = 150;
    464     } else if (width * height > 1280 * 720) {
    465       denoiser->bitrate_threshold = 2000000;
    466       denoiser->threshold_aggressive_mode = 1400;
    467     }
    468     return 0;
    469 }
    470 
    471 
    472 void vp8_denoiser_free(VP8_DENOISER *denoiser)
    473 {
    474     int i;
    475     assert(denoiser);
    476 
    477     for (i = 0; i < MAX_REF_FRAMES ; i++)
    478     {
    479         vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
    480     }
    481     vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
    482     vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_last_source);
    483     vpx_free(denoiser->denoise_state);
    484 }
    485 
    486 
    487 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
    488                              MACROBLOCK *x,
    489                              unsigned int best_sse,
    490                              unsigned int zero_mv_sse,
    491                              int recon_yoffset,
    492                              int recon_uvoffset,
    493                              loop_filter_info_n *lfi_n,
    494                              int mb_row,
    495                              int mb_col,
    496                              int block_index)
    497 
    498 {
    499     int mv_row;
    500     int mv_col;
    501     unsigned int motion_threshold;
    502     unsigned int motion_magnitude2;
    503     unsigned int sse_thresh;
    504     int sse_diff_thresh = 0;
    505     // Spatial loop filter: only applied selectively based on
    506     // temporal filter state of block relative to top/left neighbors.
    507     int apply_spatial_loop_filter = 1;
    508     MV_REFERENCE_FRAME frame = x->best_reference_frame;
    509     MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame;
    510 
    511     enum vp8_denoiser_decision decision = FILTER_BLOCK;
    512     enum vp8_denoiser_decision decision_u = COPY_BLOCK;
    513     enum vp8_denoiser_decision decision_v = COPY_BLOCK;
    514 
    515     if (zero_frame)
    516     {
    517         YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame];
    518         YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg;
    519         YV12_BUFFER_CONFIG saved_pre,saved_dst;
    520         MB_MODE_INFO saved_mbmi;
    521         MACROBLOCKD *filter_xd = &x->e_mbd;
    522         MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi;
    523         int sse_diff = 0;
    524         // Bias on zero motion vector sse.
    525         const int zero_bias = denoiser->denoise_pars.denoise_mv_bias;
    526         zero_mv_sse = (unsigned int)((int64_t)zero_mv_sse * zero_bias / 100);
    527         sse_diff = zero_mv_sse - best_sse;
    528 
    529         saved_mbmi = *mbmi;
    530 
    531         /* Use the best MV for the compensation. */
    532         mbmi->ref_frame = x->best_reference_frame;
    533         mbmi->mode = x->best_sse_inter_mode;
    534         mbmi->mv = x->best_sse_mv;
    535         mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs;
    536         mv_col = x->best_sse_mv.as_mv.col;
    537         mv_row = x->best_sse_mv.as_mv.row;
    538         // Bias to zero_mv if small amount of motion.
    539         // Note sse_diff_thresh is intialized to zero, so this ensures
    540         // we will always choose zero_mv for denoising if
    541         // zero_mv_see <= best_sse (i.e., sse_diff <= 0).
    542         if ((unsigned int)(mv_row * mv_row + mv_col * mv_col)
    543             <= NOISE_MOTION_THRESHOLD)
    544             sse_diff_thresh = (int)SSE_DIFF_THRESHOLD;
    545 
    546         if (frame == INTRA_FRAME ||
    547             sse_diff <= sse_diff_thresh)
    548         {
    549             /*
    550              * Handle intra blocks as referring to last frame with zero motion
    551              * and let the absolute pixel difference affect the filter factor.
    552              * Also consider small amount of motion as being random walk due
    553              * to noise, if it doesn't mean that we get a much bigger error.
    554              * Note that any changes to the mode info only affects the
    555              * denoising.
    556              */
    557             mbmi->ref_frame =
    558                     x->best_zeromv_reference_frame;
    559 
    560             src = &denoiser->yv12_running_avg[zero_frame];
    561 
    562             mbmi->mode = ZEROMV;
    563             mbmi->mv.as_int = 0;
    564             x->best_sse_inter_mode = ZEROMV;
    565             x->best_sse_mv.as_int = 0;
    566             best_sse = zero_mv_sse;
    567         }
    568 
    569         saved_pre = filter_xd->pre;
    570         saved_dst = filter_xd->dst;
    571 
    572         /* Compensate the running average. */
    573         filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
    574         filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
    575         filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
    576         /* Write the compensated running average to the destination buffer. */
    577         filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
    578         filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
    579         filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
    580 
    581         if (!x->skip)
    582         {
    583             vp8_build_inter_predictors_mb(filter_xd);
    584         }
    585         else
    586         {
    587             vp8_build_inter16x16_predictors_mb(filter_xd,
    588                                                filter_xd->dst.y_buffer,
    589                                                filter_xd->dst.u_buffer,
    590                                                filter_xd->dst.v_buffer,
    591                                                filter_xd->dst.y_stride,
    592                                                filter_xd->dst.uv_stride);
    593         }
    594         filter_xd->pre = saved_pre;
    595         filter_xd->dst = saved_dst;
    596         *mbmi = saved_mbmi;
    597 
    598     }
    599 
    600     mv_row = x->best_sse_mv.as_mv.row;
    601     mv_col = x->best_sse_mv.as_mv.col;
    602     motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
    603     motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
    604         NOISE_MOTION_THRESHOLD;
    605 
    606     if (motion_magnitude2 <
    607         denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
    608       x->increase_denoising = 1;
    609 
    610     sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
    611     if (x->increase_denoising)
    612       sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
    613 
    614     if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
    615       decision = COPY_BLOCK;
    616 
    617     if (decision == FILTER_BLOCK)
    618     {
    619         unsigned char *mc_running_avg_y =
    620             denoiser->yv12_mc_running_avg.y_buffer + recon_yoffset;
    621         int mc_avg_y_stride = denoiser->yv12_mc_running_avg.y_stride;
    622         unsigned char *running_avg_y =
    623             denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset;
    624         int avg_y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride;
    625 
    626         /* Filter. */
    627         decision = vp8_denoiser_filter(mc_running_avg_y, mc_avg_y_stride,
    628                                        running_avg_y, avg_y_stride,
    629                                        x->thismb, 16, motion_magnitude2,
    630                                        x->increase_denoising);
    631         denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ?
    632             kFilterNonZeroMV : kFilterZeroMV;
    633         // Only denoise UV for zero motion, and if y channel was denoised.
    634         if (denoiser->denoiser_mode != kDenoiserOnYOnly &&
    635             motion_magnitude2 == 0 &&
    636             decision == FILTER_BLOCK) {
    637           unsigned char *mc_running_avg_u =
    638               denoiser->yv12_mc_running_avg.u_buffer + recon_uvoffset;
    639           unsigned char *running_avg_u =
    640               denoiser->yv12_running_avg[INTRA_FRAME].u_buffer + recon_uvoffset;
    641           unsigned char *mc_running_avg_v =
    642               denoiser->yv12_mc_running_avg.v_buffer + recon_uvoffset;
    643           unsigned char *running_avg_v =
    644               denoiser->yv12_running_avg[INTRA_FRAME].v_buffer + recon_uvoffset;
    645           int mc_avg_uv_stride = denoiser->yv12_mc_running_avg.uv_stride;
    646           int avg_uv_stride = denoiser->yv12_running_avg[INTRA_FRAME].uv_stride;
    647           int signal_stride = x->block[16].src_stride;
    648           decision_u =
    649               vp8_denoiser_filter_uv(mc_running_avg_u, mc_avg_uv_stride,
    650                                       running_avg_u, avg_uv_stride,
    651                                       x->block[16].src + *x->block[16].base_src,
    652                                       signal_stride, motion_magnitude2, 0);
    653           decision_v =
    654               vp8_denoiser_filter_uv(mc_running_avg_v, mc_avg_uv_stride,
    655                                       running_avg_v, avg_uv_stride,
    656                                       x->block[20].src + *x->block[20].base_src,
    657                                       signal_stride, motion_magnitude2, 0);
    658         }
    659     }
    660     if (decision == COPY_BLOCK)
    661     {
    662         /* No filtering of this block; it differs too much from the predictor,
    663          * or the motion vector magnitude is considered too big.
    664          */
    665         vp8_copy_mem16x16(
    666                 x->thismb, 16,
    667                 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
    668                 denoiser->yv12_running_avg[INTRA_FRAME].y_stride);
    669         denoiser->denoise_state[block_index] = kNoFilter;
    670     }
    671     if (denoiser->denoiser_mode != kDenoiserOnYOnly) {
    672       if (decision_u == COPY_BLOCK) {
    673         vp8_copy_mem8x8(
    674             x->block[16].src + *x->block[16].base_src, x->block[16].src_stride,
    675             denoiser->yv12_running_avg[INTRA_FRAME].u_buffer + recon_uvoffset,
    676             denoiser->yv12_running_avg[INTRA_FRAME].uv_stride);
    677       }
    678       if (decision_v == COPY_BLOCK) {
    679         vp8_copy_mem8x8(
    680             x->block[20].src + *x->block[20].base_src, x->block[16].src_stride,
    681             denoiser->yv12_running_avg[INTRA_FRAME].v_buffer + recon_uvoffset,
    682             denoiser->yv12_running_avg[INTRA_FRAME].uv_stride);
    683       }
    684     }
    685     // Option to selectively deblock the denoised signal, for y channel only.
    686     if (apply_spatial_loop_filter) {
    687       loop_filter_info lfi;
    688       int apply_filter_col = 0;
    689       int apply_filter_row = 0;
    690       int apply_filter = 0;
    691       int y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride;
    692       int uv_stride =denoiser->yv12_running_avg[INTRA_FRAME].uv_stride;
    693 
    694       // Fix filter level to some nominal value for now.
    695       int filter_level = 32;
    696 
    697       int hev_index = lfi_n->hev_thr_lut[INTER_FRAME][filter_level];
    698       lfi.mblim = lfi_n->mblim[filter_level];
    699       lfi.blim = lfi_n->blim[filter_level];
    700       lfi.lim = lfi_n->lim[filter_level];
    701       lfi.hev_thr = lfi_n->hev_thr[hev_index];
    702 
    703       // Apply filter if there is a difference in the denoiser filter state
    704       // between the current and left/top block, or if non-zero motion vector
    705       // is used for the motion-compensated filtering.
    706       if (mb_col > 0) {
    707         apply_filter_col = !((denoiser->denoise_state[block_index] ==
    708             denoiser->denoise_state[block_index - 1]) &&
    709             denoiser->denoise_state[block_index] != kFilterNonZeroMV);
    710         if (apply_filter_col) {
    711           // Filter left vertical edge.
    712           apply_filter = 1;
    713           vp8_loop_filter_mbv(
    714               denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
    715               NULL, NULL, y_stride, uv_stride, &lfi);
    716         }
    717       }
    718       if (mb_row > 0) {
    719         apply_filter_row = !((denoiser->denoise_state[block_index] ==
    720             denoiser->denoise_state[block_index - denoiser->num_mb_cols]) &&
    721             denoiser->denoise_state[block_index] != kFilterNonZeroMV);
    722         if (apply_filter_row) {
    723           // Filter top horizontal edge.
    724           apply_filter = 1;
    725           vp8_loop_filter_mbh(
    726               denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
    727               NULL, NULL, y_stride, uv_stride, &lfi);
    728         }
    729       }
    730       if (apply_filter) {
    731         // Update the signal block |x|. Pixel changes are only to top and/or
    732         // left boundary pixels: can we avoid full block copy here.
    733         vp8_copy_mem16x16(
    734             denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
    735             y_stride, x->thismb, 16);
    736       }
    737     }
    738 }
    739