ref: 31193de1ccccbcc4e3580613a28340a30ad7e6d4
parent: d1124adef036af484d4fe75b131f7724cbad53fb
author: angiebird <angiebird@google.com>
date: Mon Oct 21 07:44:36 EDT 2019
Add get_gop_coding_frame_num() This function will decide number of coding frames and whether to use altref Change-Id: I736190512ea92ce5387600712bd0e250ad7cb44c
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -2477,6 +2477,122 @@
#define ARF_ABS_ZOOM_THRESH 4.0
#define MAX_GF_BOOST 5400
+
+static int get_gop_coding_frame_num(
+ int *use_alt_ref, const FRAME_INFO *frame_info,
+ const FIRST_PASS_INFO *first_pass_info, const RATE_CONTROL *rc,
+ int gf_start_show_idx, int active_min_gf_interval,
+ int active_max_gf_interval, double gop_intra_factor, int kf_zeromotion_pct,
+ int lag_in_frames) {
+ double loop_decay_rate = 1.00;
+ double mv_ratio_accumulator = 0.0;
+ double this_frame_mv_in_out = 0.0;
+ double mv_in_out_accumulator = 0.0;
+ double abs_mv_in_out_accumulator = 0.0;
+ double sr_accumulator = 0.0;
+ // Motion breakout threshold for loop below depends on image size.
+ double mv_ratio_accumulator_thresh =
+ (frame_info->frame_height + frame_info->frame_width) / 4.0;
+ double zero_motion_accumulator = 1.0;
+ int gop_coding_frames;
+
+ *use_alt_ref = 1;
+ gop_coding_frames = 0;
+ while (gop_coding_frames < rc->static_scene_max_gf_interval &&
+ gop_coding_frames < rc->frames_to_key) {
+ const FIRSTPASS_STATS *next_next_frame;
+ const FIRSTPASS_STATS *next_frame;
+ int flash_detected;
+ ++gop_coding_frames;
+
+ next_frame = fps_get_frame_stats(first_pass_info,
+ gf_start_show_idx + gop_coding_frames);
+ if (next_frame == NULL) {
+ break;
+ }
+
+ // Test for the case where there is a brief flash but the prediction
+ // quality back to an earlier frame is then restored.
+ next_next_frame = fps_get_frame_stats(
+ first_pass_info, gf_start_show_idx + gop_coding_frames + 1);
+ flash_detected = detect_flash_from_frame_stats(next_next_frame);
+
+ // 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);
+
+ // Monitor for static sections.
+ if ((rc->frames_since_key + gop_coding_frames - 1) > 1) {
+ zero_motion_accumulator =
+ VPXMIN(zero_motion_accumulator,
+ get_zero_motion_factor(frame_info, next_frame));
+ }
+
+ // Accumulate the effect of prediction quality decay.
+ if (!flash_detected) {
+ double last_loop_decay_rate = loop_decay_rate;
+ loop_decay_rate = get_prediction_decay_rate(frame_info, next_frame);
+
+ // Break clause to detect very still sections after motion. For example,
+ // a static image after a fade or other transition.
+ if (gop_coding_frames > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
+ last_loop_decay_rate < 0.9) {
+ int still_interval = 5;
+ if (check_transition_to_still(first_pass_info,
+ gf_start_show_idx + gop_coding_frames,
+ still_interval)) {
+ *use_alt_ref = 0;
+ break;
+ }
+ }
+
+ // Update the accumulator for second ref error difference.
+ // This is intended to give an indication of how much the coded error is
+ // increasing over time.
+ if (gop_coding_frames == 1) {
+ sr_accumulator += next_frame->coded_error;
+ } else {
+ sr_accumulator +=
+ (next_frame->sr_coded_error - next_frame->coded_error);
+ }
+ }
+
+ // Break out conditions.
+ // Break at maximum of active_max_gf_interval unless almost totally
+ // static.
+ //
+ // Note that the addition of a test of rc->source_alt_ref_active is
+ // deliberate. The effect of this is that after a normal altref group even
+ // if the material is static there will be one normal length GF group
+ // before allowing longer GF groups. The reason for this is that in cases
+ // such as slide shows where slides are separated by a complex transition
+ // such as a fade, the arf group spanning the transition may not be coded
+ // at a very high quality and hence this frame (with its overlay) is a
+ // poor golden frame to use for an extended group.
+ if ((gop_coding_frames >= active_max_gf_interval) &&
+ ((zero_motion_accumulator < 0.995) || (rc->source_alt_ref_active))) {
+ break;
+ }
+ if (
+ // Don't break out with a very short interval.
+ (gop_coding_frames >= active_min_gf_interval) &&
+ // If possible dont break very close to a kf
+ ((rc->frames_to_key - gop_coding_frames) >= rc->min_gf_interval) &&
+ (gop_coding_frames & 0x01) && (!flash_detected) &&
+ ((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
+ (abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH) ||
+ (sr_accumulator > gop_intra_factor * next_frame->intra_error))) {
+ break;
+ }
+ }
+ *use_alt_ref &= zero_motion_accumulator < 0.995;
+ *use_alt_ref &= kf_zeromotion_pct < STATIC_KF_GROUP_THRESH;
+ *use_alt_ref &= gop_coding_frames < lag_in_frames;
+ *use_alt_ref &= gop_coding_frames >= rc->min_gf_interval;
+ return gop_coding_frames;
+}
+
static void define_gf_group(VP9_COMP *cpi, int gf_start_show_idx) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
@@ -2485,8 +2601,7 @@
const FRAME_INFO *frame_info = &cpi->frame_info;
const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info;
const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
- int i;
- int j;
+ int gop_coding_frames;
double gf_group_err = 0.0;
double gf_group_raw_error = 0.0;
@@ -2496,7 +2611,8 @@
double gf_group_inter = 0.0;
double gf_group_motion = 0.0;
- unsigned int allow_alt_ref = is_altref_enabled(cpi);
+ int allow_alt_ref = is_altref_enabled(cpi);
+ int use_alt_ref;
int active_max_gf_interval;
int active_min_gf_interval;
@@ -2563,6 +2679,7 @@
if (cpi->multi_layer_arf) {
int layers = 0;
int max_layers = VPXMIN(MAX_ARF_LAYERS, cpi->oxcf.enable_auto_arf);
+ int i;
// Adapt the intra_error factor to active_max_gf_interval limit.
for (i = active_max_gf_interval; i > 0; i >>= 1) ++layers;
@@ -2571,121 +2688,28 @@
gop_intra_factor += (layers * 0.25);
}
- i = 0;
{
- double loop_decay_rate = 1.00;
- double mv_ratio_accumulator = 0.0;
- double this_frame_mv_in_out = 0.0;
- double mv_in_out_accumulator = 0.0;
- double abs_mv_in_out_accumulator = 0.0;
- double sr_accumulator = 0.0;
- // Motion breakout threshold for loop below depends on image size.
- double mv_ratio_accumulator_thresh =
- (cpi->initial_height + cpi->initial_width) / 4.0;
- double zero_motion_accumulator = 1.0;
-
- while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) {
- const FIRSTPASS_STATS *next_next_frame;
- const FIRSTPASS_STATS *next_frame;
- int flash_detected;
- ++i;
-
- next_frame = fps_get_frame_stats(first_pass_info, gf_start_show_idx + i);
- if (next_frame == NULL) {
- break;
- }
-
- // Test for the case where there is a brief flash but the prediction
- // quality back to an earlier frame is then restored.
- next_next_frame =
- fps_get_frame_stats(first_pass_info, gf_start_show_idx + i + 1);
- flash_detected = detect_flash_from_frame_stats(next_next_frame);
-
- // 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);
-
- // Monitor for static sections.
- if ((rc->frames_since_key + i - 1) > 1) {
- zero_motion_accumulator =
- VPXMIN(zero_motion_accumulator,
- get_zero_motion_factor(frame_info, next_frame));
- }
-
- // Accumulate the effect of prediction quality decay.
- if (!flash_detected) {
- double last_loop_decay_rate = loop_decay_rate;
- loop_decay_rate = get_prediction_decay_rate(frame_info, next_frame);
-
- // Break clause to detect very still sections after motion. For example,
- // a static image after a fade or other transition.
- if (i > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
- last_loop_decay_rate < 0.9) {
- int still_interval = 5;
- if (check_transition_to_still(first_pass_info, gf_start_show_idx + i,
- still_interval)) {
- allow_alt_ref = 0;
- break;
- }
- }
-
- // Update the accumulator for second ref error difference.
- // This is intended to give an indication of how much the coded error is
- // increasing over time.
- if (i == 1) {
- sr_accumulator += next_frame->coded_error;
- } else {
- sr_accumulator +=
- (next_frame->sr_coded_error - next_frame->coded_error);
- }
- }
-
- // Break out conditions.
- // Break at maximum of active_max_gf_interval unless almost totally
- // static.
- //
- // Note that the addition of a test of rc->source_alt_ref_active is
- // deliberate. The effect of this is that after a normal altref group even
- // if the material is static there will be one normal length GF group
- // before allowing longer GF groups. The reason for this is that in cases
- // such as slide shows where slides are separated by a complex transition
- // such as a fade, the arf group spanning the transition may not be coded
- // at a very high quality and hence this frame (with its overlay) is a
- // poor golden frame to use for an extended group.
- if ((i >= active_max_gf_interval) &&
- ((zero_motion_accumulator < 0.995) || (rc->source_alt_ref_active))) {
- break;
- }
- if (
- // Don't break out with a very short interval.
- (i >= active_min_gf_interval) &&
- // If possible dont 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) ||
- (sr_accumulator > gop_intra_factor * next_frame->intra_error))) {
- break;
- }
- }
- allow_alt_ref &= zero_motion_accumulator < 0.995;
+ gop_coding_frames = get_gop_coding_frame_num(
+ &use_alt_ref, frame_info, first_pass_info, rc, gf_start_show_idx,
+ active_min_gf_interval, active_max_gf_interval, gop_intra_factor,
+ twopass->kf_zeromotion_pct, cpi->oxcf.lag_in_frames);
+ use_alt_ref &= allow_alt_ref;
}
// Was the group length constrained by the requirement for a new KF?
- rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
+ rc->constrained_gf_group = (gop_coding_frames >= rc->frames_to_key) ? 1 : 0;
// Should we use the alternate reference frame.
- if (allow_alt_ref && (twopass->kf_zeromotion_pct < STATIC_KF_GROUP_THRESH) &&
- (i < cpi->oxcf.lag_in_frames) && (i >= rc->min_gf_interval)) {
- const int f_frames = (rc->frames_to_key - i >= i - 1)
- ? i - 1
- : VPXMAX(0, rc->frames_to_key - i);
- const int b_frames = i - 1;
+ if (use_alt_ref) {
+ const int f_frames =
+ (rc->frames_to_key - gop_coding_frames >= gop_coding_frames - 1)
+ ? gop_coding_frames - 1
+ : VPXMAX(0, rc->frames_to_key - gop_coding_frames);
+ const int b_frames = gop_coding_frames - 1;
const int avg_inter_frame_qindex = rc->avg_frame_qindex[INTER_FRAME];
// TODO(angiebird): figure out why arf's location is assigned this way
- const int arf_show_idx =
- VPXMIN(gf_start_show_idx + i + 1, fps_get_num_frames(first_pass_info));
+ const int arf_show_idx = VPXMIN(gf_start_show_idx + gop_coding_frames + 1,
+ fps_get_num_frames(first_pass_info));
// Calculate the boost for alt ref.
rc->gfu_boost =
@@ -2693,7 +2717,7 @@
b_frames, avg_inter_frame_qindex);
rc->source_alt_ref_pending = 1;
} else {
- const int f_frames = i - 1;
+ const int f_frames = gop_coding_frames - 1;
const int b_frames = 0;
const int avg_inter_frame_qindex = rc->avg_frame_qindex[INTER_FRAME];
// TODO(angiebird): figure out why arf's location is assigned this way
@@ -2717,16 +2741,18 @@
rc->arf_active_best_quality_adjustment_factor =
LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR +
(1.0 - LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR) *
- (rc->frames_to_key - i) /
- (VPXMAX(1, ((rc->frames_to_key + rc->frames_since_key) / 2 - i)));
+ (rc->frames_to_key - gop_coding_frames) /
+ (VPXMAX(1, ((rc->frames_to_key + rc->frames_since_key) / 2 -
+ gop_coding_frames)));
rc->arf_increase_active_best_quality = 1;
- } else if ((rc->frames_to_key - i) > 0) {
+ } else if ((rc->frames_to_key - gop_coding_frames) > 0) {
// Reduce the active best quality in the first half of key frame interval.
rc->arf_active_best_quality_adjustment_factor =
LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR +
(1.0 - LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR) *
- (rc->frames_since_key + i) /
- (VPXMAX(1, (rc->frames_to_key + rc->frames_since_key) / 2 + i));
+ (rc->frames_since_key + gop_coding_frames) /
+ (VPXMAX(1, (rc->frames_to_key + rc->frames_since_key) / 2 +
+ gop_coding_frames));
rc->arf_increase_active_best_quality = -1;
}
}
@@ -2733,9 +2759,9 @@
#ifdef AGGRESSIVE_VBR
// Limit maximum boost based on interval length.
- rc->gfu_boost = VPXMIN((int)rc->gfu_boost, i * 140);
+ rc->gfu_boost = VPXMIN((int)rc->gfu_boost, gop_coding_frames * 140);
#else
- rc->gfu_boost = VPXMIN((int)rc->gfu_boost, i * 200);
+ rc->gfu_boost = VPXMIN((int)rc->gfu_boost, gop_coding_frames * 200);
#endif
// Cap the ARF boost when perceptual quality AQ mode is enabled. This is
@@ -2745,7 +2771,7 @@
if (oxcf->aq_mode == PERCEPTUAL_AQ)
rc->gfu_boost = VPXMIN(rc->gfu_boost, MIN_ARF_GF_BOOST);
- rc->baseline_gf_interval = i - rc->source_alt_ref_pending;
+ rc->baseline_gf_interval = gop_coding_frames - rc->source_alt_ref_pending;
if (rc->source_alt_ref_pending)
is_alt_ref_flash = detect_flash(twopass, rc->baseline_gf_interval);
@@ -2756,8 +2782,8 @@
// If the first frame is a key frame or the overlay from a previous arf then
// the error score / cost of this frame has already been accounted for.
int start_idx = arf_active_or_kf ? 1 : 0;
- int num_coding_frames = i;
- for (j = start_idx; j < num_coding_frames; ++j) {
+ int j;
+ for (j = start_idx; j < gop_coding_frames; ++j) {
int show_idx = gf_start_show_idx + j;
const FIRSTPASS_STATS *frame_stats =
fps_get_frame_stats(first_pass_info, show_idx);