Newer
Older
}
static INLINE int get_motion_inconsistency(MOTION_DIRECTION this_mv,
MOTION_DIRECTION that_mv) {
if (this_mv == that_mv) {
return 0;
} else {
return abs(this_mv - that_mv) == 2 ? 2 : 1;
}
}
// TODO(jingning,jimbankoski,rbultje): properly skip partition types that are
// unlikely to be selected depending on previous rate-distortion optimization
// results, for encoding speed-up.
static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
TOKENEXTRA **tp, int mi_row,
int mi_col, BLOCK_SIZE bsize, int *rate,
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
const int mi_step = num_8x8_blocks_wide_lookup[bsize] / 2;
ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE];
PARTITION_CONTEXT sl[8], sa[8];
TOKENEXTRA *tp_orig = *tp;
PICK_MODE_CONTEXT *ctx = &pc_tree->none;
BLOCK_SIZE subsize;
int this_rate, sum_rate = 0, best_rate = INT_MAX;
int64_t this_dist, sum_dist = 0, best_dist = INT64_MAX;
int do_split = bsize >= BLOCK_8X8;
int do_rect = 1;
// Override skipping rectangular partition operations for edge blocks
const int force_horz_split = (mi_row + mi_step >= cm->mi_rows);
const int force_vert_split = (mi_col + mi_step >= cm->mi_cols);
const int xss = x->e_mbd.plane[1].subsampling_x;
const int yss = x->e_mbd.plane[1].subsampling_y;
BLOCK_SIZE min_size = cpi->sf.min_partition_size;
BLOCK_SIZE max_size = cpi->sf.max_partition_size;
#if CONFIG_FP_MB_STATS
unsigned int src_diff_var = UINT_MAX;
int none_complexity = 0;
#endif
int partition_none_allowed = !force_horz_split && !force_vert_split;
int partition_horz_allowed = !force_vert_split && yss <= xss &&
bsize >= BLOCK_8X8;
int partition_vert_allowed = !force_horz_split && xss <= yss &&
bsize >= BLOCK_8X8;
assert(num_8x8_blocks_wide_lookup[bsize] ==
num_8x8_blocks_high_lookup[bsize]);
set_offsets(cpi, tile, mi_row, mi_col, bsize);
if (bsize == BLOCK_16X16 && cpi->oxcf.aq_mode)
x->mb_energy = vp9_block_energy(cpi, x, bsize);
if (cpi->sf.cb_partition_search && bsize == BLOCK_16X16) {
int cb_partition_search_ctrl = ((pc_tree->index == 0 || pc_tree->index == 3)
+ get_chessboard_index(cm->current_video_frame)) & 0x1;
if (cb_partition_search_ctrl && bsize > min_size && bsize < max_size)
set_partition_range(cm, xd, mi_row, mi_col, bsize, &min_size, &max_size);
}
// Determine partition types in search according to the speed features.
// The threshold set here has to be of square block size.
if (cpi->sf.auto_min_max_partition_size) {
partition_none_allowed &= (bsize <= max_size && bsize >= min_size);
partition_horz_allowed &= ((bsize <= max_size && bsize > min_size) ||
partition_vert_allowed &= ((bsize <= max_size && bsize > min_size) ||
do_split &= bsize > min_size;
}
if (cpi->sf.use_square_partition_only) {
partition_horz_allowed &= force_horz_split;
partition_vert_allowed &= force_vert_split;
}
save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
#if CONFIG_FP_MB_STATS
if (cpi->use_fp_mb_stats) {
set_offsets(cpi, tile, mi_row, mi_col, bsize);
src_diff_var = get_sby_perpixel_diff_variance(cpi, &cpi->mb.plane[0].src,
mi_row, mi_col, bsize);
}
#endif
#if CONFIG_FP_MB_STATS
// Decide whether we shall split directly and skip searching NONE by using
// the first pass block statistics
if (cpi->use_fp_mb_stats && bsize >= BLOCK_32X32 && do_split &&
partition_none_allowed && src_diff_var > 4 &&
cm->base_qindex < qindex_split_threshold_lookup[bsize]) {
int mb_row = mi_row >> 1;
int mb_col = mi_col >> 1;
int mb_row_end =
MIN(mb_row + num_16x16_blocks_high_lookup[bsize], cm->mb_rows);
int mb_col_end =
MIN(mb_col + num_16x16_blocks_wide_lookup[bsize], cm->mb_cols);
int r, c;
// compute a complexity measure, basically measure inconsistency of motion
// vectors obtained from the first pass in the current block
for (r = mb_row; r < mb_row_end ; r++) {
for (c = mb_col; c < mb_col_end; c++) {
const int mb_index = r * cm->mb_cols + c;
MOTION_DIRECTION this_mv;
MOTION_DIRECTION right_mv;
MOTION_DIRECTION bottom_mv;
this_mv =
get_motion_direction_fp(cpi->twopass.this_frame_mb_stats[mb_index]);
// to its right
if (c != mb_col_end - 1) {
right_mv = get_motion_direction_fp(
cpi->twopass.this_frame_mb_stats[mb_index + 1]);
none_complexity += get_motion_inconsistency(this_mv, right_mv);
}
// to its bottom
if (r != mb_row_end - 1) {
bottom_mv = get_motion_direction_fp(
cpi->twopass.this_frame_mb_stats[mb_index + cm->mb_cols]);
none_complexity += get_motion_inconsistency(this_mv, bottom_mv);
}
// do not count its left and top neighbors to avoid double counting
}
}
if (none_complexity > complexity_16x16_blocks_threshold[bsize]) {
partition_none_allowed = 0;
}
}
#endif
// PARTITION_NONE
if (partition_none_allowed) {
rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &this_rate, &this_dist, bsize,
if (this_rate != INT_MAX) {
if (bsize >= BLOCK_8X8) {
pl = partition_plane_context(xd, mi_row, mi_col, bsize);
this_rate += cpi->partition_cost[pl][PARTITION_NONE];
}
sum_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_dist);
if (sum_rd < best_rd) {
int64_t dist_breakout_thr = cpi->sf.partition_search_breakout_dist_thr;
int rate_breakout_thr = cpi->sf.partition_search_breakout_rate_thr;
best_rate = this_rate;
best_dist = this_dist;
best_rd = sum_rd;
if (bsize >= BLOCK_8X8)
pc_tree->partitioning = PARTITION_NONE;
// Adjust dist breakout threshold according to the partition size.
dist_breakout_thr >>= 8 - (b_width_log2(bsize) +
// If all y, u, v transform blocks in this partition are skippable, and
// the dist & rate are within the thresholds, the partition search is
// terminated for current branch of the partition search tree.
// The dist & rate thresholds are set to 0 at speed 0 to disable the
// early termination at that speed.
if (!x->e_mbd.lossless &&
(ctx->skippable && best_dist < dist_breakout_thr &&
best_rate < rate_breakout_thr)) {
do_split = 0;
do_rect = 0;
}
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
#if CONFIG_FP_MB_STATS
// Check if every 16x16 first pass block statistics has zero
// motion and the corresponding first pass residue is small enough.
// If that is the case, check the difference variance between the
// current frame and the last frame. If the variance is small enough,
// stop further splitting in RD optimization
if (cpi->use_fp_mb_stats && do_split != 0 &&
cm->base_qindex > qindex_skip_threshold_lookup[bsize]) {
int mb_row = mi_row >> 1;
int mb_col = mi_col >> 1;
int mb_row_end =
MIN(mb_row + num_16x16_blocks_high_lookup[bsize], cm->mb_rows);
int mb_col_end =
MIN(mb_col + num_16x16_blocks_wide_lookup[bsize], cm->mb_cols);
int r, c;
int skip = 1;
for (r = mb_row; r < mb_row_end; r++) {
for (c = mb_col; c < mb_col_end; c++) {
const int mb_index = r * cm->mb_cols + c;
if (!(cpi->twopass.this_frame_mb_stats[mb_index] &
FPMB_MOTION_ZERO_MASK) ||
!(cpi->twopass.this_frame_mb_stats[mb_index] &
skip = 0;
break;
}
}
if (skip == 0) {
break;
}
}
if (skip) {
if (src_diff_var == UINT_MAX) {
set_offsets(cpi, tile, mi_row, mi_col, bsize);
src_diff_var = get_sby_perpixel_diff_variance(
cpi, &cpi->mb.plane[0].src, mi_row, mi_col, bsize);
}
if (src_diff_var < 8) {
do_split = 0;
do_rect = 0;
}
}
}
#endif
}
}
restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
}
// store estimated motion vector
if (cpi->sf.adaptive_motion_search)
// PARTITION_SPLIT
sum_rd = 0;
// TODO(jingning): use the motion vectors given by the above search as
// the starting point of motion search in the following partition type check.
if (do_split) {
subsize = get_subsize(bsize, PARTITION_SPLIT);
if (bsize == BLOCK_8X8) {
i = 4;
if (cpi->sf.adaptive_pred_interp_filter && partition_none_allowed)
pc_tree->leaf_split[0]->pred_interp_filter =
rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
pc_tree->leaf_split[0], best_rd, 0);
if (sum_rate == INT_MAX)
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
} else {
for (i = 0; i < 4 && sum_rd < best_rd; ++i) {
const int x_idx = (i & 1) * mi_step;
const int y_idx = (i >> 1) * mi_step;
if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
continue;
if (cpi->sf.adaptive_motion_search)
load_pred_mv(x, ctx);
rd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx,
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
if (sum_rd < best_rd && i == 4) {
pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rate += cpi->partition_cost[pl][PARTITION_SPLIT];
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd) {
best_rate = sum_rate;
best_dist = sum_dist;
best_rd = sum_rd;
pc_tree->partitioning = PARTITION_SPLIT;
} else {
// skip rectangular partition test when larger block size
// gives better rd cost
if (cpi->sf.less_rectangular_check)
do_rect &= !partition_none_allowed;
}
restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
// PARTITION_HORZ
if (partition_horz_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_HORZ);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
pc_tree->horizontal[0].pred_interp_filter =
rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
&pc_tree->horizontal[0], best_rd, 0);
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd && mi_row + mi_step < cm->mi_rows) {
PICK_MODE_CONTEXT *ctx = &pc_tree->horizontal[0];
update_state(cpi, ctx, mi_row, mi_col, subsize, 0);
encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
pc_tree->horizontal[1].pred_interp_filter =
rd_pick_sb_modes(cpi, tile, mi_row + mi_step, mi_col, &this_rate,
&this_dist, subsize, &pc_tree->horizontal[1],
best_rd - sum_rd, 1);
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
if (sum_rd < best_rd) {
pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rate += cpi->partition_cost[pl][PARTITION_HORZ];
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd) {
best_rd = sum_rd;
best_rate = sum_rate;
best_dist = sum_dist;
pc_tree->partitioning = PARTITION_HORZ;
restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
}
// PARTITION_VERT
if (partition_vert_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_VERT);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
pc_tree->vertical[0].pred_interp_filter =
rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
&pc_tree->vertical[0], best_rd, 0);
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd && mi_col + mi_step < cm->mi_cols) {
update_state(cpi, &pc_tree->vertical[0], mi_row, mi_col, subsize, 0);
encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize,
&pc_tree->vertical[0]);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
pc_tree->vertical[1].pred_interp_filter =
rd_pick_sb_modes(cpi, tile, mi_row, mi_col + mi_step, &this_rate,
&pc_tree->vertical[1], best_rd - sum_rd,
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
if (sum_rd < best_rd) {
pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rate += cpi->partition_cost[pl][PARTITION_VERT];
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd) {
best_rate = sum_rate;
best_dist = sum_dist;
best_rd = sum_rd;
pc_tree->partitioning = PARTITION_VERT;
restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
// TODO(jbb): This code added so that we avoid static analysis
// warning related to the fact that best_rd isn't used after this
// point. This code should be refactored so that the duplicate
// checks occur in some sub function and thus are used...
(void) best_rd;
*rate = best_rate;
*dist = best_dist;
if (best_rate < INT_MAX && best_dist < INT64_MAX && pc_tree->index != 3) {
int output_enabled = (bsize == BLOCK_64X64);
// Check the projected output rate for this SB against it's target
// and and if necessary apply a Q delta using segmentation to get
// closer to the target.
if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map)
vp9_select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled,
best_rate);
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
best_rate, best_dist);
encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize, pc_tree);
if (bsize == BLOCK_64X64) {
assert(best_rate < INT_MAX);
assert(best_dist < INT64_MAX);
static void encode_rd_sb_row(VP9_COMP *cpi, const TileInfo *const tile,
int mi_row, TOKENEXTRA **tp) {
MACROBLOCKD *const xd = &cpi->mb.e_mbd;
SPEED_FEATURES *const sf = &cpi->sf;
// Initialize the left context for the new SB row
vpx_memset(&xd->left_context, 0, sizeof(xd->left_context));
vpx_memset(xd->left_seg_context, 0, sizeof(xd->left_seg_context));
for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end;
int dummy_rate;
int64_t dummy_dist;
if (sf->adaptive_pred_interp_filter) {
cpi->leaf_tree[i].pred_interp_filter = SWITCHABLE;
cpi->pc_tree[i].vertical[0].pred_interp_filter = SWITCHABLE;
cpi->pc_tree[i].vertical[1].pred_interp_filter = SWITCHABLE;
cpi->pc_tree[i].horizontal[0].pred_interp_filter = SWITCHABLE;
cpi->pc_tree[i].horizontal[1].pred_interp_filter = SWITCHABLE;
// TODO(yunqingwang): use_lastframe_partitioning is no longer used in good-
// quality encoding. Need to evaluate it in real-time encoding later to
// decide if it can be removed too. And then, do the code cleanup.
if ((sf->partition_search_type == SEARCH_PARTITION &&
sf->use_lastframe_partitioning) ||
sf->partition_search_type == FIXED_PARTITION ||
sf->partition_search_type == VAR_BASED_PARTITION ||
sf->partition_search_type == VAR_BASED_FIXED_PARTITION) {
const int idx_str = cm->mi_stride * mi_row + mi_col;
MODE_INFO **mi = cm->mi_grid_visible + idx_str;
MODE_INFO **prev_mi = cm->prev_mi_grid_visible + idx_str;
if (sf->partition_search_type == FIXED_PARTITION) {
set_fixed_partitioning(cpi, tile, mi, mi_row, mi_col,
rd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, 1, cpi->pc_root);
} else if (cpi->skippable_frame ||
sf->partition_search_type == VAR_BASED_FIXED_PARTITION) {
BLOCK_SIZE bsize;
set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
bsize = get_rd_var_based_fixed_partition(cpi, mi_row, mi_col);
set_fixed_partitioning(cpi, tile, mi, mi_row, mi_col, bsize);
rd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, 1, cpi->pc_root);
} else if (sf->partition_search_type == VAR_BASED_PARTITION) {
choose_partitioning(cpi, tile, mi_row, mi_col);
rd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, 1, cpi->pc_root);
GF_GROUP * gf_grp = &cpi->twopass.gf_group;
int last_was_mid_sequence_overlay = 0;
if ((cpi->oxcf.pass == 2) && (gf_grp->index)) {
if (gf_grp->update_type[gf_grp->index - 1] == OVERLAY_UPDATE)
last_was_mid_sequence_overlay = 1;
}
if ((cpi->rc.frames_since_key
% sf->last_partitioning_redo_frequency) == 0
|| cm->show_frame == 0
|| cm->frame_type == KEY_FRAME
|| cpi->rc.is_src_frame_alt_ref
|| ((sf->use_lastframe_partitioning ==
sb_has_motion(cm, prev_mi, sf->lf_motion_threshold))) {
// If required set upper and lower partition size limits
if (sf->auto_min_max_partition_size) {
set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
rd_auto_partition_range(cpi, tile, mi_row, mi_col,
&sf->min_partition_size,
&sf->max_partition_size);
rd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, INT64_MAX,
if (sf->constrain_copy_partition &&
sb_has_motion(cm, prev_mi, sf->lf_motion_threshold))
constrain_copy_partitioning(cpi, tile, mi, prev_mi,
mi_row, mi_col, BLOCK_16X16);
else
copy_partitioning(cm, mi, prev_mi);
rd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, 1, cpi->pc_root);
// If required set upper and lower partition size limits
if (sf->auto_min_max_partition_size) {
set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
rd_auto_partition_range(cpi, tile, mi_row, mi_col,
&sf->min_partition_size,
&sf->max_partition_size);
rd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, INT64_MAX, cpi->pc_root);
static void init_encode_frame_mb_context(VP9_COMP *cpi) {
MACROBLOCK *const x = &cpi->mb;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
const int aligned_mi_cols = mi_cols_aligned_to_sb(cm->mi_cols);
vp9_setup_block_planes(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
// Note: this memset assumes above_context[0], [1] and [2]
// are allocated as part of the same buffer.
vpx_memset(xd->above_context[0], 0,
sizeof(*xd->above_context[0]) *
2 * aligned_mi_cols * MAX_MB_PLANE);
vpx_memset(xd->above_seg_context, 0,
sizeof(*xd->above_seg_context) * aligned_mi_cols);
static int check_dual_ref_flags(VP9_COMP *cpi) {
const int ref_flags = cpi->ref_frame_flags;
if (vp9_segfeature_active(&cpi->common.seg, 1, SEG_LVL_REF_FRAME)) {
return (!!(ref_flags & VP9_GOLD_FLAG) + !!(ref_flags & VP9_LAST_FLAG)
+ !!(ref_flags & VP9_ALT_FLAG)) >= 2;
Ronald S. Bultje
committed
}
static void reset_skip_tx_size(VP9_COMMON *cm, TX_SIZE max_tx_size) {
const int mis = cm->mi_stride;
MODE_INFO **mi_ptr = cm->mi_grid_visible;
for (mi_row = 0; mi_row < cm->mi_rows; ++mi_row, mi_ptr += mis) {
for (mi_col = 0; mi_col < cm->mi_cols; ++mi_col) {
if (mi_ptr[mi_col]->mbmi.tx_size > max_tx_size)
mi_ptr[mi_col]->mbmi.tx_size = max_tx_size;
}
}
static MV_REFERENCE_FRAME get_frame_type(const VP9_COMP *cpi) {
if (frame_is_intra_only(&cpi->common))
else if (cpi->rc.is_src_frame_alt_ref && cpi->refresh_golden_frame)
else if (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)
static TX_MODE select_tx_mode(const VP9_COMP *cpi) {
if (cpi->sf.tx_size_search_method == USE_LARGESTALL)
return ALLOW_32X32;
else if (cpi->sf.tx_size_search_method == USE_FULL_RD||
cpi->sf.tx_size_search_method == USE_TX_8X8)
return TX_MODE_SELECT;
else
return cpi->common.tx_mode;
static void nonrd_pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile,
int mi_row, int mi_col,
int *rate, int64_t *dist,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
set_offsets(cpi, tile, mi_row, mi_col, bsize);
mbmi = &xd->mi[0]->mbmi;
mbmi->sb_type = bsize;
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled)
if (mbmi->segment_id && x->in_static_area)
x->rdmult = vp9_cyclic_refresh_get_rdmult(cpi->cyclic_refresh);
if (vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP))
set_mode_info_seg_skip(x, cm->tx_mode, rate, dist, bsize);
else
vp9_pick_inter_mode(cpi, x, tile, mi_row, mi_col, rate, dist, bsize, ctx);
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
}
static void fill_mode_info_sb(VP9_COMMON *cm, MACROBLOCK *x,
int mi_row, int mi_col,
BLOCK_SIZE bsize, BLOCK_SIZE subsize,
PC_TREE *pc_tree) {
MACROBLOCKD *xd = &x->e_mbd;
int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
PARTITION_TYPE partition = pc_tree->partitioning;
assert(bsize >= BLOCK_8X8);
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
switch (partition) {
case PARTITION_NONE:
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
*(xd->mi[0]) = pc_tree->none.mic;
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
break;
case PARTITION_VERT:
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
*(xd->mi[0]) = pc_tree->vertical[0].mic;
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
if (mi_col + hbs < cm->mi_cols) {
set_modeinfo_offsets(cm, xd, mi_row, mi_col + hbs);
*(xd->mi[0]) = pc_tree->vertical[1].mic;
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col + hbs, bsize);
}
break;
case PARTITION_HORZ:
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
*(xd->mi[0]) = pc_tree->horizontal[0].mic;
duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
if (mi_row + hbs < cm->mi_rows) {
set_modeinfo_offsets(cm, xd, mi_row + hbs, mi_col);
*(xd->mi[0]) = pc_tree->horizontal[1].mic;
duplicate_mode_info_in_sb(cm, xd, mi_row + hbs, mi_col, bsize);
}
break;
case PARTITION_SPLIT: {
BLOCK_SIZE subsubsize = get_subsize(subsize, PARTITION_SPLIT);
fill_mode_info_sb(cm, x, mi_row, mi_col, subsize,
fill_mode_info_sb(cm, x, mi_row, mi_col + hbs, subsize,
fill_mode_info_sb(cm, x, mi_row + hbs, mi_col, subsize,
fill_mode_info_sb(cm, x, mi_row + hbs, mi_col + hbs, subsize,
default:
break;
}
}
static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
TOKENEXTRA **tp, int mi_row,
int mi_col, BLOCK_SIZE bsize, int *rate,
int64_t *dist, int do_recon, int64_t best_rd,
PC_TREE *pc_tree) {
const SPEED_FEATURES *const sf = &cpi->sf;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
const int ms = num_8x8_blocks_wide_lookup[bsize] / 2;
TOKENEXTRA *tp_orig = *tp;
PICK_MODE_CONTEXT *ctx = &pc_tree->none;
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
int this_rate, sum_rate = 0, best_rate = INT_MAX;
int64_t this_dist, sum_dist = 0, best_dist = INT64_MAX;
int64_t sum_rd = 0;
int do_split = bsize >= BLOCK_8X8;
int do_rect = 1;
// Override skipping rectangular partition operations for edge blocks
const int force_horz_split = (mi_row + ms >= cm->mi_rows);
const int force_vert_split = (mi_col + ms >= cm->mi_cols);
const int xss = x->e_mbd.plane[1].subsampling_x;
const int yss = x->e_mbd.plane[1].subsampling_y;
int partition_none_allowed = !force_horz_split && !force_vert_split;
int partition_horz_allowed = !force_vert_split && yss <= xss &&
bsize >= BLOCK_8X8;
int partition_vert_allowed = !force_horz_split && xss <= yss &&
bsize >= BLOCK_8X8;
(void) *tp_orig;
assert(num_8x8_blocks_wide_lookup[bsize] ==
num_8x8_blocks_high_lookup[bsize]);
// Determine partition types in search according to the speed features.
// The threshold set here has to be of square block size.
if (sf->auto_min_max_partition_size) {
partition_none_allowed &= (bsize <= sf->max_partition_size &&
bsize >= sf->min_partition_size);
partition_horz_allowed &= ((bsize <= sf->max_partition_size &&
bsize > sf->min_partition_size) ||
force_horz_split);
partition_vert_allowed &= ((bsize <= sf->max_partition_size &&
bsize > sf->min_partition_size) ||
force_vert_split);
do_split &= bsize > sf->min_partition_size;
partition_horz_allowed &= force_horz_split;
partition_vert_allowed &= force_vert_split;
}
// PARTITION_NONE
if (partition_none_allowed) {
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col,
&this_rate, &this_dist, bsize, ctx);
ctx->mic.mbmi = xd->mi[0]->mbmi;
ctx->skip_txfm[0] = x->skip_txfm[0];
ctx->skip = x->skip;
if (this_rate != INT_MAX) {
int pl = partition_plane_context(xd, mi_row, mi_col, bsize);
this_rate += cpi->partition_cost[pl][PARTITION_NONE];
sum_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_dist);
if (sum_rd < best_rd) {
int64_t stop_thresh = 4096;
int64_t stop_thresh_rd;
best_rate = this_rate;
best_dist = this_dist;
best_rd = sum_rd;
if (bsize >= BLOCK_8X8)
pc_tree->partitioning = PARTITION_NONE;
// Adjust threshold according to partition size.
stop_thresh >>= 8 - (b_width_log2(bsize) +
b_height_log2(bsize));
stop_thresh_rd = RDCOST(x->rdmult, x->rddiv, 0, stop_thresh);
// If obtained distortion is very small, choose current partition
// and stop splitting.
if (!x->e_mbd.lossless && best_rd < stop_thresh_rd) {
do_split = 0;
do_rect = 0;
}
}
}
}
// store estimated motion vector
store_pred_mv(x, ctx);
// PARTITION_SPLIT
sum_rd = 0;
if (do_split) {
int pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rate += cpi->partition_cost[pl][PARTITION_SPLIT];
subsize = get_subsize(bsize, PARTITION_SPLIT);
for (i = 0; i < 4 && sum_rd < best_rd; ++i) {
const int x_idx = (i & 1) * ms;
const int y_idx = (i >> 1) * ms;
if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
continue;
load_pred_mv(x, ctx);
nonrd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx,
subsize, &this_rate, &this_dist, 0,
best_rd - sum_rd, pc_tree->split[i]);
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
}
if (sum_rd < best_rd) {
best_rate = sum_rate;
best_dist = sum_dist;
best_rd = sum_rd;
pc_tree->partitioning = PARTITION_SPLIT;
} else {
// skip rectangular partition test when larger block size
// gives better rd cost
do_rect &= !partition_none_allowed;
}
}
// PARTITION_HORZ
if (partition_horz_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_HORZ);
load_pred_mv(x, ctx);
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col,
&this_rate, &this_dist, subsize,
&pc_tree->horizontal[0]);
pc_tree->horizontal[0].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->horizontal[0].skip_txfm[0] = x->skip_txfm[0];
pc_tree->horizontal[0].skip = x->skip;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd && mi_row + ms < cm->mi_rows) {
load_pred_mv(x, ctx);
nonrd_pick_sb_modes(cpi, tile, mi_row + ms, mi_col,
&this_rate, &this_dist, subsize,
&pc_tree->horizontal[1]);
pc_tree->horizontal[1].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->horizontal[1].skip_txfm[0] = x->skip_txfm[0];
pc_tree->horizontal[1].skip = x->skip;
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
int pl = partition_plane_context(xd, mi_row, mi_col, bsize);
this_rate += cpi->partition_cost[pl][PARTITION_HORZ];
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
}
if (sum_rd < best_rd) {
best_rd = sum_rd;
best_rate = sum_rate;
best_dist = sum_dist;
pc_tree->partitioning = PARTITION_HORZ;
}
}
// PARTITION_VERT
if (partition_vert_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_VERT);
load_pred_mv(x, ctx);
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col,
&this_rate, &this_dist, subsize,
&pc_tree->vertical[0]);
pc_tree->vertical[0].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->vertical[0].skip_txfm[0] = x->skip_txfm[0];
pc_tree->vertical[0].skip = x->skip;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
if (sum_rd < best_rd && mi_col + ms < cm->mi_cols) {
load_pred_mv(x, ctx);
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col + ms,
&this_rate, &this_dist, subsize,
&pc_tree->vertical[1]);
pc_tree->vertical[1].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->vertical[1].skip_txfm[0] = x->skip_txfm[0];
pc_tree->vertical[1].skip = x->skip;
if (this_rate == INT_MAX) {
sum_rd = INT64_MAX;
} else {
int pl = partition_plane_context(xd, mi_row, mi_col, bsize);
this_rate += cpi->partition_cost[pl][PARTITION_VERT];
sum_rate += this_rate;
sum_dist += this_dist;
sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
}
}
if (sum_rd < best_rd) {
best_rate = sum_rate;
best_dist = sum_dist;
best_rd = sum_rd;
pc_tree->partitioning = PARTITION_VERT;
// TODO(JBB): The following line is here just to avoid a static warning
// that occurs because at this point we never again reuse best_rd
// despite setting it here. The code should be refactored to avoid this.
(void) best_rd;
*rate = best_rate;
*dist = best_dist;
if (best_rate == INT_MAX)
return;
// update mode info array
subsize = get_subsize(bsize, pc_tree->partitioning);
fill_mode_info_sb(cm, x, mi_row, mi_col, bsize, subsize,
pc_tree);
if (best_rate < INT_MAX && best_dist < INT64_MAX && do_recon) {
int output_enabled = (bsize == BLOCK_64X64);
// Check the projected output rate for this SB against it's target
// and and if necessary apply a Q delta using segmentation to get
// closer to the target.
if ((oxcf->aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) {
vp9_select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled,
best_rate);
if (oxcf->aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
best_rate, best_dist);
encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize, pc_tree);
}
if (bsize == BLOCK_64X64) {
assert(tp_orig < *tp);
assert(best_rate < INT_MAX);
assert(best_dist < INT64_MAX);
} else {
assert(tp_orig == *tp);
}
}
static void nonrd_use_partition(VP9_COMP *cpi,
const TileInfo *const tile,
TOKENEXTRA **tp,
int mi_row, int mi_col,
BLOCK_SIZE bsize, int output_enabled,
int *totrate, int64_t *totdist,
PC_TREE *pc_tree) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
const int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
const int mis = cm->mi_stride;
PARTITION_TYPE partition;
BLOCK_SIZE subsize;
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
return;
subsize = (bsize >= BLOCK_8X8) ? mi[0]->mbmi.sb_type : BLOCK_4X4;
partition = partition_lookup[bsl][subsize];
switch (partition) {
case PARTITION_NONE:
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, totrate, totdist,
subsize, &pc_tree->none);
pc_tree->none.mic.mbmi = xd->mi[0]->mbmi;
pc_tree->none.skip_txfm[0] = x->skip_txfm[0];
pc_tree->none.skip = x->skip;
break;
case PARTITION_VERT:
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, totrate, totdist,
subsize, &pc_tree->vertical[0]);
pc_tree->vertical[0].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->vertical[0].skip_txfm[0] = x->skip_txfm[0];
pc_tree->vertical[0].skip = x->skip;
if (mi_col + hbs < cm->mi_cols) {
nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col + hbs,
&rate, &dist, subsize, &pc_tree->vertical[1]);
pc_tree->vertical[1].mic.mbmi = xd->mi[0]->mbmi;
pc_tree->vertical[1].skip_txfm[0] = x->skip_txfm[0];