Allow lower bound on KF interval for auto KF mode.
This allows specifying separate lower and upper bound on keyframe
interval in automatic keyframe placement mode.
BUG=aomedia:2726
Change-Id: Ib38f4add2c447e5f9bb1ede63d6e41a3b50f3c11
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index c028abf..88633e7 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -418,14 +418,6 @@
RANGE_CHECK(cfg, rc_superres_kf_qthresh, 1, 63);
RANGE_CHECK_HI(extra_cfg, cdf_update_mode, 2);
- // AV1 does not support a lower bound on the keyframe interval in
- // automatic keyframe placement mode.
- if (cfg->kf_mode != AOM_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist &&
- cfg->kf_min_dist > 0)
- ERROR(
- "kf_min_dist not supported in auto mode, use 0 "
- "or kf_max_dist instead.");
-
RANGE_CHECK_HI(extra_cfg, motion_vector_unit_test, 2);
RANGE_CHECK_HI(extra_cfg, sb_multipass_unit_test, 1);
RANGE_CHECK_HI(extra_cfg, ext_tile_debug, 1);
@@ -854,7 +846,8 @@
kf_cfg->fwd_kf_enabled = cfg->fwd_kf_enabled;
kf_cfg->auto_key =
cfg->kf_mode == AOM_KF_AUTO && cfg->kf_min_dist != cfg->kf_max_dist;
- kf_cfg->key_freq = cfg->kf_max_dist;
+ kf_cfg->key_freq_min = cfg->kf_min_dist;
+ kf_cfg->key_freq_max = cfg->kf_max_dist;
kf_cfg->sframe_dist = cfg->sframe_dist;
kf_cfg->sframe_mode = cfg->sframe_mode;
kf_cfg->enable_sframe = extra_cfg->s_frame_mode;
@@ -1983,7 +1976,7 @@
*num_lap_buffers = priv->cfg.g_lag_in_frames;
*num_lap_buffers =
clamp(*num_lap_buffers, 1,
- AOMMIN(MAX_LAP_BUFFERS, priv->oxcf.kf_cfg.key_freq +
+ AOMMIN(MAX_LAP_BUFFERS, priv->oxcf.kf_cfg.key_freq_max +
SCENE_CUT_KEY_TEST_INTERVAL));
if ((int)priv->cfg.g_lag_in_frames - (*num_lap_buffers) >=
LAP_LAG_IN_FRAMES) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index afb3b60..a2b1249 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -467,8 +467,10 @@
/*!\cond */
typedef struct {
+ // Indicates the minimum distance to a key frame.
+ int key_freq_min;
// Indicates the maximum distance to a key frame.
- int key_freq;
+ int key_freq_max;
// Indicates if temporal filtering should be applied on keyframe.
int enable_keyframe_filtering;
// Indicates the number of frames after which a frame may be coded as an
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 58efaea..fa4e906 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2062,7 +2062,8 @@
double loop_decay_rate;
// Check for a scene cut.
- if (test_candidate_kf(twopass, &last_frame, this_frame, twopass->stats_in,
+ if (frames_since_key >= kf_cfg->key_freq_min &&
+ test_candidate_kf(twopass, &last_frame, this_frame, twopass->stats_in,
frames_since_key, oxcf->rc_mode,
cpi->rc.enable_scenecut_detection)) {
scenecut_detected = 1;
@@ -2083,8 +2084,9 @@
// Special check for transition or high motion followed by a
// static scene.
- if (detect_transition_to_still(twopass, rc->min_gf_interval, i,
- kf_cfg->key_freq - i, loop_decay_rate,
+ if (frames_since_key >= kf_cfg->key_freq_min &&
+ detect_transition_to_still(twopass, rc->min_gf_interval, i,
+ kf_cfg->key_freq_max - i, loop_decay_rate,
decay_accumulator)) {
scenecut_detected = 1;
// In the case of transition followed by a static scene, the key frame
@@ -2099,8 +2101,8 @@
++frames_since_key;
// If we don't have a real key frame within the next two
- // key_freq intervals then break out of the loop.
- if (frames_to_key >= 2 * kf_cfg->key_freq) break;
+ // key_freq_max intervals then break out of the loop.
+ if (frames_to_key >= 2 * kf_cfg->key_freq_max) break;
} else {
++frames_to_key;
++frames_since_key;
@@ -2300,7 +2302,7 @@
if (num_frames_to_app_forced_key != -1)
rc->frames_to_key = num_frames_to_app_forced_key;
else
- rc->frames_to_key = AOMMAX(1, kf_cfg->key_freq);
+ rc->frames_to_key = AOMMAX(1, kf_cfg->key_freq_max);
correct_frames_to_key(cpi);
rc->kf_boost = DEFAULT_KF_BOOST;
rc->source_alt_ref_active = 0;
@@ -2328,12 +2330,12 @@
kf_mod_err = calculate_modified_err(frame_info, twopass, oxcf, this_frame);
frames_to_key =
- define_kf_interval(cpi, this_frame, &kf_group_err, kf_cfg->key_freq);
+ define_kf_interval(cpi, this_frame, &kf_group_err, kf_cfg->key_freq_max);
if (frames_to_key != -1)
- rc->frames_to_key = AOMMIN(kf_cfg->key_freq, frames_to_key);
+ rc->frames_to_key = AOMMIN(kf_cfg->key_freq_max, frames_to_key);
else
- rc->frames_to_key = kf_cfg->key_freq;
+ rc->frames_to_key = kf_cfg->key_freq_max;
if (cpi->lap_enabled) correct_frames_to_key(cpi);
@@ -2341,7 +2343,7 @@
// 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 (kf_cfg->auto_key && rc->frames_to_key > kf_cfg->key_freq) {
+ if (kf_cfg->auto_key && rc->frames_to_key > kf_cfg->key_freq_max) {
FIRSTPASS_STATS tmp_frame = first_frame;
rc->frames_to_key /= 2;
@@ -2360,7 +2362,7 @@
rc->next_key_frame_forced = 1;
} else if ((twopass->stats_in == twopass->stats_buf_ctx->stats_in_end &&
is_stat_consumption_stage_twopass(cpi)) ||
- rc->frames_to_key >= kf_cfg->key_freq) {
+ rc->frames_to_key >= kf_cfg->key_freq_max) {
rc->next_key_frame_forced = 1;
} else {
rc->next_key_frame_forced = 0;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 958cebf..a00370b 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -2225,12 +2225,12 @@
// Set frame type.
if ((!cpi->use_svc && rc->frames_to_key == 0) ||
(cpi->use_svc && cpi->svc.spatial_layer_id == 0 &&
- cpi->svc.current_superframe % cpi->oxcf.kf_cfg.key_freq == 0) ||
+ cpi->svc.current_superframe % cpi->oxcf.kf_cfg.key_freq_max == 0) ||
(frame_flags & FRAMEFLAGS_KEY)) {
frame_params->frame_type = KEY_FRAME;
rc->this_key_frame_forced =
cm->current_frame.frame_number != 0 && rc->frames_to_key == 0;
- rc->frames_to_key = cpi->oxcf.kf_cfg.key_freq;
+ rc->frames_to_key = cpi->oxcf.kf_cfg.key_freq_max;
rc->kf_boost = DEFAULT_KF_BOOST_RT;
rc->source_alt_ref_active = 0;
gf_group->update_type[gf_group->index] = KF_UPDATE;