Separate gf length from define_gf_group.
The gf group length decision is now separated from the
define_gf_group function. Also we can now determine the length
in batch, and store them for future use. This enables lookahead
in future commits.
Change-Id: Ifc13c21c20e06a93dd7db871a178dfdab05bc8f7
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 573b65d..7c8cfe5 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -782,12 +782,177 @@
}
#define ARF_ABS_ZOOM_THRESH 4.4
+static INLINE int detect_gf_cut(AV1_COMP *cpi, int frame_index, int cur_start,
+ int flash_detected, double loop_decay_rate,
+ double last_loop_decay_rate,
+ int active_max_gf_interval,
+ int active_min_gf_interval,
+ double zero_motion_accumulator,
+ double mv_ratio_accumulator,
+ double abs_mv_in_out_accumulator) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ TWO_PASS *const twopass = &cpi->twopass;
+ // Motion breakout threshold for loop below depends on image size.
+ const double mv_ratio_accumulator_thresh =
+ (cpi->initial_height + cpi->initial_width) / 4.0;
+
+ if (!flash_detected) {
+ // Break clause to detect very still sections after motion. For example,
+ // a static image after a fade or other transition.
+ if (detect_transition_to_still(cpi, frame_index - cur_start, 5,
+ loop_decay_rate, last_loop_decay_rate)) {
+ return 1;
+ }
+ }
+
+ // Some conditions to breakout after min interval.
+ if (frame_index - cur_start >= active_min_gf_interval &&
+ // If possible don't break very close to a kf
+ (rc->frames_to_key - frame_index >= rc->min_gf_interval) &&
+ ((frame_index - cur_start) & 0x01) && !flash_detected &&
+ (mv_ratio_accumulator > mv_ratio_accumulator_thresh ||
+ abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) {
+ return 1;
+ }
+
+ // If almost totally static, we will not use the the max GF length later,
+ // so we can continue for more frames.
+ if (((frame_index - cur_start) >= active_max_gf_interval + 1) &&
+ !is_almost_static(zero_motion_accumulator, twopass->kf_zeromotion_pct)) {
+ return 1;
+ }
+ return 0;
+}
+
#define GROUP_ADAPTIVE_MAXQ 1
#if GROUP_ADAPTIVE_MAXQ
#define RC_FACTOR_MIN 0.75
#define RC_FACTOR_MAX 1.25
#endif // GROUP_ADAPTIVE_MAXQ
#define MIN_FWD_KF_INTERVAL 8
+// This function decides the gf group length of future frames in batch
+// rc->gf_intervals is modified to store the group lengths
+static void calculate_gf_length(AV1_COMP *cpi) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ TWO_PASS *const twopass = &cpi->twopass;
+ FIRSTPASS_STATS next_frame;
+ const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+ FRAME_INFO *frame_info = &cpi->frame_info;
+ int i;
+
+ double mv_ratio_accumulator = 0.0;
+ double zero_motion_accumulator = 1.0;
+
+ double this_frame_mv_in_out = 0.0;
+ double mv_in_out_accumulator = 0.0;
+ double abs_mv_in_out_accumulator = 0.0;
+
+ int flash_detected;
+ double loop_decay_rate = 1.00;
+ double last_loop_decay_rate = 1.00;
+
+ aom_clear_system_state();
+ av1_zero(next_frame);
+
+ if (has_no_stats_stage(cpi)) {
+ for (i = 0; i < NUM_GF_INTERVALS; i++) {
+ rc->gf_intervals[i] = MAX_GF_INTERVAL;
+ }
+ rc->cur_gf_index = 0;
+ rc->intervals_till_gf_calculate_due = NUM_GF_INTERVALS;
+ return;
+ }
+
+ // TODO(urvang): Try logic to vary min and max interval based on q.
+ const int active_min_gf_interval = rc->min_gf_interval;
+ const int active_max_gf_interval =
+ AOMMIN(rc->max_gf_interval, get_fixed_gf_length(oxcf->gf_max_pyr_height));
+
+ i = 0;
+ const int max_intervals = NUM_GF_INTERVALS;
+ int cut_pos[NUM_GF_INTERVALS + 1] = { 0 };
+ int count_cuts = 1;
+ int cur_start = 0, cur_last;
+ int cut_here;
+ while (count_cuts < max_intervals + 1) {
+ ++i;
+
+ // reaches next key frame, break here
+ if (i >= rc->frames_to_key) {
+ cut_pos[count_cuts] = i - 1;
+ count_cuts++;
+ break;
+ }
+
+ // reached maximum len, but nothing special yet (almost static)
+ // let's look at the next interval
+ if (i - cur_start >= rc->static_scene_max_gf_interval) {
+ cut_here = 1;
+ } else {
+ // reaches last frame, break
+ if (EOF == input_stats(twopass, &next_frame)) {
+ cut_pos[count_cuts] = i - 1;
+ count_cuts++;
+ break;
+ }
+ // Update the motion related elements to the boost calculation.
+ accumulate_frame_motion_stats(
+ &next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator,
+ &abs_mv_in_out_accumulator, &mv_ratio_accumulator);
+
+ // Test for the case where there is a brief flash but the prediction
+ // quality back to an earlier frame is then restored.
+ flash_detected = detect_flash(twopass, 0);
+ // Monitor for static sections.
+ if (!flash_detected) {
+ last_loop_decay_rate = loop_decay_rate;
+ loop_decay_rate = get_prediction_decay_rate(frame_info, &next_frame);
+
+ if ((rc->frames_since_key + i - 1) > 1) {
+ zero_motion_accumulator =
+ AOMMIN(zero_motion_accumulator,
+ get_zero_motion_factor(frame_info, &next_frame));
+ }
+ }
+ cut_here =
+ detect_gf_cut(cpi, i, cur_start, flash_detected, loop_decay_rate,
+ last_loop_decay_rate, active_max_gf_interval,
+ active_min_gf_interval, zero_motion_accumulator,
+ mv_ratio_accumulator, abs_mv_in_out_accumulator);
+ }
+ if (cut_here) {
+ cur_last = i - 1; // the current last frame in the gf group
+
+ cut_pos[count_cuts] = cur_last;
+ count_cuts++;
+
+ // reset pointers to the shrinked location
+ twopass->stats_in = start_pos + cur_last;
+ cur_start = cur_last;
+ i = cur_last;
+
+ // reset accumulators
+ mv_ratio_accumulator = 0.0;
+ zero_motion_accumulator = 1.0;
+
+ this_frame_mv_in_out = 0.0;
+ mv_in_out_accumulator = 0.0;
+ abs_mv_in_out_accumulator = 0.0;
+
+ loop_decay_rate = 1.00;
+ last_loop_decay_rate = 1.00;
+ }
+ }
+
+ // save intervals
+ rc->intervals_till_gf_calculate_due = count_cuts - 1;
+ for (int n = 1; n < count_cuts; n++) {
+ rc->gf_intervals[n - 1] = cut_pos[n] + 1 - cut_pos[n - 1];
+ }
+ rc->cur_gf_index = 0;
+ twopass->stats_in = start_pos;
+}
static void define_gf_group_pass0(AV1_COMP *cpi,
const EncodeFrameParams *const frame_params) {
@@ -795,10 +960,13 @@
GF_GROUP *const gf_group = &cpi->gf_group;
int target;
- if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
+ if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
av1_cyclic_refresh_set_golden_update(cpi);
- else
- rc->baseline_gf_interval = MAX_GF_INTERVAL;
+ } else {
+ rc->baseline_gf_interval = rc->gf_intervals[rc->cur_gf_index];
+ rc->intervals_till_gf_calculate_due--;
+ rc->cur_gf_index++;
+ }
if (rc->baseline_gf_interval > rc->frames_to_key)
rc->baseline_gf_interval = rc->frames_to_key;
@@ -918,9 +1086,6 @@
gf_group_skip_pct -= this_frame->intra_skip_pct;
gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows;
}
- // Motion breakout threshold for loop below depends on image size.
- const double mv_ratio_accumulator_thresh =
- (cpi->initial_height + cpi->initial_width) / 4.0;
// TODO(urvang): Try logic to vary min and max interval based on q.
const int active_min_gf_interval = rc->min_gf_interval;
@@ -941,7 +1106,8 @@
int non_zero_stdev_count = 0;
i = 0;
- while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) {
+ // get the determined gf group length from rc->gf_intervals
+ while (i < rc->gf_intervals[rc->cur_gf_index]) {
++i;
// Accumulate error score of frames in this gf group.
@@ -995,29 +1161,12 @@
if (detect_transition_to_still(cpi, i, 5, loop_decay_rate,
last_loop_decay_rate)) {
allow_alt_ref = 0;
- break;
}
}
-
- // If almost totally static, we will not use the the max GF length later,
- // so we can continue for more frames.
- if ((i >= active_max_gf_interval + 1) &&
- !is_almost_static(zero_motion_accumulator,
- twopass->kf_zeromotion_pct)) {
- break;
- }
-
- // Some conditions to breakout after min interval.
- if (i >= active_min_gf_interval &&
- // If possible don't break very close to a kf
- (rc->frames_to_key - i >= rc->min_gf_interval) && (i & 0x01) &&
- !flash_detected &&
- (mv_ratio_accumulator > mv_ratio_accumulator_thresh ||
- abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) {
- break;
- }
*this_frame = next_frame;
}
+ rc->intervals_till_gf_calculate_due--;
+ rc->cur_gf_index++;
// Was the group length constrained by the requirement for a new KF?
rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
@@ -1439,6 +1588,7 @@
// KF is always a GF so clear frames till next gf counter.
rc->frames_till_gf_update_due = 0;
+ rc->intervals_till_gf_calculate_due = 0;
rc->frames_to_key = 1;
@@ -1871,6 +2021,10 @@
if (rc->frames_till_gf_update_due == 0) {
assert(cpi->common.current_frame.frame_number == 0 ||
gf_group->index == gf_group->size);
+ if (rc->intervals_till_gf_calculate_due == 0) {
+ calculate_gf_length(cpi);
+ }
+
define_gf_group(cpi, &this_frame, frame_params);
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
cpi->num_gf_group_show_frames = 0;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 72e473d..cc95e97 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -48,6 +48,8 @@
#define MAX_GF_INTERVAL 16
#define FIXED_GF_INTERVAL 8 // Used in some testing modes only
+#define NUM_GF_INTERVALS 150
+
typedef struct {
int resize_width;
int resize_height;
@@ -95,6 +97,14 @@
int frames_since_golden;
int frames_till_gf_update_due;
+
+ // number of determined gf group length left
+ int intervals_till_gf_calculate_due;
+ // stores gf group length intervals
+ int gf_intervals[NUM_GF_INTERVALS];
+ // the current index in gf_intervals
+ int cur_gf_index;
+
int min_gf_interval;
int max_gf_interval;
int static_scene_max_gf_interval;