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;