fix denoiser for temporal patterns and rd
authorJim Bankoski <jimbankoski@google.com>
Thu, 24 May 2012 14:44:03 +0000 (07:44 -0700)
committerJim Bankoski <jimbankoski@google.com>
Thu, 24 May 2012 14:44:03 +0000 (07:44 -0700)
This extends the denoiser to work for temporally scalable
coding.

I believe this also fixes a very rare but really bad bug in the original
implementation.

Change-Id: I8b3593a8c54b86eb76f785af1970935f7d56262a

vp8/common/blockd.h
vp8/encoder/block.h
vp8/encoder/denoising.c
vp8/encoder/denoising.h
vp8/encoder/encodeframe.c
vp8/encoder/onyx_if.c
vp8/encoder/pickinter.c
vp8/encoder/pickinter.h
vp8/encoder/rdopt.c
vp8_scalable_patterns.c

index 1945edb..c7206b2 100644 (file)
@@ -224,12 +224,6 @@ typedef struct macroblockd
     MODE_INFO *mode_info_context;
     int mode_info_stride;
 
-#if CONFIG_TEMPORAL_DENOISING
-    MB_PREDICTION_MODE best_sse_inter_mode;
-    int_mv best_sse_mv;
-    unsigned char need_to_clamp_best_mvs;
-#endif
-
     FRAME_TYPE frame_type;
 
     int up_available;
index 4ecbf1f..9756acc 100644 (file)
@@ -119,6 +119,16 @@ typedef struct macroblock
     int optimize;
     int q_index;
 
+#if CONFIG_TEMPORAL_DENOISING
+    MB_PREDICTION_MODE best_sse_inter_mode;
+    int_mv best_sse_mv;
+    MV_REFERENCE_FRAME best_reference_frame;
+    MV_REFERENCE_FRAME best_zeromv_reference_frame;
+    unsigned char need_to_clamp_best_mvs;
+#endif
+
+
+
     void (*short_fdct4x4)(short *input, short *output, int pitch);
     void (*short_fdct8x4)(short *input, short *output, int pitch);
     void (*short_walsh4x4)(short *input, short *output, int pitch);
index 45d54ee..194d422 100644 (file)
@@ -22,68 +22,6 @@ static const unsigned int SSE_DIFF_THRESHOLD = 16 * 16 * 20;
 static const unsigned int SSE_THRESHOLD = 16 * 16 * 40;
 
 
-static unsigned int denoiser_motion_compensate(YV12_BUFFER_CONFIG *src,
-        YV12_BUFFER_CONFIG *dst,
-        MACROBLOCK *x,
-        unsigned int best_sse,
-        unsigned int zero_mv_sse,
-        int recon_yoffset,
-        int recon_uvoffset)
-{
-    MACROBLOCKD filter_xd = x->e_mbd;
-    int mv_col;
-    int mv_row;
-    int sse_diff = zero_mv_sse - best_sse;
-    // Compensate the running average.
-    filter_xd.pre.y_buffer = src->y_buffer + recon_yoffset;
-    filter_xd.pre.u_buffer = src->u_buffer + recon_uvoffset;
-    filter_xd.pre.v_buffer = src->v_buffer + recon_uvoffset;
-    // Write the compensated running average to the destination buffer.
-    filter_xd.dst.y_buffer = dst->y_buffer + recon_yoffset;
-    filter_xd.dst.u_buffer = dst->u_buffer + recon_uvoffset;
-    filter_xd.dst.v_buffer = dst->v_buffer + recon_uvoffset;
-    // Use the best MV for the compensation.
-    filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
-    filter_xd.mode_info_context->mbmi.mode = filter_xd.best_sse_inter_mode;
-    filter_xd.mode_info_context->mbmi.mv = filter_xd.best_sse_mv;
-    filter_xd.mode_info_context->mbmi.need_to_clamp_mvs =
-        filter_xd.need_to_clamp_best_mvs;
-    mv_col = filter_xd.best_sse_mv.as_mv.col;
-    mv_row = filter_xd.best_sse_mv.as_mv.row;
-
-    if (filter_xd.mode_info_context->mbmi.mode <= B_PRED ||
-        (mv_row *mv_row + mv_col *mv_col <= NOISE_MOTION_THRESHOLD &&
-         sse_diff < SSE_DIFF_THRESHOLD))
-    {
-        // Handle intra blocks as referring to last frame with zero motion and
-        // let the absolute pixel difference affect the filter factor.
-        // Also consider small amount of motion as being random walk due to
-        // noise, if it doesn't mean that we get a much bigger error.
-        // Note that any changes to the mode info only affects the denoising.
-        filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
-        filter_xd.mode_info_context->mbmi.mode = ZEROMV;
-        filter_xd.mode_info_context->mbmi.mv.as_int = 0;
-        x->e_mbd.best_sse_inter_mode = ZEROMV;
-        x->e_mbd.best_sse_mv.as_int = 0;
-        best_sse = zero_mv_sse;
-    }
-
-    if (!x->skip)
-    {
-        vp8_build_inter_predictors_mb(&filter_xd);
-    }
-    else
-    {
-        vp8_build_inter16x16_predictors_mb(&filter_xd,
-                                           filter_xd.dst.y_buffer,
-                                           filter_xd.dst.u_buffer,
-                                           filter_xd.dst.v_buffer,
-                                           filter_xd.dst.y_stride,
-                                           filter_xd.dst.uv_stride);
-    }
-
-    return best_sse;
-}
 
 // The filtering coefficients used for denoizing are adjusted for static
 // blocks, or blocks with very small motion vectors. This is done through
