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;