Rework cut-off decisions in cyclic refresh aq mode

This commit removes the cyclic aq mode dependency on
in_static_area and reworks the corresponding cut-off thresholds.
It improves the compression performance of speed -5 by 1.47% in
PSNR and 2.07% in SSIM, and the compression performance of speed
-6 by 3.10% in PSNR and 5.25% in SSIM. Speed wise, about 1% faster
in both settings at high bit-rates.

Change-Id: I1ffc775afdc047964448d9dff5751491ba4ff4a9
This commit is contained in:
Jingning Han 2014-11-04 14:32:04 -08:00
parent 7e491de1c4
commit caaf63b2c4
4 changed files with 29 additions and 41 deletions

View File

@ -94,19 +94,17 @@ static int candidate_refresh_aq(const CYCLIC_REFRESH *cr,
const MB_MODE_INFO *mbmi,
BLOCK_SIZE bsize, int use_rd) {
if (use_rd) {
MV mv = mbmi->mv[0].as_mv;
// If projected rate is below the thresh_rate (well below target,
// so undershoot expected), accept it for lower-qp coding.
if (cr->projected_rate_sb < cr->thresh_rate_sb)
return 1;
// Otherwise, reject the block for lower-qp coding if any of the following:
// 1) prediction block size is below min_block_size
// 2) mode is non-zero mv and projected distortion is above thresh_dist
// 3) mode is an intra-mode (we may want to allow some of this under
// 1) mode uses large mv
// 2) mode is an intra-mode (we may want to allow some of this under
// another thresh_dist)
else if (bsize < cr->min_block_size ||
(mbmi->mv[0].as_int != 0 &&
cr->projected_dist_sb > cr->thresh_dist_sb) ||
!is_inter_block(mbmi))
else if (mv.row > 32 || mv.row < -32 ||
mv.col > 32 || mv.col < -32 || !is_inter_block(mbmi))
return 0;
else
return 1;
@ -135,8 +133,7 @@ void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi,
const int xmis = MIN(cm->mi_cols - mi_col, bw);
const int ymis = MIN(cm->mi_rows - mi_row, bh);
const int block_index = mi_row * cm->mi_cols + mi_col;
const int refresh_this_block = cpi->mb.in_static_area ||
candidate_refresh_aq(cr, mbmi, bsize, use_rd);
const int refresh_this_block = candidate_refresh_aq(cr, mbmi, bsize, use_rd);
// Default is to not update the refresh map.
int new_map_value = cr->map[block_index];
int x = 0; int y = 0;
@ -161,6 +158,7 @@ void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi,
// Leave it marked as block that is not candidate for refresh.
new_map_value = 1;
}
// Update entries in the cyclic refresh map with new_map_value, and
// copy mbmi->segment_id into global segmentation map.
for (y = 0; y < ymis; y++)
@ -214,8 +212,8 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
if (cpi->sf.use_nonrd_pick_mode) {
// May want to be more conservative with thresholds in non-rd mode for now
// as rate/distortion are derived from model based on prediction residual.
cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 3;
cr->thresh_dist_sb = 4 * (int)(q * q);
cr->thresh_rate_sb = (rc->sb64_target_rate * 256);
cr->thresh_dist_sb = 16 * (int)(q * q);
}
cr->num_seg_blocks = 0;

View File

@ -98,8 +98,6 @@ struct macroblock {
// note that token_costs is the cost when eob node is skipped
vp9_coeff_cost token_costs[TX_SIZES];
int in_static_area;
int optimize;
// indicate if it is in the rd search loop or encoding process

View File

@ -46,6 +46,11 @@ typedef struct {
int64_t tx_rd_diff[TX_MODES];
int64_t best_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
// scope of refactoring.
int rate;
int64_t dist;
#if CONFIG_VP9_TEMPORAL_DENOISING
unsigned int newmv_sse;
unsigned int zeromv_sse;

View File

@ -641,6 +641,9 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
// Else for cyclic refresh mode update the segment map, set the segment id
// and then update the quantizer.
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
ctx->rate, ctx->dist);
vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0].src_mi->mbmi,
mi_row, mi_col, bsize, 1);
}
@ -910,6 +913,9 @@ static void rd_pick_sb_modes(VP9_COMP *cpi,
// refactored to provide proper exit/return handle.
if (rd_cost->rate == INT_MAX)
rd_cost->rdcost = INT64_MAX;
ctx->rate = rd_cost->rate;
ctx->dist = rd_cost->dist;
}
static void update_stats(VP9_COMMON *cm, const MACROBLOCK *x) {
@ -1334,6 +1340,8 @@ static void update_state_rt(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
: cm->last_frame_seg_map;
mbmi->segment_id = vp9_get_segment_id(cm, map, bsize, mi_row, mi_col);
} else {
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
ctx->rate, ctx->dist);
// Setting segmentation map for cyclic_refresh
vp9_cyclic_refresh_update_segment(cpi, mbmi, mi_row, mi_col, bsize, 1);
}
@ -1725,10 +1733,6 @@ static void rd_use_partition(VP9_COMP *cpi,
vp9_select_in_frame_q_segment(cpi, mi_row, mi_col,
output_enabled, chosen_rdc.rate);
}
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
chosen_rdc.rate, chosen_rdc.dist);
encode_sb(cpi, tile_info, tp, mi_row, mi_col, output_enabled, bsize,
pc_tree);
}
@ -2467,10 +2471,6 @@ static void rd_pick_partition(VP9_COMP *cpi,
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_rdc.rate);
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
best_rdc.rate, best_rdc.dist);
encode_sb(cpi, tile_info, tp, mi_row, mi_col, output_enabled,
bsize, pc_tree);
}
@ -2638,7 +2638,7 @@ static void nonrd_pick_sb_modes(VP9_COMP *cpi,
mbmi->sb_type = bsize;
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled)
if (mbmi->segment_id && x->in_static_area)
if (mbmi->segment_id)
x->rdmult = vp9_cyclic_refresh_get_rdmult(cpi->cyclic_refresh);
if (vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP))
@ -2651,6 +2651,9 @@ static void nonrd_pick_sb_modes(VP9_COMP *cpi,
if (rd_cost->rate == INT_MAX)
vp9_rd_cost_reset(rd_cost);
ctx->rate = rd_cost->rate;
ctx->dist = rd_cost->dist;
}
static void fill_mode_info_sb(VP9_COMMON *cm, MACROBLOCK *x,
@ -2973,11 +2976,6 @@ static void nonrd_pick_partition(VP9_COMP *cpi,
vp9_select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled,
best_rdc.rate);
}
if (oxcf->aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
best_rdc.rate, best_rdc.dist);
encode_sb_rt(cpi, tile_info, tp, mi_row, mi_col, output_enabled,
bsize, pc_tree);
}
@ -3114,12 +3112,8 @@ static void nonrd_select_partition(VP9_COMP *cpi,
}
}
if (bsize == BLOCK_64X64 && output_enabled) {
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
rd_cost->rate, rd_cost->dist);
if (bsize == BLOCK_64X64 && output_enabled)
encode_sb_rt(cpi, tile_info, tp, mi_row, mi_col, 1, bsize, pc_tree);
}
}
@ -3232,13 +3226,9 @@ static void nonrd_use_partition(VP9_COMP *cpi,
break;
}
if (bsize == BLOCK_64X64 && output_enabled) {
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
rd_cost->rate, rd_cost->dist);
if (bsize == BLOCK_64X64 && output_enabled)
encode_sb_rt(cpi, &tile_data->tile_info, tp, mi_row, mi_col,
1, bsize, pc_tree);
}
}
static void encode_nonrd_sb_row(VP9_COMP *cpi,
@ -3263,7 +3253,6 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi,
const int idx_str = cm->mi_stride * mi_row + mi_col;
MODE_INFO *mi = cm->mi + idx_str;
BLOCK_SIZE bsize;
x->in_static_area = 0;
x->source_variance = UINT_MAX;
vp9_zero(x->pred_mv);
vp9_rd_cost_init(&dummy_rdc);
@ -3290,10 +3279,8 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi,
break;
case REFERENCE_PARTITION:
set_offsets(cpi, tile_info, mi_row, mi_col, BLOCK_64X64);
x->in_static_area = is_background(cpi, tile_info, mi_row, mi_col);
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled &&
xd->mi[0].src_mi->mbmi.segment_id && x->in_static_area) {
xd->mi[0].src_mi->mbmi.segment_id) {
auto_partition_range(cpi, tile_info, mi_row, mi_col,
&sf->min_partition_size,
&sf->max_partition_size);