@@ -216,27 +154,34 @@ void vp8_denoiser_filter_c(YV12_BUFFER_CONFIG *mc_running_avg,
 
 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height)
 {
+    int i;
     assert(denoiser);
-    denoiser->yv12_running_avg.flags = 0;
 
-    if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width,
-                                    height, VP8BORDERINPIXELS) < 0)
+    /* don't need one for intra start at 1 */
+    for (i = 1; i < MAX_REF_FRAMES; i++)
     {
-        vp8_denoiser_free(denoiser);
-        return 1;
-    }
+        denoiser->yv12_running_avg[i].flags = 0;
 
+        if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width,
+                                        height, VP8BORDERINPIXELS)
+            < 0)
+        {
+            vp8_denoiser_free(denoiser);
+            return 1;
+        }
+        vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0,
+                   denoiser->yv12_running_avg[i].frame_size);
+
+    }
     denoiser->yv12_mc_running_avg.flags = 0;
 
     if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
-                                    height, VP8BORDERINPIXELS) < 0)
+                                   height, VP8BORDERINPIXELS) < 0)
     {
         vp8_denoiser_free(denoiser);
         return 1;
     }
 
-    vpx_memset(denoiser->yv12_running_avg.buffer_alloc, 0,
-               denoiser->yv12_running_avg.frame_size);
     vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
                denoiser->yv12_mc_running_avg.frame_size);
     return 0;
@@ -244,11 +189,18 @@ int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height)
 
 void vp8_denoiser_free(VP8_DENOISER *denoiser)
 {
+    int i;
     assert(denoiser);
-    vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg);
+
+    /* we don't have one for intra ref frame */
+    for (i = 1; i < MAX_REF_FRAMES ; i++)
+    {
+        vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
+    }
     vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
 }
 
+
 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
                              MACROBLOCK *x,
                              unsigned int best_sse,
@@ -259,32 +211,103 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
     int mv_row;
     int mv_col;
     unsigned int motion_magnitude2;
+
+    MV_REFERENCE_FRAME frame = x->best_reference_frame;
+    MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame;
+
     // Motion compensate the running average.
