diff options
author | Paul Wilkins <paulwilkins@google.com> | 2014-12-10 10:44:27 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@gerrit.golo.chromium.org> | 2014-12-10 10:44:27 -0800 |
commit | 65cfb808d06fc8646bc298aa7439efe3ff206bf5 (patch) | |
tree | cec773f776b6effc356fac373d4021e3533b7e31 | |
parent | ad19724f1a77dd9a449f316507ce4dc73de8e27a (diff) | |
parent | e68c8dcfd2ae9bed6adb486974c6c3410e3bc7da (diff) | |
download | libvpx-65cfb808d06fc8646bc298aa7439efe3ff206bf5.tar libvpx-65cfb808d06fc8646bc298aa7439efe3ff206bf5.tar.gz libvpx-65cfb808d06fc8646bc298aa7439efe3ff206bf5.tar.bz2 libvpx-65cfb808d06fc8646bc298aa7439efe3ff206bf5.zip |
Merge "Substantial restructuring of AQ mode 2."
-rw-r--r-- | vp9/encoder/vp9_aq_complexity.c | 111 | ||||
-rw-r--r-- | vp9/encoder/vp9_aq_complexity.h | 9 | ||||
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 62 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 7 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.h | 2 |
5 files changed, 83 insertions, 108 deletions
diff --git a/vp9/encoder/vp9_aq_complexity.c b/vp9/encoder/vp9_aq_complexity.c index 9ec4799e3..22e5217b6 100644 --- a/vp9/encoder/vp9_aq_complexity.c +++ b/vp9/encoder/vp9_aq_complexity.c @@ -16,19 +16,29 @@ #include "vp9/common/vp9_seg_common.h" #include "vp9/encoder/vp9_segmentation.h" -#define AQ_C_SEGMENTS 3 -#define AQ_C_STRENGTHS 3 -static const int aq_c_active_segments[AQ_C_STRENGTHS] = {1, 2, 3}; +#define AQ_C_SEGMENTS 5 +#define DEFAULT_AQ2_SEG 3 // Neutral Q segment +#define AQ_C_STRENGTHS 3 static const double aq_c_q_adj_factor[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = - {{1.0, 1.0, 1.0}, {1.0, 2.0, 1.0}, {1.0, 1.5, 2.5}}; + { {1.75, 1.25, 1.05, 1.00, 0.90}, + {2.00, 1.50, 1.15, 1.00, 0.85}, + {2.50, 1.75, 1.25, 1.00, 0.80} }; static const double aq_c_transitions[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = - {{1.0, 1.0, 1.0}, {1.0, 0.25, 0.0}, {1.0, 0.5, 0.25}}; -static const double aq_c_var_thresholds[AQ_C_SEGMENTS] = {100.0, -1.0, -2.0}; + { {0.15, 0.30, 0.55, 2.00, 100.0}, + {0.20, 0.40, 0.65, 2.00, 100.0}, + {0.25, 0.50, 0.75, 2.00, 100.0} }; +static const double aq_c_var_thresholds[AQ_C_STRENGTHS][AQ_C_SEGMENTS] = + { {-4.0, -3.0, -2.0, 100.00, 100.0}, + {-3.5, -2.5, -1.5, 100.00, 100.0}, + {-3.0, -2.0, -1.0, 100.00, 100.0} }; + +#define DEFAULT_COMPLEXITY 64 + static int get_aq_c_strength(int q_index, vpx_bit_depth_t bit_depth) { // Approximate base quatizer (truncated to int) const int base_quant = vp9_ac_quant(q_index, 0, bit_depth) / 4; - return (base_quant > 20) + (base_quant > 45); + return (base_quant > 10) + (base_quant > 25); } void vp9_setup_in_frame_q_adj(VP9_COMP *cpi) { @@ -43,13 +53,10 @@ void vp9_setup_in_frame_q_adj(VP9_COMP *cpi) { (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { int segment; const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth); - const int active_segments = aq_c_active_segments[aq_strength]; // Clear down the segment map. - vpx_memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); - - // Clear down the complexity map used for rd. - vpx_memset(cpi->complexity_map, 0, cm->mi_rows * cm->mi_cols); + vpx_memset(cpi->segmentation_map, DEFAULT_AQ2_SEG, + cm->mi_rows * cm->mi_cols); vp9_clearall_segfeatures(seg); @@ -65,15 +72,21 @@ void vp9_setup_in_frame_q_adj(VP9_COMP *cpi) { // Select delta coding method. seg->abs_delta = SEGMENT_DELTADATA; - // Segment 0 "Q" feature is disabled so it defaults to the baseline Q. - vp9_disable_segfeature(seg, 0, SEG_LVL_ALT_Q); + // Default segment "Q" feature is disabled so it defaults to the baseline Q. + vp9_disable_segfeature(seg, DEFAULT_AQ2_SEG, SEG_LVL_ALT_Q); // Use some of the segments for in frame Q adjustment. - for (segment = 1; segment < active_segments; ++segment) { - int qindex_delta = - vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex, - aq_c_q_adj_factor[aq_strength][segment], - cm->bit_depth); + for (segment = 0; segment < AQ_C_SEGMENTS; ++segment) { + int qindex_delta; + + if (segment == DEFAULT_AQ2_SEG) + continue; + + qindex_delta = + vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex, + aq_c_q_adj_factor[aq_strength][segment], + cm->bit_depth); + // For AQ complexity mode, we dont allow Q0 in a segment if the base // Q is not 0. Q0 (lossless) implies 4x4 only and in AQ mode 2 a segment @@ -91,67 +104,53 @@ void vp9_setup_in_frame_q_adj(VP9_COMP *cpi) { } #define DEFAULT_LV_THRESH 10.0 - -// Select a segment for the current SB64 block. +#define MIN_DEFAULT_LV_THRESH 8.0 +#define VAR_STRENGTH_STEP 0.25 +// Select a segment for the current block. // The choice of segment for a block depends on the ratio of the projected -// bits for the block vs a target average. -// An "aq_strength" value determines how many segments are supported, -// the set of transition points to use and the extent of the quantizer -// adjustment for each segment (configured in vp9_setup_in_frame_q_adj()). -void vp9_select_in_frame_q_segment(VP9_COMP *cpi, MACROBLOCK *mb, - BLOCK_SIZE bs, - int mi_row, int mi_col, - int output_enabled, int projected_rate) { +// bits for the block vs a target average and its spatial complexity. +void vp9_caq_select_segment(VP9_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs, + int mi_row, int mi_col, int projected_rate) { VP9_COMMON *const cm = &cpi->common; const int mi_offset = mi_row * cm->mi_cols + mi_col; const int bw = num_8x8_blocks_wide_lookup[BLOCK_64X64]; const int bh = num_8x8_blocks_high_lookup[BLOCK_64X64]; - const int xmis = MIN(cm->mi_cols - mi_col, bw); - const int ymis = MIN(cm->mi_rows - mi_row, bh); - int complexity_metric = 64; + const int xmis = MIN(cm->mi_cols - mi_col, num_8x8_blocks_wide_lookup[bs]); + const int ymis = MIN(cm->mi_rows - mi_row, num_8x8_blocks_high_lookup[bs]); int x, y; - + int i; unsigned char segment; - if (!output_enabled) { - segment = 0; + if (0) { + segment = DEFAULT_AQ2_SEG; } else { // Rate depends on fraction of a SB64 in frame (xmis * ymis / bw * bh). // It is converted to bits * 256 units. const int target_rate = (cpi->rc.sb64_target_rate * xmis * ymis * 256) / (bw * bh); - const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth); - const int active_segments = aq_c_active_segments[aq_strength]; double logvar; double low_var_thresh; + const int aq_strength = get_aq_c_strength(cm->base_qindex, cm->bit_depth); vp9_clear_system_state(); - low_var_thresh = - (cpi->oxcf.pass == 2) ? cpi->twopass.mb_av_energy : DEFAULT_LV_THRESH; + low_var_thresh = (cpi->oxcf.pass == 2) + ? MAX(cpi->twopass.mb_av_energy, MIN_DEFAULT_LV_THRESH) + : DEFAULT_LV_THRESH; vp9_setup_src_planes(mb, cpi->Source, mi_row, mi_col); logvar = vp9_log_block_var(cpi, mb, bs); - // The number of segments considered and the transition points used to - // select them is determined by the "aq_strength" value. - // Currently this loop only supports segments that reduce Q (i.e. where - // there is undershoot. - // The loop counts down towards segment 0 which is the default segment - // with no Q adjustment. - segment = active_segments - 1; - while (segment > 0) { + segment = AQ_C_SEGMENTS - 1; // Just in case no break out below. + for (i = 0; i < AQ_C_SEGMENTS; ++i) { + // Test rate against a threshold value and variance against a threshold. + // Increasing segment number (higher variance and complexity) = higher Q. if ((projected_rate < - target_rate * aq_c_transitions[aq_strength][segment]) && - (logvar < (low_var_thresh + aq_c_var_thresholds[segment]))) { + target_rate * aq_c_transitions[aq_strength][i]) && + (logvar < (low_var_thresh + aq_c_var_thresholds[aq_strength][i]))) { + segment = i; break; } - --segment; - } - - if (target_rate > 0) { - complexity_metric = - clamp((int)((projected_rate * 64) / target_rate), 16, 255); } } @@ -159,8 +158,6 @@ void vp9_select_in_frame_q_segment(VP9_COMP *cpi, MACROBLOCK *mb, for (y = 0; y < ymis; y++) { for (x = 0; x < xmis; x++) { cpi->segmentation_map[mi_offset + y * cm->mi_cols + x] = segment; - cpi->complexity_map[mi_offset + y * cm->mi_cols + x] = - (unsigned char)complexity_metric; } } } diff --git a/vp9/encoder/vp9_aq_complexity.h b/vp9/encoder/vp9_aq_complexity.h index 3f885e450..c0dce6c5b 100644 --- a/vp9/encoder/vp9_aq_complexity.h +++ b/vp9/encoder/vp9_aq_complexity.h @@ -19,11 +19,10 @@ extern "C" { struct VP9_COMP; struct macroblock; -// Select a segment for the current SB64. -void vp9_select_in_frame_q_segment(struct VP9_COMP *cpi, struct macroblock *x, - BLOCK_SIZE bs, - int mi_row, int mi_col, - int output_enabled, int projected_rate); +// Select a segment for the current Block. +void vp9_caq_select_segment(struct VP9_COMP *cpi, struct macroblock *, + BLOCK_SIZE bs, + int mi_row, int mi_col, int projected_rate); // This function sets up a set of segments with delta Q values around // the baseline frame quantizer. diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 83da55195..69dedaccd 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -699,7 +699,7 @@ static void update_state(VP9_COMP *cpi, ThreadData *td, mi_addr->src_mi = mi_addr; // If segmentation in use - if (seg->enabled && output_enabled) { + if (seg->enabled) { // For in frame complexity AQ copy the segment id from the segment map. if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { const uint8_t *const map = seg->update_map ? cpi->segmentation_map @@ -862,6 +862,18 @@ static void set_mode_info_seg_skip(MACROBLOCK *x, TX_MODE tx_mode, vp9_rd_cost_init(rd_cost); } +static int set_segment_rdmult(VP9_COMP *const cpi, + MACROBLOCK *const x, + int8_t segment_id) { + int segment_qindex; + VP9_COMMON *const cm = &cpi->common; + vp9_init_plane_quantizers(cpi, x); + vp9_clear_system_state(); + segment_qindex = vp9_get_qindex(&cm->seg, segment_id, + cm->base_qindex); + return vp9_compute_rd_mult(cpi, segment_qindex + cm->y_dc_delta_q); +} + static void rd_pick_sb_modes(VP9_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *const x, @@ -918,7 +930,6 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, if (aq_mode == VARIANCE_AQ) { const int energy = bsize <= BLOCK_16X16 ? x->mb_energy : vp9_block_energy(cpi, x, bsize); - int segment_qindex; if (cm->frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame || (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { @@ -928,18 +939,9 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, : cm->last_frame_seg_map; mbmi->segment_id = vp9_get_segment_id(cm, map, bsize, mi_row, mi_col); } - vp9_init_plane_quantizers(cpi, x); - vp9_clear_system_state(); - segment_qindex = vp9_get_qindex(&cm->seg, mbmi->segment_id, - cm->base_qindex); - x->rdmult = vp9_compute_rd_mult(cpi, segment_qindex + cm->y_dc_delta_q); + x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); } else if (aq_mode == COMPLEXITY_AQ) { - const int mi_offset = mi_row * cm->mi_cols + mi_col; - unsigned char complexity = cpi->complexity_map[mi_offset]; - const int is_edge = (mi_row <= 1) || (mi_row >= (cm->mi_rows - 2)) || - (mi_col <= 1) || (mi_col >= (cm->mi_cols - 2)); - if (!is_edge && (complexity > 128)) - x->rdmult += ((x->rdmult * (complexity - 128)) / 256); + x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); } else if (aq_mode == CYCLIC_REFRESH_AQ) { const uint8_t *const map = cm->seg.update_map ? cpi->segmentation_map : cm->last_frame_seg_map; @@ -966,6 +968,16 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, } } + + // Examine the resulting rate and for AQ mode 2 make a segment choice. + if ((rd_cost->rate != INT_MAX) && + (aq_mode == COMPLEXITY_AQ) && (bsize >= BLOCK_16X16) && + (cm->frame_type == KEY_FRAME || + cpi->refresh_alt_ref_frame || + (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref))) { + vp9_caq_select_segment(cpi, x, bsize, mi_row, mi_col, rd_cost->rate); + } + x->rdmult = orig_rdmult; // TODO(jingning) The rate-distortion optimization flow needs to be @@ -1762,14 +1774,6 @@ static void rd_use_partition(VP9_COMP *cpi, if (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 ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) { - vp9_select_in_frame_q_segment(cpi, x, bsize, mi_row, mi_col, - output_enabled, chosen_rdc.rate); - } encode_sb(cpi, td, tile_info, tp, mi_row, mi_col, output_enabled, bsize, pc_tree); } @@ -2501,13 +2505,6 @@ static void rd_pick_partition(VP9_COMP *cpi, ThreadData *td, if (best_rdc.rate < INT_MAX && best_rdc.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, x, bsize, mi_row, mi_col, - output_enabled, best_rdc.rate); encode_sb(cpi, td, tile_info, tp, mi_row, mi_col, output_enabled, bsize, pc_tree); } @@ -2785,7 +2782,6 @@ static void nonrd_pick_partition(VP9_COMP *cpi, ThreadData *td, 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; TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCK *const x = &td->mb; @@ -3017,14 +3013,6 @@ static void nonrd_pick_partition(VP9_COMP *cpi, ThreadData *td, if (best_rdc.rate < INT_MAX && best_rdc.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, x, bsize, mi_row, mi_col, - output_enabled, best_rdc.rate); - } encode_sb_rt(cpi, td, tile_info, tp, mi_row, mi_col, output_enabled, bsize, pc_tree); } diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index a03131ca6..aaa6b238d 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -213,9 +213,6 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { vpx_free(cpi->coding_context.last_frame_seg_map_copy); cpi->coding_context.last_frame_seg_map_copy = NULL; - vpx_free(cpi->complexity_map); - cpi->complexity_map = NULL; - vpx_free(cpi->nmvcosts[0]); vpx_free(cpi->nmvcosts[1]); cpi->nmvcosts[0] = NULL; @@ -1445,10 +1442,6 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) { CHECK_MEM_ERROR(cm, cpi->segmentation_map, vpx_calloc(cm->mi_rows * cm->mi_cols, 1)); - // Create a complexity map used for rd adjustment - CHECK_MEM_ERROR(cm, cpi->complexity_map, - vpx_calloc(cm->mi_rows * cm->mi_cols, 1)); - // Create a map used for cyclic background refresh. CHECK_MEM_ERROR(cm, cpi->cyclic_refresh, vp9_cyclic_refresh_alloc(cm->mi_rows, cm->mi_cols)); diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 7342f7496..14f7c7f0c 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -351,8 +351,6 @@ typedef struct VP9_COMP { // segment threashold for encode breakout int segment_encode_breakout[MAX_SEGMENTS]; - unsigned char *complexity_map; - CYCLIC_REFRESH *cyclic_refresh; fractional_mv_step_fp *find_fractional_mv_step; |