From 71e6ed7bd12016ba7169711d3c232c10e72cc0f0 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 10 Mar 2015 15:16:10 -0700 Subject: [PATCH] Adjustments to aq-mode=3. Factor in segment#2 and skip blocks into the postencode estimated bits, and increase somewhat the aggressiveness of the refresh. PSNR/SSIM Metrics on RTC set go up by ~0.8/0.5%. Change-Id: I5d4e7cb00a3aefb25d18c88b6b24118b72dc5d51 --- vp9/encoder/vp9_aq_cyclicrefresh.c | 67 ++++++++++++++++++------------ vp9/encoder/vp9_aq_cyclicrefresh.h | 11 ++++- vp9/encoder/vp9_encodeframe.c | 5 ++- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c index 958d52acf..4bd083c27 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.c +++ b/vp9/encoder/vp9_aq_cyclicrefresh.c @@ -30,10 +30,11 @@ struct CYCLIC_REFRESH { // excess of the cycle time, i.e., in the case of all zero motion, block // will be refreshed every (100/percent_refresh + time_for_refresh) frames. int time_for_refresh; - // // Target number of (8x8) blocks that are set for delta-q (segment 1). + // Target number of (8x8) blocks that are set for delta-q. int target_num_seg_blocks; - // Actual number of (8x8) blocks that were applied delta-q (segment 1). - int actual_num_seg_blocks; + // Actual number of (8x8) blocks that were applied delta-q. + int actual_num_seg1_blocks; + int actual_num_seg2_blocks; // RD mult. parameters for segment 1. int rdmult; // Cyclic refresh map. @@ -48,6 +49,8 @@ struct CYCLIC_REFRESH { // Rate target ratio to set q delta. double rate_ratio_qdelta; double low_content_avg; + int qindex_delta_seg1; + int qindex_delta_seg2; }; CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) { @@ -110,7 +113,7 @@ static int candidate_refresh_aq(const CYCLIC_REFRESH *cr, mv.col > cr->motion_thresh || mv.col < -cr->motion_thresh || !is_inter_block(mbmi))) return CR_SEGMENT_ID_BASE; - else if (bsize >= BLOCK_32X32 && + else if (bsize >= BLOCK_16X16 && rate < cr->thresh_rate_sb && is_inter_block(mbmi) && mbmi->mv[0].as_int == 0) @@ -146,15 +149,19 @@ int vp9_cyclic_refresh_estimate_bits_at_q(const VP9_COMP *cpi, int num8x8bl = mbs << 2; // Weight for non-base segments: use actual number of blocks refreshed in // previous/just encoded frame. Note number of blocks here is in 8x8 units. - double weight_segment = (double)cr->actual_num_seg_blocks / num8x8bl; - // Compute delta-q that was used in the just encoded frame. - int deltaq = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta); + double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl; + double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl; // Take segment weighted average for estimated bits. - estimated_bits = (int)((1.0 - weight_segment) * + estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) * vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs, correction_factor, cm->bit_depth) + - weight_segment * - vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex + deltaq, mbs, + weight_segment1 * + vp9_estimate_bits_at_q(cm->frame_type, + cm->base_qindex + cr->qindex_delta_seg1, mbs, + correction_factor, cm->bit_depth) + + weight_segment2 * + vp9_estimate_bits_at_q(cm->frame_type, + cm->base_qindex + cr->qindex_delta_seg2, mbs, correction_factor, cm->bit_depth)); return estimated_bits; } @@ -170,15 +177,11 @@ int vp9_cyclic_refresh_rc_bits_per_mb(const VP9_COMP *cpi, int i, CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; int bits_per_mb; int num8x8bl = cm->MBs << 2; - // Weight for segment 1 prior to encoding: take the target number for the - // frame to be encoded. Number of blocks here is in 8x8 units. - // Note that this is called in rc_regulate_q, which is called before the - // cyclic_refresh_setup (which sets cr->target_num_seg_blocks). So a mismatch - // may occur between the cr->target_num_seg_blocks value here and the - // cr->target_num_seg_block set for encoding the frame. For the current use - // case of fixed cr->percent_refresh and cr->time_for_refresh = 0, mismatch - // does not occur/is very small. - double weight_segment = (double)cr->target_num_seg_blocks / num8x8bl; + // Weight for segment prior to encoding: take the average of the target + // number for the frame to be encoded and the actual from the previous frame. + double weight_segment = (double)((cr->target_num_seg_blocks + + cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) >> 1) / + num8x8bl; // Compute delta-q corresponding to qindex i. int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta); // Take segment weighted average for bits per mb. @@ -198,7 +201,8 @@ void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi, int mi_row, int mi_col, BLOCK_SIZE bsize, int64_t rate, - int64_t dist) { + int64_t dist, + int skip) { const VP9_COMMON *const cm = &cpi->common; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; const int bw = num_8x8_blocks_wide_lookup[bsize]; @@ -214,8 +218,12 @@ void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi, // If this block is labeled for refresh, check if we should reset the // segment_id. - if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) + if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) { mbmi->segment_id = refresh_this_block; + // Reset segment_id if will be skipped. + if (skip) + mbmi->segment_id = CR_SEGMENT_ID_BASE; + } // Update the cyclic refresh map, to be used for setting segmentation map // for the next frame. If the block will be refreshed this frame, mark it @@ -250,12 +258,16 @@ void vp9_cyclic_refresh_postencode(VP9_COMP *const cpi) { CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; unsigned char *const seg_map = cpi->segmentation_map; int mi_row, mi_col; - cr->actual_num_seg_blocks = 0; + cr->actual_num_seg1_blocks = 0; + cr->actual_num_seg2_blocks = 0; for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) { - if (cyclic_refresh_segment_id_boosted( - seg_map[mi_row * cm->mi_cols + mi_col])) - cr->actual_num_seg_blocks++; + if (cyclic_refresh_segment_id( + seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST1) + cr->actual_num_seg1_blocks++; + else if (cyclic_refresh_segment_id( + seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST2) + cr->actual_num_seg2_blocks++; } } @@ -413,7 +425,7 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) { cr->time_for_refresh = 0; // Set rate threshold to some multiple (set to 2 for now) of the target // rate (target is given by sb64_target_rate and scaled by 256). - cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 1; + cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 2; // Distortion threshold, quadratic in Q, scale factor to be adjusted. // q will not exceed 457, so (q * q) is within 32bit; see: // vp9_convert_qindex_to_q(), vp9_ac_quant(), ac_qlookup*[]. @@ -442,9 +454,11 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) { // Set the q delta for segment BOOST1. qindex_delta = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta); + cr->qindex_delta_seg1 = qindex_delta; // Compute rd-mult for segment BOOST1. qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ); + cr->rdmult = vp9_compute_rd_mult(cpi, qindex2); vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta); @@ -453,6 +467,7 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) { qindex_delta = compute_deltaq(cpi, cm->base_qindex, MIN(CR_MAX_RATE_TARGET_RATIO, CR_BOOST2_FAC * cr->rate_ratio_qdelta)); + cr->qindex_delta_seg2 = qindex_delta; vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q, qindex_delta); // Update the segmentation and refresh map. diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.h b/vp9/encoder/vp9_aq_cyclicrefresh.h index 34224c1d3..21f114b5e 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.h +++ b/vp9/encoder/vp9_aq_cyclicrefresh.h @@ -55,7 +55,7 @@ int vp9_cyclic_refresh_rc_bits_per_mb(const struct VP9_COMP *cpi, int i, void vp9_cyclic_refresh_update_segment(struct VP9_COMP *const cpi, MB_MODE_INFO *const mbmi, int mi_row, int mi_col, BLOCK_SIZE bsize, - int64_t rate, int64_t dist); + int64_t rate, int64_t dist, int skip); // Update the segmentation map, and related quantities: cyclic refresh map, // refresh sb_index, and target number of blocks to be refreshed. @@ -83,6 +83,15 @@ static INLINE int cyclic_refresh_segment_id_boosted(int segment_id) { segment_id == CR_SEGMENT_ID_BOOST2; } +static INLINE int cyclic_refresh_segment_id(int segment_id) { + if (segment_id == CR_SEGMENT_ID_BOOST1) + return CR_SEGMENT_ID_BOOST1; + else if (segment_id == CR_SEGMENT_ID_BOOST2) + return CR_SEGMENT_ID_BOOST2; + else + return CR_SEGMENT_ID_BASE; +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index ac9de21cc..9aeb9f8f7 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -868,7 +868,8 @@ static void update_state(VP9_COMP *cpi, ThreadData *td, // and then update the quantizer. if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0].src_mi->mbmi, mi_row, - mi_col, bsize, ctx->rate, ctx->dist); + mi_col, bsize, ctx->rate, ctx->dist, + x->skip); } } @@ -1557,7 +1558,7 @@ static void update_state_rt(VP9_COMP *cpi, ThreadData *td, } else { // Setting segmentation map for cyclic_refresh. vp9_cyclic_refresh_update_segment(cpi, mbmi, mi_row, mi_col, bsize, - ctx->rate, ctx->dist); + ctx->rate, ctx->dist, x->skip); } vp9_init_plane_quantizers(cpi, x); }