-    best_sse = denoiser_motion_compensate(&denoiser->yv12_running_avg,
-                                          &denoiser->yv12_mc_running_avg,
-                                          x,
-                                          best_sse,
-                                          zero_mv_sse,
-                                          recon_yoffset,
-                                          recon_uvoffset);
-
-    mv_row = x->e_mbd.best_sse_mv.as_mv.row;
-    mv_col = x->e_mbd.best_sse_mv.as_mv.col;
-    motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
+    if(zero_frame)
+    {
+        YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame];
+        YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg;
+        YV12_BUFFER_CONFIG saved_pre,saved_dst;
+        MB_MODE_INFO saved_mbmi;
+        MACROBLOCKD *filter_xd = &x->e_mbd;
+        MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi;
+        int mv_col;
+        int mv_row;
+        int sse_diff = zero_mv_sse - best_sse;
+
+        saved_mbmi = *mbmi;
+
+        // Use the best MV for the compensation.
+        mbmi->ref_frame = x->best_reference_frame;
+        mbmi->mode = x->best_sse_inter_mode;
+        mbmi->mv = x->best_sse_mv;
+        mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs;
+        mv_col = x->best_sse_mv.as_mv.col;
+        mv_row = x->best_sse_mv.as_mv.row;
+
+        if(frame == INTRA_FRAME ||
+            (mv_row *mv_row + mv_col *mv_col <= NOISE_MOTION_THRESHOLD &&
+             sse_diff < SSE_DIFF_THRESHOLD))
+        {
+            // Handle intra blocks as referring to last frame with zero motion
+            // and let the absolute pixel difference affect the filter factor.
+            // Also consider small amount of motion as being random walk due to
+            // noise, if it doesn't mean that we get a much bigger error.
+            // Note that any changes to the mode info only affects the denoising.
+            mbmi->ref_frame =
+                    x->best_zeromv_reference_frame;
+
+            src = &denoiser->yv12_running_avg[zero_frame];
+
+            mbmi->mode = ZEROMV;
+            mbmi->mv.as_int = 0;
+            x->best_sse_inter_mode = ZEROMV;
+            x->best_sse_mv.as_int = 0;
+            best_sse = zero_mv_sse;
+        }
+
+        saved_pre = filter_xd->pre;
+        saved_dst = filter_xd->dst;
 
-    if (best_sse > SSE_THRESHOLD ||
-        motion_magnitude2 > 8 * NOISE_MOTION_THRESHOLD)
+        // Compensate the running average.
+        filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
+        filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
+        filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
+        // Write the compensated running average to the destination buffer.
+        filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
+        filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
+        filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
+
+        if (!x->skip)
+        {
+            vp8_build_inter_predictors_mb(filter_xd);
+        }
+        else
+        {
+            vp8_build_inter16x16_predictors_mb(filter_xd,
+                                               filter_xd->dst.y_buffer,
+                                               filter_xd->dst.u_buffer,
+                                               filter_xd->dst.v_buffer,
+                                               filter_xd->dst.y_stride,
+                                               filter_xd->dst.uv_stride);
+        }
+        filter_xd->pre = saved_pre;
+        filter_xd->dst = saved_dst;
+        *mbmi = saved_mbmi;
+
+    }
+
+    mv_row = x->best_sse_mv.as_mv.row;
+    mv_col = x->best_sse_mv.as_mv.col;
+    motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
+    if (best_sse > SSE_THRESHOLD || motion_magnitude2
+           > 8 * NOISE_MOTION_THRESHOLD)
     {
-        // No filtering of this block since it differs too much from the
-        // predictor, or the motion vector magnitude is considered too big.
-        vp8_copy_mem16x16(x->thismb, 16,
-                          denoiser->yv12_running_avg.y_buffer + recon_yoffset,
-                          denoiser->yv12_running_avg.y_stride);
+        // No filtering of this block; it differs too much from the predictor,
+        // or the motion vector magnitude is considered too big.
+        vp8_copy_mem16x16(
+                x->thismb, 16,
+                denoiser->yv12_running_avg[LAST_FRAME].y_buffer + recon_yoffset,
+                denoiser->yv12_running_avg[LAST_FRAME].y_stride);
         return;
     }
 
     // Filter.
     vp8_denoiser_filter(&denoiser->yv12_mc_running_avg,
-                        &denoiser->yv12_running_avg, x, motion_magnitude2,
+                        &denoiser->yv12_running_avg[LAST_FRAME], x,
+                        motion_magnitude2,
                         recon_yoffset, recon_uvoffset);
 }
