diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h index 766b4ea1e..30c4cbbca 100644 --- a/vp8/common/onyx.h +++ b/vp8/common/onyx.h @@ -41,7 +41,8 @@ extern "C" { USAGE_STREAM_FROM_SERVER = 0x0, USAGE_LOCAL_FILE_PLAYBACK = 0x1, - USAGE_CONSTRAINED_QUALITY = 0x2 + USAGE_CONSTRAINED_QUALITY = 0x2, + USAGE_CONSTANT_QUALITY = 0x3 } END_USAGE; diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 9a7b9c560..93831d6b4 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -153,7 +153,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, #else RANGE_CHECK_HI(cfg, g_lag_in_frames, 25); #endif - RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); + RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_Q); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); @@ -204,7 +204,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6); RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); RANGE_CHECK(vp8_cfg, cq_level, 0, 63); - if(finalize && cfg->rc_end_usage == VPX_CQ) + if (finalize && (cfg->rc_end_usage == VPX_CQ || cfg->rc_end_usage == VPX_Q)) RANGE_CHECK(vp8_cfg, cq_level, cfg->rc_min_quantizer, cfg->rc_max_quantizer); @@ -327,17 +327,14 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh; oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh; - if (cfg.rc_end_usage == VPX_VBR) - { - oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; - } - else if (cfg.rc_end_usage == VPX_CBR) - { - oxcf->end_usage = USAGE_STREAM_FROM_SERVER; - } - else if (cfg.rc_end_usage == VPX_CQ) - { - oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + if (cfg.rc_end_usage == VPX_VBR) { + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; + } else if (cfg.rc_end_usage == VPX_CBR) { + oxcf->end_usage = USAGE_STREAM_FROM_SERVER; + } else if (cfg.rc_end_usage == VPX_CQ) { + oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + } else if (cfg.rc_end_usage == VPX_Q) { + oxcf->end_usage = USAGE_CONSTANT_QUALITY; } oxcf->target_bandwidth = cfg.rc_target_bitrate; diff --git a/vp9/common/vp9_onyx.h b/vp9/common/vp9_onyx.h index 152046f6f..c488fb3f0 100644 --- a/vp9/common/vp9_onyx.h +++ b/vp9/common/vp9_onyx.h @@ -46,7 +46,8 @@ extern "C" typedef enum { USAGE_STREAM_FROM_SERVER = 0x0, USAGE_LOCAL_FILE_PLAYBACK = 0x1, - USAGE_CONSTRAINED_QUALITY = 0x2 + USAGE_CONSTRAINED_QUALITY = 0x2, + USAGE_CONSTANT_QUALITY = 0x3, } END_USAGE; diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 92485f934..0cbe3abb8 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -1092,7 +1092,6 @@ static int estimate_cq(VP9_COMP *cpi, return q; } - extern void vp9_new_framerate(VP9_COMP *cpi, double framerate); void vp9_init_second_pass(VP9_COMP *cpi) { @@ -2079,63 +2078,71 @@ void vp9_second_pass(VP9_COMP *cpi) { vp9_clear_system_state(); - // Special case code for first frame. - if (cpi->common.current_video_frame == 0) { - cpi->twopass.est_max_qcorrection_factor = 1.0; + if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) { + cpi->active_worst_quality = cpi->oxcf.cq_level; + } else { + // Special case code for first frame. + if (cpi->common.current_video_frame == 0) { + int section_target_bandwidth = + (int)(cpi->twopass.bits_left / frames_left); + cpi->twopass.est_max_qcorrection_factor = 1.0; - // Set a cq_level in constrained quality mode. - if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) { - int est_cq = estimate_cq(cpi, &cpi->twopass.total_left_stats, - (int)(cpi->twopass.bits_left / frames_left)); + // Set a cq_level in constrained quality mode. + if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) { + int est_cq = estimate_cq(cpi, &cpi->twopass.total_left_stats, + section_target_bandwidth); - cpi->cq_target_quality = cpi->oxcf.cq_level; - if (est_cq > cpi->cq_target_quality) - cpi->cq_target_quality = est_cq; + cpi->cq_target_quality = cpi->oxcf.cq_level; + if (est_cq > cpi->cq_target_quality) + cpi->cq_target_quality = est_cq; + } + + // guess at maxq needed in 2nd pass + cpi->twopass.maxq_max_limit = cpi->worst_quality; + cpi->twopass.maxq_min_limit = cpi->best_quality; + + tmp_q = estimate_max_q(cpi, &cpi->twopass.total_left_stats, + section_target_bandwidth); + + cpi->active_worst_quality = tmp_q; + cpi->ni_av_qi = tmp_q; + cpi->avg_q = vp9_convert_qindex_to_q(tmp_q); + +#ifndef ONE_SHOT_Q_ESTIMATE + // Limit the maxq value returned subsequently. + // This increases the risk of overspend or underspend if the initial + // estimate for the clip is bad, but helps prevent excessive + // variation in Q, especially near the end of a clip + // where for example a small overspend may cause Q to crash + adjust_maxq_qrange(cpi); +#endif } - // guess at maxq needed in 2nd pass - cpi->twopass.maxq_max_limit = cpi->worst_quality; - cpi->twopass.maxq_min_limit = cpi->best_quality; - - tmp_q = estimate_max_q(cpi, &cpi->twopass.total_left_stats, - (int)(cpi->twopass.bits_left / frames_left)); - - cpi->active_worst_quality = tmp_q; - cpi->ni_av_qi = tmp_q; - cpi->avg_q = vp9_convert_qindex_to_q(tmp_q); - #ifndef ONE_SHOT_Q_ESTIMATE - // Limit the maxq value returned subsequently. - // This increases the risk of overspend or underspend if the initial - // estimate for the clip is bad, but helps prevent excessive - // variation in Q, especially near the end of a clip - // where for example a small overspend may cause Q to crash - adjust_maxq_qrange(cpi); + // The last few frames of a clip almost always have to few or too many + // bits and for the sake of over exact rate control we dont want to make + // radical adjustments to the allowed quantizer range just to use up a + // few surplus bits or get beneath the target rate. + else if ((cpi->common.current_video_frame < + (((unsigned int)cpi->twopass.total_stats.count * 255) >> 8)) && + ((cpi->common.current_video_frame + cpi->baseline_gf_interval) < + (unsigned int)cpi->twopass.total_stats.count)) { + int section_target_bandwidth = + (int)(cpi->twopass.bits_left / frames_left); + if (frames_left < 1) + frames_left = 1; + + tmp_q = estimate_max_q( + cpi, + &cpi->twopass.total_left_stats, + section_target_bandwidth); + + // Make a damped adjustment to active max Q + cpi->active_worst_quality = + adjust_active_maxq(cpi->active_worst_quality, tmp_q); + } #endif } - -#ifndef ONE_SHOT_Q_ESTIMATE - // The last few frames of a clip almost always have to few or too many - // bits and for the sake of over exact rate control we dont want to make - // radical adjustments to the allowed quantizer range just to use up a - // few surplus bits or get beneath the target rate. - else if ((cpi->common.current_video_frame < - (((unsigned int)cpi->twopass.total_stats.count * 255) >> 8)) && - ((cpi->common.current_video_frame + cpi->baseline_gf_interval) < - (unsigned int)cpi->twopass.total_stats.count)) { - if (frames_left < 1) - frames_left = 1; - - tmp_q = estimate_max_q( - cpi, - &cpi->twopass.total_left_stats, - (int)(cpi->twopass.bits_left / frames_left)); - - // Make a damped adjustment to active max Q - cpi->active_worst_quality = - adjust_active_maxq(cpi->active_worst_quality, tmp_q); - } -#endif vp9_zero(this_frame); if (EOF == input_stats(cpi, &this_frame)) return; diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index d35b739fb..4de38d04f 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -2714,9 +2714,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, if (cm->frame_type == KEY_FRAME) { #if !CONFIG_MULTIPLE_ARF - // Special case for key frames forced because we have reached - // the maximum key frame interval. Here force the Q to a range - // based on the ambient Q to reduce the risk of popping + // Special case for key frames forced because we have reached + // the maximum key frame interval. Here force the Q to a range + // based on the ambient Q to reduce the risk of popping if (cpi->this_key_frame_forced) { int delta_qindex; int qindex = cpi->last_boosted_qindex; @@ -2725,7 +2725,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, delta_qindex = compute_qdelta(cpi, last_boosted_q, (last_boosted_q * 0.75)); - cpi->active_best_quality = MAX(qindex + delta_qindex, cpi->best_quality); + cpi->active_best_quality = MAX(qindex + delta_qindex, + cpi->best_quality); } else { int high = 5000; int low = 400; @@ -2746,7 +2747,6 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cpi->active_best_quality = kf_low_motion_minq[q] + adjustment; } - // Allow somewhat lower kf minq with small image formats. if ((cm->width * cm->height) <= (352 * 288)) { q_adj_factor -= 0.25; @@ -2755,14 +2755,14 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, // Make a further adjustment based on the kf zero motion measure. q_adj_factor += 0.05 - (0.001 * (double)cpi->kf_zeromotion_pct); - // Convert the adjustment factor to a qindex delta on active_best_quality. + // Convert the adjustment factor to a qindex delta + // on active_best_quality. q_val = vp9_convert_qindex_to_q(cpi->active_best_quality); cpi->active_best_quality += - compute_qdelta(cpi, q_val, (q_val * q_adj_factor)); + compute_qdelta(cpi, q_val, (q_val * q_adj_factor)); } #else double current_q; - // Force the KF quantizer to be 30% of the active_worst_quality. current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality); cpi->active_best_quality = cpi->active_worst_quality @@ -2779,13 +2779,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cpi->avg_frame_qindex < cpi->active_worst_quality) { q = cpi->avg_frame_qindex; } - // For constrained quality dont allow Q less than the cq level if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && q < cpi->cq_target_quality) { q = cpi->cq_target_quality; } - if (cpi->gfu_boost > high) { cpi->active_best_quality = gf_low_motion_minq[q]; } else if (cpi->gfu_boost < low) { @@ -2802,29 +2800,71 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, // Constrained quality use slightly lower active best. if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) cpi->active_best_quality = cpi->active_best_quality * 15 / 16; + + // TODO(debargha): Refine the logic below + if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) { + if (!cpi->refresh_alt_ref_frame) { + if (cpi->gfu_boost > high) { + cpi->active_best_quality = cpi->cq_target_quality * 14 / 16; + } else if (cpi->gfu_boost < low) { + cpi->active_best_quality = cpi->cq_target_quality; + } else { + const int gap = high - low; + const int offset = high - cpi->gfu_boost; + const int qdiff = cpi->cq_target_quality * 2 / 16; + const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap; + cpi->active_best_quality = cpi->cq_target_quality * 14 / 16 + + adjustment; + } + } else { + if (cpi->frames_since_key > 1) { + if (cpi->gfu_boost > high) { + cpi->active_best_quality = cpi->cq_target_quality * 6 / 16; + } else if (cpi->gfu_boost < low) { + cpi->active_best_quality = cpi->cq_target_quality * 10 / 16; + } else { + const int gap = high - low; + const int offset = high - cpi->gfu_boost; + const int qdiff = cpi->cq_target_quality * 4 / 16; + const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap; + cpi->active_best_quality = cpi->cq_target_quality * 6 / 16 + + adjustment; + } + } + } + } } else { + if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) { + cpi->active_best_quality = cpi->cq_target_quality; + } else { #ifdef ONE_SHOT_Q_ESTIMATE #ifdef STRICT_ONE_SHOT_Q - cpi->active_best_quality = q; + cpi->active_best_quality = q; #else - cpi->active_best_quality = inter_minq[q]; + cpi->active_best_quality = inter_minq[q]; #endif #else - cpi->active_best_quality = inter_minq[q]; + cpi->active_best_quality = inter_minq[q]; #endif - // For the constant/constrained quality mode we don't want - // q to fall below the cq level. - if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && - (cpi->active_best_quality < cpi->cq_target_quality)) { - // If we are strongly undershooting the target rate in the last - // frames then use the user passed in cq value not the auto - // cq value. - if (cpi->rolling_actual_bits < cpi->min_frame_bandwidth) - cpi->active_best_quality = cpi->oxcf.cq_level; - else - cpi->active_best_quality = cpi->cq_target_quality; + // For the constant/constrained quality mode we don't want + // q to fall below the cq level. + if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (cpi->active_best_quality < cpi->cq_target_quality)) { + // If we are strongly undershooting the target rate in the last + // frames then use the user passed in cq value not the auto + // cq value. + if (cpi->rolling_actual_bits < cpi->min_frame_bandwidth) + cpi->active_best_quality = cpi->oxcf.cq_level; + else + cpi->active_best_quality = cpi->cq_target_quality; + } } + /* + if (cm->current_video_frame == 1) + printf("q/active_best/worst_quality = %d %d %d\n", + q, cpi->active_best_quality, cpi->active_worst_quality); + */ } // Clip the active best and worst quality values to limits @@ -2841,7 +2881,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cpi->active_worst_quality = cpi->active_best_quality; // Special case code to try and match quality with forced key frames - if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { + if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) { + q = cpi->active_best_quality; + } else if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { q = cpi->last_boosted_qindex; } else { // Determine initial Q to try @@ -2853,7 +2895,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, #if CONFIG_MULTIPLE_ARF // Force the quantizer determined by the coding order pattern. - if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME)) { + if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) && + cpi->oxcf.end_usage != USAGE_CONSTANT_QUALITY) { double new_q; double current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality); int level = cpi->this_frame_weight; @@ -2988,124 +3031,130 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, active_worst_qchanged = 0; // Special case handling for forced key frames - if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { - int last_q = q; - int kf_err = vp9_calc_ss_err(cpi->Source, - &cm->yv12_fb[cm->new_fb_idx]); - - int high_err_target = cpi->ambient_err; - int low_err_target = cpi->ambient_err >> 1; - - // Prevent possible divide by zero error below for perfect KF - kf_err += !kf_err; - - // The key frame is not good enough or we can afford - // to make it better without undue risk of popping. - if ((kf_err > high_err_target && - cpi->projected_frame_size <= frame_over_shoot_limit) || - (kf_err > low_err_target && - cpi->projected_frame_size <= frame_under_shoot_limit)) { - // Lower q_high - q_high = q > q_low ? q - 1 : q_low; - - // Adjust Q - q = (q * high_err_target) / kf_err; - q = MIN(q, (q_high + q_low) >> 1); - } else if (kf_err < low_err_target && - cpi->projected_frame_size >= frame_under_shoot_limit) { - // The key frame is much better than the previous frame - // Raise q_low - q_low = q < q_high ? q + 1 : q_high; - - // Adjust Q - q = (q * low_err_target) / kf_err; - q = MIN(q, (q_high + q_low + 1) >> 1); - } - - // Clamp Q to upper and lower limits: - q = clamp(q, q_low, q_high); - - loop = q != last_q; - } - - // Is the projected frame size out of range and are we allowed to attempt to recode. - else if (recode_loop_test(cpi, - frame_over_shoot_limit, frame_under_shoot_limit, - q, top_index, bottom_index)) { - int last_q = q; - int retries = 0; - - // Frame size out of permitted range: - // Update correction factor & compute new Q to try... - - // Frame is too large - if (cpi->projected_frame_size > cpi->this_frame_target) { - // Raise Qlow as to at least the current value - q_low = q < q_high ? q + 1 : q_high; - - if (undershoot_seen || loop_count > 1) { - // Update rate_correction_factor unless cpi->active_worst_quality - // has changed. - if (!active_worst_qchanged) - vp9_update_rate_correction_factors(cpi, 1); - - q = (q_high + q_low + 1) / 2; - } else { - // Update rate_correction_factor unless cpi->active_worst_quality has changed. - if (!active_worst_qchanged) - vp9_update_rate_correction_factors(cpi, 0); - - q = vp9_regulate_q(cpi, cpi->this_frame_target); - - while (q < q_low && retries < 10) { - vp9_update_rate_correction_factors(cpi, 0); - q = vp9_regulate_q(cpi, cpi->this_frame_target); - retries++; - } - } - - overshoot_seen = 1; - } else { - // Frame is too small - q_high = q > q_low ? q - 1 : q_low; - - if (overshoot_seen || loop_count > 1) { - // Update rate_correction_factor unless cpi->active_worst_quality has changed. - if (!active_worst_qchanged) - vp9_update_rate_correction_factors(cpi, 1); - - q = (q_high + q_low) / 2; - } else { - // Update rate_correction_factor unless cpi->active_worst_quality has changed. - if (!active_worst_qchanged) - vp9_update_rate_correction_factors(cpi, 0); - - q = vp9_regulate_q(cpi, cpi->this_frame_target); - - // Special case reset for qlow for constrained quality. - // 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.end_usage == USAGE_CONSTRAINED_QUALITY && q < q_low) { - q_low = q; - } - - while (q > q_high && retries < 10) { - vp9_update_rate_correction_factors(cpi, 0); - q = vp9_regulate_q(cpi, cpi->this_frame_target); - retries++; - } - } - - undershoot_seen = 1; - } - - // Clamp Q to upper and lower limits: - q = clamp(q, q_low, q_high); - - loop = q != last_q; - } else { + if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) { loop = 0; + } else { + if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { + int last_q = q; + int kf_err = vp9_calc_ss_err(cpi->Source, + &cm->yv12_fb[cm->new_fb_idx]); + + int high_err_target = cpi->ambient_err; + int low_err_target = cpi->ambient_err >> 1; + + // Prevent possible divide by zero error below for perfect KF + kf_err += !kf_err; + + // The key frame is not good enough or we can afford + // to make it better without undue risk of popping. + if ((kf_err > high_err_target && + cpi->projected_frame_size <= frame_over_shoot_limit) || + (kf_err > low_err_target && + cpi->projected_frame_size <= frame_under_shoot_limit)) { + // Lower q_high + q_high = q > q_low ? q - 1 : q_low; + + // Adjust Q + q = (q * high_err_target) / kf_err; + q = MIN(q, (q_high + q_low) >> 1); + } else if (kf_err < low_err_target && + cpi->projected_frame_size >= frame_under_shoot_limit) { + // The key frame is much better than the previous frame + // Raise q_low + q_low = q < q_high ? q + 1 : q_high; + + // Adjust Q + q = (q * low_err_target) / kf_err; + q = MIN(q, (q_high + q_low + 1) >> 1); + } + + // Clamp Q to upper and lower limits: + q = clamp(q, q_low, q_high); + + loop = q != last_q; + } else if (recode_loop_test( + cpi, frame_over_shoot_limit, frame_under_shoot_limit, + q, top_index, bottom_index)) { + // Is the projected frame size out of range and are we allowed + // to attempt to recode. + int last_q = q; + int retries = 0; + + // Frame size out of permitted range: + // Update correction factor & compute new Q to try... + + // Frame is too large + if (cpi->projected_frame_size > cpi->this_frame_target) { + // Raise Qlow as to at least the current value + q_low = q < q_high ? q + 1 : q_high; + + if (undershoot_seen || loop_count > 1) { + // Update rate_correction_factor unless + // cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp9_update_rate_correction_factors(cpi, 1); + + q = (q_high + q_low + 1) / 2; + } else { + // Update rate_correction_factor unless + // cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp9_update_rate_correction_factors(cpi, 0); + + q = vp9_regulate_q(cpi, cpi->this_frame_target); + + while (q < q_low && retries < 10) { + vp9_update_rate_correction_factors(cpi, 0); + q = vp9_regulate_q(cpi, cpi->this_frame_target); + retries++; + } + } + + overshoot_seen = 1; + } else { + // Frame is too small + q_high = q > q_low ? q - 1 : q_low; + + if (overshoot_seen || loop_count > 1) { + // Update rate_correction_factor unless + // cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp9_update_rate_correction_factors(cpi, 1); + + q = (q_high + q_low) / 2; + } else { + // Update rate_correction_factor unless + // cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp9_update_rate_correction_factors(cpi, 0); + + q = vp9_regulate_q(cpi, cpi->this_frame_target); + + // Special case reset for qlow for constrained quality. + // 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.end_usage == USAGE_CONSTRAINED_QUALITY && q < q_low) { + q_low = q; + } + + while (q > q_high && retries < 10) { + vp9_update_rate_correction_factors(cpi, 0); + q = vp9_regulate_q(cpi, cpi->this_frame_target); + retries++; + } + } + + undershoot_seen = 1; + } + + // Clamp Q to upper and lower limits: + q = clamp(q, q_low, q_high); + + loop = q != last_q; + } else { + loop = 0; + } } if (cpi->is_src_frame_alt_ref) @@ -3114,10 +3163,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, if (!loop && cm->frame_type != KEY_FRAME && sf->search_best_filter) { if (mcomp_filter_index < mcomp_filters) { int64_t err = vp9_calc_ss_err(cpi->Source, - &cm->yv12_fb[cm->new_fb_idx]); + &cm->yv12_fb[cm->new_fb_idx]); int64_t rate = cpi->projected_frame_size << 8; mcomp_filter_cost[mcomp_filter_index] = - (RDCOST(cpi->RDMULT, cpi->RDDIV, rate, err)); + (RDCOST(cpi->RDMULT, cpi->RDDIV, rate, err)); mcomp_filter_index++; if (mcomp_filter_index < mcomp_filters) { cm->mcomp_filter_type = mcomp_filters_to_search[mcomp_filter_index]; @@ -3139,10 +3188,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cm->mcomp_filter_type = mcomp_best_filter; } /* - printf(" best filter = %d, ( ", mcomp_best_filter); - for (f=0;fcurrent_video_frame ? "a" : "w"); int recon_err; vp9_clear_system_state(); // __asm emms; @@ -3349,7 +3398,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, &cm->yv12_fb[cm->new_fb_idx]); if (cpi->twopass.total_left_stats.coded_error != 0.0) - fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d" + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %10d" "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" "%6d %6d %5d %5d %5d %8.2f %10d %10.3f" "%10.3f %8d %10d %10d %10d\n", @@ -3359,6 +3408,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, (int)cpi->total_target_vs_actual, (int)(cpi->oxcf.starting_buffer_level - cpi->bits_off_target), (int)cpi->total_actual_bits, + cm->base_qindex, vp9_convert_qindex_to_q(cm->base_qindex), (double)vp9_dc_quant(cm->base_qindex, 0) / 4.0, vp9_convert_qindex_to_q(cpi->active_best_quality), @@ -3377,7 +3427,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cpi->tot_recode_hits, recon_err, cpi->kf_boost, cpi->kf_zeromotion_pct); else - fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d" + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %10d" "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" "%5d %5d %5d %8d %8d %8.2f %10d %10.3f" "%8d %10d %10d %10d\n", @@ -3388,6 +3438,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, (int)cpi->total_target_vs_actual, (int)(cpi->oxcf.starting_buffer_level - cpi->bits_off_target), (int)cpi->total_actual_bits, + cm->base_qindex, vp9_convert_qindex_to_q(cm->base_qindex), (double)vp9_dc_quant(cm->base_qindex, 0) / 4.0, vp9_convert_qindex_to_q(cpi->active_best_quality), diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index e9549228e..732229edc 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -148,7 +148,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(cfg, g_threads, 64); RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS); - RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); + RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_Q); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); @@ -262,13 +262,15 @@ static vpx_codec_err_t set_vp9e_config(VP9_CONFIG *oxcf, // VBR only supported for now. // CBR code has been deprectated for experimental phase. // CQ mode not yet tested - oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; - /*if (cfg.rc_end_usage == VPX_CQ) - oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; - else - oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;*/ + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; + /* + if (cfg.rc_end_usage == VPX_CQ) + oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + */ + if (cfg.rc_end_usage == VPX_Q) + oxcf->end_usage = USAGE_CONSTANT_QUALITY; - oxcf->target_bandwidth = cfg.rc_target_bitrate; + oxcf->target_bandwidth = cfg.rc_target_bitrate; oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct; oxcf->best_allowed_q = cfg.rc_min_quantizer; diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index ffdbc0644..f70cbe07b 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -217,9 +217,10 @@ extern "C" { /*!\brief Rate control mode */ enum vpx_rc_mode { - VPX_VBR, /**< Variable Bit Rate (VBR) mode */ + VPX_VBR, /**< Variable Bit Rate (VBR) mode */ VPX_CBR, /**< Constant Bit Rate (CBR) mode */ - VPX_CQ /**< Constant Quality (CQ) mode */ + VPX_CQ, /**< Constrained Quality (CQ) mode */ + VPX_Q, /**< Constant Quality (Q) mode */ }; diff --git a/vpxenc.c b/vpxenc.c index 5d29c15e2..0c742ca22 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -1046,6 +1046,7 @@ static const struct arg_enum_list end_usage_enum[] = { {"vbr", VPX_VBR}, {"cbr", VPX_CBR}, {"cq", VPX_CQ}, + {"q", VPX_Q}, {NULL, 0} }; static const arg_def_t end_usage = ARG_DEF_ENUM(NULL, "end-usage", 1, @@ -1126,7 +1127,7 @@ static const struct arg_enum_list tuning_enum[] = { static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, "Material to favor", tuning_enum); static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, - "Constrained Quality Level"); + "Constant/Constrained Quality level"); static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, "Max I-frame bitrate (pct)"); static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");