Refactor kf and gfu boost calculation in LAP
Moved the projection of kf_boost and gfu_boost
to pass2_strategy.c to ensure consistent max
and min clips of the boost values.
STATS_CHANGED
Change-Id: I6f95f406d8041e08349284a7bc17cee692a5286e
(cherry picked from commit 93f76853492e2f913084d165ec3767b1d03985cf)
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 42bf1e7..c47a6c2 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4012,11 +4012,8 @@
}
#if !CONFIG_REALTIME_ONLY
-#define MAX_GFUBOOST_FACTOR 10.0
-#define MIN_GFUBOOST_FACTOR 4.0
-static double get_gfu_boost_projection_factor(double min_factor,
- double max_factor,
- int frame_count) {
+double av1_get_gfu_boost_projection_factor(double min_factor, double max_factor,
+ int frame_count) {
double factor = sqrt((double)frame_count);
factor = AOMMIN(factor, max_factor);
factor = AOMMAX(factor, min_factor);
@@ -4026,13 +4023,13 @@
static int get_gfu_boost_from_r0_lap(double min_factor, double max_factor,
double r0, int frames_to_key) {
- double factor =
- get_gfu_boost_projection_factor(min_factor, max_factor, frames_to_key);
+ double factor = av1_get_gfu_boost_projection_factor(min_factor, max_factor,
+ frames_to_key);
const int boost = (int)rint(factor / r0);
return boost;
}
-static double get_kf_boost_projection_factor(int frame_count) {
+double av1_get_kf_boost_projection_factor(int frame_count) {
double factor = sqrt((double)frame_count);
factor = AOMMIN(factor, 10.0);
factor = AOMMAX(factor, 4.0);
@@ -4041,54 +4038,10 @@
}
static int get_kf_boost_from_r0(double r0, int frames_to_key) {
- double factor = get_kf_boost_projection_factor(frames_to_key);
+ double factor = av1_get_kf_boost_projection_factor(frames_to_key);
const int boost = (int)rint(factor / r0);
return boost;
}
-
-static int get_projected_prior_gfu_boost(AV1_COMP *cpi) {
- int num_stats_used_for_gfu_boost = cpi->rc.num_stats_used_for_gfu_boost;
- int frames_to_project = cpi->rc.num_stats_required_for_gfu_boost;
-
- /*
- * If frames_to_project is equal to num_stats_used_for_gfu_boost,
- * it means that gfu_boost was calculated over frames_to_project to
- * begin with(ie; all stats required were available), hence return
- * the original boost.
- */
- if (num_stats_used_for_gfu_boost >= frames_to_project)
- return cpi->rc.gfu_boost;
-
- double min_boost_factor = sqrt(cpi->rc.baseline_gf_interval);
- // Get the current tpl factor (number of frames = frames_to_project).
- double tpl_factor = get_gfu_boost_projection_factor(
- min_boost_factor, MAX_GFUBOOST_FACTOR, frames_to_project);
- // Get the tpl factor when number of frames = num_stats_used_for_prior_boost.
- double tpl_factor_num_stats = get_gfu_boost_projection_factor(
- min_boost_factor, MAX_GFUBOOST_FACTOR, num_stats_used_for_gfu_boost);
- int projected_gfu_boost =
- (int)rint((tpl_factor * cpi->rc.gfu_boost) / tpl_factor_num_stats);
- return projected_gfu_boost;
-}
-
-static int get_projected_prior_boost(AV1_COMP *cpi) {
- /*
- * If num_stats_used_for_kf_boost >= frames_to_key, then
- * all stats needed for prior boost calculation are available.
- * Hence projecting the prior boost is not needed in this cases.
- */
- if (cpi->rc.num_stats_used_for_kf_boost >= cpi->rc.frames_to_key)
- return cpi->rc.kf_boost;
-
- // Get the current tpl factor (number of frames = frames_to_key).
- double tpl_factor = get_kf_boost_projection_factor(cpi->rc.frames_to_key);
- // Get the tpl factor when number of frames = num_stats_used_for_kf_boost.
- double tpl_factor_num_stats =
- get_kf_boost_projection_factor(cpi->rc.num_stats_used_for_kf_boost);
- int projected_kf_boost =
- (int)rint((tpl_factor * cpi->rc.kf_boost) / tpl_factor_num_stats);
- return projected_kf_boost;
-}
#endif
#define MIN_BOOST_COMBINE_FACTOR 4.0
@@ -4157,11 +4110,10 @@
const int gfu_boost = get_gfu_boost_from_r0_lap(
min_boost_factor, MAX_GFUBOOST_FACTOR, cpi->rd.arf_r0,
cpi->rc.num_stats_required_for_gfu_boost);
- const int prior_boost = get_projected_prior_gfu_boost(cpi);
- // printf("old boost %d new boost %d\n", prior_boost,
+ // printf("old boost %d new boost %d\n", cpi->rc.gfu_boost,
// gfu_boost);
cpi->rc.gfu_boost = combine_prior_with_tpl_boost(
- min_boost_factor, MAX_BOOST_COMBINE_FACTOR, prior_boost,
+ min_boost_factor, MAX_BOOST_COMBINE_FACTOR, cpi->rc.gfu_boost,
gfu_boost, cpi->rc.num_stats_used_for_gfu_boost);
} else {
const int gfu_boost = (int)(200.0 / cpi->rd.r0);
@@ -4177,10 +4129,9 @@
const int kf_boost =
get_kf_boost_from_r0(cpi->rd.r0, cpi->rc.frames_to_key);
if (cpi->lap_enabled) {
- const int projected_prior_boost = get_projected_prior_boost(cpi);
cpi->rc.kf_boost = combine_prior_with_tpl_boost(
MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR,
- projected_prior_boost, kf_boost,
+ cpi->rc.kf_boost, kf_boost,
cpi->rc.num_stats_used_for_kf_boost);
} else {
cpi->rc.kf_boost = combine_prior_with_tpl_boost(
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index b36b186..6248e86 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1636,6 +1636,12 @@
// field.
aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi);
+#define MAX_GFUBOOST_FACTOR 10.0
+#define MIN_GFUBOOST_FACTOR 4.0
+double av1_get_gfu_boost_projection_factor(double min_factor, double max_factor,
+ int frame_count);
+double av1_get_kf_boost_projection_factor(int frame_count);
+
#define ENABLE_KF_TPL 1
#define MAX_PYR_LEVEL_FROMTOP_DELTAQ 0
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index 210e894..b8ade1d 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -48,7 +48,7 @@
gf_group->frame_disp_idx[*frame_ind] = start;
gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
- twopass, rc, frame_info, start, end - start, 0, NULL);
+ twopass, rc, frame_info, start, end - start, 0, NULL, NULL);
gf_group->max_layer_depth =
AOMMAX(gf_group->max_layer_depth, layer_depth);
++(*frame_ind);
@@ -65,7 +65,7 @@
// Get the boost factor for intermediate ARF frames.
gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
- twopass, rc, frame_info, m, end - m, m - start, NULL);
+ twopass, rc, frame_info, m, end - m, m - start, NULL, NULL);
++(*frame_ind);
// Frames displayed before this internal ARF.
diff --git a/av1/encoder/gop_structure.h b/av1/encoder/gop_structure.h
index e76ba21..5cfe30d 100644
--- a/av1/encoder/gop_structure.h
+++ b/av1/encoder/gop_structure.h
@@ -34,7 +34,8 @@
int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc,
FRAME_INFO *frame_info, int offset, int f_frames,
- int b_frames, int *num_fpstats_used);
+ int b_frames, int *num_fpstats_used,
+ int *num_fpstats_required);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 7bcd125..847f4b9 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -458,11 +458,35 @@
return AOMMIN(frame_boost, max_boost * boost_q_correction);
}
+static int get_projected_gfu_boost(const RATE_CONTROL *rc, int gfu_boost,
+ int frames_to_project,
+ int num_stats_used_for_gfu_boost) {
+ /*
+ * If frames_to_project is equal to num_stats_used_for_gfu_boost,
+ * it means that gfu_boost was calculated over frames_to_project to
+ * begin with(ie; all stats required were available), hence return
+ * the original boost.
+ */
+ if (num_stats_used_for_gfu_boost >= frames_to_project) return gfu_boost;
+
+ double min_boost_factor = sqrt(rc->baseline_gf_interval);
+ // Get the current tpl factor (number of frames = frames_to_project).
+ double tpl_factor = av1_get_gfu_boost_projection_factor(
+ min_boost_factor, MAX_GFUBOOST_FACTOR, frames_to_project);
+ // Get the tpl factor when number of frames = num_stats_used_for_prior_boost.
+ double tpl_factor_num_stats = av1_get_gfu_boost_projection_factor(
+ min_boost_factor, MAX_GFUBOOST_FACTOR, num_stats_used_for_gfu_boost);
+ int projected_gfu_boost =
+ (int)rint((tpl_factor * gfu_boost) / tpl_factor_num_stats);
+ return projected_gfu_boost;
+}
+
#define GF_MAX_BOOST 90.0
#define MIN_DECAY_FACTOR 0.01
int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc,
FRAME_INFO *frame_info, int offset, int f_frames,
- int b_frames, int *num_fpstats_used) {
+ int b_frames, int *num_fpstats_used,
+ int *num_fpstats_required) {
int i;
double boost_score = (double)NORMAL_BOOST;
double mv_ratio_accumulator = 0.0;
@@ -543,6 +567,14 @@
}
arf_boost += (int)boost_score;
+ if (num_fpstats_required) {
+ *num_fpstats_required = f_frames + b_frames;
+ if (num_fpstats_used) {
+ arf_boost = get_projected_gfu_boost(rc, arf_boost, *num_fpstats_required,
+ *num_fpstats_used);
+ }
+ }
+
if (arf_boost < ((b_frames + f_frames) * 50))
arf_boost = ((b_frames + f_frames) * 50);
@@ -1298,6 +1330,43 @@
}
}
+static INLINE void set_baseline_gf_interval(AV1_COMP *cpi, int arf_position,
+ int active_max_gf_interval,
+ int use_alt_ref,
+ int is_final_pass) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ TWO_PASS *const twopass = &cpi->twopass;
+ // Set the interval until the next gf.
+ // If forward keyframes are enabled, ensure the final gf group obeys the
+ // MIN_FWD_KF_INTERVAL.
+ if (cpi->oxcf.fwd_kf_enabled && use_alt_ref &&
+ ((twopass->stats_in - arf_position + rc->frames_to_key) <
+ twopass->stats_buf_ctx->stats_in_end) &&
+ cpi->rc.next_is_fwd_key) {
+ if (arf_position == rc->frames_to_key) {
+ rc->baseline_gf_interval = arf_position;
+ // if the last gf group will be smaller than MIN_FWD_KF_INTERVAL
+ } else if ((rc->frames_to_key - arf_position <
+ AOMMAX(MIN_FWD_KF_INTERVAL, rc->min_gf_interval)) &&
+ (rc->frames_to_key != arf_position)) {
+ // if possible, merge the last two gf groups
+ if (rc->frames_to_key <= active_max_gf_interval) {
+ rc->baseline_gf_interval = rc->frames_to_key;
+ if (is_final_pass) rc->intervals_till_gf_calculate_due = 0;
+ // if merging the last two gf groups creates a group that is too long,
+ // split them and force the last gf group to be the MIN_FWD_KF_INTERVAL
+ } else {
+ rc->baseline_gf_interval = rc->frames_to_key - MIN_FWD_KF_INTERVAL;
+ if (is_final_pass) rc->intervals_till_gf_calculate_due = 0;
+ }
+ } else {
+ rc->baseline_gf_interval = arf_position - rc->source_alt_ref_pending;
+ }
+ } else {
+ rc->baseline_gf_interval = arf_position - rc->source_alt_ref_pending;
+ }
+}
+
// Analyse and define a gf/arf group.
#define MAX_GF_BOOST 5400
static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame,
@@ -1598,57 +1667,35 @@
// Should we use the alternate reference frame.
if (use_alt_ref) {
+ rc->source_alt_ref_pending = 1;
+ gf_group->max_layer_depth_allowed = cpi->oxcf.gf_max_pyr_height;
+ set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref,
+ is_final_pass);
+
const int forward_frames = (rc->frames_to_key - i >= i - 1)
? i - 1
: AOMMAX(0, rc->frames_to_key - i);
// Calculate the boost for alt ref.
- rc->gfu_boost =
- av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, forward_frames,
- (i - 1), &rc->num_stats_used_for_gfu_boost);
- rc->num_stats_required_for_gfu_boost = (forward_frames + i - 1);
- rc->source_alt_ref_pending = 1;
- gf_group->max_layer_depth_allowed = cpi->oxcf.gf_max_pyr_height;
+ rc->gfu_boost = av1_calc_arf_boost(
+ twopass, rc, frame_info, alt_offset, forward_frames, (i - 1),
+ cpi->lap_enabled ? &rc->num_stats_used_for_gfu_boost : NULL,
+ cpi->lap_enabled ? &rc->num_stats_required_for_gfu_boost : NULL);
} else {
reset_fpf_position(twopass, start_pos);
- rc->gfu_boost =
- AOMMIN(MAX_GF_BOOST,
- av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, (i - 1),
- 0, &rc->num_stats_used_for_gfu_boost));
- rc->num_stats_required_for_gfu_boost = (i - 1);
rc->source_alt_ref_pending = 0;
gf_group->max_layer_depth_allowed = 0;
+ set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref,
+ is_final_pass);
+
+ rc->gfu_boost = AOMMIN(
+ MAX_GF_BOOST,
+ av1_calc_arf_boost(
+ twopass, rc, frame_info, alt_offset, (i - 1), 0,
+ cpi->lap_enabled ? &rc->num_stats_used_for_gfu_boost : NULL,
+ cpi->lap_enabled ? &rc->num_stats_required_for_gfu_boost : NULL));
}
- // Set the interval until the next gf.
- // If forward keyframes are enabled, ensure the final gf group obeys the
- // MIN_FWD_KF_INTERVAL.
- if (cpi->oxcf.fwd_kf_enabled && use_alt_ref &&
- ((twopass->stats_in - i + rc->frames_to_key) <
- twopass->stats_buf_ctx->stats_in_end) &&
- cpi->rc.next_is_fwd_key) {
- if (i == rc->frames_to_key) {
- rc->baseline_gf_interval = i;
- // if the last gf group will be smaller than MIN_FWD_KF_INTERVAL
- } else if ((rc->frames_to_key - i <
- AOMMAX(MIN_FWD_KF_INTERVAL, rc->min_gf_interval)) &&
- (rc->frames_to_key != i)) {
- // if possible, merge the last two gf groups
- if (rc->frames_to_key <= active_max_gf_interval) {
- rc->baseline_gf_interval = rc->frames_to_key;
- if (is_final_pass) rc->intervals_till_gf_calculate_due = 0;
- // if merging the last two gf groups creates a group that is too long,
- // split them and force the last gf group to be the MIN_FWD_KF_INTERVAL
- } else {
- rc->baseline_gf_interval = rc->frames_to_key - MIN_FWD_KF_INTERVAL;
- if (is_final_pass) rc->intervals_till_gf_calculate_due = 0;
- }
- } else {
- rc->baseline_gf_interval = i - rc->source_alt_ref_pending;
- }
- } else {
- rc->baseline_gf_interval = i - rc->source_alt_ref_pending;
- }
// rc->gf_intervals assumes the usage of alt_ref, therefore adding one overlay
// frame to the next gf. If no alt_ref is used, should substract 1 frame from
// the next gf group.
@@ -1897,6 +1944,25 @@
return num_frames_to_app_forced_key;
}
+static int get_projected_kf_boost(AV1_COMP *cpi) {
+ /*
+ * If num_stats_used_for_kf_boost >= frames_to_key, then
+ * all stats needed for prior boost calculation are available.
+ * Hence projecting the prior boost is not needed in this cases.
+ */
+ if (cpi->rc.num_stats_used_for_kf_boost >= cpi->rc.frames_to_key)
+ return cpi->rc.kf_boost;
+
+ // Get the current tpl factor (number of frames = frames_to_key).
+ double tpl_factor = av1_get_kf_boost_projection_factor(cpi->rc.frames_to_key);
+ // Get the tpl factor when number of frames = num_stats_used_for_kf_boost.
+ double tpl_factor_num_stats =
+ av1_get_kf_boost_projection_factor(cpi->rc.num_stats_used_for_kf_boost);
+ int projected_kf_boost =
+ (int)rint((tpl_factor * cpi->rc.kf_boost) / tpl_factor_num_stats);
+ return projected_kf_boost;
+}
+
static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) {
RATE_CONTROL *const rc = &cpi->rc;
TWO_PASS *const twopass = &cpi->twopass;
@@ -2144,6 +2210,10 @@
rc->kf_boost = (int)boost_score;
+ if (cpi->lap_enabled) {
+ rc->kf_boost = get_projected_kf_boost(cpi);
+ }
+
// Special case for static / slide show content but don't apply
// if the kf group is very short.
if ((zero_motion_accumulator > STATIC_KF_GROUP_FLOAT_THRESH) &&