index 0a54e71..441bccd 100644 (file)
@@ -17,8 +17,8 @@
 
 typedef struct vp8_denoiser
 {
-  YV12_BUFFER_CONFIG yv12_running_avg;
-  YV12_BUFFER_CONFIG yv12_mc_running_avg;
+    YV12_BUFFER_CONFIG yv12_running_avg[MAX_REF_FRAMES];
+    YV12_BUFFER_CONFIG yv12_mc_running_avg;
 } VP8_DENOISER;
 
 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height);
index f0ffaea..2cef01e 100644 (file)
@@ -1177,9 +1177,11 @@ int vp8cx_encode_inter_macroblock
 
 #if CONFIG_TEMPORAL_DENOISING
     // Reset the best sse mode/mv for each macroblock.
-    x->e_mbd.best_sse_inter_mode = 0;
-    x->e_mbd.best_sse_mv.as_int = 0;
-    x->e_mbd.need_to_clamp_best_mvs = 0;
+    x->best_reference_frame = INTRA_FRAME;
+    x->best_zeromv_reference_frame = INTRA_FRAME;
+    x->best_sse_inter_mode = 0;
+    x->best_sse_mv.as_int = 0;
+    x->need_to_clamp_best_mvs = 0;
 #endif
 
     if (cpi->sf.RD)
index 372d5aa..67a8b5a 100644 (file)
@@ -3153,9 +3153,49 @@ void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm)
 #if CONFIG_TEMPORAL_DENOISING
     if (cpi->oxcf.noise_sensitivity)
     {
-      vp8_yv12_extend_frame_borders(&cpi->denoiser.yv12_running_avg);
+
+
+        /* we shouldn't have to keep multiple copies as we know in advance which
+         * buffer we should start - for now to get something up and running
+         * I've chosen to copy the buffers
+         */
+        if (cm->frame_type == KEY_FRAME)
+        {
+            int i;
+            vp8_yv12_copy_frame(
+                    cpi->Source,
+                    &cpi->denoiser.yv12_running_avg[LAST_FRAME]);
+
+            vp8_yv12_extend_frame_borders(
+                    &cpi->denoiser.yv12_running_avg[LAST_FRAME]);
+
+            for (i = 2; i < MAX_REF_FRAMES - 1; i++)
+                vp8_yv12_copy_frame(
+                        cpi->Source,
+                        &cpi->denoiser.yv12_running_avg[i]);
+        }
+        else /* For non key frames */
+        {
+            vp8_yv12_extend_frame_borders(
+                    &cpi->denoiser.yv12_running_avg[LAST_FRAME]);
+
+            if (cm->refresh_alt_ref_frame || cm->copy_buffer_to_arf)
+            {
+                vp8_yv12_copy_frame(
+                        &cpi->denoiser.yv12_running_avg[LAST_FRAME],
+                        &cpi->denoiser.yv12_running_avg[ALTREF_FRAME]);
+            }
+            if (cm->refresh_golden_frame || cm->copy_buffer_to_gf)
+            {
+                vp8_yv12_copy_frame(
+                        &cpi->denoiser.yv12_running_avg[LAST_FRAME],
+                        &cpi->denoiser.yv12_running_avg[GOLDEN_FRAME]);
+            }
+        }
+
     }
 #endif
+
 }
 
 static void encode_frame_to_data_rate
index 4de84fd..47d646f 100644 (file)
@@ -61,7 +61,7 @@ int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d,
 }
 
 
