diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h index 3724b11e0..426b8fc2b 100644 --- a/vp8/common/onyx.h +++ b/vp8/common/onyx.h @@ -46,7 +46,8 @@ extern "C" typedef enum { USAGE_STREAM_FROM_SERVER = 0x0, - USAGE_LOCAL_FILE_PLAYBACK = 0x1 + USAGE_LOCAL_FILE_PLAYBACK = 0x1, + USAGE_CONSTRAINED_QUALITY = 0x2 } END_USAGE; @@ -150,6 +151,7 @@ extern "C" int fixed_q; int worst_allowed_q; int best_allowed_q; + int cq_level; // allow internal resizing ( currently disabled in the build !!!!!) int allow_spatial_resampling; @@ -187,7 +189,6 @@ extern "C" int arnr_strength ; int arnr_type ; - struct vpx_fixed_buf two_pass_stats_in; struct vpx_codec_pkt_list *output_pkt_list; diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 856c58a3a..5a727af3d 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -785,20 +785,6 @@ void vp8_encode_frame(VP8_COMP *cpi) x->activity_sum = 0; -#if 0 - // Experimental rd code - // 2 Pass - Possibly set Rdmult based on last frame distortion + this frame target bits or other metrics - // such as cpi->rate_correction_factor that indicate relative complexity. - /*if ( cpi->pass == 2 && (cpi->last_frame_distortion > 0) && (cpi->target_bits_per_mb > 0) ) - { - //x->rdmult = ((cpi->last_frame_distortion * 256)/cpi->common.MBs)/ cpi->target_bits_per_mb; - x->rdmult = (int)(cpi->RDMULT * cpi->rate_correction_factor); - } - else - x->rdmult = cpi->RDMULT; */ - //x->rdmult = (int)(cpi->RDMULT * pow( (cpi->rate_correction_factor * 2.0), 0.75 )); -#endif - xd->mode_info_context->mbmi.mode = DC_PRED; xd->mode_info_context->mbmi.uv_mode = DC_PRED; diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index da4d740cb..0c79adee4 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -58,6 +58,7 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; #define KF_MB_INTRA_MIN 300 #define GF_MB_INTRA_MIN 200 + #define DOUBLE_DIVIDE_CHECK(X) ((X)<0?(X)-.000001:(X)+.000001) #define POW1 (double)cpi->oxcf.two_pass_vbrbias/100.0 @@ -67,6 +68,18 @@ static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3}; static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3}; +const int cq_level[QINDEX_RANGE] = +{ + 0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9, + 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20, + 20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31, + 32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43, + 44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56, + 57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70, + 71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85, + 86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100 +}; + void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame); int vp8_input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps); @@ -890,7 +903,7 @@ void vp8_first_pass(VP8_COMP *cpi) } extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; -#define BASE_ERRPERMB 150 +#define BASE_ERRPERMB 100 static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) { int Q; @@ -907,7 +920,7 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ double pow_lowq = 0.40; if (section_target_bandwitdh <= 0) - return MAXQ; + return cpi->maxq_max_limit; // Highest value allowed target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); @@ -943,10 +956,12 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ // Correction factor used for Q values >= 20 corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); - corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + corr_high = (corr_high < 0.05) + ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; - // Try and pick a Q that should be high enough to encode the content at the given rate. - for (Q = 0; Q < MAXQ; Q++) + // Try and pick a max Q that will be high enough to encode the + // content at the given rate. + for (Q = cpi->maxq_min_limit; Q < cpi->maxq_max_limit; Q++) { int bits_per_mb_at_this_q; @@ -965,6 +980,15 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ break; } + // Restriction on active max q for constrained quality mode. + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < cpi->cq_target_quality) ) + //(Q < cpi->oxcf.cq_target_quality) ) + { + Q = cpi->cq_target_quality; + //Q = cpi->oxcf.cq_target_quality; + } + return Q; } static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) @@ -1113,6 +1137,79 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta return Q; } + +// For cq mode estimate a cq level that matches the observed +// complexity and data rate. +static int estimate_cq(VP8_COMP *cpi, double section_err, + int section_target_bandwitdh, int Height, int Width) +{ + int Q; + int num_mbs = ((Height * Width) / (16 * 16)); + int target_norm_bits_per_mb; + + double err_per_mb = section_err / num_mbs; + double correction_factor; + double corr_high; + double speed_correction = 1.0; + double pow_highq = 0.90; + double pow_lowq = 0.40; + double clip_iiratio; + double clip_iifactor; + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) + ? (512 * section_target_bandwitdh) / num_mbs + : 512 * (section_target_bandwitdh / num_mbs); + + // Corrections for higher compression speed settings + // (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + // II ratio correction factor for clip as a whole + clip_iiratio = cpi->total_stats->intra_error / + DOUBLE_DIVIDE_CHECK(cpi->total_stats->coded_error); + clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025); + if (clip_iifactor < 0.80) + clip_iifactor = 0.80; + + // Correction factor used for Q values >= 20 + corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); + corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + + // Try and pick a Q that can encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + if (Q < 50) + { + correction_factor = + pow( err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); + + correction_factor = (correction_factor < 0.05) ? 0.05 + : (correction_factor > 5.0) ? 5.0 + : correction_factor; + } + else + correction_factor = corr_high; + + bits_per_mb_at_this_q = + (int)( .5 + correction_factor * + speed_correction * + clip_iifactor * + (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + return cq_level[Q]; +} + extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate); void vp8_init_second_pass(VP8_COMP *cpi) @@ -1766,7 +1863,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) vp8_avg_stats(§ionstats); - cpi->section_intra_rating = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + cpi->section_intra_rating = + sectionstats.intra_error / + DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); //if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) @@ -1993,21 +2092,48 @@ void vp8_second_pass(VP8_COMP *cpi) if (cpi->common.current_video_frame == 0) { - // guess at 2nd pass q cpi->est_max_qcorrection_factor = 1.0; - tmp_q = estimate_max_q(cpi, (cpi->total_coded_error_left / frames_left), (int)(cpi->bits_left / frames_left), cpi->common.Height, cpi->common.Width); - if (tmp_q < cpi->worst_quality) + // Experimental code to try and set a cq_level in constrained + // quality mode. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY ) { - cpi->active_worst_quality = tmp_q; - cpi->ni_av_qi = tmp_q; - } - else - { - cpi->active_worst_quality = cpi->worst_quality; - cpi->ni_av_qi = cpi->worst_quality; + int est_cq; + + est_cq = + estimate_cq( cpi, + (cpi->total_coded_error_left / frames_left), + (int)(cpi->bits_left / frames_left), + cpi->common.Height, cpi->common.Width); + + 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->maxq_max_limit = cpi->worst_quality; + cpi->maxq_min_limit = cpi->best_quality; + tmp_q = estimate_max_q( cpi, + (cpi->total_coded_error_left / frames_left), + (int)(cpi->bits_left / frames_left), + cpi->common.Height, + cpi->common.Width); + + // Limit the maxq value returned subsequently. + // This increases the risk of overspend 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 + cpi->maxq_max_limit = ((tmp_q + 32) < cpi->worst_quality) + ? (tmp_q + 32) : cpi->worst_quality; + cpi->maxq_min_limit = ((tmp_q - 32) > cpi->best_quality) + ? (tmp_q - 32) : cpi->best_quality; + + cpi->active_worst_quality = tmp_q; + cpi->ni_av_qi = tmp_q; } + // 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 @@ -2029,13 +2155,6 @@ void vp8_second_pass(VP8_COMP *cpi) cpi->active_worst_quality --; cpi->active_worst_quality = ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4; - - // Clamp to user set limits - if (cpi->active_worst_quality > cpi->worst_quality) - cpi->active_worst_quality = cpi->worst_quality; - else if (cpi->active_worst_quality < cpi->best_quality) - cpi->active_worst_quality = cpi->best_quality; - } cpi->frames_to_key --; diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 1bc0f5865..1e26dd0fb 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -155,25 +155,25 @@ extern const int vp8cx_base_skip_false_prob[128]; // Tables relating active max Q to active min Q static const int kf_low_motion_minq[QINDEX_RANGE] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, - 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 10,10, - 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, - 19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, - 27,27,28,28,29,29,30,30,31,32,33,34,35,36,37,38, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, + 3,3,3,3,3,3,4,4,4,5,5,5,5,5,6,6, + 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, + 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, + 16,16,17,17,18,18,18,18,19,20,20,21,21,22,23,23 }; static const int kf_high_motion_minq[QINDEX_RANGE] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,10, - 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, - 19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, - 27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34, - 35,35,36,36,37,38,39,40,41,42,43,44,45,46,47,48, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3, + 3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6, + 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, + 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, + 16,16,17,17,18,18,18,18,19,19,20,20,20,20,21,21, + 21,21,22,22,23,23,24,25,25,26,26,27,28,28,29,30 }; static const int gf_low_motion_minq[QINDEX_RANGE] = { @@ -195,7 +195,7 @@ static const int gf_mid_motion_minq[QINDEX_RANGE] = 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29, 30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37, 38,39,39,40,40,41,41,42,42,43,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, + 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 }; static const int gf_high_motion_minq[QINDEX_RANGE] = { @@ -206,7 +206,7 @@ static const int gf_high_motion_minq[QINDEX_RANGE] = 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32, 33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40, 41,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54, - 55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80, + 55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80 }; static const int inter_minq[QINDEX_RANGE] = { @@ -573,7 +573,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) cpi->mbs_tested_so_far = 0; - // best quality + // best quality defaults sf->RD = 1; sf->search_method = NSTEP; sf->improved_quant = 1; @@ -1265,6 +1265,15 @@ void vp8_set_speed_features(VP8_COMP *cpi) }; + // Slow quant, dct and trellis not worthwhile for first pass + // so make sure they are always turned off. + if ( cpi->pass == 1 ) + { + sf->improved_quant = 0; + sf->optimize_coefficients = 0; + sf->improved_dct = 0; + } + if (cpi->sf.search_method == NSTEP) { vp8_init3smotion_compensation(&cpi->mb, cm->yv12_fb[cm->lst_fb_idx].y_stride); @@ -2014,6 +2023,9 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->active_best_quality = cpi->oxcf.best_allowed_q; cpi->buffered_mode = (cpi->oxcf.optimal_buffer_level > 0) ? TRUE : FALSE; + // Experimental cq target value + cpi->cq_target_quality = oxcf->cq_level; + cpi->rolling_target_bits = cpi->av_per_frame_bandwidth; cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth; cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth; @@ -3077,9 +3089,6 @@ static int pick_frame_size(VP8_COMP *cpi) } } - // Note target_size in bits * 256 per MB - cpi->target_bits_per_mb = (cpi->this_frame_target * 256) / cpi->common.MBs; - return 1; } static void set_quantizer(VP8_COMP *cpi, int Q) @@ -3502,12 +3511,14 @@ static BOOL recode_loop_test( VP8_COMP *cpi, { // General over and under shoot tests if ( ((cpi->projected_frame_size > high_limit) && (q < maxq)) || - ((cpi->projected_frame_size < low_limit) && (q > minq)) ) + ((cpi->projected_frame_size < low_limit) && (q > minq)) || + ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (q > cpi->cq_target_quality) && + (cpi->projected_frame_size < + ((cpi->this_frame_target * 7) >> 3))) ) { force_recode = TRUE; } - // Specific rate control mode related tests - // TBD } return force_recode; @@ -3802,15 +3813,7 @@ static void encode_frame_to_data_rate cpi->active_best_quality = gf_high_motion_minq[Q]; else cpi->active_best_quality = gf_mid_motion_minq[Q]; - - /*cpi->active_best_quality = gf_arf_minq[Q]; - tmp = (cpi->gfu_boost > 1000) ? 600 : cpi->gfu_boost - 400; - //tmp = (cpi->gfu_boost > 1000) ? 600 : - //(cpi->gfu_boost < 400) ? 0 : cpi->gfu_boost - 400; - tmp = 128 - (tmp >> 4); - cpi->active_best_quality = (cpi->active_best_quality * tmp)>>7;*/ - - } + } // KEY FRAMES else { @@ -3823,6 +3826,14 @@ static void encode_frame_to_data_rate else { cpi->active_best_quality = inter_minq[Q]; + + // For the constant/constrained quality mode we dont want + // the quality to rise above the cq level. + if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (cpi->active_best_quality < cpi->cq_target_quality) ) + { + cpi->active_best_quality = cpi->cq_target_quality; + } } // If CBR and the buffer is as full then it is reasonable to allow higher quality on the frames @@ -4556,7 +4567,8 @@ static void encode_frame_to_data_rate (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), (int)cpi->total_actual_bits, cm->base_qindex, cpi->active_best_quality, cpi->active_worst_quality, - cpi->avg_frame_qindex, cpi->zbin_over_quant, + cpi->cq_target_quality, cpi->zbin_over_quant, + //cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, cpi->est_max_qcorrection_factor, (int)cpi->bits_left, @@ -4574,7 +4586,8 @@ static void encode_frame_to_data_rate (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), (int)cpi->total_actual_bits, cm->base_qindex, cpi->active_best_quality, cpi->active_worst_quality, - cpi->avg_frame_qindex, cpi->zbin_over_quant, + cpi->cq_target_quality, cpi->zbin_over_quant, + //cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, cpi->est_max_qcorrection_factor, (int)cpi->bits_left, diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 899fdf6e3..45238622b 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -369,7 +369,6 @@ typedef struct int this_frame_target; int projected_frame_size; int last_q[2]; // Separate values for Intra/Inter - int target_bits_per_mb; double rate_correction_factor; double key_frame_rate_correction_factor; @@ -451,6 +450,10 @@ typedef struct int best_quality; int active_best_quality; + int cq_target_quality; + int maxq_max_limit; + int maxq_min_limit; + int drop_frames_allowed; // Are we permitted to drop frames? int drop_frame; // Drop this frame? int drop_count; // How many frames have we dropped? diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index 8455b7bdb..b69a1965e 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -1550,12 +1550,21 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; } } - // VBR + // VBR and CQ mode // Note that tighter restrictions here can help quality but hurt encode speed else { - *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; - *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + // Stron overshoot limit for constrained quality + if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 2 / 8; + } + else + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + } } } } diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index e6c7c9ab3..d694d39fb 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -36,7 +36,6 @@ #include "dct.h" #include "systemdependent.h" -#define DIAMONDSEARCH 1 #if CONFIG_RUNTIME_CPU_DETECT #define IF_RTCD(x) (x) #else @@ -46,19 +45,6 @@ void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x); - -#define RDFUNC(RM,DM,R,D,target_rd) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) -/*int RDFUNC( int RM,int DM, int R, int D, int target_r ) -{ - int rd_value; - - rd_value = ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ); - - return rd_value; -}*/ - -#define UVRDFUNC(RM,DM,R,D,target_r) RDFUNC(RM,DM,R,D,target_r) - #define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) #define MAXF(a,b) (((a) > (b)) ? (a) : (b)) @@ -223,8 +209,6 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue) { int q; int i; - int *thresh; - int threshmult; double capped_q = (Qvalue < 160) ? (double)Qvalue : 160.0; double rdconst = 3.00; @@ -271,22 +255,6 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue) if (q < 8) q = 8; - if (cpi->ref_frame_flags == VP8_ALT_FLAG) - { - thresh = &cpi->rd_threshes[THR_NEWA]; - threshmult = cpi->sf.thresh_mult[THR_NEWA]; - } - else if (cpi->ref_frame_flags == VP8_GOLD_FLAG) - { - thresh = &cpi->rd_threshes[THR_NEWG]; - threshmult = cpi->sf.thresh_mult[THR_NEWG]; - } - else - { - thresh = &cpi->rd_threshes[THR_NEWMV]; - threshmult = cpi->sf.thresh_mult[THR_NEWMV]; - } - if (cpi->RDMULT > 1000) { cpi->RDDIV = 1; @@ -775,7 +743,7 @@ static int vp8_rd_inter_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *distort *rate = rd_cost_mbuv(x); *distortion = ENCODEMB_INVOKE(&cpi->rtcd.encodemb, mbuverr)(x) / 4; - return UVRDFUNC(x->rdmult, x->rddiv, *rate, *distortion, cpi->target_bits_per_mb); + return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); } int vp8_rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *rate_tokenonly, int *distortion) @@ -800,7 +768,7 @@ int vp8_rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *ra distortion = vp8_get_mbuvrecon_error(IF_RTCD(&cpi->rtcd.variance), x); - this_rd = UVRDFUNC(x->rdmult, x->rddiv, rate, distortion, cpi->target_bits_per_mb); + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); if (this_rd < best_rd) { @@ -1097,7 +1065,7 @@ void vp8_rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, BEST_SEG_INFO *bsi, // Segmentation method overheads rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation); rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts); - this_segment_rd += RDFUNC(x->rdmult, x->rddiv, rate, 0, cpi->target_bits_per_mb); + this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0); br += rate; for (i = 0; i < label_count; i++) @@ -1252,7 +1220,7 @@ void vp8_rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, BEST_SEG_INFO *bsi, labelyrate = rdcost_mbsegment_y(x, labels, i, ta_s, tl_s); rate += labelyrate; - this_rd = RDFUNC(x->rdmult, x->rddiv, rate, distortion, cpi->target_bits_per_mb); + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); if (this_rd < best_label_rd) { @@ -1751,7 +1719,7 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int //int intermodecost[MAX_MODES]; MB_PREDICTION_MODE uv_intra_mode; - int uvintra_eob = 0; + int force_no_skip = 0; MV mvp; @@ -1770,27 +1738,6 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); - // Experimental code - // Adjust the RD multiplier based on the best case distortion we saw in the most recently coded mb - //if ( (cpi->last_mb_distortion) > 0 && (cpi->target_bits_per_mb > 0) ) - /*{ - int tmprdmult; - - //tmprdmult = (cpi->last_mb_distortion * 256) / ((cpi->av_per_frame_bandwidth*256)/cpi->common.MBs); - tmprdmult = (cpi->last_mb_distortion * 256) / cpi->target_bits_per_mb; - //tmprdmult = tmprdmult; - - //if ( tmprdmult > cpi->RDMULT * 2 ) - // tmprdmult = cpi->RDMULT * 2; - //else if ( tmprdmult < cpi->RDMULT / 2 ) - // tmprdmult = cpi->RDMULT / 2; - - //tmprdmult = (tmprdmult < 25) ? 25 : tmprdmult; - - //x->rdmult = tmprdmult; - - }*/ - // Special case treatment when GF and ARF are not sensible options for reference if (cpi->ref_frame_flags == VP8_LAST_FLAG) { @@ -1820,12 +1767,6 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; vp8_rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion); uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode; - { - uvintra_eob = 0; - - for (i = 16; i < 24; i++) - uvintra_eob += x->e_mbd.block[i].eob; - } for (mode_index = 0; mode_index < MAX_MODES; mode_index++) { @@ -2339,8 +2280,8 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int distortion_uv = sse2; disable_skip = 1; - this_rd = RDFUNC(x->rdmult, x->rddiv, rate2, - distortion2, cpi->target_bits_per_mb); + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, + distortion2); break; } @@ -2414,7 +2355,7 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int } } // Calculate the final RD estimate for this mode - this_rd = RDFUNC(x->rdmult, x->rddiv, rate2, distortion2, cpi->target_bits_per_mb); + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); } // Experimental debug code. @@ -2442,8 +2383,8 @@ int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int other_cost += ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; /* Calculate the final y RD estimate for this mode */ - best_yrd = RDFUNC(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), - (distortion2-distortion_uv), cpi->target_bits_per_mb); + best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), + (distortion2-distortion_uv)); *returnrate = rate2; *returndistortion = distortion2; diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index a833ea5cf..09a9151bc 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -39,6 +39,7 @@ struct vp8_extracfg unsigned int arnr_type; /* alt_ref filter type */ unsigned int experimental; vp8e_tuning tuning; + unsigned int cq_level; /* constrained quality level */ }; @@ -71,6 +72,7 @@ static const struct extraconfig_map extracfg_map[] = 3, /* arnr_type*/ 0, /* experimental mode */ 0, /* tuning*/ + 10, /* cq_level */ } } }; @@ -150,7 +152,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, #else RANGE_CHECK_HI(cfg, g_lag_in_frames, 0); #endif - RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CBR); + RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO); @@ -192,6 +194,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15); 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 (cfg->g_pass == VPX_RC_LAST_PASS) { @@ -301,6 +304,10 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, { oxcf->end_usage = USAGE_STREAM_FROM_SERVER; } + else if (cfg.rc_end_usage == VPX_CQ) + { + oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + } oxcf->target_bandwidth = cfg.rc_target_bitrate; @@ -342,6 +349,7 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->arnr_type = vp8_cfg.arnr_type; oxcf->tuning = vp8_cfg.tuning; + oxcf->cq_level = vp8_cfg.cq_level; /* printf("Current VP8 Settings: \n"); @@ -456,6 +464,7 @@ static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx, MAP(VP8E_SET_ARNR_STRENGTH , xcfg.arnr_strength); MAP(VP8E_SET_ARNR_TYPE , xcfg.arnr_type); MAP(VP8E_SET_TUNING, xcfg.tuning); + MAP(VP8E_SET_CQ_LEVEL, xcfg.cq_level); } @@ -1056,6 +1065,7 @@ static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = {VP8E_SET_ARNR_STRENGTH , set_param}, {VP8E_SET_ARNR_TYPE , set_param}, {VP8E_SET_TUNING, set_param}, + {VP8E_SET_CQ_LEVEL, set_param}, { -1, NULL}, }; @@ -1091,7 +1101,6 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = 4, /* rc_min_quantizer */ 63, /* rc_max_quantizer */ - 95, /* rc_undershoot_pct */ 200, /* rc_overshoot_pct */ diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 0e6eea614..a8437d0e3 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -151,6 +151,7 @@ enum vp8e_enc_control_id VP8E_SET_ARNR_STRENGTH , /**< control function to set the filter strength for the arf */ VP8E_SET_ARNR_TYPE , /**< control function to set the type of filter to use for the arf*/ VP8E_SET_TUNING, /**< control function to set visual tuning */ + VP8E_SET_CQ_LEVEL, /**< control function to set constrained quality level */ }; /*!\brief vpx 1-D scaling mode @@ -277,6 +278,7 @@ VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int) VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH , unsigned int) VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_TYPE , unsigned int) VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, vp8e_tuning) +VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL , unsigned int) VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *) VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index 3acb19945..0d53f410d 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -179,7 +179,8 @@ extern "C" { enum vpx_rc_mode { VPX_VBR, /**< Variable Bit Rate (VBR) mode */ - VPX_CBR /**< Constant Bit Rate (CBR) mode */ + VPX_CBR, /**< Constant Bit Rate (CBR) mode */ + VPX_CQ /**< Constant Quality (CQ) mode */ }; diff --git a/vpxenc.c b/vpxenc.c index 9d1d2f0bb..0abcfb2ae 100755 --- a/vpxenc.c +++ b/vpxenc.c @@ -921,7 +921,7 @@ static const arg_def_t resize_up_thresh = ARG_DEF(NULL, "resize-up", 1, static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1, "Downscale threshold (buf %)"); static const arg_def_t end_usage = ARG_DEF(NULL, "end-usage", 1, - "VBR=0 | CBR=1"); + "VBR=0 | CBR=1 | CQ=2"); static const arg_def_t target_bitrate = ARG_DEF(NULL, "target-bitrate", 1, "Bitrate (kbps)"); static const arg_def_t min_quantizer = ARG_DEF(NULL, "min-q", 1, @@ -1004,12 +1004,14 @@ 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"); static const arg_def_t *vp8_args[] = { &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, - &tune_ssim, NULL + &tune_ssim, &cq_level, NULL }; static const int vp8_arg_ctrl_map[] = { @@ -1017,7 +1019,7 @@ static const int vp8_arg_ctrl_map[] = VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, VP8E_SET_TOKEN_PARTITIONS, VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH , VP8E_SET_ARNR_TYPE, - VP8E_SET_TUNING, 0 + VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, 0 }; #endif