Let define_kf_interval detect current key frame
This is needed for one pass mode.
We made several other changes.
1) Move end-of-gop define_kf_interval() call before
find_next_key_frame. This way, when define_kf_interval()
return 0, it means current frame should be key frame.
Then since frames_to_key will stay zero. We will call
find_next_key_frame to try to find the next key after
current frame.
2) Compute kf_group_err in one place.
After this CL, encoder is able to detect key frame locations
of mixedformat1080.y4m properly in one-pass mode
Including two previous CLs,
https://aomedia-review.googlesource.com/c/aom/+/142541
https://aomedia-review.googlesource.com/c/aom/+/142941,
The overall performance improvement is as follows.
One pass:
ovr_psnr avg_psnr ssim
ugc360p -1.495% -1.423% -1.453%
lowres -0.080% -0.139% -0.094%
hdres -0.056% -0.059% -0.067%
Two pass:
ovr_psnr avg_psnr ssim
ugc360p 0.002% 0.009% 0.010%
lowres 0% 0% 0%
hdres 0% 0% 0%
For two pass, almost all video's coding stats remain unchanged,
only UgcVert_360-aeaabeaad9a88ca3-723.33.y4m has slightly changed
0.085% drop in avg_psnr and 0.452% drop in ovr_psnr
I will investigate this change later.
BUG=aomedia:3069
BUG=aomedia:3070
Change-Id: Ia7c85f2b8caabbdb135e86cc259b36fef9e1a21f
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 4e2f1a7..4974b53 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2799,26 +2799,28 @@
*
* \param[in] cpi Top-level encoder structure
* \param[in] firstpass_info struct for firstpass info
- * \param[out] kf_group_err The total error in the KF group
* \param[in] num_frames_to_detect_scenecut Maximum lookahead frames.
+ * \param[in] search_start_idx the start index for searching key frame.
+ * Set it to one if we already know the
+ * current frame is key frame. Otherwise,
+ * set it to zero.
*
- * \return Number of frames to the next key.
+ * \return Number of frames to the next key including the current frame.
*/
static int define_kf_interval(AV1_COMP *cpi,
const FIRSTPASS_INFO *firstpass_info,
- double *kf_group_err,
- int num_frames_to_detect_scenecut) {
- TWO_PASS *const twopass = &cpi->ppi->twopass;
- RATE_CONTROL *const rc = &cpi->rc;
+ int num_frames_to_detect_scenecut,
+ int search_start_idx) {
+ const TWO_PASS *const twopass = &cpi->ppi->twopass;
+ const RATE_CONTROL *const rc = &cpi->rc;
PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
const KeyFrameCfg *const kf_cfg = &oxcf->kf_cfg;
double recent_loop_decay[FRAMES_TO_CHECK_DECAY];
double decay_accumulator = 1.0;
int i = 0, j;
- int frames_to_key = 1;
+ int frames_to_key = search_start_idx;
int frames_since_key = rc->frames_since_key + 1;
- FRAME_INFO *const frame_info = &cpi->frame_info;
int num_stats_used_for_kf_boost = 1;
int scenecut_detected = 0;
@@ -2842,8 +2844,6 @@
const int num_mbs = (oxcf->resize_cfg.resize_mode != RESIZE_NONE)
? cpi->initial_mbs
: cpi->common.mi_params.MBs;
- const FIRSTPASS_STATS *this_stats =
- av1_firstpass_info_peek(firstpass_info, 0);
const int future_stats_count =
av1_firstpass_info_future_count(firstpass_info, 0);
while (frames_to_key < future_stats_count &&
@@ -2851,22 +2851,9 @@
// Accumulate total number of stats available till next key frame
num_stats_used_for_kf_boost++;
- // Accumulate kf group error.
- if (kf_group_err != NULL) {
- *kf_group_err += calculate_modified_err_new(
- frame_info, &firstpass_info->total_stats, this_stats,
- oxcf->rc_cfg.vbrbias, twopass->modified_error_min,
- twopass->modified_error_max);
- }
-
- // Load the next frame's stats.
- this_stats = av1_firstpass_info_peek(firstpass_info, frames_to_key);
-
// Provided that we are not at the end of the file...
if ((cpi->ppi->p_rc.enable_scenecut_detection > 0) && kf_cfg->auto_key &&
frames_to_key + 1 < future_stats_count) {
- const FIRSTPASS_STATS *next_stats =
- av1_firstpass_info_peek(firstpass_info, frames_to_key + 1);
double loop_decay_rate;
// Check for a scene cut.
@@ -2881,6 +2868,8 @@
}
// How fast is the prediction quality decaying?
+ const FIRSTPASS_STATS *next_stats =
+ av1_firstpass_info_peek(firstpass_info, frames_to_key + 1);
loop_decay_rate = get_prediction_decay_rate(next_stats);
// We want to know something about the recent past... rather than
@@ -2921,10 +2910,6 @@
}
++i;
}
-
- if (kf_group_err != NULL)
- p_rc->num_stats_used_for_kf_boost = num_stats_used_for_kf_boost;
-
if (cpi->ppi->lap_enabled && !scenecut_detected)
frames_to_key = num_frames_to_next_key;
@@ -3141,7 +3126,6 @@
double boost_score = 0.0;
double kf_raw_err = 0.0;
double kf_mod_err = 0.0;
- double kf_group_err = 0.0;
double sr_accumulator = 0.0;
double kf_group_avg_error = 0.0;
int frames_to_key, frames_to_key_clipped = INT_MAX;
@@ -3156,13 +3140,16 @@
kf_raw_err = this_frame->intra_error;
kf_mod_err = calculate_modified_err(frame_info, twopass, oxcf, this_frame);
- frames_to_key = define_kf_interval(cpi, firstpass_info, &kf_group_err,
- kf_cfg->key_freq_max);
+ // We assume the current frame is a key frame and we are looking for the next
+ // key frame. Therefore search_start_idx = 1
+ frames_to_key = define_kf_interval(cpi, firstpass_info, kf_cfg->key_freq_max,
+ 1 /*search_start_idx*/);
- if (frames_to_key != -1)
+ if (frames_to_key != -1) {
rc->frames_to_key = AOMMIN(kf_cfg->key_freq_max, frames_to_key);
- else
+ } else {
rc->frames_to_key = kf_cfg->key_freq_max;
+ }
rc->frames_to_fwd_kf = kf_cfg->fwd_kf_dist;
@@ -3179,13 +3166,8 @@
// Reset to the start of the group.
reset_fpf_position(&cpi->twopass_frame, 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_modified_err(frame_info, twopass, oxcf, &tmp_frame);
if (EOF == input_stats(twopass, &cpi->twopass_frame, &tmp_frame)) break;
}
p_rc->next_key_frame_forced = 1;
@@ -3205,18 +3187,23 @@
av1_firstpass_info_future_count(firstpass_info, 0);
// Special case for the last key frame of the file.
if (frames_to_key == future_stats_count) {
- // Accumulate kf group error.
- // TODO(angiebird): Why do we need to add last frame's stats
- // here? Move it to a proper place.
- const FIRSTPASS_STATS *last_stats =
- av1_firstpass_info_peek(firstpass_info, frames_to_key - 1);
- kf_group_err += calculate_modified_err_new(
- frame_info, &firstpass_info->total_stats, last_stats,
- oxcf->rc_cfg.vbrbias, twopass->modified_error_min,
- twopass->modified_error_max);
p_rc->next_is_fwd_key = 0;
}
+ double kf_group_err = 0;
+ for (i = 0; i < rc->frames_to_key; ++i) {
+ const FIRSTPASS_STATS *this_stats =
+ av1_firstpass_info_peek(&twopass->firstpass_info, i);
+ if (this_stats != NULL) {
+ // Accumulate kf group error.
+ kf_group_err += calculate_modified_err_new(
+ frame_info, &firstpass_info->total_stats, this_stats,
+ oxcf->rc_cfg.vbrbias, twopass->modified_error_min,
+ twopass->modified_error_max);
+ ++p_rc->num_stats_used_for_kf_boost;
+ }
+ }
+
// Calculate the number of bits that should be assigned to the kf group.
if ((twopass->bits_left > 0 && twopass->modified_error_left > 0.0) ||
(cpi->ppi->lap_enabled && oxcf->rc_cfg.mode != AOM_Q)) {
@@ -3630,6 +3617,17 @@
rc->active_worst_quality = oxcf->rc_cfg.cq_level;
}
+ if (cpi->gf_frame_index == gf_group->size) {
+ if (cpi->ppi->lap_enabled && cpi->ppi->p_rc.enable_scenecut_detection) {
+ const int num_frames_to_detect_scenecut = MAX_GF_LENGTH_LAP + 1;
+ const int frames_to_key = define_kf_interval(
+ cpi, &twopass->firstpass_info, num_frames_to_detect_scenecut,
+ 0 /*search_start_idx*/);
+ if (frames_to_key != -1)
+ rc->frames_to_key = AOMMIN(rc->frames_to_key, frames_to_key);
+ }
+ }
+
// Keyframe and section processing.
FIRSTPASS_STATS this_frame_copy;
this_frame_copy = this_frame;
@@ -3690,19 +3688,6 @@
// Define a new GF/ARF group. (Should always enter here for key frames).
if (cpi->gf_frame_index == gf_group->size) {
- const FIRSTPASS_STATS *const start_position = cpi->twopass_frame.stats_in;
-
- if (cpi->ppi->lap_enabled && cpi->ppi->p_rc.enable_scenecut_detection) {
- int num_frames_to_detect_scenecut, frames_to_key;
- num_frames_to_detect_scenecut = MAX_GF_LENGTH_LAP + 1;
- frames_to_key = define_kf_interval(cpi, &twopass->firstpass_info, NULL,
- num_frames_to_detect_scenecut);
- if (frames_to_key != -1)
- rc->frames_to_key = AOMMIN(rc->frames_to_key, frames_to_key);
- }
-
- reset_fpf_position(&cpi->twopass_frame, start_position);
-
int max_gop_length =
(oxcf->gf_cfg.lag_in_frames >= 32 &&
is_stat_consumption_stage_twopass(cpi))