-static int get_inter_mbpred_error(MACROBLOCK *mb,
+int vp8_get_inter_mbpred_error(MACROBLOCK *mb,
                                   const vp8_variance_fn_ptr_t *vfp,
                                   unsigned int *sse,
                                   int_mv this_mv)
@@ -486,7 +486,7 @@ static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, V
 
     if((this_mode != NEWMV) ||
         !(cpi->sf.half_pixel_search) || cpi->common.full_pixel==1)
-        *distortion2 = get_inter_mbpred_error(x,
+        *distortion2 = vp8_get_inter_mbpred_error(x,
                                               &cpi->fn_ptr[BLOCK_16X16],
                                               sse, mv);
 
@@ -523,7 +523,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
     int best_mode_index = 0;
     unsigned int sse = INT_MAX, best_rd_sse = INT_MAX;
 #if CONFIG_TEMPORAL_DENOISING
-    unsigned int zero_mv_sse = 0, best_sse = INT_MAX;
+    unsigned int zero_mv_sse = INT_MAX, best_sse = INT_MAX;
 #endif
 
     int_mv mvp;
@@ -964,25 +964,27 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
 #if CONFIG_TEMPORAL_DENOISING
         if (cpi->oxcf.noise_sensitivity)
         {
-          // Store for later use by denoiser.
-          if (this_mode == ZEROMV &&
-              x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME)
-          {
-            zero_mv_sse = sse;
-          }
-
-          // Store the best NEWMV in x for later use in the denoiser.
-          // We are restricted to the LAST_FRAME since the denoiser only keeps
-          // one filter state.
-          if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV &&
-              x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME)
-          {
-            best_sse = sse;
-            x->e_mbd.best_sse_inter_mode = NEWMV;
-            x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv;
-            x->e_mbd.need_to_clamp_best_mvs =
-                x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs;
-          }
+
+            // Store for later use by denoiser.
+            if (this_mode == ZEROMV && sse < zero_mv_sse )
+            {
+                zero_mv_sse = sse;
+                x->best_zeromv_reference_frame =
+                        x->e_mbd.mode_info_context->mbmi.ref_frame;
+            }
+
+            // Store the best NEWMV in x for later use in the denoiser.
+            if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV &&
+                    sse < best_sse)
+            {
+                best_sse = sse;
+                x->best_sse_inter_mode = NEWMV;
+                x->best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv;
+                x->need_to_clamp_best_mvs =
+                    x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs;
+                x->best_reference_frame =
+                    x->e_mbd.mode_info_context->mbmi.ref_frame;
+            }
         }
 #endif
 
@@ -1058,37 +1060,47 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
 #if CONFIG_TEMPORAL_DENOISING
     if (cpi->oxcf.noise_sensitivity)
     {
-      if (x->e_mbd.best_sse_inter_mode == DC_PRED) {
-        // No best MV found.
-        x->e_mbd.best_sse_inter_mode = best_mbmode.mode;
-        x->e_mbd.best_sse_mv = best_mbmode.mv;
-        x->e_mbd.need_to_clamp_best_mvs = best_mbmode.need_to_clamp_mvs;
-        best_sse = best_rd_sse;
-      }
-      vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
-                              recon_yoffset, recon_uvoffset);
-
-      // Reevaluate ZEROMV after denoising.
-      if (best_mbmode.ref_frame == INTRA_FRAME)
-      {
-        int this_rd = 0;
-        rate2 = 0;
-        distortion2 = 0;
-        x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
-        rate2 += x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
-        this_mode = ZEROMV;
-        rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
-        x->e_mbd.mode_info_context->mbmi.mode = this_mode;
-        x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
-        x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
-        this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x);
+        if (x->best_sse_inter_mode == DC_PRED)
+        {
+            // No best MV found.
+            x->best_sse_inter_mode = best_mbmode.mode;
+            x->best_sse_mv = best_mbmode.mv;
+            x->need_to_clamp_best_mvs = best_mbmode.need_to_clamp_mvs;
+            x->best_reference_frame = best_mbmode.ref_frame;
+            best_sse = best_rd_sse;
+        }
+        vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
+                                recon_yoffset, recon_uvoffset);
 
-        if (this_rd < best_rd || x->skip)
+
+        // Reevaluate ZEROMV after denoising.
+        if (best_mbmode.ref_frame == INTRA_FRAME &&
+            x->best_zeromv_reference_frame != INTRA_FRAME)
         {
-            vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi,
-                       sizeof(MB_MODE_INFO));
+            int this_rd = 0;
+            int this_ref_frame = x->best_zeromv_reference_frame;
+            rate2 = x->ref_frame_cost[this_ref_frame] +
+                    vp8_cost_mv_ref(ZEROMV, mdcounts);
+            distortion2 = 0;
+
+            // set up the proper prediction buffers for the frame
+            x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame;
+            x->e_mbd.pre.y_buffer = plane[this_ref_frame][0];
+            x->e_mbd.pre.u_buffer = plane[this_ref_frame][1];
+            x->e_mbd.pre.v_buffer = plane[this_ref_frame][2];
+
+            x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
+            x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
+            x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
+            this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x);
+
+            if (this_rd < best_rd)
+            {
+                vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi,
+                           sizeof(MB_MODE_INFO));
+            }
         }
