diff --git a/vp9/common/vp9_seg_common.c b/vp9/common/vp9_seg_common.c index c8ef618b7..7af61629a 100644 --- a/vp9/common/vp9_seg_common.c +++ b/vp9/common/vp9_seg_common.c @@ -28,6 +28,7 @@ static const int seg_feature_data_max[SEG_LVL_MAX] = { void vp9_clearall_segfeatures(struct segmentation *seg) { vp9_zero(seg->feature_data); vp9_zero(seg->feature_mask); + seg->aq_av_offset = 0; } void vp9_enable_segfeature(struct segmentation *seg, int segment_id, diff --git a/vp9/common/vp9_seg_common.h b/vp9/common/vp9_seg_common.h index 5b75d8d4e..7ea7c3dd7 100644 --- a/vp9/common/vp9_seg_common.h +++ b/vp9/common/vp9_seg_common.h @@ -47,6 +47,7 @@ struct segmentation { int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX]; unsigned int feature_mask[MAX_SEGMENTS]; + int aq_av_offset; }; static INLINE int segfeature_active(const struct segmentation *seg, diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 5b679d25e..73adf2a8d 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -4137,6 +4137,31 @@ static INTERP_FILTER get_interp_filter( } } +static int compute_frame_aq_offset(struct VP9_COMP *cpi) { + VP9_COMMON *const cm = &cpi->common; + MODE_INFO **mi_8x8_ptr = cm->mi_grid_visible; + struct segmentation *const seg = &cm->seg; + + int mi_row, mi_col; + int sum_delta = 0; + int map_index = 0; + int qdelta_index; + int segment_id; + + for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) { + MODE_INFO **mi_8x8 = mi_8x8_ptr; + for (mi_col = 0; mi_col < cm->mi_cols; mi_col++, mi_8x8++) { + segment_id = mi_8x8[0]->segment_id; + qdelta_index = get_segdata(seg, segment_id, SEG_LVL_ALT_Q); + sum_delta += qdelta_index; + map_index++; + } + mi_8x8_ptr += cm->mi_stride; + } + + return sum_delta / (cm->mi_rows * cm->mi_cols); +} + void vp9_encode_frame(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; @@ -4259,8 +4284,13 @@ void vp9_encode_frame(VP9_COMP *cpi) { cm->reference_mode = SINGLE_REFERENCE; encode_frame_internal(cpi); } -} + // If segmentated AQ is enabled compute the average AQ weighting. + if (cm->seg.enabled && (cpi->oxcf.aq_mode != NO_AQ) && + (cm->seg.update_map || cm->seg.update_data)) { + cm->seg.aq_av_offset = compute_frame_aq_offset(cpi); + } +} static void sum_intra_stats(FRAME_COUNTS *counts, const MODE_INFO *mi) { const PREDICTION_MODE y_mode = mi->mode; const PREDICTION_MODE uv_mode = mi->uv_mode; diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 9ed70b628..68537e97f 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -3137,7 +3137,7 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) { "%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf" "%6d %6d %5d %5d %5d " "%10"PRId64" %10.3lf" - "%10lf %8u %10"PRId64" %10d %10d %10d %10d\n", + "%10lf %8u %10"PRId64" %10d %10d %10d %10d %10d\n", cpi->common.current_video_frame, cm->width, cm->height, cpi->td.rd_counts.m_search_count, @@ -3171,7 +3171,8 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) { cpi->tot_recode_hits, recon_err, cpi->rc.kf_boost, cpi->twopass.kf_zeromotion_pct, cpi->twopass.fr_content_type, - cm->lf.filter_level); + cm->lf.filter_level, + cm->seg.aq_av_offset); } fclose(f); diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 3e34c012c..7c59c8e9b 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -2849,6 +2849,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { void vp9_twopass_postencode_update(VP9_COMP *cpi) { TWO_PASS *const twopass = &cpi->twopass; RATE_CONTROL *const rc = &cpi->rc; + VP9_COMMON *const cm = &cpi->common; const int bits_used = rc->base_frame_target; // VBR correction is done through rc->vbr_bits_off_target. Based on the @@ -2886,6 +2887,22 @@ void vp9_twopass_postencode_update(VP9_COMP *cpi) { rc->worst_quality - twopass->active_worst_quality; const int minq_adj_limit = (cpi->oxcf.rc_mode == VPX_CQ ? MINQ_ADJ_LIMIT_CQ : MINQ_ADJ_LIMIT); + int aq_extend_min = 0; + int aq_extend_max = 0; + + // Extend min or Max Q range to account for imbalance from the base + // value when using AQ. + if (cpi->oxcf.aq_mode != NO_AQ) { + if (cm->seg.aq_av_offset < 0) { + // The balance of the AQ map tends towarda lowering the average Q. + aq_extend_min = 0; + aq_extend_max = VPXMIN(maxq_adj_limit, -cm->seg.aq_av_offset); + } else { + // The balance of the AQ map tends towards raising the average Q. + aq_extend_min = VPXMIN(minq_adj_limit, cm->seg.aq_av_offset); + aq_extend_max = 0; + } + } // Undershoot. if (rc->rate_error_estimate > cpi->oxcf.under_shoot_pct) { @@ -2910,8 +2927,10 @@ void vp9_twopass_postencode_update(VP9_COMP *cpi) { --twopass->extend_maxq; } - twopass->extend_minq = clamp(twopass->extend_minq, 0, minq_adj_limit); - twopass->extend_maxq = clamp(twopass->extend_maxq, 0, maxq_adj_limit); + twopass->extend_minq = + clamp(twopass->extend_minq, aq_extend_min, minq_adj_limit); + twopass->extend_maxq = + clamp(twopass->extend_maxq, aq_extend_max, maxq_adj_limit); // If there is a big and undexpected undershoot then feed the extra // bits back in quickly. One situation where this may happen is if a