Adds a motion compensated temporal denoiser to the encoder.

Some refactoring in rdopt.c and pickinter.c.

Change-Id: I4f50020eb3313c37f4d441d708fedcaf219d3038
This commit is contained in:
Stefan Holmer 2012-03-06 10:48:18 +01:00
parent c21f53a501
commit 9c41143d66
13 changed files with 730 additions and 239 deletions

4
configure vendored
View File

@ -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() {

View File

@ -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]);

View File

@ -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;

View File

@ -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)
{

212
vp8/encoder/denoising.c Normal file
View File

@ -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);
}

33
vp8/encoder/denoising.h Normal file
View File

@ -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_

View File

@ -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;

View File

@ -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)
{

View File

@ -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];

View File

@ -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))
{

View File

@ -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;
}
/* 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)
{
// 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;
}
this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost,
disable_skip, uv_intra_tteob,
intra_rd_penalty, cpi, x);
// Keep record of best intra distortion
if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
(this_rd < best_intra_rd) )
(this_rd < best_mode.intra_rd) )
{
best_intra_rd = this_rd;
*returnintra = distortion2 ;
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;
}
}
#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;

View File

@ -183,13 +183,19 @@ 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);

View File

@ -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