-      }
+
     }
 #endif
 
index 3d83782..6fbd887 100644 (file)
@@ -20,4 +20,8 @@ extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
                                 int mb_row, int mb_col);
 extern void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate);
 
+extern int vp8_get_inter_mbpred_error(MACROBLOCK *mb,
+                                      const vp8_variance_fn_ptr_t *vfp,
+                                      unsigned int *sse,
+                                      int_mv this_mv);
 #endif
index 1a2eb11..b457f03 100644 (file)
@@ -21,6 +21,7 @@
 #include "onyx_int.h"
 #include "modecosts.h"
 #include "encodeintra.h"
+#include "pickinter.h"
 #include "vp8/common/entropymode.h"
 #include "vp8/common/reconinter.h"
 #include "vp8/common/reconintra4x4.h"
@@ -36,7 +37,6 @@
 #if CONFIG_TEMPORAL_DENOISING
 #include "denoising.h"
 #endif
-
 extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x);
 
 #define MAXF(a,b)            (((a) > (b)) ? (a) : (b))
@@ -1965,6 +1965,11 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
     int intra_rd_penalty =  10* vp8_dc_quant(cpi->common.base_qindex,
                                              cpi->common.y1dc_delta_q);
 
+#if CONFIG_TEMPORAL_DENOISING
+    unsigned int zero_mv_sse = INT_MAX, best_sse = INT_MAX,
+            best_rd_sse = INT_MAX;
+#endif
+
     mode_mv = mode_mv_sb[sign_bias];
     best_ref_mv.as_int = 0;
     best_mode.rd = INT_MAX;
@@ -2375,21 +2380,38 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
           best_mode.intra_rd = this_rd;
             *returnintra = rd.distortion2 ;
         }
-
 #if CONFIG_TEMPORAL_DENOISING
         if (cpi->oxcf.noise_sensitivity)
         {
-          // Store the best NEWMV in x for later use in the denoiser.
-          // We are restricted to the LAST_FRAME since the denoiser only keeps
-          // one filter state.
-          if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV &&
-              x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME)
-          {
-            x->e_mbd.best_sse_inter_mode = NEWMV;
-            x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv;
-            x->e_mbd.need_to_clamp_best_mvs =
-                x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs;
-          }
+            unsigned int sse;
+            vp8_get_inter_mbpred_error(x,&cpi->fn_ptr[BLOCK_16X16],&sse,
+                                   mode_mv[this_mode]);
+
+            if (sse < best_rd_sse)
+                best_rd_sse = sse;
+
+            // Store for later use by denoiser.
+            if (this_mode == ZEROMV && sse < zero_mv_sse )
+            {
+                zero_mv_sse = sse;
+                x->best_zeromv_reference_frame =
+                        x->e_mbd.mode_info_context->mbmi.ref_frame;
+            }
+
+            // Store the best NEWMV in x for later use in the denoiser.
+            if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV &&
+                    sse < best_sse)
+            {
+                best_sse = sse;
+                vp8_get_inter_mbpred_error(x,&cpi->fn_ptr[BLOCK_16X16],&best_sse,
+                                       mode_mv[this_mode]);
+                x->best_sse_inter_mode = NEWMV;
+                x->best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv;
+                x->need_to_clamp_best_mvs =
+                    x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs;
+                x->best_reference_frame =
+                    x->e_mbd.mode_info_context->mbmi.ref_frame;
+            }
         }
 #endif
 
