// bars and partially discounts other 0 energy areas.
#define MIN_ACTIVE_AREA 0.5
#define MAX_ACTIVE_AREA 1.0
-static double calculate_active_area(const VP9_COMP *cpi,
+static double calculate_active_area(const FRAME_INFO *frame_info,
const FIRSTPASS_STATS *this_frame) {
double active_pct;
active_pct =
1.0 -
((this_frame->intra_skip_pct / 2) +
- ((this_frame->inactive_zone_rows * 2) / (double)cpi->common.mb_rows));
+ ((this_frame->inactive_zone_rows * 2) / (double)frame_info->mb_rows));
return fclamp(active_pct, MIN_ACTIVE_AREA, MAX_ACTIVE_AREA);
}
// remaining active MBs. The correction here assumes that coding
// 0.5N blocks of complexity 2X is a little easier than coding N
// blocks of complexity X.
- modified_score *=
- pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION);
+ modified_score *= pow(calculate_active_area(&cpi->frame_info, this_frame),
+ ACT_AREA_CORRECTION);
return modified_score;
}
-static double calculate_norm_frame_score(const VP9_COMP *cpi,
- const TWO_PASS *twopass,
- const VP9EncoderConfig *oxcf,
- const FIRSTPASS_STATS *this_frame,
- const double av_err) {
+static double calc_norm_frame_score(const VP9EncoderConfig *oxcf,
+ const FRAME_INFO *frame_info,
+ const FIRSTPASS_STATS *this_frame,
+ double mean_mod_score, double av_err) {
double modified_score =
av_err * pow(this_frame->coded_error * this_frame->weight /
DOUBLE_DIVIDE_CHECK(av_err),
// 0.5N blocks of complexity 2X is a little easier than coding N
// blocks of complexity X.
modified_score *=
- pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION);
+ pow(calculate_active_area(frame_info, this_frame), ACT_AREA_CORRECTION);
// Normalize to a midpoint score.
- modified_score /= DOUBLE_DIVIDE_CHECK(twopass->mean_mod_score);
-
+ modified_score /= DOUBLE_DIVIDE_CHECK(mean_mod_score);
return fclamp(modified_score, min_score, max_score);
}
+static double calculate_norm_frame_score(const VP9_COMP *cpi,
+ const TWO_PASS *twopass,
+ const VP9EncoderConfig *oxcf,
+ const FIRSTPASS_STATS *this_frame,
+ const double av_err) {
+ return calc_norm_frame_score(oxcf, &cpi->frame_info, this_frame,
+ twopass->mean_mod_score, av_err);
+}
+
// This function returns the maximum target rate per frame.
static int frame_max_bits(const RATE_CONTROL *rc,
const VP9EncoderConfig *oxcf) {
#define LOW_CODED_ERR_PER_MB 10.0
#define NCOUNT_FRAME_II_THRESH 6.0
-static double get_sr_decay_rate(const VP9_COMP *cpi,
+static double get_sr_decay_rate(const FRAME_INFO *frame_info,
const FIRSTPASS_STATS *frame) {
double sr_diff = (frame->sr_coded_error - frame->coded_error);
double sr_decay = 1.0;
double modified_pct_inter;
double modified_pcnt_intra;
const double motion_amplitude_part =
- frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) /
- (cpi->initial_height + cpi->initial_width));
+ frame->pcnt_motion *
+ ((frame->mvc_abs + frame->mvr_abs) /
+ (frame_info->frame_height + frame_info->frame_width));
modified_pct_inter = frame->pcnt_inter;
if ((frame->coded_error > LOW_CODED_ERR_PER_MB) &&
// This function gives an estimate of how badly we believe the prediction
// quality is decaying from frame to frame.
-static double get_zero_motion_factor(const VP9_COMP *cpi,
- const FIRSTPASS_STATS *frame) {
- const double zero_motion_pct = frame->pcnt_inter - frame->pcnt_motion;
- double sr_decay = get_sr_decay_rate(cpi, frame);
+static double get_zero_motion_factor(const FRAME_INFO *frame_info,
+ const FIRSTPASS_STATS *frame_stats) {
+ const double zero_motion_pct =
+ frame_stats->pcnt_inter - frame_stats->pcnt_motion;
+ double sr_decay = get_sr_decay_rate(frame_info, frame_stats);
return VPXMIN(sr_decay, zero_motion_pct);
}
#define ZM_POWER_FACTOR 0.75
-static double get_prediction_decay_rate(const VP9_COMP *cpi,
- const FIRSTPASS_STATS *next_frame) {
- const double sr_decay_rate = get_sr_decay_rate(cpi, next_frame);
+static double get_prediction_decay_rate(const FRAME_INFO *frame_info,
+ const FIRSTPASS_STATS *frame_stats) {
+ const double sr_decay_rate = get_sr_decay_rate(frame_info, frame_stats);
const double zero_motion_factor =
- (0.95 * pow((next_frame->pcnt_inter - next_frame->pcnt_motion),
+ (0.95 * pow((frame_stats->pcnt_inter - frame_stats->pcnt_motion),
ZM_POWER_FACTOR));
return VPXMAX(zero_motion_factor,
(sr_decay_rate + ((1.0 - sr_decay_rate) * zero_motion_factor)));
}
+static int get_show_idx(const TWO_PASS *twopass) {
+ return (int)(twopass->stats_in - twopass->stats_in_start);
+}
// Function to test for a condition where a complex transition is followed
// by a static section. For example in slide shows where there is a fade
// between slides. This is to help with more optimal kf and gf positioning.
+static int check_transition_to_still(const FIRST_PASS_INFO *first_pass_info,
+ int show_idx, int still_interval) {
+ int j;
+ int num_frames = fps_get_num_frames(first_pass_info);
+ if (show_idx + still_interval > num_frames) {
+ return 0;
+ }
+
+ // Look ahead a few frames to see if static condition persists...
+ for (j = 0; j < still_interval; ++j) {
+ const FIRSTPASS_STATS *stats =
+ fps_get_frame_stats(first_pass_info, show_idx + j);
+ if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break;
+ }
+
+ // Only if it does do we signal a transition to still.
+ return j == still_interval;
+}
+
static int detect_transition_to_still(VP9_COMP *cpi, int frame_interval,
int still_interval,
double loop_decay_rate,
double last_decay_rate) {
- TWO_PASS *const twopass = &cpi->twopass;
+ const TWO_PASS *const twopass = &cpi->twopass;
RATE_CONTROL *const rc = &cpi->rc;
+ int show_idx = get_show_idx(twopass);
// Break clause to detect very still sections after motion
// For example a static image after a fade or other transition
// instead of a clean scene cut.
if (frame_interval > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
last_decay_rate < 0.9) {
- int j;
-
- // Look ahead a few frames to see if static condition persists...
- for (j = 0; j < still_interval; ++j) {
- const FIRSTPASS_STATS *stats = &twopass->stats_in[j];
- if (stats >= twopass->stats_in_end) break;
-
- if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break;
- }
-
- // Only if it does do we signal a transition to still.
- return j == still_interval;
+ return check_transition_to_still(&twopass->first_pass_info, show_idx,
+ still_interval);
}
return 0;
// This function detects a flash through the high relative pcnt_second_ref
// score in the frame following a flash frame. The offset passed in should
// reflect this.
-static int detect_flash(const TWO_PASS *twopass, int offset) {
- const FIRSTPASS_STATS *const next_frame = read_frame_stats(twopass, offset);
-
+static int detect_flash_from_frame_stats(const FIRSTPASS_STATS *frame_stats) {
// What we are looking for here is a situation where there is a
// brief break in prediction (such as a flash) but subsequent frames
// are reasonably well predicted by an earlier (pre flash) frame.
// The recovery after a flash is indicated by a high pcnt_second_ref
// useage or a second ref coded error notabley lower than the last
// frame coded error.
- return next_frame != NULL &&
- ((next_frame->sr_coded_error < next_frame->coded_error) ||
- ((next_frame->pcnt_second_ref > next_frame->pcnt_inter) &&
- (next_frame->pcnt_second_ref >= 0.5)));
+ if (frame_stats == NULL) {
+ return 0;
+ }
+ return (frame_stats->sr_coded_error < frame_stats->coded_error) ||
+ ((frame_stats->pcnt_second_ref > frame_stats->pcnt_inter) &&
+ (frame_stats->pcnt_second_ref >= 0.5));
+}
+
+static int detect_flash(const TWO_PASS *twopass, int offset) {
+ const FIRSTPASS_STATS *const next_frame = read_frame_stats(twopass, offset);
+ return detect_flash_from_frame_stats(next_frame);
}
// Update the motion related elements to the GF arf boost calculation.
#define BASELINE_ERR_PER_MB 12500.0
#define GF_MAX_BOOST 96.0
-static double calc_frame_boost(VP9_COMP *cpi, const FIRSTPASS_STATS *this_frame,
+static double calc_frame_boost(const FRAME_INFO *frame_info,
+ const FIRSTPASS_STATS *this_frame,
+ int avg_frame_qindex,
double this_frame_mv_in_out) {
double frame_boost;
- const double lq = vp9_convert_qindex_to_q(
- cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth);
+ const double lq =
+ vp9_convert_qindex_to_q(avg_frame_qindex, frame_info->bit_depth);
const double boost_q_correction = VPXMIN((0.5 + (lq * 0.015)), 1.5);
- const double active_area = calculate_active_area(cpi, this_frame);
+ const double active_area = calculate_active_area(frame_info, this_frame);
// Underlying boost factor is based on inter error ratio.
frame_boost = (BASELINE_ERR_PER_MB * active_area) /
const double lq = vp9_convert_qindex_to_q(
cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth);
const double boost_q_correction = VPXMIN((0.50 + (lq * 0.015)), 2.00);
- const double active_area = calculate_active_area(cpi, this_frame);
+ const double active_area =
+ calculate_active_area(&cpi->frame_info, this_frame);
// Underlying boost factor is based on inter error ratio.
frame_boost = (kf_err_per_mb(cpi) * active_area) /
return VPXMIN(frame_boost, max_boost * boost_q_correction);
}
-static int calc_arf_boost(VP9_COMP *cpi, int f_frames, int b_frames) {
- TWO_PASS *const twopass = &cpi->twopass;
+static int compute_arf_boost(const FRAME_INFO *frame_info,
+ const FIRST_PASS_INFO *first_pass_info,
+ int arf_show_idx, int f_frames, int b_frames,
+ int avg_frame_qindex) {
int i;
double boost_score = 0.0;
double mv_ratio_accumulator = 0.0;
// Search forward from the proposed arf/next gf position.
for (i = 0; i < f_frames; ++i) {
- const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
+ const FIRSTPASS_STATS *this_frame =
+ fps_get_frame_stats(first_pass_info, arf_show_idx + i);
+ const FIRSTPASS_STATS *next_frame =
+ fps_get_frame_stats(first_pass_info, arf_show_idx + i + 1);
if (this_frame == NULL) break;
// Update the motion related elements to the boost calculation.
// We want to discount the flash frame itself and the recovery
// frame that follows as both will have poor scores.
- flash_detected = detect_flash(twopass, i) || detect_flash(twopass, i + 1);
+ flash_detected = detect_flash_from_frame_stats(this_frame) ||
+ detect_flash_from_frame_stats(next_frame);
// Accumulate the effect of prediction quality decay.
if (!flash_detected) {
- decay_accumulator *= get_prediction_decay_rate(cpi, this_frame);
+ decay_accumulator *= get_prediction_decay_rate(frame_info, this_frame);
decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR
? MIN_DECAY_FACTOR
: decay_accumulator;
}
- boost_score += decay_accumulator *
- calc_frame_boost(cpi, this_frame, this_frame_mv_in_out);
+ boost_score += decay_accumulator * calc_frame_boost(frame_info, this_frame,
+ avg_frame_qindex,
+ this_frame_mv_in_out);
}
arf_boost = (int)boost_score;
// Search backward towards last gf position.
for (i = -1; i >= -b_frames; --i) {
- const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
+ const FIRSTPASS_STATS *this_frame =
+ fps_get_frame_stats(first_pass_info, arf_show_idx + i);
+ const FIRSTPASS_STATS *next_frame =
+ fps_get_frame_stats(first_pass_info, arf_show_idx + i + 1);
if (this_frame == NULL) break;
// Update the motion related elements to the boost calculation.
// We want to discount the the flash frame itself and the recovery
// frame that follows as both will have poor scores.
- flash_detected = detect_flash(twopass, i) || detect_flash(twopass, i + 1);
+ flash_detected = detect_flash_from_frame_stats(this_frame) ||
+ detect_flash_from_frame_stats(next_frame);
// Cumulative effect of prediction quality decay.
if (!flash_detected) {
- decay_accumulator *= get_prediction_decay_rate(cpi, this_frame);
+ decay_accumulator *= get_prediction_decay_rate(frame_info, this_frame);
decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR
? MIN_DECAY_FACTOR
: decay_accumulator;
}
- boost_score += decay_accumulator *
- calc_frame_boost(cpi, this_frame, this_frame_mv_in_out);
+ boost_score += decay_accumulator * calc_frame_boost(frame_info, this_frame,
+ avg_frame_qindex,
+ this_frame_mv_in_out);
}
arf_boost += (int)boost_score;
return arf_boost;
}
+static int calc_arf_boost(VP9_COMP *cpi, int f_frames, int b_frames) {
+ const FRAME_INFO *frame_info = &cpi->frame_info;
+ TWO_PASS *const twopass = &cpi->twopass;
+ const int avg_inter_frame_qindex = cpi->rc.avg_frame_qindex[INTER_FRAME];
+ int arf_show_idx = get_show_idx(twopass);
+ return compute_arf_boost(frame_info, &twopass->first_pass_info, arf_show_idx,
+ f_frames, b_frames, avg_inter_frame_qindex);
+}
+
// Calculate a section intra ratio used in setting max loop filter.
static int calculate_section_intra_ratio(const FIRSTPASS_STATS *begin,
const FIRSTPASS_STATS *end,
#define ARF_ABS_ZOOM_THRESH 4.0
#define MAX_GF_BOOST 5400
-static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
+
+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;
VP9EncoderConfig *const oxcf = &cpi->oxcf;
TWO_PASS *const twopass = &cpi->twopass;
- FIRSTPASS_STATS next_frame;
+ 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 gop_coding_frames;
double gf_group_err = 0.0;
double gf_group_raw_error = 0.0;
double gf_group_inactive_zone_rows = 0.0;
double gf_group_inter = 0.0;
double gf_group_motion = 0.0;
- double gf_first_frame_err = 0.0;
- double mod_frame_err = 0.0;
-
- double mv_ratio_accumulator = 0.0;
- double zero_motion_accumulator = 1.0;
- double loop_decay_rate = 1.00;
- double last_loop_decay_rate = 1.00;
- double this_frame_mv_in_out = 0.0;
- double mv_in_out_accumulator = 0.0;
- double abs_mv_in_out_accumulator = 0.0;
- double mv_ratio_accumulator_thresh;
- double abs_mv_in_out_thresh;
- double sr_accumulator = 0.0;
- const double av_err = get_distribution_av_err(cpi, twopass);
- unsigned int allow_alt_ref = is_altref_enabled(cpi);
+ int allow_alt_ref = is_altref_enabled(cpi);
+ int use_alt_ref;
- int flash_detected;
int active_max_gf_interval;
int active_min_gf_interval;
int64_t gf_group_bits;
int gf_arf_bits;
const int is_key_frame = frame_is_intra_only(cm);
+ // If this is a key frame or the overlay from a previous arf then
+ // the error score / cost of this frame has already been accounted for.
const int arf_active_or_kf = is_key_frame || rc->source_alt_ref_active;
int is_alt_ref_flash = 0;
}
vpx_clear_system_state();
- vp9_zero(next_frame);
-
- // Load stats for the current frame.
- mod_frame_err =
- calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
-
- // Note the error of the frame at the start of the group. This will be
- // the GF frame error if we code a normal gf.
- gf_first_frame_err = mod_frame_err;
-
- // If this is a key frame or the overlay from a previous arf then
- // the error score / cost of this frame has already been accounted for.
- if (arf_active_or_kf) {
- gf_group_err -= gf_first_frame_err;
- gf_group_raw_error -= this_frame->coded_error;
- gf_group_noise -= this_frame->frame_noise_energy;
- gf_group_skip_pct -= this_frame->intra_skip_pct;
- gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows;
- gf_group_inter -= this_frame->pcnt_inter;
- gf_group_motion -= this_frame->pcnt_motion;
- }
-
- // Motion breakout threshold for loop below depends on image size.
- mv_ratio_accumulator_thresh =
- (cpi->initial_height + cpi->initial_width) / 4.0;
- abs_mv_in_out_thresh = ARF_ABS_ZOOM_THRESH;
// Set a maximum and minimum interval for the GF group.
// If the image appears almost completely static we can extend beyond this.
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;
gop_intra_factor += (layers * 0.25);
}
- i = 0;
- while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) {
- ++i;
-
- // Accumulate error score of frames in this gf group.
- mod_frame_err =
- calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
- gf_group_err += mod_frame_err;
- gf_group_raw_error += this_frame->coded_error;
- gf_group_noise += this_frame->frame_noise_energy;
- gf_group_skip_pct += this_frame->intra_skip_pct;
- gf_group_inactive_zone_rows += this_frame->inactive_zone_rows;
- gf_group_inter += this_frame->pcnt_inter;
- gf_group_motion += this_frame->pcnt_motion;
-
- if (EOF == input_stats(twopass, &next_frame)) break;
-
- // 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);
-
- // 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(cpi, &next_frame));
- }
-
- // Accumulate the effect of prediction quality decay.
- if (!flash_detected) {
- last_loop_decay_rate = loop_decay_rate;
- loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
-
- // 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, i, 5, loop_decay_rate,
- last_loop_decay_rate)) {
- 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))) ||
- (
- // 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 > abs_mv_in_out_thresh) ||
- (sr_accumulator > gop_intra_factor * next_frame.intra_error)))) {
- break;
- }
-
- *this_frame = next_frame;
+ {
+ 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 ((zero_motion_accumulator < 0.995) && allow_alt_ref &&
- (twopass->kf_zeromotion_pct < STATIC_KF_GROUP_THRESH) &&
- (i < cpi->oxcf.lag_in_frames) && (i >= rc->min_gf_interval)) {
- const int forward_frames = (rc->frames_to_key - i >= i - 1)
- ? i - 1
- : VPXMAX(0, rc->frames_to_key - i);
+ 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 + gop_coding_frames + 1,
+ fps_get_num_frames(first_pass_info));
// Calculate the boost for alt ref.
- rc->gfu_boost = calc_arf_boost(cpi, forward_frames, (i - 1));
+ rc->gfu_boost =
+ compute_arf_boost(frame_info, first_pass_info, arf_show_idx, f_frames,
+ b_frames, avg_inter_frame_qindex);
rc->source_alt_ref_pending = 1;
} else {
- reset_fpf_position(twopass, start_pos);
- rc->gfu_boost = VPXMIN(MAX_GF_BOOST, calc_arf_boost(cpi, (i - 1), 0));
+ 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
+ const int gld_show_idx =
+ VPXMIN(gf_start_show_idx + 1, fps_get_num_frames(first_pass_info));
+ const int arf_boost =
+ compute_arf_boost(frame_info, first_pass_info, gld_show_idx, f_frames,
+ b_frames, avg_inter_frame_qindex);
+ rc->gfu_boost = VPXMIN(MAX_GF_BOOST, arf_boost);
rc->source_alt_ref_pending = 0;
}
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;
}
}
#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
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;
-
- // Reset the file position.
- reset_fpf_position(twopass, start_pos);
+ 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);
+ {
+ const double av_err = get_distribution_av_err(cpi, twopass);
+ const double mean_mod_score = twopass->mean_mod_score;
+ // 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 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);
+ // Accumulate error score of frames in this gf group.
+ gf_group_err += calc_norm_frame_score(oxcf, frame_info, frame_stats,
+ mean_mod_score, av_err);
+ gf_group_raw_error += frame_stats->coded_error;
+ gf_group_noise += frame_stats->frame_noise_energy;
+ gf_group_skip_pct += frame_stats->intra_skip_pct;
+ gf_group_inactive_zone_rows += frame_stats->inactive_zone_rows;
+ gf_group_inter += frame_stats->pcnt_inter;
+ gf_group_motion += frame_stats->pcnt_motion;
+ }
+ }
+
// Calculate the bits to be allocated to the gf/arf group as a whole
gf_group_bits = calculate_total_gf_group_bits(cpi, gf_group_err);
#define MAX_KF_TOT_BOOST 5400
#endif
-static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
+static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame,
+ int kf_show_idx) {
int i, j;
RATE_CONTROL *const rc = &cpi->rc;
TWO_PASS *const twopass = &cpi->twopass;
GF_GROUP *const gf_group = &twopass->gf_group;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
- const FIRSTPASS_STATS first_frame = *this_frame;
+ const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info;
+ const FRAME_INFO *frame_info = &cpi->frame_info;
const FIRSTPASS_STATS *const start_position = twopass->stats_in;
FIRSTPASS_STATS next_frame;
FIRSTPASS_STATS last_frame;
double sr_accumulator = 0.0;
double abs_mv_in_out_accumulator = 0.0;
const double av_err = get_distribution_av_err(cpi, twopass);
+ const double mean_mod_score = twopass->mean_mod_score;
vp9_zero(next_frame);
cpi->common.frame_type = KEY_FRAME;
i = 0;
while (twopass->stats_in < twopass->stats_in_end &&
rc->frames_to_key < cpi->oxcf.key_freq) {
- // Accumulate kf group error.
- kf_group_err +=
- calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
-
// Load the next frame's stats.
last_frame = *this_frame;
input_stats(twopass, this_frame);
break;
// How fast is the prediction quality decaying?
- loop_decay_rate = get_prediction_decay_rate(cpi, twopass->stats_in);
+ loop_decay_rate =
+ get_prediction_decay_rate(&cpi->frame_info, twopass->stats_in);
// We want to know something about the recent past... rather than
// as used elsewhere where we are concerned with decay in prediction
break;
// Step on to the next frame.
- ++rc->frames_to_key;
-
- // If we don't have a real key frame within the next two
- // key_freq intervals then break out of the loop.
- if (rc->frames_to_key >= 2 * cpi->oxcf.key_freq) break;
- } else {
- ++rc->frames_to_key;
}
+ ++rc->frames_to_key;
++i;
}
// We already breakout of the loop above at 2x max.
// This code centers the extra kf if the actual natural interval
// is between 1x and 2x.
- if (cpi->oxcf.auto_key && rc->frames_to_key > cpi->oxcf.key_freq) {
- FIRSTPASS_STATS tmp_frame = first_frame;
-
- rc->frames_to_key /= 2;
-
- // Reset to the start of the group.
- reset_fpf_position(twopass, start_position);
-
- kf_group_err = 0.0;
-
- // Rescan to get the correct error data for the forced kf group.
- for (i = 0; i < rc->frames_to_key; ++i) {
- kf_group_err +=
- calculate_norm_frame_score(cpi, twopass, oxcf, &tmp_frame, av_err);
- input_stats(twopass, &tmp_frame);
- }
- rc->next_key_frame_forced = 1;
- } else if (twopass->stats_in == twopass->stats_in_end ||
- rc->frames_to_key >= cpi->oxcf.key_freq) {
+ if (twopass->stats_in == twopass->stats_in_end ||
+ rc->frames_to_key >= cpi->oxcf.key_freq) {
rc->next_key_frame_forced = 1;
} else {
rc->next_key_frame_forced = 0;
}
- // Special case for the last key frame of the file.
- if (twopass->stats_in >= twopass->stats_in_end) {
+ for (i = 0; i < rc->frames_to_key; ++i) {
+ const FIRSTPASS_STATS *frame_stats =
+ fps_get_frame_stats(first_pass_info, kf_show_idx + i);
// Accumulate kf group error.
- kf_group_err +=
- calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
+ kf_group_err += calc_norm_frame_score(oxcf, frame_info, frame_stats,
+ mean_mod_score, av_err);
}
// Calculate the number of bits that should be assigned to the kf group.
// Monitor for static sections.
// First frame in kf group the second ref indicator is invalid.
if (i > 0) {
- zero_motion_accumulator = VPXMIN(
- zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame));
+ zero_motion_accumulator =
+ VPXMIN(zero_motion_accumulator,
+ get_zero_motion_factor(&cpi->frame_info, &next_frame));
} else {
zero_motion_accumulator =
next_frame.pcnt_inter - next_frame.pcnt_motion;
TWO_PASS *const twopass = &cpi->twopass;
GF_GROUP *const gf_group = &twopass->gf_group;
FIRSTPASS_STATS this_frame;
+ const int show_idx = cm->current_video_frame;
if (!twopass->stats_in) return;
FIRSTPASS_STATS this_frame_copy;
this_frame_copy = this_frame;
// Define next KF group and assign bits to it.
- find_next_key_frame(cpi, &this_frame);
+ find_next_key_frame(cpi, &this_frame, show_idx);
this_frame = this_frame_copy;
} else {
cm->frame_type = INTER_FRAME;
// Define a new GF/ARF group. (Should always enter here for key frames).
if (rc->frames_till_gf_update_due == 0) {
- define_gf_group(cpi, &this_frame);
+ define_gf_group(cpi, show_idx);
rc->frames_till_gf_update_due = rc->baseline_gf_interval;