/* * Copyright (c) 2010 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.
*/
staticint pick_intra4x4mby_modes(MACROBLOCK *mb, int *Rate, int *best_dist) {
MACROBLOCKD *const xd = &mb->e_mbd; int i; int cost = mb->mbmode_cost[xd->frame_type][B_PRED]; int error; int distortion = 0; constint *bmode_costs;
for (i = 0; i < 16; ++i) {
MODE_INFO *const mic = xd->mode_info_context; constint mis = xd->mode_info_stride;
B_PREDICTION_MODE best_mode = B_MODE_COUNT; int r = 0, d = 0;
if (mb->e_mbd.frame_type == KEY_FRAME) { const B_PREDICTION_MODE A = above_block_mode(mic, i, mis); const B_PREDICTION_MODE L = left_block_mode(mic, i);
bmode_costs = mb->bmode_costs[A][L];
}
pick_intra4x4block(mb, i, &best_mode, bmode_costs, &r, &d);
staticvoid update_mvcount(MACROBLOCK *x, int_mv *best_ref_mv) {
MACROBLOCKD *xd = &x->e_mbd; /* Split MV modes currently not supported when RD is nopt enabled,
* therefore, only need to modify MVcount in NEWMV mode. */ if (xd->mode_info_context->mbmi.mode == NEWMV) { constint row_val =
((xd->mode_info_context->mbmi.mv.as_mv.row - best_ref_mv->as_mv.row) >>
1); constint row_idx = mv_max + row_val; constint col_val =
((xd->mode_info_context->mbmi.mv.as_mv.col - best_ref_mv->as_mv.col) >>
1); constint col_idx = mv_max + col_val; if (row_idx >= 0 && row_idx < MVvals && col_idx >= 0 && col_idx < MVvals) {
x->MVcount[0][row_idx]++;
x->MVcount[1][col_idx]++;
}
}
}
#if CONFIG_MULTI_RES_ENCODING staticvoid get_lower_res_motion_info(VP8_COMP *cpi, MACROBLOCKD *xd, int *dissim, int *parent_ref_frame,
MB_PREDICTION_MODE *parent_mode,
int_mv *parent_ref_mv, int mb_row, int mb_col) {
LOWER_RES_MB_INFO *store_mode_info =
((LOWER_RES_FRAME_INFO *)cpi->oxcf.mr_low_res_mode_info)->mb_info; unsignedint parent_mb_index;
/* Consider different down_sampling_factor. */
{ /* TODO: Removed the loop that supports special down_sampling_factor * such as 2, 4, 8. Will revisit it if needed. * Should also try using a look-up table to see if it helps
* performance. */ int parent_mb_row, parent_mb_col;
/* Read lower-resolution mode & motion result from memory.*/
*parent_ref_frame = store_mode_info[parent_mb_index].ref_frame;
*parent_mode = store_mode_info[parent_mb_index].mode;
*dissim = store_mode_info[parent_mb_index].dissim;
/* For highest-resolution encoder, adjust dissim value. Lower its quality
* for good performance. */ if (cpi->oxcf.mr_encoder_id == (cpi->oxcf.mr_total_resolutions - 1))
*dissim >>= 1;
if (*parent_ref_frame != INTRA_FRAME) { /* Consider different down_sampling_factor. * The result can be rounded to be more precise, but it takes more time.
*/
(*parent_ref_mv).as_mv.row = store_mode_info[parent_mb_index].mv.as_mv.row *
cpi->oxcf.mr_down_sampling_factor.num /
cpi->oxcf.mr_down_sampling_factor.den;
(*parent_ref_mv).as_mv.col = store_mode_info[parent_mb_index].mv.as_mv.col *
cpi->oxcf.mr_down_sampling_factor.num /
cpi->oxcf.mr_down_sampling_factor.den;
// Adjust rd for ZEROMV and LAST, if LAST is the closest reference frame. // TODO: We should also add condition on distance of closest to current. if (!cpi->oxcf.screen_content_mode && this_mode == ZEROMV &&
x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME &&
(denoise_aggressive || (cpi->closest_reference_frame == LAST_FRAME))) { // No adjustment if block is considered to be skin area. if (x->is_skin) rd_adj = 100;
void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra, int mb_row, int mb_col) {
BLOCK *b = &x->block[0];
BLOCKD *d = &x->e_mbd.block[0];
MACROBLOCKD *xd = &x->e_mbd;
MB_MODE_INFO best_mbmode;
int_mv best_ref_mv_sb[2] = { { 0 }, { 0 } };
int_mv mode_mv_sb[2][MB_MODE_COUNT];
int_mv best_ref_mv;
int_mv *mode_mv;
MB_PREDICTION_MODE this_mode; int num00; int mdcounts[4]; int best_rd = INT_MAX; int rd_adjustment = 100; int best_intra_rd = INT_MAX; int mode_index; int rate; int rate2; int distortion2; int bestsme = INT_MAX; int best_mode_index = 0; unsignedint sse = UINT_MAX, best_rd_sse = UINT_MAX; #if CONFIG_TEMPORAL_DENOISING unsignedint zero_mv_sse = UINT_MAX, best_sse = UINT_MAX; #endif
int sf_improved_mv_pred = cpi->sf.improved_mv_pred;
#if CONFIG_MULTI_RES_ENCODING int dissim = INT_MAX; int parent_ref_frame = 0;
int_mv parent_ref_mv;
MB_PREDICTION_MODE parent_mode = 0; int parent_ref_valid = 0; #endif
int_mv mvp;
int near_sadidx[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; int saddone = 0; /* search range got from mv_pred(). It uses step_param levels. (0-7) */ int sr = 0;
unsignedchar *plane[4][3] = { { 0, 0 } }; int ref_frame_map[4]; int sign_bias = 0; int dot_artifact_candidate = 0;
get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset);
// If the current frame is using LAST as a reference, check for // biasing the mode selection for dot artifacts. if (cpi->ref_frame_flags & VP8_LAST_FRAME) { unsignedchar *target_y = x->src.y_buffer; unsignedchar *target_u = x->block[16].src + *x->block[16].base_src; unsignedchar *target_v = x->block[20].src + *x->block[20].base_src; int stride = x->src.y_stride; int stride_uv = x->block[16].src_stride; #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { constint uv_denoise = (cpi->oxcf.noise_sensitivity >= 2) ? 1 : 0;
target_y =
cpi->denoiser.yv12_running_avg[LAST_FRAME].y_buffer + recon_yoffset;
stride = cpi->denoiser.yv12_running_avg[LAST_FRAME].y_stride; if (uv_denoise) {
target_u = cpi->denoiser.yv12_running_avg[LAST_FRAME].u_buffer +
recon_uvoffset;
target_v = cpi->denoiser.yv12_running_avg[LAST_FRAME].v_buffer +
recon_uvoffset;
stride_uv = cpi->denoiser.yv12_running_avg[LAST_FRAME].uv_stride;
}
} #endif
assert(plane[LAST_FRAME][0] != NULL);
dot_artifact_candidate = check_dot_artifact_candidate(
cpi, x, target_y, stride, plane[LAST_FRAME][0], mb_row, mb_col, 0); // If not found in Y channel, check UV channel. if (!dot_artifact_candidate) {
assert(plane[LAST_FRAME][1] != NULL);
dot_artifact_candidate = check_dot_artifact_candidate(
cpi, x, target_u, stride_uv, plane[LAST_FRAME][1], mb_row, mb_col, 1); if (!dot_artifact_candidate) {
assert(plane[LAST_FRAME][2] != NULL);
dot_artifact_candidate = check_dot_artifact_candidate(
cpi, x, target_v, stride_uv, plane[LAST_FRAME][2], mb_row, mb_col,
2);
}
}
}
#if CONFIG_MULTI_RES_ENCODING // |parent_ref_valid| will be set here if potentially we can do mv resue for // this higher resol (|cpi->oxcf.mr_encoder_id| > 0) frame. // |parent_ref_valid| may be reset depending on |parent_ref_frame| for // the current macroblock below.
parent_ref_valid = cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail; if (parent_ref_valid) { int parent_ref_flag;
/* TODO(jkoleszar): The references available (ref_frame_flags) to the * lower res encoder should match those available to this encoder, but * there seems to be a situation where this mismatch can happen in the * case of frame dropping and temporal layers. For example, * GOLD being disallowed in ref_frame_flags, but being returned as * parent_ref_frame. * * In this event, take the conservative approach of disabling the * lower res info for this MB.
*/
parent_ref_flag = 0; // Note availability for mv reuse is only based on last and golden. if (parent_ref_frame == LAST_FRAME)
parent_ref_flag = (cpi->ref_frame_flags & VP8_LAST_FRAME); elseif (parent_ref_frame == GOLDEN_FRAME)
parent_ref_flag = (cpi->ref_frame_flags & VP8_GOLD_FRAME);
// assert(!parent_ref_frame || parent_ref_flag);
// If |parent_ref_frame| did not match either last or golden then // shut off mv reuse. if (parent_ref_frame && !parent_ref_flag) parent_ref_valid = 0;
// Don't do mv reuse since we want to allow for another mode besides // ZEROMV_LAST to remove dot artifact. if (dot_artifact_candidate) parent_ref_valid = 0;
} #endif
// Check if current macroblock is in skin area.
x->is_skin = 0; if (!cpi->oxcf.screen_content_mode) { int block_index = mb_row * cpi->common.mb_cols + mb_col;
x->is_skin = cpi->skin_map[block_index];
} #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { // Under aggressive denoising mode, should we use skin map to reduce // denoiser // and ZEROMV bias? Will need to revisit the accuracy of this detection for // very noisy input. For now keep this as is (i.e., don't turn it off). // if (cpi->denoiser.denoiser_mode == kDenoiserOnYUVAggressive) // x->is_skin = 0;
} #endif
/* Check to see if there is at least 1 valid reference frame that we need * to calculate near_mvs.
*/ if (ref_frame_map[1] > 0) {
sign_bias = vp8_find_near_mvs_bias(
&x->e_mbd, x->e_mbd.mode_info_context, mode_mv_sb, best_ref_mv_sb,
mdcounts, ref_frame_map[1], cpi->common.ref_frame_sign_bias);
/* If the frame has big static background and current MB is in low * motion area, its mode decision is biased to ZEROMV mode. * No adjustment if cpu_used is <= -12 (i.e., cpi->Speed >= 12). * At such speed settings, ZEROMV is already heavily favored.
*/ if (cpi->Speed < 12) {
calculate_zeromv_rd_adjustment(cpi, x, &rd_adjustment);
}
if (dot_artifact_candidate) { // Bias against ZEROMV_LAST mode.
rd_adjustment = 150;
}
/* if we encode a new mv this is important * find the best new motion vector
*/ for (mode_index = 0; mode_index < MAX_MODES; ++mode_index) { int frame_cost; int this_rd = INT_MAX; int this_ref_frame = ref_frame_map[vp8_ref_frame_order[mode_index]];
if (best_rd <= x->rd_threshes[mode_index]) continue;
/* Check to see if the testing frequency for this mode is at its max * If so then prevent it from being tested and increase the threshold
* for its testing */ if (x->mode_test_hit_counts[mode_index] &&
(cpi->mode_check_freq[mode_index] > 1)) { if (x->mbs_tested_so_far <= (cpi->mode_check_freq[mode_index] *
x->mode_test_hit_counts[mode_index])) { /* Increase the threshold for coding this mode to make it less
* likely to be chosen */
x->rd_thresh_mult[mode_index] += 4;
if (x->rd_thresh_mult[mode_index] > MAX_THRESHMULT) {
x->rd_thresh_mult[mode_index] = MAX_THRESHMULT;
}
/* We have now reached the point where we are going to test the current * mode so increment the counter for the number of times it has been
* tested */
x->mode_test_hit_counts[mode_index]++;
/* Work out the cost assosciated with selecting the reference frame */
frame_cost = x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
rate2 += frame_cost;
/* Only consider ZEROMV/ALTREF_FRAME for alt ref frame, * unless ARNR filtering is enabled in which case we want
* an unfiltered alternative */ if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) { if (this_mode != ZEROMV ||
x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) { continue;
}
}
switch (this_mode) { case B_PRED: /* Pass best so far to pick_intra4x4mby_modes to use as breakout */
distortion2 = best_rd_sse;
pick_intra4x4mby_modes(x, &rate, &distortion2);
/* Further step/diamond searches as necessary */
step_param = cpi->sf.first_step + speed_adjust;
#if CONFIG_MULTI_RES_ENCODING /* If lower-res frame is not available for mv reuse (because of frame dropping or different temporal layer pattern), then higher resol encoder does motion search without any previous knowledge. Also, since last frame motion info is not stored, then we can not
use improved_mv_pred. */ if (cpi->oxcf.mr_encoder_id) sf_improved_mv_pred = 0;
// Only use parent MV as predictor if this candidate reference frame // (|this_ref_frame|) is equal to |parent_ref_frame|. if (parent_ref_valid && (parent_ref_frame == this_ref_frame)) { /* Use parent MV as predictor. Adjust search range * accordingly.
*/
mvp.as_int = parent_ref_mv.as_int;
mvp_full.as_mv.col = parent_ref_mv.as_mv.col >> 3;
mvp_full.as_mv.row = parent_ref_mv.as_mv.row >> 3;
if (cpi->sf.search_method == HEX) { #if CONFIG_MULTI_RES_ENCODING /* TODO: In higher-res pick_inter_mode, step_param is used to * modify hex search range. Here, set step_param to 0 not to * change the behavior in lowest-resolution encoder. * Will improve it later.
*/ /* Set step_param to 0 to ensure large-range motion search * when mv reuse if not valid (i.e. |parent_ref_valid| = 0), * or if this candidate reference frame (|this_ref_frame|) is * not equal to |parent_ref_frame|.
*/ if (!parent_ref_valid || (parent_ref_frame != this_ref_frame))
step_param = 0; #endif
bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, step_param,
sadpb, &cpi->fn_ptr[BLOCK_16X16],
x->mvsadcost, &best_ref_mv);
mode_mv[NEWMV].as_int = d->bmi.mv.as_int;
} else {
bestsme = cpi->diamond_search_sad(
x, b, d, &mvp_full, &d->bmi.mv, step_param, sadpb, &num00,
&cpi->fn_ptr[BLOCK_16X16], x->mvcost, &best_ref_mv);
mode_mv[NEWMV].as_int = d->bmi.mv.as_int;
/* Further step/diamond searches as necessary */
n = num00;
num00 = 0;
mode_mv[NEWMV].as_int = d->bmi.mv.as_int; // The clamp below is not necessary from the perspective // of VP8 bitstream, but is added to improve ChromeCast // mirroring's robustness. Please do not remove.
vp8_clamp_mv2(&mode_mv[this_mode], xd); /* mv cost; */
rate2 +=
vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, cpi->mb.mvcost, 128);
} // fall through
case NEARESTMV: case NEARMV: if (mode_mv[this_mode].as_int == 0) continue; // fall through
case ZEROMV:
/* Trap vectors that reach beyond the UMV borders * Note that ALL New MV, Nearest MV Near MV and Zero MV code drops * through to this point because of the lack of break statements * in the previous two cases.
*/ if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) ||
((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) ||
((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) ||
((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) { continue;
}
#if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { /* Store for later use by denoiser. */ // Don't denoise with GOLDEN OR ALTREF is they are old reference // frames (greater than MAX_GF_ARF_DENOISE_RANGE frames in past). int skip_old_reference = ((this_ref_frame != LAST_FRAME) &&
(cpi->common.current_video_frame -
cpi->current_ref_frames[this_ref_frame] >
MAX_GF_ARF_DENOISE_RANGE))
? 1
: 0; if (this_mode == ZEROMV && sse < zero_mv_sse && !skip_old_reference) {
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 &&
!skip_old_reference) {
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
if (this_rd < best_rd || x->skip) { /* Note index of best mode */
best_mode_index = mode_index;
/* Testing this mode gave rise to an improvement in best error * score. Lower threshold a bit for next time
*/
x->rd_thresh_mult[mode_index] =
(x->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2))
? x->rd_thresh_mult[mode_index] - 2
: MIN_THRESHMULT;
x->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) *
x->rd_thresh_mult[mode_index];
}
/* If the mode did not help improve the best error case then raise the * threshold for testing that mode next time around.
*/ else {
x->rd_thresh_mult[mode_index] += 4;
if (x->rd_thresh_mult[mode_index] > MAX_THRESHMULT) {
x->rd_thresh_mult[mode_index] = MAX_THRESHMULT;
}
/* Reduce the activation RD thresholds for the best choice mode */ if ((cpi->rd_baseline_thresh[best_mode_index] > 0) &&
(cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) { int best_adjustment = (x->rd_thresh_mult[best_mode_index] >> 3);
#if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { int block_index = mb_row * cpi->common.mb_cols + mb_col; int reevaluate = 0; int is_noisy = 0; 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;
} // For non-skin blocks that have selected ZEROMV for this current frame, // and have been selecting ZEROMV_LAST (on the base layer frame) at // least |x~20| consecutive past frames in a row, label the block for // possible increase in denoising strength. We also condition this // labeling on there being significant denoising in the scene if (cpi->oxcf.noise_sensitivity == 4) { if (cpi->denoiser.nmse_source_diff >
70 * cpi->denoiser.threshold_aggressive_mode / 100) {
is_noisy = 1;
}
} else { if (cpi->mse_source_denoised > 1000) is_noisy = 1;
}
x->increase_denoising = 0; if (!x->is_skin && x->best_sse_inter_mode == ZEROMV &&
(x->best_reference_frame == LAST_FRAME ||
x->best_reference_frame == cpi->closest_reference_frame) &&
cpi->consec_zero_last[block_index] >= 20 && is_noisy) {
x->increase_denoising = 1;
}
x->denoise_zeromv = 0;
vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
recon_yoffset, recon_uvoffset, &cpi->common.lf_info,
mb_row, mb_col, block_index,
cpi->consec_zero_last_mvbias[block_index]);
// Reevaluate ZEROMV after denoising: for large noise content // (i.e., cpi->mse_source_denoised is above threshold), do this for all // blocks that did not pick ZEROMV as best mode but are using ZEROMV // for denoising. Otherwise, always re-evaluate for blocks that picked // INTRA mode as best mode. // Avoid blocks that have been biased against ZERO_LAST // (i.e., dot artifact candidate blocks).
reevaluate = (best_mbmode.ref_frame == INTRA_FRAME) ||
(best_mbmode.mode != ZEROMV && x->denoise_zeromv &&
cpi->mse_source_denoised > 2000); if (!dot_artifact_candidate && reevaluate &&
x->best_zeromv_reference_frame != INTRA_FRAME) { int this_rd = 0; int this_ref_frame = x->best_zeromv_reference_frame;
rd_adjustment = 100;
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];
/* set to the best mb mode, this copy can be skip if x->skip since it
* already has the right content */ if (!x->skip) {
memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO));
}
if (best_mbmode.mode <= B_PRED) { /* set mode_info_context->mbmi.uv_mode */
pick_intra_mbuv_mode(x);
}
if (sign_bias !=
cpi->common.ref_frame_sign_bias[xd->mode_info_context->mbmi.ref_frame]) {
best_ref_mv.as_int = best_ref_mv_sb[!sign_bias].as_int;
}
update_mvcount(x, &best_ref_mv);
}
void vp8_pick_intra_mode(MACROBLOCK *x, int *rate) { int error4x4, error16x16 = INT_MAX; int rate_, best_rate = 0, distortion, best_sse;
MB_PREDICTION_MODE mode, best_mode = DC_PRED; int this_rd; unsignedint sse;
BLOCK *b = &x->block[0];
MACROBLOCKD *xd = &x->e_mbd;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.