Commit f78e5a04 authored by Jim Bankoski's avatar Jim Bankoski Committed by John Koleszar
Browse files

fix denoiser for temporal patterns and rd

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
parent 5715c39c
......@@ -216,12 +216,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;
......
......@@ -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);
......
......@@ -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);
}
......@@ -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);
......
......@@ -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)
......
......@@ -3156,9 +3156,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
......
......@@ -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
......
......@@ -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
......@@ -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))
......@@ -1962,6 +1962,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;
......@@ -2372,21 +2377,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
......@@ -2459,42 +2481,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;