@@ -2462,42 +2484,55 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
 #if CONFIG_TEMPORAL_DENOISING
     if (cpi->oxcf.noise_sensitivity)
     {
-      if (x->e_mbd.best_sse_inter_mode == DC_PRED) {
-        // No best MV found.
-        x->e_mbd.best_sse_inter_mode = best_mode.mbmode.mode;
-        x->e_mbd.best_sse_mv = best_mode.mbmode.mv;
-        x->e_mbd.need_to_clamp_best_mvs = best_mode.mbmode.need_to_clamp_mvs;
-      }
-
-      // TODO(holmer): No SSEs are calculated in rdopt.c. What else can be used?
-      vp8_denoiser_denoise_mb(&cpi->denoiser, x, 0, 0,
-                              recon_yoffset, recon_uvoffset);
-      // Reevalute ZEROMV if the current mode is INTRA.
-      if (best_mode.mbmode.ref_frame == INTRA_FRAME)
-      {
-        int this_rd = INT_MAX;
-        int disable_skip = 0;
-        int other_cost = 0;
-        vpx_memset(&rd, 0, sizeof(rd));
-        x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
-        rd.rate2 += x->ref_frame_cost[LAST_FRAME];
-        rd.rate2 += vp8_cost_mv_ref(ZEROMV, mdcounts);
-        x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
-        x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
-        x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
-        this_rd = evaluate_inter_mode_rd(mdcounts, &rd, &disable_skip, cpi, x);
-        this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost,
-                                           disable_skip, uv_intra_tteob,
-                                           intra_rd_penalty, cpi, x);
-        if (this_rd < best_mode.rd || x->skip)
+        if (x->best_sse_inter_mode == DC_PRED)
         {
-            // Note index of best mode so far
-            best_mode_index = mode_index;
-            *returnrate = rd.rate2;
-            *returndistortion = rd.distortion2;
-            update_best_mode(&best_mode, this_rd, &rd, other_cost, x);
+            // No best MV found.
+            x->best_sse_inter_mode = best_mode.mbmode.mode;
+            x->best_sse_mv = best_mode.mbmode.mv;
+            x->need_to_clamp_best_mvs = best_mode.mbmode.need_to_clamp_mvs;
+            x->best_reference_frame = best_mode.mbmode.ref_frame;
+            best_sse = best_rd_sse;
         }
-      }
+        vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
+                                recon_yoffset, recon_uvoffset);
+
+
+        // Reevaluate ZEROMV after denoising.
+        if (best_mode.mbmode.ref_frame == INTRA_FRAME &&
+            x->best_zeromv_reference_frame != INTRA_FRAME)
+        {
+            int this_rd = INT_MAX;
+            int disable_skip = 0;
+            int other_cost = 0;
+            int this_ref_frame = x->best_zeromv_reference_frame;
+            rd.rate2 = x->ref_frame_cost[this_ref_frame] +
+                    vp8_cost_mv_ref(ZEROMV, mdcounts);
+            rd.distortion2 = 0;
+
+            // set up the proper prediction buffers for the frame
+            x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame;
+            x->e_mbd.pre.y_buffer = plane[this_ref_frame][0];
+            x->e_mbd.pre.u_buffer = plane[this_ref_frame][1];
+            x->e_mbd.pre.v_buffer = plane[this_ref_frame][2];
+
+            x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
+            x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
+            x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
+
+            this_rd = evaluate_inter_mode_rd(mdcounts, &rd, &disable_skip, cpi, x);
+            this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost,
+                                               disable_skip, uv_intra_tteob,
+                                               intra_rd_penalty, cpi, x);
+            if (this_rd < best_mode.rd || x->skip)
+            {
+                // Note index of best mode so far
+                best_mode_index = mode_index;
+                *returnrate = rd.rate2;
+                *returndistortion = rd.distortion2;
+                update_best_mode(&best_mode, this_rd, &rd, other_cost, x);
+            }
+        }
+
     }
 #endif
 
index aa931e2..8d151dd 100644 (file)
@@ -493,6 +493,7 @@ int main(int argc, char **argv) {
     // Cap CPU & first I-frame size
     vpx_codec_control (&codec, VP8E_SET_CPUUSED,                -6);
     vpx_codec_control (&codec, VP8E_SET_STATIC_THRESHOLD,      800);
+    vpx_codec_control (&codec, VP8E_SET_NOISE_SENSITIVITY,       1);
 
     max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
                          * ((double) cfg.g_timebase.den / cfg.g_timebase.num)