Experiment to adapt for net AQ offset.
In Aq mode 1 the segment and AQ delta for each block is based on spatial variance. There may be a net imbalance between blocks that have lower Q than the baseline value and those that have higher Q. This patch monitors that imbalance and extends the allowed baseline Q range for the frame to accommodate adjustment of that baseline value to compensate. Change-Id: Iae8a48c7c01fe2af94a141e149d03acf467237ca
This commit is contained in:
parent
52889c1016
commit
4b590058c8
@ -28,6 +28,7 @@ static const int seg_feature_data_max[SEG_LVL_MAX] = {
|
|||||||
void vp9_clearall_segfeatures(struct segmentation *seg) {
|
void vp9_clearall_segfeatures(struct segmentation *seg) {
|
||||||
vp9_zero(seg->feature_data);
|
vp9_zero(seg->feature_data);
|
||||||
vp9_zero(seg->feature_mask);
|
vp9_zero(seg->feature_mask);
|
||||||
|
seg->aq_av_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vp9_enable_segfeature(struct segmentation *seg, int segment_id,
|
void vp9_enable_segfeature(struct segmentation *seg, int segment_id,
|
||||||
|
@ -47,6 +47,7 @@ struct segmentation {
|
|||||||
|
|
||||||
int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
|
int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
|
||||||
unsigned int feature_mask[MAX_SEGMENTS];
|
unsigned int feature_mask[MAX_SEGMENTS];
|
||||||
|
int aq_av_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static INLINE int segfeature_active(const struct segmentation *seg,
|
static INLINE int segfeature_active(const struct segmentation *seg,
|
||||||
|
@ -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) {
|
void vp9_encode_frame(VP9_COMP *cpi) {
|
||||||
VP9_COMMON *const cm = &cpi->common;
|
VP9_COMMON *const cm = &cpi->common;
|
||||||
|
|
||||||
@ -4259,8 +4284,13 @@ void vp9_encode_frame(VP9_COMP *cpi) {
|
|||||||
cm->reference_mode = SINGLE_REFERENCE;
|
cm->reference_mode = SINGLE_REFERENCE;
|
||||||
encode_frame_internal(cpi);
|
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) {
|
static void sum_intra_stats(FRAME_COUNTS *counts, const MODE_INFO *mi) {
|
||||||
const PREDICTION_MODE y_mode = mi->mode;
|
const PREDICTION_MODE y_mode = mi->mode;
|
||||||
const PREDICTION_MODE uv_mode = mi->uv_mode;
|
const PREDICTION_MODE uv_mode = mi->uv_mode;
|
||||||
|
@ -3137,7 +3137,7 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) {
|
|||||||
"%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
|
"%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
|
||||||
"%6d %6d %5d %5d %5d "
|
"%6d %6d %5d %5d %5d "
|
||||||
"%10"PRId64" %10.3lf"
|
"%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,
|
cpi->common.current_video_frame,
|
||||||
cm->width, cm->height,
|
cm->width, cm->height,
|
||||||
cpi->td.rd_counts.m_search_count,
|
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->tot_recode_hits, recon_err, cpi->rc.kf_boost,
|
||||||
cpi->twopass.kf_zeromotion_pct,
|
cpi->twopass.kf_zeromotion_pct,
|
||||||
cpi->twopass.fr_content_type,
|
cpi->twopass.fr_content_type,
|
||||||
cm->lf.filter_level);
|
cm->lf.filter_level,
|
||||||
|
cm->seg.aq_av_offset);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
@ -2849,6 +2849,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
|
|||||||
void vp9_twopass_postencode_update(VP9_COMP *cpi) {
|
void vp9_twopass_postencode_update(VP9_COMP *cpi) {
|
||||||
TWO_PASS *const twopass = &cpi->twopass;
|
TWO_PASS *const twopass = &cpi->twopass;
|
||||||
RATE_CONTROL *const rc = &cpi->rc;
|
RATE_CONTROL *const rc = &cpi->rc;
|
||||||
|
VP9_COMMON *const cm = &cpi->common;
|
||||||
const int bits_used = rc->base_frame_target;
|
const int bits_used = rc->base_frame_target;
|
||||||
|
|
||||||
// VBR correction is done through rc->vbr_bits_off_target. Based on the
|
// 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;
|
rc->worst_quality - twopass->active_worst_quality;
|
||||||
const int minq_adj_limit =
|
const int minq_adj_limit =
|
||||||
(cpi->oxcf.rc_mode == VPX_CQ ? MINQ_ADJ_LIMIT_CQ : 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.
|
// Undershoot.
|
||||||
if (rc->rate_error_estimate > cpi->oxcf.under_shoot_pct) {
|
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_maxq;
|
||||||
}
|
}
|
||||||
|
|
||||||
twopass->extend_minq = clamp(twopass->extend_minq, 0, minq_adj_limit);
|
twopass->extend_minq =
|
||||||
twopass->extend_maxq = clamp(twopass->extend_maxq, 0, maxq_adj_limit);
|
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
|
// 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
|
// bits back in quickly. One situation where this may happen is if a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user