summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure4
-rw-r--r--vp8/common/alloccommon.c1
-rw-r--r--vp8/common/blockd.h6
-rw-r--r--vp8/common/postproc.c2
-rw-r--r--vp8/encoder/denoising.c212
-rw-r--r--vp8/encoder/denoising.h33
-rw-r--r--vp8/encoder/encodeframe.c7
-rw-r--r--vp8/encoder/onyx_if.c23
-rw-r--r--vp8/encoder/onyx_int.h7
-rw-r--r--vp8/encoder/pickinter.c151
-rw-r--r--vp8/encoder/rdopt.c511
-rw-r--r--vp8/vp8_cx_iface.c8
-rw-r--r--vp8/vp8cx.mk2
13 files changed, 729 insertions, 238 deletions
diff --git a/configure b/configure
index cf3eb32ec..2724c3008 100755
--- a/configure
+++ b/configure
@@ -47,6 +47,7 @@ Advanced options:
${toggle_small} favor smaller size over speed
${toggle_postproc_visualizer} macro block / block level visualizers
${toggle_multi_res_encoding} enable multiple-resolution encoding
+ ${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser
Codecs:
Codecs can be selectively enabled or disabled individually, or by family:
@@ -165,6 +166,7 @@ enable md5
enable spatial_resampling
enable multithread
enable os_support
+enable temporal_denoising
[ -d ${source_path}/../include ] && enable alt_tree_layout
for d in vp8; do
@@ -263,6 +265,7 @@ CONFIG_LIST="
os_support
unit_tests
multi_res_encoding
+ temporal_denoising
"
CMDLINE_SELECT="
extra_warnings
@@ -307,6 +310,7 @@ CMDLINE_SELECT="
postproc_visualizer
unit_tests
multi_res_encoding
+ temporal_denoising
"
process_cmdline() {
diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c
index b606aaca0..b32d8a939 100644
--- a/vp8/common/alloccommon.c
+++ b/vp8/common/alloccommon.c
@@ -37,7 +37,6 @@ static void update_mode_info_border(MODE_INFO *mi, int rows, int cols)
void vp8_de_alloc_frame_buffers(VP8_COMMON *oci)
{
int i;
-
for (i = 0; i < NUM_YV12_BUFFERS; i++)
vp8_yv12_de_alloc_frame_buffer(&oci->yv12_fb[i]);
diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h
index c8d1bab7d..692f0ebd2 100644
--- a/vp8/common/blockd.h
+++ b/vp8/common/blockd.h
@@ -215,6 +215,12 @@ 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;
diff --git a/vp8/common/postproc.c b/vp8/common/postproc.c
index 401989ba5..a8b169170 100644
--- a/vp8/common/postproc.c
+++ b/vp8/common/postproc.c
@@ -362,6 +362,7 @@ void vp8_deblock(YV12_BUFFER_CONFIG *source,
vp8_post_proc_down_and_across(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
}
+#if !(CONFIG_TEMPORAL_DENOISING)
void vp8_de_noise(YV12_BUFFER_CONFIG *source,
YV12_BUFFER_CONFIG *post,
int q,
@@ -398,6 +399,7 @@ void vp8_de_noise(YV12_BUFFER_CONFIG *source,
source->uv_width - 4, ppl);
}
+#endif
double vp8_gaussian(double sigma, double mu, double x)
{
diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c
new file mode 100644
index 000000000..6773a659d
--- /dev/null
+++ b/vp8/encoder/denoising.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "denoising.h"
+
+#include "vp8/common/reconinter.h"
+#include "vpx/vpx_integer.h"
+#include "vpx_mem/vpx_mem.h"
+#include "vpx_rtcd.h"
+
+const unsigned int NOISE_MOTION_THRESHOLD = 20*20;
+const unsigned int NOISE_DIFF2_THRESHOLD = 75;
+// SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming var(noise) ~= 100.
+const unsigned int SSE_DIFF_THRESHOLD = 16*16*20;
+const unsigned int SSE_THRESHOLD = 16*16*40;
+
+static __inline uint8_t blend(uint8_t state, uint8_t sample, uint8_t factor_q8)
+{
+ return (uint8_t)(
+ (((uint16_t)factor_q8 * ((uint16_t)state) + // Q8
+ (uint16_t)(256 - factor_q8) * ((uint16_t)sample)) + 128) // Q8
+ >> 8);
+}
+
+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;
+}
+
+static void denoiser_filter(YV12_BUFFER_CONFIG* mc_running_avg,
+ YV12_BUFFER_CONFIG* running_avg,
+ MACROBLOCK* signal,
+ unsigned int motion_magnitude2,
+ int y_offset,
+ int uv_offset)
+{
+ unsigned char* sig = signal->thismb;
+ int sig_stride = 16;
+ unsigned char* mc_running_avg_y = mc_running_avg->y_buffer + y_offset;
+ int mc_avg_y_stride = mc_running_avg->y_stride;
+ unsigned char* running_avg_y = running_avg->y_buffer + y_offset;
+ int avg_y_stride = running_avg->y_stride;
+ int r, c;
+ for (r = 0; r < 16; r++)
+ {
+ for (c = 0; c < 16; c++)
+ {
+ int diff;
+ int absdiff = 0;
+ unsigned int filter_coefficient;
+ absdiff = sig[c] - mc_running_avg_y[c];
+ absdiff = absdiff > 0 ? absdiff : -absdiff;
+ assert(absdiff >= 0 && absdiff < 256);
+ filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3));
+ // Allow some additional filtering of static blocks, or blocks with very
+ // small motion vectors.
+ filter_coefficient += filter_coefficient / (3 + (motion_magnitude2 >> 3));
+ filter_coefficient = filter_coefficient > 255 ? 255 : filter_coefficient;
+
+ running_avg_y[c] = blend(mc_running_avg_y[c], sig[c], filter_coefficient);
+ diff = sig[c] - running_avg_y[c];
+
+ if (diff * diff < NOISE_DIFF2_THRESHOLD)
+ {
+ // Replace with mean to suppress the noise.
+ sig[c] = running_avg_y[c];
+ }
+ else
+ {
+ // Replace the filter state with the signal since the change in this
+ // pixel isn't classified as noise.
+ running_avg_y[c] = sig[c];
+ }
+ }
+ sig += sig_stride;
+ mc_running_avg_y += mc_avg_y_stride;
+ running_avg_y += avg_y_stride;
+ }
+}
+
+int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height)
+{
+ assert(denoiser);
+ denoiser->yv12_running_avg.flags = 0;
+ if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width,
+ height, VP8BORDERINPIXELS) < 0)
+ {
+ vp8_denoiser_free(denoiser);
+ return 1;
+ }
+ denoiser->yv12_mc_running_avg.flags = 0;
+ if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
+ 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;
+}
+
+void vp8_denoiser_free(VP8_DENOISER *denoiser)
+{
+ assert(denoiser);
+ vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg);
+ 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,
+ unsigned int zero_mv_sse,
+ int recon_yoffset,
+ int recon_uvoffset) {
+ int mv_row;
+ int mv_col;
+ unsigned int motion_magnitude2;
+ // 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 (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);
+ return;
+ }
+ // Filter.
+ denoiser_filter(&denoiser->yv12_mc_running_avg,
+ &denoiser->yv12_running_avg,
+ x,
+ motion_magnitude2,
+ recon_yoffset,
+ recon_uvoffset);
+}
diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h
new file mode 100644
index 000000000..343531bb1
--- /dev/null
+++ b/vp8/encoder/denoising.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VP8_ENCODER_DENOISING_H_
+#define VP8_ENCODER_DENOISING_H_
+
+#include "block.h"
+
+typedef struct vp8_denoiser
+{
+ YV12_BUFFER_CONFIG yv12_running_avg;
+ YV12_BUFFER_CONFIG yv12_mc_running_avg;
+} VP8_DENOISER;
+
+int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height);
+
+void vp8_denoiser_free(VP8_DENOISER *denoiser);
+
+void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
+ MACROBLOCK *x,
+ unsigned int best_sse,
+ unsigned int zero_mv_sse,
+ int recon_yoffset,
+ int recon_uvoffset);
+
+#endif // VP8_ENCODER_DENOISING_H_
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c
index 21757f8f0..962a719c8 100644
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -1179,6 +1179,13 @@ int vp8cx_encode_inter_macroblock
else
x->encode_breakout = cpi->oxcf.encode_breakout;
+#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;
+#endif
+
if (cpi->sf.RD)
{
int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled;
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 5ad51e846..dbb7bb368 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -1680,6 +1680,17 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf)
cpi->alt_ref_source = NULL;
cpi->is_src_frame_alt_ref = 0;
+#if CONFIG_TEMPORAL_DENOISING
+ if (cpi->oxcf.noise_sensitivity)
+ {
+ if (!cpi->denoiser.yv12_mc_running_avg.buffer_alloc)
+ {
+ int width = (cpi->oxcf.Width + 15) & ~15;
+ int height = (cpi->oxcf.Height + 15) & ~15;
+ vp8_denoiser_allocate(&cpi->denoiser, width, height);
+ }
+ }
+#endif
#if 0
// Experimental RD Code
@@ -2314,6 +2325,9 @@ void vp8_remove_compressor(VP8_COMP **ptr)
vp8cx_remove_encoder_threads(cpi);
#endif
+#if CONFIG_TEMPORAL_DENOISING
+ vp8_denoiser_free(&cpi->denoiser);
+#endif
dealloc_compressor_data(cpi);
vpx_free(cpi->mb.ss);
vpx_free(cpi->tok);
@@ -3133,7 +3147,12 @@ void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm)
}
vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show);
-
+#if CONFIG_TEMPORAL_DENOISING
+ if (cpi->oxcf.noise_sensitivity)
+ {
+ vp8_yv12_extend_frame_borders(&cpi->denoiser.yv12_running_avg);
+ }
+#endif
}
static void encode_frame_to_data_rate
@@ -3589,7 +3608,7 @@ static void encode_frame_to_data_rate
scale_and_extend_source(cpi->un_scaled_source, cpi);
-#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC
+#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC && !(CONFIG_TEMPORAL_DENOISING)
if (cpi->oxcf.noise_sensitivity > 0)
{
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h
index e17d8ead0..487cd6e61 100644
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -28,6 +28,9 @@
#include "mcomp.h"
#include "vp8/common/findnearmv.h"
#include "lookahead.h"
+#if CONFIG_TEMPORAL_DENOISING
+#include "vp8/encoder/denoising.h"
+#endif
//#define SPEEDSTATS 1
#define MIN_GF_INTERVAL 4
@@ -661,6 +664,10 @@ typedef struct VP8_COMP
int droppable;
+#if CONFIG_TEMPORAL_DENOISING
+ VP8_DENOISER denoiser;
+#endif
+
// Coding layer state variables
unsigned int current_layer;
LAYER_CONTEXT layer_context[MAX_LAYERS];
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index 236cb2326..ef1fd9ffe 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -24,6 +24,9 @@
#include "mcomp.h"
#include "rdopt.h"
#include "vpx_mem/vpx_mem.h"
+#if CONFIG_TEMPORAL_DENOISING
+#include "denoising.h"
+#endif
extern int VP8_UVSSE(MACROBLOCK *x);
@@ -450,6 +453,48 @@ void get_lower_res_motion_info(VP8_COMP *cpi, MACROBLOCKD *xd, int *dissim,
}
#endif
+static void check_for_encode_breakout(unsigned int sse, MACROBLOCK* x)
+{
+ if (sse < x->encode_breakout)
+ {
+ // Check u and v to make sure skip is ok
+ int sse2 = 0;
+
+ sse2 = VP8_UVSSE(x);
+
+ if (sse2 * 2 < x->encode_breakout)
+ x->skip = 1;
+ else
+ x->skip = 0;
+ }
+}
+
+static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, VP8_COMP *cpi, MACROBLOCK *x)
+{
+ MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode;
+ int_mv mv = x->e_mbd.mode_info_context->mbmi.mv;
+ int this_rd;
+ /* Exit early and don't compute the distortion if this macroblock
+ * is marked inactive. */
+ if (cpi->active_map_enabled && x->active_ptr[0] == 0)
+ {
+ *sse = 0;
+ *distortion2 = 0;
+ x->skip = 1;
+ return INT_MAX;
+ }
+
+ if((this_mode != NEWMV) ||
+ !(cpi->sf.half_pixel_search) || cpi->common.full_pixel==1)
+ *distortion2 = get_inter_mbpred_error(x,
+ &cpi->fn_ptr[BLOCK_16X16],
+ sse, mv);
+
+ this_rd = RDCOST(x->rdmult, x->rddiv, rate2, *distortion2);
+
+ check_for_encode_breakout(*sse, x);
+ return this_rd;
+}
void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int recon_uvoffset, int *returnrate,
@@ -476,7 +521,10 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int distortion2;
int bestsme = INT_MAX;
int best_mode_index = 0;
- unsigned int sse = INT_MAX, best_sse = INT_MAX;
+ unsigned int sse = INT_MAX, best_rd_sse = INT_MAX;
+#if CONFIG_TEMPORAL_DENOISING
+ unsigned int zero_mv_sse = 0, best_sse = INT_MAX;
+#endif
int_mv mvp;
@@ -488,9 +536,6 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int ref_frame_map[4];
int sign_bias = 0;
- int have_subp_search = cpi->sf.half_pixel_search; /* In real-time mode,
- when Speed >= 15, no sub-pixel search. */
-
#if CONFIG_MULTI_RES_ENCODING
int dissim = INT_MAX;
int parent_ref_frame = 0;
@@ -657,7 +702,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
{
case B_PRED:
/* Pass best so far to pick_intra4x4mby_modes to use as breakout */
- distortion2 = best_sse;
+ distortion2 = best_rd_sse;
pick_intra4x4mby_modes(x, &rate, &distortion2);
if (distortion2 == INT_MAX)
@@ -905,43 +950,38 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
x->e_mbd.mode_info_context->mbmi.mv.as_int =
mode_mv[this_mode].as_int;
-
- /* Exit early and don't compute the distortion if this macroblock
- * is marked inactive. */
- if (cpi->active_map_enabled && x->active_ptr[0] == 0)
- {
- sse = 0;
- distortion2 = 0;
- x->skip = 1;
- break;
- }
-
- if((this_mode != NEWMV) ||
- !(have_subp_search) || cpi->common.full_pixel==1)
- distortion2 = get_inter_mbpred_error(x,
- &cpi->fn_ptr[BLOCK_16X16],
- &sse, mode_mv[this_mode]);
-
- this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
-
- if (sse < x->encode_breakout)
- {
- // Check u and v to make sure skip is ok
- int sse2 = 0;
-
- sse2 = VP8_UVSSE(x);
-
- if (sse2 * 2 < x->encode_breakout)
- x->skip = 1;
- else
- x->skip = 0;
- }
+ this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x);
break;
default:
break;
}
+#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;
+ }
+ }
+#endif
+
if (this_rd < best_rd || x->skip)
{
// Note index of best mode
@@ -949,7 +989,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
*returnrate = rate2;
*returndistortion = distortion2;
- best_sse = sse;
+ best_rd_sse = sse;
best_rd = this_rd;
vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi,
sizeof(MB_MODE_INFO));
@@ -1011,6 +1051,43 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
cpi->error_bins[this_rdbin] ++;
}
+#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 (this_rd < best_rd || x->skip)
+ {
+ vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi,
+ sizeof(MB_MODE_INFO));
+ }
+ }
+ }
+#endif
+
if (cpi->is_src_frame_alt_ref &&
(best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME))
{
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index d6c643222..c6ed701fd 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -33,11 +33,33 @@
#include "rdopt.h"
#include "vpx_mem/vpx_mem.h"
#include "vp8/common/systemdependent.h"
+#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))
+typedef struct rate_distortion_struct
+{
+ int rate2;
+ int rate_y;
+ int rate_uv;
+ int distortion2;
+ int distortion_uv;
+} RATE_DISTORTION;
+
+typedef struct best_mode_struct
+{
+ int yrd;
+ int rd;
+ int intra_rd;
+ MB_MODE_INFO mbmode;
+ union b_mode_info bmodes[16];
+ PARTITION_INFO partition;
+} BEST_MODE;
+
static const int auto_speed_thresh[17] =
{
1000,
@@ -1711,6 +1733,181 @@ static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv)
}
}
+static int evaluate_inter_mode_rd(int mdcounts[4],
+ RATE_DISTORTION* rd,
+ int* disable_skip,
+ VP8_COMP *cpi, MACROBLOCK *x)
+{
+ MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode;
+ BLOCK *b = &x->block[0];
+ MACROBLOCKD *xd = &x->e_mbd;
+ int distortion;
+ vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16);
+
+ if (cpi->active_map_enabled && x->active_ptr[0] == 0) {
+ x->skip = 1;
+ }
+ else if (x->encode_breakout)
+ {
+ unsigned int sse;
+ unsigned int var;
+ int threshold = (xd->block[0].dequant[1]
+ * xd->block[0].dequant[1] >>4);
+
+ if(threshold < x->encode_breakout)
+ threshold = x->encode_breakout;
+
+ var = vp8_variance16x16
+ (*(b->base_src), b->src_stride,
+ x->e_mbd.predictor, 16, &sse);
+
+ if (sse < threshold)
+ {
+ unsigned int q2dc = xd->block[24].dequant[0];
+ /* If theres is no codeable 2nd order dc
+ or a very small uniform pixel change change */
+ if ((sse - var < q2dc * q2dc >>4) ||
+ (sse /2 > var && sse-var < 64))
+ {
+ // Check u and v to make sure skip is ok
+ int sse2= VP8_UVSSE(x);
+ if (sse2 * 2 < threshold)
+ {
+ x->skip = 1;
+ rd->distortion2 = sse + sse2;
+ rd->rate2 = 500;
+
+ /* for best_yrd calculation */
+ rd->rate_uv = 0;
+ rd->distortion_uv = sse2;
+
+ *disable_skip = 1;
+ return RDCOST(x->rdmult, x->rddiv, rd->rate2,
+ rd->distortion2);
+ }
+ }
+ }
+ }
+
+
+ //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code
+
+ // Add in the Mv/mode cost
+ rd->rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
+
+ // Y cost and distortion
+ macro_block_yrd(x, &rd->rate_y, &distortion);
+ rd->rate2 += rd->rate_y;
+ rd->distortion2 += distortion;
+
+ // UV cost and distortion
+ rd_inter16x16_uv(cpi, x, &rd->rate_uv, &rd->distortion_uv,
+ cpi->common.full_pixel);
+ rd->rate2 += rd->rate_uv;
+ rd->distortion2 += rd->distortion_uv;
+ return INT_MAX;
+}
+
+static int calculate_final_rd_costs(int this_rd,
+ RATE_DISTORTION* rd,
+ int* other_cost,
+ int disable_skip,
+ int uv_intra_tteob,
+ int intra_rd_penalty,
+ VP8_COMP *cpi, MACROBLOCK *x)
+{
+ MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode;
+ // Where skip is allowable add in the default per mb cost for the no skip case.
+ // where we then decide to skip we have to delete this and replace it with the
+ // cost of signallying a skip
+ if (cpi->common.mb_no_coeff_skip)
+ {
+ *other_cost += vp8_cost_bit(cpi->prob_skip_false, 0);
+ rd->rate2 += *other_cost;
+ }
+
+ /* Estimate the reference frame signaling cost and add it
+ * to the rolling cost variable.
+ */
+ rd->rate2 +=
+ x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
+
+ if (!disable_skip)
+ {
+ // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate
+ if (cpi->common.mb_no_coeff_skip)
+ {
+ int i;
+ int tteob;
+ int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED);
+
+ tteob = 0;
+ if(has_y2_block)
+ tteob += x->e_mbd.eobs[24];
+
+ for (i = 0; i < 16; i++)
+ tteob += (x->e_mbd.eobs[i] > has_y2_block);
+
+ if (x->e_mbd.mode_info_context->mbmi.ref_frame)
+ {
+ for (i = 16; i < 24; i++)
+ tteob += x->e_mbd.eobs[i];
+ }
+ else
+ tteob += uv_intra_tteob;
+
+ if (tteob == 0)
+ {
+ rd->rate2 -= (rd->rate_y + rd->rate_uv);
+ //for best_yrd calculation
+ rd->rate_uv = 0;
+
+ // Back out no skip flag costing and add in skip flag costing
+ if (cpi->prob_skip_false)
+ {
+ int prob_skip_cost;
+
+ prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1);
+ prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0);
+ rd->rate2 += prob_skip_cost;
+ *other_cost += prob_skip_cost;
+ }
+ }
+ }
+ // Calculate the final RD estimate for this mode
+ this_rd = RDCOST(x->rdmult, x->rddiv, rd->rate2, rd->distortion2);
+ if (this_rd < INT_MAX && x->e_mbd.mode_info_context->mbmi.ref_frame
+ == INTRA_FRAME)
+ this_rd += intra_rd_penalty;
+ }
+ return this_rd;
+}
+
+static void update_best_mode(BEST_MODE* best_mode, int this_rd,
+ RATE_DISTORTION* rd, int other_cost, MACROBLOCK *x)
+{
+ MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode;
+
+ other_cost +=
+ x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
+
+ /* Calculate the final y RD estimate for this mode */
+ best_mode->yrd = RDCOST(x->rdmult, x->rddiv, (rd->rate2-rd->rate_uv-other_cost),
+ (rd->distortion2-rd->distortion_uv));
+
+ best_mode->rd = this_rd;
+ vpx_memcpy(&best_mode->mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO));
+ vpx_memcpy(&best_mode->partition, x->partition_info, sizeof(PARTITION_INFO));
+
+ if ((this_mode == B_PRED) || (this_mode == SPLITMV))
+ {
+ int i;
+ for (i = 0; i < 16; i++)
+ {
+ best_mode->bmodes[i] = x->e_mbd.block[i].bmi;
+ }
+ }
+}
void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int recon_uvoffset, int *returnrate,
@@ -1719,9 +1916,6 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
BLOCK *b = &x->block[0];
BLOCKD *d = &x->e_mbd.block[0];
MACROBLOCKD *xd = &x->e_mbd;
- union b_mode_info best_bmodes[16];
- MB_MODE_INFO best_mbmode;
- PARTITION_INFO best_partition;
int_mv best_ref_mv_sb[2];
int_mv mode_mv_sb[2][MB_MODE_COUNT];
int_mv best_ref_mv;
@@ -1729,21 +1923,16 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
MB_PREDICTION_MODE this_mode;
int num00;
int best_mode_index = 0;
+ BEST_MODE best_mode;
int i;
int mode_index;
int mdcounts[4];
int rate;
- int distortion;
- int best_rd = INT_MAX;
- int best_intra_rd = INT_MAX;
- int rate2, distortion2;
+ RATE_DISTORTION rd;
int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly;
int uv_intra_tteob = 0;
int uv_intra_done = 0;
- int rate_y, UNINITIALIZED_IS_SAFE(rate_uv);
- int distortion_uv;
- int best_yrd = INT_MAX;
MB_PREDICTION_MODE uv_intra_mode = 0;
int_mv mvp;
@@ -1760,9 +1949,12 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
mode_mv = mode_mv_sb[sign_bias];
best_ref_mv.as_int = 0;
+ best_mode.rd = INT_MAX;
+ best_mode.yrd = INT_MAX;
+ best_mode.intra_rd = INT_MAX;
vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb));
- vpx_memset(&best_mbmode, 0, sizeof(best_mbmode));
- vpx_memset(&best_bmodes, 0, sizeof(best_bmodes));
+ vpx_memset(&best_mode.mbmode, 0, sizeof(best_mode.mbmode));
+ vpx_memset(&best_mode.bmodes, 0, sizeof(best_mode.bmodes));
/* Setup search priorities */
get_reference_search_order(cpi, ref_frame_map);
@@ -1799,15 +1991,15 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int this_ref_frame = ref_frame_map[vp8_ref_frame_order[mode_index]];
// Test best rd so far against threshold for trying this mode.
- if (best_rd <= cpi->rd_threshes[mode_index])
+ if (best_mode.rd <= cpi->rd_threshes[mode_index])
continue;
if (this_ref_frame < 0)
continue;
// These variables hold are rolling total cost and distortion for this mode
- rate2 = 0;
- distortion2 = 0;
+ rd.rate2 = 0;
+ rd.distortion2 = 0;
this_mode = vp8_mode_order[mode_index];
@@ -1907,16 +2099,17 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int tmp_rd;
// Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED];
- tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, best_yrd);
- rate2 += rate;
- distortion2 += distortion;
+ int distortion;
+ tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rd.rate_y, &distortion, best_mode.yrd);
+ rd.rate2 += rate;
+ rd.distortion2 += distortion;
- if(tmp_rd < best_yrd)
+ if(tmp_rd < best_mode.yrd)
{
- rate2 += uv_intra_rate;
- rate_uv = uv_intra_rate_tokenonly;
- distortion2 += uv_intra_distortion;
- distortion_uv = uv_intra_distortion;
+ rd.rate2 += uv_intra_rate;
+ rd.rate_uv = uv_intra_rate_tokenonly;
+ rd.distortion2 += uv_intra_distortion;
+ rd.distortion_uv = uv_intra_distortion;
}
else
{
@@ -1930,24 +2123,25 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
{
int tmp_rd;
int this_rd_thresh;
+ int distortion;
this_rd_thresh = (vp8_ref_frame_order[mode_index] == 1) ? cpi->rd_threshes[THR_NEW1] : cpi->rd_threshes[THR_NEW3];
this_rd_thresh = (vp8_ref_frame_order[mode_index] == 2) ? cpi->rd_threshes[THR_NEW2] : this_rd_thresh;
tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv,
- best_yrd, mdcounts,
- &rate, &rate_y, &distortion, this_rd_thresh) ;
+ best_mode.yrd, mdcounts,
+ &rate, &rd.rate_y, &distortion, this_rd_thresh) ;
- rate2 += rate;
- distortion2 += distortion;
+ rd.rate2 += rate;
+ rd.distortion2 += distortion;
// If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV
- if (tmp_rd < best_yrd)
+ if (tmp_rd < best_mode.yrd)
{
// Now work out UV cost and add it in
- rd_inter4x4_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel);
- rate2 += rate_uv;
- distortion2 += distortion_uv;
+ rd_inter4x4_uv(cpi, x, &rd.rate_uv, &rd.distortion_uv, cpi->common.full_pixel);
+ rd.rate2 += rd.rate_uv;
+ rd.distortion2 += rd.distortion_uv;
}
else
{
@@ -1960,18 +2154,21 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
case V_PRED:
case H_PRED:
case TM_PRED:
+ {
+ int distortion;
x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME;
vp8_build_intra_predictors_mby
(&x->e_mbd);
- macro_block_yrd(x, &rate_y, &distortion) ;
- rate2 += rate_y;
- distortion2 += distortion;
- rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode];
- rate2 += uv_intra_rate;
- rate_uv = uv_intra_rate_tokenonly;
- distortion2 += uv_intra_distortion;
- distortion_uv = uv_intra_distortion;
- break;
+ macro_block_yrd(x, &rd.rate_y, &distortion) ;
+ rd.rate2 += rd.rate_y;
+ rd.distortion2 += distortion;
+ rd.rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode];
+ rd.rate2 += uv_intra_rate;
+ rd.rate_uv = uv_intra_rate_tokenonly;
+ rd.distortion2 += uv_intra_distortion;
+ rd.distortion_uv = uv_intra_distortion;
+ }
+ break;
case NEWMV:
{
@@ -2114,7 +2311,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
mode_mv[NEWMV].as_int = d->bmi.mv.as_int;
// Add the new motion vector cost to our rolling cost variable
- rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96);
+ rd.rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96);
}
case NEARESTMV:
@@ -2136,177 +2333,57 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
continue;
vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]);
- vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16);
-
- if (cpi->active_map_enabled && x->active_ptr[0] == 0) {
- x->skip = 1;
- }
- else if (x->encode_breakout)
- {
- unsigned int sse;
- unsigned int var;
- int threshold = (xd->block[0].dequant[1]
- * xd->block[0].dequant[1] >>4);
-
- if(threshold < x->encode_breakout)
- threshold = x->encode_breakout;
-
- var = vp8_variance16x16
- (*(b->base_src), b->src_stride,
- x->e_mbd.predictor, 16, &sse);
-
- if (sse < threshold)
- {
- unsigned int q2dc = xd->block[24].dequant[0];
- /* If theres is no codeable 2nd order dc
- or a very small uniform pixel change change */
- if ((sse - var < q2dc * q2dc >>4) ||
- (sse /2 > var && sse-var < 64))
- {
- // Check u and v to make sure skip is ok
- int sse2= VP8_UVSSE(x);
- if (sse2 * 2 < threshold)
- {
- x->skip = 1;
- distortion2 = sse + sse2;
- rate2 = 500;
-
- /* for best_yrd calculation */
- rate_uv = 0;
- distortion_uv = sse2;
-
- disable_skip = 1;
- this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
-
- break;
- }
- }
- }
- }
-
-
- //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code
-
- // Add in the Mv/mode cost
- rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
-
- // Y cost and distortion
- macro_block_yrd(x, &rate_y, &distortion);
- rate2 += rate_y;
- distortion2 += distortion;
-
- // UV cost and distortion
- rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel);
- rate2 += rate_uv;
- distortion2 += distortion_uv;
+ this_rd = evaluate_inter_mode_rd(mdcounts, &rd,
+ &disable_skip, cpi, x);
break;
default:
break;
}
- // Where skip is allowable add in the default per mb cost for the no skip case.
- // where we then decide to skip we have to delete this and replace it with the
- // cost of signallying a skip
- if (cpi->common.mb_no_coeff_skip)
- {
- other_cost += vp8_cost_bit(cpi->prob_skip_false, 0);
- rate2 += other_cost;
- }
+ this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost,
+ disable_skip, uv_intra_tteob,
+ intra_rd_penalty, cpi, x);
- /* Estimate the reference frame signaling cost and add it
- * to the rolling cost variable.
- */
- rate2 +=
- x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
-
- if (!disable_skip)
+ // Keep record of best intra distortion
+ if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
+ (this_rd < best_mode.intra_rd) )
{
- // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate
- if (cpi->common.mb_no_coeff_skip)
- {
- int tteob;
- int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED);
-
- tteob = 0;
- if(has_y2_block)
- tteob += x->e_mbd.eobs[24];
-
- for (i = 0; i < 16; i++)
- tteob += (x->e_mbd.eobs[i] > has_y2_block);
-
- if (x->e_mbd.mode_info_context->mbmi.ref_frame)
- {
- for (i = 16; i < 24; i++)
- tteob += x->e_mbd.eobs[i];
- }
- else
- tteob += uv_intra_tteob;
-
- if (tteob == 0)
- {
- rate2 -= (rate_y + rate_uv);
- //for best_yrd calculation
- rate_uv = 0;
-
- // Back out no skip flag costing and add in skip flag costing
- if (cpi->prob_skip_false)
- {
- int prob_skip_cost;
-
- prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1);
- prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0);
- rate2 += prob_skip_cost;
- other_cost += prob_skip_cost;
- }
- }
- }
- // Calculate the final RD estimate for this mode
- this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
- if (this_rd < INT_MAX && x->e_mbd.mode_info_context->mbmi.ref_frame
- == INTRA_FRAME)
- this_rd += intra_rd_penalty;
+ best_mode.intra_rd = this_rd;
+ *returnintra = rd.distortion2 ;
}
- // Keep record of best intra distortion
- if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
- (this_rd < best_intra_rd) )
+#if CONFIG_TEMPORAL_DENOISING
+ if (cpi->oxcf.noise_sensitivity)
{
- best_intra_rd = this_rd;
- *returnintra = distortion2 ;
+ // 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;
+ }
}
+#endif
// Did this mode help.. i.i is it the new best mode
- if (this_rd < best_rd || x->skip)
+ 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;
if (this_mode <= B_PRED)
{
x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode;
/* required for left and above block mv */
x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
}
-
- other_cost +=
- x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
-
- /* Calculate the final y RD estimate for this mode */
- best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost),
- (distortion2-distortion_uv));
-
- *returnrate = rate2;
- *returndistortion = distortion2;
- best_rd = this_rd;
- vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO));
- vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO));
-
- if ((this_mode == B_PRED) || (this_mode == SPLITMV))
- for (i = 0; i < 16; i++)
- {
- best_bmodes[i] = x->e_mbd.block[i].bmi;
- }
+ update_best_mode(&best_mode, this_rd, &rd, other_cost, x);
// Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time
@@ -2359,9 +2436,50 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
// Note how often each mode chosen as best
cpi->mode_chosen_counts[best_mode_index] ++;
+#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)
+ {
+ // 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
if (cpi->is_src_frame_alt_ref &&
- (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME))
+ (best_mode.mbmode.mode != ZEROMV || best_mode.mbmode.ref_frame != ALTREF_FRAME))
{
x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME;
@@ -2370,26 +2488,25 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
x->e_mbd.mode_info_context->mbmi.mb_skip_coeff =
(cpi->common.mb_no_coeff_skip);
x->e_mbd.mode_info_context->mbmi.partitioning = 0;
-
return;
}
// macroblock modes
- vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO));
+ vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mode.mbmode, sizeof(MB_MODE_INFO));
- if (best_mbmode.mode == B_PRED)
+ if (best_mode.mbmode.mode == B_PRED)
{
for (i = 0; i < 16; i++)
- xd->mode_info_context->bmi[i].as_mode = best_bmodes[i].as_mode;
+ xd->mode_info_context->bmi[i].as_mode = best_mode.bmodes[i].as_mode;
}
- if (best_mbmode.mode == SPLITMV)
+ if (best_mode.mbmode.mode == SPLITMV)
{
for (i = 0; i < 16; i++)
- xd->mode_info_context->bmi[i].mv.as_int = best_bmodes[i].mv.as_int;
+ xd->mode_info_context->bmi[i].mv.as_int = best_mode.bmodes[i].mv.as_int;
- vpx_memcpy(x->partition_info, &best_partition, sizeof(PARTITION_INFO));
+ vpx_memcpy(x->partition_info, &best_mode.partition, sizeof(PARTITION_INFO));
x->e_mbd.mode_info_context->mbmi.mv.as_int =
x->partition_info->bmi[15].mv.as_int;
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index fa78ec31c..683194a1d 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -183,14 +183,20 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref);
RANGE_CHECK(vp8_cfg, cpu_used, -16, 16);
-
+#if CONFIG_TEMPORAL_DENOISING
+ RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 1);
+#endif
#if !(CONFIG_REALTIME_ONLY)
RANGE_CHECK(vp8_cfg, encoding_mode, VP8_BEST_QUALITY_ENCODING, VP8_REAL_TIME_ENCODING);
+#if !(CONFIG_TEMPORAL_DENOISING)
RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6);
+#endif
#else
RANGE_CHECK(vp8_cfg, encoding_mode, VP8_REAL_TIME_ENCODING, VP8_REAL_TIME_ENCODING);
+#if !(CONFIG_TEMPORAL_DENOISING)
RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 0);
#endif
+#endif
RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION);
RANGE_CHECK_HI(vp8_cfg, Sharpness, 7);
diff --git a/vp8/vp8cx.mk b/vp8/vp8cx.mk
index b96c9adab..9a82b19e7 100644
--- a/vp8/vp8cx.mk
+++ b/vp8/vp8cx.mk
@@ -47,6 +47,8 @@ VP8_CX_SRCS-yes += encoder/firstpass.c
VP8_CX_SRCS-yes += encoder/block.h
VP8_CX_SRCS-yes += encoder/boolhuff.h
VP8_CX_SRCS-yes += encoder/bitstream.h
+VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.h
+VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.c
VP8_CX_SRCS-yes += encoder/encodeintra.h
VP8_CX_SRCS-yes += encoder/encodemb.h
VP8_CX_SRCS-yes += encoder/encodemv.h