diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index f8475ed61..af6689fd9 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -1216,6 +1216,7 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = { 50, /* rc_two_pass_vbrbias */ 0, /* rc_two_pass_vbrmin_section */ 400, /* rc_two_pass_vbrmax_section */ + 0, // rc_2pass_vbr_corpus_complexity (only has meaningfull for VP9) /* keyframing settings (kf) */ VPX_KF_AUTO, /* g_kfmode*/ diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index e7f62e4af..54f040453 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -3646,6 +3646,7 @@ static int get_qstep_adj(int rate_excess, int rate_limit) { static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest) { + const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; int bottom_index, top_index; @@ -3682,9 +3683,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, qrange_adj = VPXMAX(1, (top_index - bottom_index) / 2); bottom_index = - VPXMAX(bottom_index - qrange_adj / 2, cpi->oxcf.best_allowed_q); - top_index = - VPXMIN(cpi->oxcf.worst_allowed_q, top_index + qrange_adj / 2); + VPXMAX(bottom_index - qrange_adj / 2, oxcf->best_allowed_q); + top_index = VPXMIN(oxcf->worst_allowed_q, top_index + qrange_adj / 2); } #endif // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed. @@ -3712,7 +3712,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_source, - (cpi->oxcf.pass == 0), EIGHTTAP, 0); + (oxcf->pass == 0), EIGHTTAP, 0); // Unfiltered raw source used in metrics calculation if the source // has been filtered. @@ -3721,7 +3721,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, if (is_spatial_denoise_enabled(cpi)) { cpi->raw_source_frame = vp9_scale_if_required( cm, &cpi->raw_unscaled_source, &cpi->raw_scaled_source, - (cpi->oxcf.pass == 0), EIGHTTAP, 0); + (oxcf->pass == 0), EIGHTTAP, 0); } else { cpi->raw_source_frame = cpi->Source; } @@ -3731,9 +3731,9 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, } if (cpi->unscaled_last_source != NULL) - cpi->Last_Source = vp9_scale_if_required( - cm, cpi->unscaled_last_source, &cpi->scaled_last_source, - (cpi->oxcf.pass == 0), EIGHTTAP, 0); + cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source, + &cpi->scaled_last_source, + (oxcf->pass == 0), EIGHTTAP, 0); if (frame_is_intra_only(cm) == 0) { if (loop_count > 0) { @@ -3748,13 +3748,13 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, // Variance adaptive and in frame q adjustment experiments are mutually // exclusive. - if (cpi->oxcf.aq_mode == VARIANCE_AQ) { + if (oxcf->aq_mode == VARIANCE_AQ) { vp9_vaq_frame_setup(cpi); - } else if (cpi->oxcf.aq_mode == EQUATOR360_AQ) { + } else if (oxcf->aq_mode == EQUATOR360_AQ) { vp9_360aq_frame_setup(cpi); - } else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { + } else if (oxcf->aq_mode == COMPLEXITY_AQ) { vp9_setup_in_frame_q_adj(cpi); - } else if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ) { + } else if (oxcf->aq_mode == LOOKAHEAD_AQ) { vp9_alt_ref_aq_setup_map(cpi->alt_ref_aq, cpi); } @@ -3778,7 +3778,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1; } - if (cpi->oxcf.rc_mode == VPX_Q) { + if (oxcf->rc_mode == VPX_Q) { loop = 0; } else { if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced && @@ -3915,7 +3915,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, // This should only trigger where there is very substantial // undershoot on a frame and the auto cq level is above // the user passsed in value. - if (cpi->oxcf.rc_mode == VPX_CQ && q < q_low) { + if (oxcf->rc_mode == VPX_CQ && q < q_low) { q_low = q; } @@ -3959,7 +3959,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, #ifdef AGGRESSIVE_VBR if (two_pass_first_group_inter(cpi)) { cpi->twopass.active_worst_quality = - VPXMIN(q + qrange_adj, cpi->oxcf.worst_allowed_q); + VPXMIN(q + qrange_adj, oxcf->worst_allowed_q); } else if (!frame_is_kf_gf_arf(cpi)) { #else if (!frame_is_kf_gf_arf(cpi)) { @@ -3968,11 +3968,10 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, // rate miss. If so adjust the active maxQ for the subsequent frames. if (q > cpi->twopass.active_worst_quality) { cpi->twopass.active_worst_quality = q; -#ifdef CORPUS_VBR_EXPERIMENT - } else if (q == q_low && rc->projected_frame_size < rc->this_frame_target) { + } else if (oxcf->vbr_corpus_complexity && q == q_low && + rc->projected_frame_size < rc->this_frame_target) { cpi->twopass.active_worst_quality = VPXMAX(q, cpi->twopass.active_worst_quality - 1); -#endif } } diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index e5115ab7b..303194a3b 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -209,6 +209,7 @@ typedef struct VP9EncoderConfig { int two_pass_vbrbias; // two pass datarate control tweaks int two_pass_vbrmin_section; int two_pass_vbrmax_section; + int vbr_corpus_complexity; // 0 indicates corpus vbr disabled // END DATARATE CONTROL OPTIONS // ---------------------------------------------------------------- diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index f9494dc51..24c6f7e88 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -43,10 +43,6 @@ #define ARF_STATS_OUTPUT 0 #define COMPLEXITY_STATS_OUTPUT 0 -#ifdef CORPUS_VBR_EXPERIMENT -#define CORPUS_VBR_MIDPOINT 82.0 -#endif - #define FIRST_PASS_Q 10.0 #define GF_MAX_BOOST 96.0 #define INTRA_MODE_PENALTY 1024 @@ -241,20 +237,20 @@ static double calculate_active_area(const VP9_COMP *cpi, } // Get the average weighted error for the clip (or corpus) -static double get_distribution_av_err(TWO_PASS *const twopass) { +static double get_distribution_av_err(VP9_COMP *cpi, TWO_PASS *const twopass) { const double av_weight = twopass->total_stats.weight / twopass->total_stats.count; -#ifdef CORPUS_VBR_EXPERIMENT - return av_weight * CORPUS_VBR_MIDPOINT; -#else - return (twopass->total_stats.coded_error * av_weight) / - twopass->total_stats.count; -#endif + + if (cpi->oxcf.vbr_corpus_complexity) + return av_weight * twopass->mean_mod_score; + else + return (twopass->total_stats.coded_error * av_weight) / + twopass->total_stats.count; } +#define ACT_AREA_CORRECTION 0.5 // Calculate a modified Error used in distributing bits between easier and // harder frames. -#define ACT_AREA_CORRECTION 0.5 static double calculate_mod_frame_score(const VP9_COMP *cpi, const VP9EncoderConfig *oxcf, const FIRSTPASS_STATS *this_frame, @@ -274,6 +270,7 @@ static double calculate_mod_frame_score(const VP9_COMP *cpi, return modified_score; } + static double calculate_norm_frame_score(const VP9_COMP *cpi, const TWO_PASS *twopass, const VP9EncoderConfig *oxcf, @@ -1722,23 +1719,25 @@ void vp9_init_second_pass(VP9_COMP *cpi) { { double modified_score_total = 0.0; const FIRSTPASS_STATS *s = twopass->stats_in; - const double av_err = get_distribution_av_err(twopass); + double av_err; -#ifdef CORPUS_VBR_EXPERIMENT - twopass->mean_mod_score = CORPUS_VBR_MIDPOINT; -#else - // The first scan is unclamped and gives a raw average. - while (s < twopass->stats_in_end) { - modified_score_total += calculate_mod_frame_score(cpi, oxcf, s, av_err); - ++s; + if (oxcf->vbr_corpus_complexity) { + twopass->mean_mod_score = (double)oxcf->vbr_corpus_complexity / 10.0; + av_err = get_distribution_av_err(cpi, twopass); + } else { + av_err = get_distribution_av_err(cpi, twopass); + // The first scan is unclamped and gives a raw average. + while (s < twopass->stats_in_end) { + modified_score_total += calculate_mod_frame_score(cpi, oxcf, s, av_err); + ++s; + } + + // The average error from this first scan is used to define the midpoint + // error for the rate distribution function. + twopass->mean_mod_score = + modified_score_total / DOUBLE_DIVIDE_CHECK(stats->count); } - // The average error from this first scan is used to define the midpoint - // error for the rate distribution function. - twopass->mean_mod_score = - modified_score_total / DOUBLE_DIVIDE_CHECK(stats->count); -#endif - // Second scan using clamps based on the previous cycle average. // This may modify the total and average somewhat but we dont bother with // further itterations. @@ -1751,12 +1750,13 @@ void vp9_init_second_pass(VP9_COMP *cpi) { } twopass->normalized_score_left = modified_score_total; -#ifdef CORPUS_VBR_EXPERIMENT - // If using Corpus wide VBR mode then update the clip target bandwidth. - oxcf->target_bandwidth = - (int64_t)((double)oxcf->target_bandwidth * - (twopass->normalized_score_left / stats->count)); -#endif + // If using Corpus wide VBR mode then update the clip target bandwidth to + // reflect how the clip compares to the rest of the corpus. + if (oxcf->vbr_corpus_complexity) { + oxcf->target_bandwidth = + (int64_t)((double)oxcf->target_bandwidth * + (twopass->normalized_score_left / stats->count)); + } #if COMPLEXITY_STATS_OUTPUT { @@ -2185,9 +2185,9 @@ static void get_arf_buffer_indices(unsigned char *arf_buffer_indices) { arf_buffer_indices[1] = ARF_SLOT2; } -#ifdef CORPUS_VBR_EXPERIMENT -// Calculates the total normalized group complexity score for a given number -// of frames starting at the current position in the stats file. +// Used in corpus vbr: Calculates the total normalized group complexity score +// for a given number of frames starting at the current position in the stats +// file. static double calculate_group_score(VP9_COMP *cpi, double av_score, int frame_count) { VP9EncoderConfig *const oxcf = &cpi->oxcf; @@ -2196,6 +2196,9 @@ static double calculate_group_score(VP9_COMP *cpi, double av_score, double score_total = 0.0; int i = 0; + // We dont ever want to return a 0 score here. + if (frame_count == 0) return 1.0; + while ((i < frame_count) && (s < twopass->stats_in_end)) { score_total += calculate_norm_frame_score(cpi, twopass, oxcf, s, av_score); ++s; @@ -2205,10 +2208,10 @@ static double calculate_group_score(VP9_COMP *cpi, double av_score, return score_total; } -#endif static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, int gf_arf_bits) { + VP9EncoderConfig *const oxcf = &cpi->oxcf; RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; GF_GROUP *const gf_group = &twopass->gf_group; @@ -2217,7 +2220,7 @@ static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, int frame_index = 1; int target_frame_size; int key_frame; - const int max_bits = frame_max_bits(&cpi->rc, &cpi->oxcf); + const int max_bits = frame_max_bits(&cpi->rc, oxcf); int64_t total_group_bits = gf_group_bits; int mid_boost_bits = 0; int mid_frame_idx; @@ -2228,12 +2231,9 @@ static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, int normal_frames; int normal_frame_bits; int last_frame_reduction = 0; - -#ifdef CORPUS_VBR_EXPERIMENT - double av_score = get_distribution_av_err(twopass); - double tot_norm_frame_score; - double this_frame_score; -#endif + double av_score = 1.0; + double tot_norm_frame_score = 1.0; + double this_frame_score = 1.0; // Only encode alt reference frame in temporal base layer. if (has_temporal_layers) alt_frame_index = cpi->svc.number_temporal_layers; @@ -2305,18 +2305,15 @@ static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, mid_frame_idx = frame_index + (rc->baseline_gf_interval >> 1) - 1; normal_frames = (rc->baseline_gf_interval - rc->source_alt_ref_pending); - -#ifndef CORPUS_VBR_EXPERIMENT - // The last frame in the group is used less as a predictor so reduce - // its allocation a little. - if (normal_frames > 1) { + if (normal_frames > 1) normal_frame_bits = (int)(total_group_bits / normal_frames); - } else { + else normal_frame_bits = (int)total_group_bits; + + if (oxcf->vbr_corpus_complexity) { + av_score = get_distribution_av_err(cpi, twopass); + tot_norm_frame_score = calculate_group_score(cpi, av_score, normal_frames); } -#else - tot_norm_frame_score = calculate_group_score(cpi, av_score, normal_frames); -#endif // Allocate bits to the other frames in the group. for (i = 0; i < normal_frames; ++i) { @@ -2327,12 +2324,12 @@ static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, ++frame_index; } -#ifdef CORPUS_VBR_EXPERIMENT - this_frame_score = calculate_norm_frame_score(cpi, twopass, &cpi->oxcf, - &frame_stats, av_score); - normal_frame_bits = (int)((double)total_group_bits * - (this_frame_score / tot_norm_frame_score)); -#endif + if (oxcf->vbr_corpus_complexity) { + this_frame_score = calculate_norm_frame_score(cpi, twopass, oxcf, + &frame_stats, av_score); + normal_frame_bits = (int)((double)total_group_bits * + (this_frame_score / tot_norm_frame_score)); + } target_frame_size = normal_frame_bits; if ((i == (normal_frames - 1)) && (i >= 1)) { @@ -2439,7 +2436,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { double mv_in_out_thresh; double abs_mv_in_out_thresh; double sr_accumulator = 0.0; - const double av_err = get_distribution_av_err(twopass); + const double av_err = get_distribution_av_err(cpi, twopass); unsigned int allow_alt_ref = is_altref_enabled(cpi); int f_boost = 0; @@ -2868,7 +2865,7 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { double kf_group_err = 0.0; double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; double sr_accumulator = 0.0; - const double av_err = get_distribution_av_err(twopass); + const double av_err = get_distribution_av_err(cpi, twopass); vp9_zero(next_frame); cpi->common.frame_type = KEY_FRAME; diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index a936ec943..767ae6dd6 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1973,11 +1973,11 @@ void vp9_set_target_rate(VP9_COMP *cpi) { else target_rate = vp9_rc_clamp_pframe_target_size(cpi, target_rate); -#ifndef CORPUS_VBR_EXPERIMENT - // Correction to rate target based on prior over or under shoot. - if (cpi->oxcf.rc_mode == VPX_VBR || cpi->oxcf.rc_mode == VPX_CQ) - vbr_rate_correction(cpi, &target_rate); -#endif + if (!cpi->oxcf.vbr_corpus_complexity) { + // Correction to rate target based on prior over or under shoot. + if (cpi->oxcf.rc_mode == VPX_VBR || cpi->oxcf.rc_mode == VPX_CQ) + vbr_rate_correction(cpi, &target_rate); + } vp9_rc_set_frame_target(cpi, target_rate); } diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index 61e50e9f7..8a785c994 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -24,9 +24,6 @@ extern "C" { // Used to control aggressive VBR mode. // #define AGGRESSIVE_VBR 1 -// Used to control Corpus VBR experiment -// #define CORPUS_VBR_EXPERIMENT 1 - // Bits Per MB at different Q (Multiplied by 512) #define BPER_MB_NORMBITS 9 diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 766b45874..14df8daba 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -157,6 +157,7 @@ static void set_good_speed_feature_framesize_independent(VP9_COMP *cpi, VP9_COMMON *cm, SPEED_FEATURES *sf, int speed) { + const VP9EncoderConfig *const oxcf = &cpi->oxcf; const int boosted = frame_is_boosted(cpi); int i; @@ -182,7 +183,7 @@ static void set_good_speed_feature_framesize_independent(VP9_COMP *cpi, } if (speed >= 1) { - if (cpi->oxcf.pass == 2) { + if (oxcf->pass == 2) { TWO_PASS *const twopass = &cpi->twopass; if ((twopass->fr_content_type == FC_GRAPHICS_ANIMATION) || vp9_internal_image_edge(cpi)) { @@ -225,16 +226,16 @@ static void set_good_speed_feature_framesize_independent(VP9_COMP *cpi, } if (speed >= 2) { -#ifdef CORPUS_VBR_EXPERIMENT - sf->recode_loop = ALLOW_RECODE_FIRST; -#else - sf->recode_loop = ALLOW_RECODE_KFARFGF; -#endif + if (oxcf->vbr_corpus_complexity) + sf->recode_loop = ALLOW_RECODE_FIRST; + else + sf->recode_loop = ALLOW_RECODE_KFARFGF; + sf->tx_size_search_method = frame_is_boosted(cpi) ? USE_FULL_RD : USE_LARGESTALL; // Reference masking is not supported in dynamic scaling mode. - sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0; + sf->reference_masking = oxcf->resize_mode != RESIZE_DYNAMIC ? 1 : 0; sf->mode_search_skip_flags = (cm->frame_type == KEY_FRAME) diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index db18862c7..fe17901be 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -171,6 +171,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 100); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); + RANGE_CHECK(cfg, rc_2pass_vbr_corpus_complexity, 0, 10000); RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO); RANGE_CHECK_BOOL(cfg, rc_resize_allowed); RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100); @@ -526,6 +527,7 @@ static vpx_codec_err_t set_encoder_config( oxcf->two_pass_vbrbias = cfg->rc_2pass_vbr_bias_pct; oxcf->two_pass_vbrmin_section = cfg->rc_2pass_vbr_minsection_pct; oxcf->two_pass_vbrmax_section = cfg->rc_2pass_vbr_maxsection_pct; + oxcf->vbr_corpus_complexity = cfg->rc_2pass_vbr_corpus_complexity; oxcf->auto_key = cfg->kf_mode == VPX_KF_AUTO && cfg->kf_min_dist != cfg->kf_max_dist; @@ -636,6 +638,7 @@ static vpx_codec_err_t set_encoder_config( printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); + printf("vbr_corpus_complexity: %d\n", oxcf->vbr_corpus_complexity); printf("lag_in_frames: %d\n", oxcf->lag_in_frames); printf("enable_auto_arf: %d\n", oxcf->enable_auto_arf); printf("Version: %d\n", oxcf->Version); @@ -1698,6 +1701,7 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { 50, // rc_two_pass_vbrbias 0, // rc_two_pass_vbrmin_section 2000, // rc_two_pass_vbrmax_section + 0, // rc_2pass_vbr_corpus_complexity (non 0 for corpus vbr) // keyframing settings (kf) VPX_KF_AUTO, // g_kfmode diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index c915ed671..53bb75dff 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -63,7 +63,7 @@ extern "C" { * fields to structures */ #define VPX_ENCODER_ABI_VERSION \ - (5 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ + (6 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ /*! \brief Encoder capabilities bitfield * @@ -508,25 +508,31 @@ typedef struct vpx_codec_enc_cfg { /*!\brief Rate control adaptation undershoot control * - * This value, expressed as a percentage of the target bitrate, + * VP8: Expressed as a percentage of the target bitrate, * controls the maximum allowed adaptation speed of the codec. * This factor controls the maximum amount of bits that can * be subtracted from the target bitrate in order to compensate * for prior overshoot. - * - * Valid values in the range 0-1000. + * VP9: Expressed as a percentage of the target bitrate, a threshold + * undershoot level (current rate vs target) beyond which more agressive + * corrective measures are taken. + * * + * Valid values in the range VP8:0-1000 VP9: 0-100. */ unsigned int rc_undershoot_pct; /*!\brief Rate control adaptation overshoot control * - * This value, expressed as a percentage of the target bitrate, + * VP8: Expressed as a percentage of the target bitrate, * controls the maximum allowed adaptation speed of the codec. * This factor controls the maximum amount of bits that can * be added to the target bitrate in order to compensate for * prior undershoot. + * VP9: Expressed as a percentage of the target bitrate, a threshold + * overshoot level (current rate vs target) beyond which more agressive + * corrective measures are taken. * - * Valid values in the range 0-1000. + * Valid values in the range VP8:0-1000 VP9: 0-100. */ unsigned int rc_overshoot_pct; @@ -591,6 +597,13 @@ typedef struct vpx_codec_enc_cfg { */ unsigned int rc_2pass_vbr_maxsection_pct; + /*!\brief Two-pass corpus vbr mode complexity control + * Used only in VP9: A value representing the corpus midpoint complexity + * for corpus vbr mode. This value defaults to 0 which disables corpus vbr + * mode in favour of normal vbr mode. + */ + unsigned int rc_2pass_vbr_corpus_complexity; + /* * keyframing settings (kf) */ diff --git a/vpxenc.c b/vpxenc.c index 845336a69..74c636ab7 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -321,8 +321,11 @@ static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1, "GOP min bitrate (% of target)"); static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1, "GOP max bitrate (% of target)"); -static const arg_def_t *rc_twopass_args[] = { &bias_pct, &minsection_pct, - &maxsection_pct, NULL }; +static const arg_def_t corpus_complexity = + ARG_DEF(NULL, "corpus-complexity", 1, "corpus vbr complexity midpoint"); +static const arg_def_t *rc_twopass_args[] = { + &bias_pct, &minsection_pct, &maxsection_pct, &corpus_complexity, NULL +}; static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1, "Minimum keyframe interval (frames)"); @@ -1233,6 +1236,11 @@ static int parse_stream_params(struct VpxEncoderConfig *global, } else if (arg_match(&arg, &maxsection_pct, argi)) { config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); + if (global->passes < 2) + warn("option %s ignored in one-pass mode.\n", arg.name); + } else if (arg_match(&arg, &corpus_complexity, argi)) { + config->cfg.rc_2pass_vbr_corpus_complexity = arg_parse_uint(&arg); + if (global->passes < 2) warn("option %s ignored in one-pass mode.\n", arg.name); } else if (arg_match(&arg, &kf_min_dist, argi)) { @@ -1431,6 +1439,7 @@ static void show_stream_config(struct stream_state *stream, SHOW(rc_2pass_vbr_bias_pct); SHOW(rc_2pass_vbr_minsection_pct); SHOW(rc_2pass_vbr_maxsection_pct); + SHOW(rc_2pass_vbr_corpus_complexity); SHOW(kf_mode); SHOW(kf_min_dist); SHOW(kf_max_dist);