From 23ebacdb81adeee7a082a573068d84921898f39d Mon Sep 17 00:00:00 2001 From: Adrian Grange Date: Fri, 14 Nov 2014 15:29:18 -0800 Subject: [PATCH] Auto-adaptive encoder frame resizing logic Note: This feature is still in development. Add an option for the encoder to decide the resolution at which to encode each frame. Each KF/GF/ARF goup is tested to see if it would be better encoded at a lower resolution. At present, each KF/GF/ARF is coded first at full-size and if the coded size exceeds a threshold (twice target data rate) at the maximum active Q then the entire group is encoded at lower resolution. This feature is enabled in vpxenc by setting: --resize-allowed=1 In addition, if the vpxenc command line also specifies valid frame dimensions using: --resize-width=XXXX & --resize_height=YYYY then *all* frames will be encoded at this resolution. Change-Id: I13f341e0a82512f9e84e144e0f3b5aed8a65402b --- vp9/encoder/vp9_encoder.c | 115 ++++++++++++++++++++++++++++----------- vp9/encoder/vp9_encoder.h | 4 ++ vp9/encoder/vp9_firstpass.c | 65 +++++++++++++++++++--- vp9/encoder/vp9_firstpass.h | 9 ++- vp9/encoder/vp9_ratectrl.c | 74 +++++++++++++++++-------- vp9/encoder/vp9_ratectrl.h | 31 +++++++++++ vp9/encoder/vp9_rdopt.c | 33 ++++++----- vp9/encoder/vp9_speed_features.c | 9 ++- 8 files changed, 259 insertions(+), 81 deletions(-) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index a4c77dd..65b6605 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2307,26 +2307,43 @@ static void scale_and_extend_frame(const YV12_BUFFER_CONFIG *src, vp9_extend_frame_borders(dst); } +static int scale_down(VP9_COMP *cpi, int q) { + RATE_CONTROL *const rc = &cpi->rc; + GF_GROUP *const gf_group = &cpi->twopass.gf_group; + int scale = 0; + assert(frame_is_kf_gf_arf(cpi)); + + if (rc->frame_size_selector == UNSCALED && + q >= rc->rf_level_maxq[gf_group->rf_level[gf_group->index]]) { + const int max_size_thresh = (int)(rate_thresh_mult[SCALE_STEP1] + * MAX(rc->this_frame_target, rc->avg_frame_bandwidth)); + scale = rc->projected_frame_size > max_size_thresh ? 1 : 0; + } + return scale; +} + // Function to test for conditions that indicate we should loop // back and recode a frame. -static int recode_loop_test(const VP9_COMP *cpi, +static int recode_loop_test(VP9_COMP *cpi, int high_limit, int low_limit, int q, int maxq, int minq) { const RATE_CONTROL *const rc = &cpi->rc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; + const int frame_is_kfgfarf = frame_is_kf_gf_arf(cpi); int force_recode = 0; - // Special case trap if maximum allowed frame size exceeded. - if (rc->projected_frame_size > rc->max_frame_bandwidth) { - force_recode = 1; - - // Is frame recode allowed. - // Yes if either recode mode 1 is selected or mode 2 is selected - // and the frame is a key frame, golden frame or alt_ref_frame - } else if ((cpi->sf.recode_loop == ALLOW_RECODE) || - ((cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF) && - frame_is_kf_gf_arf(cpi))) { - // General over and under shoot tests + if ((cpi->sf.recode_loop == ALLOW_RECODE) || + (frame_is_kfgfarf && + (cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF))) { + if (frame_is_kfgfarf && + (oxcf->resize_mode == RESIZE_DYNAMIC) && + scale_down(cpi, q)) { + // Code this group at a lower resolution. + cpi->resize_pending = 1; + return 1; + } + + // TODO(agrange) high_limit could be greater than the scale-down threshold. if ((rc->projected_frame_size > high_limit && q < maxq) || (rc->projected_frame_size < low_limit && q > minq)) { force_recode = 1; @@ -2557,13 +2574,15 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) { recon_err = vp9_get_y_sse(cpi->Source, get_frame_new_buffer(cm)); if (cpi->twopass.total_left_stats.coded_error != 0.0) - fprintf(f, "%10u %10d %10d %10d %10d" + fprintf(f, "%10u %dx%d %10d %10d %10d %10d" "%10"PRId64" %10"PRId64" %10"PRId64" %10"PRId64" %10d " "%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf" "%6d %6d %5d %5d %5d " "%10"PRId64" %10.3lf" "%10lf %8u %10"PRId64" %10d %10d\n", - cpi->common.current_video_frame, cpi->rc.this_frame_target, + cpi->common.current_video_frame, + cm->width, cm->height, + cpi->rc.this_frame_target, cpi->rc.projected_frame_size, cpi->rc.projected_frame_size / cpi->common.MBs, (cpi->rc.projected_frame_size - cpi->rc.this_frame_target), @@ -2699,14 +2718,17 @@ static void init_motion_estimation(VP9_COMP *cpi) { void set_frame_size(VP9_COMP *cpi) { int ref_frame; VP9_COMMON *const cm = &cpi->common; - const VP9EncoderConfig *const oxcf = &cpi->oxcf; + VP9EncoderConfig *const oxcf = &cpi->oxcf; MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; if (oxcf->pass == 2 && - cm->current_video_frame == 0 && - oxcf->resize_mode == RESIZE_FIXED && - oxcf->rc_mode == VPX_VBR) { - // Internal scaling is triggered on the first frame. + oxcf->rc_mode == VPX_VBR && + ((oxcf->resize_mode == RESIZE_FIXED && cm->current_video_frame == 0) || + (oxcf->resize_mode == RESIZE_DYNAMIC && cpi->resize_pending))) { + calculate_coded_size( + cpi, &oxcf->scaled_frame_width, &oxcf->scaled_frame_height); + + // There has been a change in frame size. vp9_set_size_literal(cpi, oxcf->scaled_frame_width, oxcf->scaled_frame_height); } @@ -2757,7 +2779,7 @@ void set_frame_size(VP9_COMP *cpi) { static void encode_without_recode_loop(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; - int q, bottom_index, top_index; // Dummy variables. + int q = 0, bottom_index = 0, top_index = 0; // Dummy variables. vp9_clear_system_state(); @@ -2804,13 +2826,13 @@ static void encode_with_recode_loop(VP9_COMP *cpi, RATE_CONTROL *const rc = &cpi->rc; int bottom_index, top_index; int loop_count = 0; + int loop_at_this_size = 0; int loop = 0; int overshoot_seen = 0; int undershoot_seen = 0; int frame_over_shoot_limit; int frame_under_shoot_limit; int q = 0, q_low = 0, q_high = 0; - int frame_size_changed = 0; set_size_independent_vars(cpi); @@ -2819,19 +2841,31 @@ static void encode_with_recode_loop(VP9_COMP *cpi, set_frame_size(cpi); - if (loop_count == 0 || frame_size_changed != 0) { + if (loop_count == 0 || cpi->resize_pending != 0) { set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); - q_low = bottom_index; - q_high = top_index; // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed. set_mv_search_params(cpi); + + // Reset the loop state for new frame size. + overshoot_seen = 0; + undershoot_seen = 0; + + // Reconfiguration for change in frame size has concluded. + cpi->resize_pending = 0; + + q_low = bottom_index; + q_high = top_index; + + loop_at_this_size = 0; } - // Decide frame size bounds - vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target, - &frame_under_shoot_limit, - &frame_over_shoot_limit); + // Decide frame size bounds first time through. + if (loop_count == 0) { + vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target, + &frame_under_shoot_limit, + &frame_over_shoot_limit); + } cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_source); @@ -2944,6 +2978,20 @@ static void encode_with_recode_loop(VP9_COMP *cpi, int last_q = q; int retries = 0; + if (cpi->resize_pending == 1) { + // Change in frame size so go back around the recode loop. + cpi->rc.frame_size_selector = + SCALE_STEP1 - cpi->rc.frame_size_selector; + cpi->rc.next_frame_size_selector = cpi->rc.frame_size_selector; + +#if CONFIG_INTERNAL_STATS + ++cpi->tot_recode_hits; +#endif + ++loop_count; + loop = 1; + continue; + } + // Frame size out of permitted range: // Update correction factor & compute new Q to try... @@ -2956,7 +3004,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, // Raise Qlow as to at least the current value q_low = q < q_high ? q + 1 : q_high; - if (undershoot_seen || loop_count > 1) { + if (undershoot_seen || loop_at_this_size > 1) { // Update rate_correction_factor unless vp9_rc_update_rate_correction_factors(cpi); @@ -2981,7 +3029,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, // Frame is too small q_high = q > q_low ? q - 1 : q_low; - if (overshoot_seen || loop_count > 1) { + if (overshoot_seen || loop_at_this_size > 1) { vp9_rc_update_rate_correction_factors(cpi); q = (q_high + q_low) / 2; } else { @@ -3011,7 +3059,7 @@ static void encode_with_recode_loop(VP9_COMP *cpi, // Clamp Q to upper and lower limits: q = clamp(q, q_low, q_high); - loop = q != last_q; + loop = (q != last_q); } else { loop = 0; } @@ -3023,10 +3071,11 @@ static void encode_with_recode_loop(VP9_COMP *cpi, loop = 0; if (loop) { - loop_count++; + ++loop_count; + ++loop_at_this_size; #if CONFIG_INTERNAL_STATS - cpi->tot_recode_hits++; + ++cpi->tot_recode_hits; #endif } } while (loop); diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index e0ed06b..1e4c982 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -448,6 +448,8 @@ typedef struct VP9_COMP { VP9_DENOISER denoiser; #endif + int resize_pending; + // Multi-threading int num_workers; VP9Worker *workers; @@ -593,6 +595,8 @@ static INLINE int *cond_cost_list(const struct VP9_COMP *cpi, int *cost_list) { return cpi->sf.mv.subpel_search_method != SUBPEL_TREE ? cost_list : NULL; } +void vp9_new_framerate(VP9_COMP *cpi, double framerate); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 053552d..366aeb1 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -1134,7 +1134,38 @@ static int get_twopass_worst_quality(const VP9_COMP *cpi, } } -extern void vp9_new_framerate(VP9_COMP *cpi, double framerate); +static void setup_rf_level_maxq(VP9_COMP *cpi) { + int i; + RATE_CONTROL *const rc = &cpi->rc; + for (i = INTER_NORMAL; i < RATE_FACTOR_LEVELS; ++i) { + int qdelta = vp9_frame_type_qdelta(cpi, i, rc->worst_quality); + rc->rf_level_maxq[i] = MAX(rc->worst_quality + qdelta, rc->best_quality); + } +} + +void vp9_init_subsampling(VP9_COMP *cpi) { + const VP9_COMMON *const cm = &cpi->common; + RATE_CONTROL *const rc = &cpi->rc; + const int w = cm->width; + const int h = cm->height; + int i; + + for (i = 0; i < FRAME_SCALE_STEPS; ++i) { + // Note: Frames with odd-sized dimensions may result from this scaling. + rc->frame_width[i] = (w * 16) / frame_scale_factor[i]; + rc->frame_height[i] = (h * 16) / frame_scale_factor[i]; + } + + setup_rf_level_maxq(cpi); +} + +void calculate_coded_size(VP9_COMP *cpi, + int *scaled_frame_width, + int *scaled_frame_height) { + RATE_CONTROL *const rc = &cpi->rc; + *scaled_frame_width = rc->frame_width[rc->frame_size_selector]; + *scaled_frame_height = rc->frame_height[rc->frame_size_selector]; +} void vp9_init_second_pass(VP9_COMP *cpi) { SVC *const svc = &cpi->svc; @@ -1204,6 +1235,10 @@ void vp9_init_second_pass(VP9_COMP *cpi) { // Static sequence monitor variables. twopass->kf_zeromotion_pct = 100; twopass->last_kfgroup_zeromotion_pct = 100; + + if (oxcf->resize_mode != RESIZE_NONE) { + vp9_init_subsampling(cpi); + } } #define SR_DIFF_PART 0.0015 @@ -1696,8 +1731,9 @@ static void allocate_gf_group_bits(VP9_COMP *cpi, int64_t gf_group_bits, // Analyse and define a gf/arf group. static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { + VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; - const VP9EncoderConfig *const oxcf = &cpi->oxcf; + VP9EncoderConfig *const oxcf = &cpi->oxcf; TWO_PASS *const twopass = &cpi->twopass; FIRSTPASS_STATS next_frame; const FIRSTPASS_STATS *const start_pos = twopass->stats_in; @@ -1733,10 +1769,11 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { int64_t gf_group_bits; double gf_group_error_left; int gf_arf_bits; + int is_key_frame = frame_is_intra_only(cm); // Reset the GF group data structures unless this is a key // frame in which case it will already have been done. - if (cpi->common.frame_type != KEY_FRAME) { + if (is_key_frame == 0) { vp9_zero(twopass->gf_group); } @@ -1752,7 +1789,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // If this is a key frame or the overlay from a previous arf then // the error score / cost of this frame has already been accounted for. - if (cpi->common.frame_type == KEY_FRAME || rc->source_alt_ref_active) { + if (is_key_frame || rc->source_alt_ref_active) { gf_group_err -= gf_first_frame_err; #if GROUP_ADAPTIVE_MAXQ gf_group_raw_error -= this_frame->coded_error; @@ -1864,7 +1901,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0; // Set the interval until the next gf. - if (cpi->common.frame_type == KEY_FRAME || rc->source_alt_ref_active) + if (is_key_frame || rc->source_alt_ref_active) rc->baseline_gf_interval = i - 1; else rc->baseline_gf_interval = i; @@ -1927,9 +1964,9 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { get_twopass_worst_quality(cpi, group_av_err, vbr_group_bits_per_frame, twopass->kfgroup_inter_fraction); - if (tmp_q < twopass->baseline_worst_quality) { + if (tmp_q < twopass->baseline_active_worst_quality) { twopass->active_worst_quality = - (tmp_q + twopass->baseline_worst_quality + 1) / 2; + (tmp_q + twopass->baseline_active_worst_quality + 1) / 2; } else { twopass->active_worst_quality = tmp_q; } @@ -1951,7 +1988,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // also a key frame in which case it has already been accounted for. if (rc->source_alt_ref_pending) { gf_group_error_left = gf_group_err - mod_frame_err; - } else if (cpi->common.frame_type != KEY_FRAME) { + } else if (is_key_frame == 0) { gf_group_error_left = gf_group_err - gf_first_frame_err; } else { gf_group_error_left = gf_group_err; @@ -1969,6 +2006,11 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { calculate_section_intra_ratio(start_pos, twopass->stats_in_end, rc->baseline_gf_interval); } + + if (oxcf->resize_mode == RESIZE_DYNAMIC) { + // Default to starting GF groups at normal frame size. + cpi->rc.next_frame_size_selector = UNSCALED; + } } // TODO(PGW) Re-examine the use of II ration in this code in the light of# @@ -2293,6 +2335,11 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // The count of bits left is adjusted elsewhere based on real coded frame // sizes. twopass->modified_error_left -= kf_group_err; + + if (oxcf->resize_mode == RESIZE_DYNAMIC) { + // Default to normal-sized frame on keyframes. + cpi->rc.next_frame_size_selector = UNSCALED; + } } // Define the reference buffers that will be updated post encode. @@ -2433,7 +2480,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { section_target_bandwidth, DEFAULT_GRP_WEIGHT); twopass->active_worst_quality = tmp_q; - twopass->baseline_worst_quality = tmp_q; + twopass->baseline_active_worst_quality = tmp_q; rc->ni_av_qi = tmp_q; rc->last_q[INTER_FRAME] = tmp_q; rc->avg_q = vp9_convert_qindex_to_q(tmp_q, cm->bit_depth); diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index 3476770..08e7a8b 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -118,8 +118,8 @@ typedef struct { int kf_zeromotion_pct; int last_kfgroup_zeromotion_pct; int gf_zeromotion_pct; - int baseline_worst_quality; int active_worst_quality; + int baseline_active_worst_quality; int extend_minq; int extend_maxq; @@ -138,6 +138,13 @@ void vp9_rc_get_second_pass_params(struct VP9_COMP *cpi); // Post encode update of the rate control parameters for 2-pass void vp9_twopass_postencode_update(struct VP9_COMP *cpi); + +void vp9_init_subsampling(struct VP9_COMP *cpi); + +void calculate_coded_size(struct VP9_COMP *cpi, + int *scaled_frame_width, + int *scaled_frame_height); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 11da367..8d316d6 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -360,26 +360,32 @@ int vp9_rc_drop_frame(VP9_COMP *cpi) { static double get_rate_correction_factor(const VP9_COMP *cpi) { const RATE_CONTROL *const rc = &cpi->rc; + double rcf; if (cpi->common.frame_type == KEY_FRAME) { - return rc->rate_correction_factors[KF_STD]; + rcf = rc->rate_correction_factors[KF_STD]; } else if (cpi->oxcf.pass == 2) { RATE_FACTOR_LEVEL rf_lvl = cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; - return rc->rate_correction_factors[rf_lvl]; + rcf = rc->rate_correction_factors[rf_lvl]; } else { if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) && !rc->is_src_frame_alt_ref && !cpi->use_svc && (cpi->oxcf.rc_mode != VPX_CBR || cpi->oxcf.gf_cbr_boost_pct > 20)) - return rc->rate_correction_factors[GF_ARF_STD]; + rcf = rc->rate_correction_factors[GF_ARF_STD]; else - return rc->rate_correction_factors[INTER_NORMAL]; + rcf = rc->rate_correction_factors[INTER_NORMAL]; } + rcf *= rcf_mult[rc->frame_size_selector]; + return rcf > MAX_BPB_FACTOR ? MAX_BPB_FACTOR : rcf; } static void set_rate_correction_factor(VP9_COMP *cpi, double factor) { RATE_CONTROL *const rc = &cpi->rc; + // Normalize RCF to account for the size-dependent scaling factor. + factor /= rcf_mult[cpi->rc.frame_size_selector]; + if (cpi->common.frame_type == KEY_FRAME) { rc->rate_correction_factors[KF_STD] = factor; } else if (cpi->oxcf.pass == 2) { @@ -911,6 +917,23 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi, return q; } +int vp9_frame_type_qdelta(const VP9_COMP *cpi, int rf_level, int q) { + static const double rate_factor_deltas[RATE_FACTOR_LEVELS] = { + 1.00, // INTER_NORMAL + 1.00, // INTER_HIGH + 1.50, // GF_ARF_LOW + 1.75, // GF_ARF_STD + 2.00, // KF_STD + }; + static const FRAME_TYPE frame_type[RATE_FACTOR_LEVELS] = + {INTER_FRAME, INTER_FRAME, INTER_FRAME, INTER_FRAME, KEY_FRAME}; + const VP9_COMMON *const cm = &cpi->common; + int qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, frame_type[rf_level], + q, rate_factor_deltas[rf_level], + cm->bit_depth); + return qdelta; +} + #define STATIC_MOTION_THRESH 95 static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, int *bottom_index, @@ -918,6 +941,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, const VP9_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; + const GF_GROUP *gf_group = &cpi->twopass.gf_group; const int cq_level = get_active_cq_level(rc, oxcf); int active_best_quality; int active_worst_quality = cpi->twopass.active_worst_quality; @@ -999,7 +1023,6 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, if (!cpi->refresh_alt_ref_frame) { active_best_quality = cq_level; } else { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth); // Modify best quality for second level arfs. For mode VPX_Q this @@ -1025,7 +1048,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, } } - // Extenstion to max or min Q if undershoot or overshoot is outside + // Extension to max or min Q if undershoot or overshoot is outside // the permitted range. if ((cpi->oxcf.rc_mode == VPX_VBR) && (cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD)) { @@ -1046,25 +1069,21 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, if (!((frame_is_intra_only(cm) || vp9_is_upper_layer_key_frame(cpi))) || !rc->this_key_frame_forced || (cpi->twopass.last_kfgroup_zeromotion_pct < STATIC_MOTION_THRESH)) { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - const double rate_factor_deltas[RATE_FACTOR_LEVELS] = { - 1.00, // INTER_NORMAL - 1.00, // INTER_HIGH - 1.50, // GF_ARF_LOW - 1.75, // GF_ARF_STD - 2.00, // KF_STD - }; - const double rate_factor = - rate_factor_deltas[gf_group->rf_level[gf_group->index]]; - int qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, - active_worst_quality, rate_factor, - cm->bit_depth); - active_worst_quality = active_worst_quality + qdelta; - active_worst_quality = MAX(active_worst_quality, active_best_quality); + int qdelta = vp9_frame_type_qdelta(cpi, gf_group->rf_level[gf_group->index], + active_worst_quality); + active_worst_quality = MAX(active_worst_quality + qdelta, + active_best_quality); } #endif - // Clip the active best and worst quality values to limits. + // Modify active_best_quality for downscaled normal frames. + if (rc->frame_size_selector != UNSCALED && !frame_is_kf_gf_arf(cpi)) { + int qdelta = vp9_compute_qdelta_by_rate(rc, cm->frame_type, + active_best_quality, 2.0, + cm->bit_depth); + active_best_quality = MAX(active_best_quality + qdelta, rc->best_quality); + } + active_best_quality = clamp(active_best_quality, rc->best_quality, rc->worst_quality); active_worst_quality = clamp(active_worst_quality, @@ -1151,6 +1170,12 @@ void vp9_rc_set_frame_target(VP9_COMP *cpi, int target) { rc->this_frame_target = target; + // Modify frame size target when down-scaling. + if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC && + rc->frame_size_selector != UNSCALED) + rc->this_frame_target = + rc->this_frame_target * rate_thresh_mult[rc->frame_size_selector]; + // Target rate per SB64 (including partial SB64s. rc->sb64_target_rate = ((int64_t)rc->this_frame_target * 64 * 64) / (cm->width * cm->height); @@ -1285,6 +1310,11 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) { rc->frames_since_key++; rc->frames_to_key--; } + + // Trigger the resizing of the next frame if it is scaled. + cpi->resize_pending = + rc->next_frame_size_selector != rc->frame_size_selector; + rc->frame_size_selector = rc->next_frame_size_selector; } void vp9_rc_postencode_update_drop_frame(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index 9774127..705796a 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -33,6 +33,27 @@ typedef enum { RATE_FACTOR_LEVELS = 5 } RATE_FACTOR_LEVEL; +// Internal frame scaling level. +typedef enum { + UNSCALED = 0, // Frame is unscaled. + SCALE_STEP1 = 1, // First-level down-scaling. + FRAME_SCALE_STEPS +} FRAME_SCALE_LEVEL; + +// Frame dimensions multiplier wrt the native frame size, in 1/16ths, +// specified for the scale-up case. +// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is +// intended to match the capabilities of the normative scaling filters, +// giving precedence to the up-scaling accuracy. +static const int frame_scale_factor[FRAME_SCALE_STEPS] = {16, 24}; + +// Multiplier of the target rate to be used as threshold for triggering scaling. +static const double rate_thresh_mult[FRAME_SCALE_STEPS] = {1.0, 2.0}; + +// Scale dependent Rate Correction Factor multipliers. Compensates for the +// greater number of bits per pixel generated in down-scaled frames. +static const double rcf_mult[FRAME_SCALE_STEPS] = {1.0, 2.0}; + typedef struct { // Rate targetting variables int base_frame_target; // A baseline frame target before adjustment @@ -100,6 +121,7 @@ typedef struct { int64_t starting_buffer_level; int64_t optimal_buffer_level; int64_t maximum_buffer_size; + // rate control history for last frame(1) and the frame before(2). // -1: undershot // 1: overshoot @@ -108,6 +130,13 @@ typedef struct { int rc_2_frame; int q_1_frame; int q_2_frame; + + // Auto frame-scaling variables. + FRAME_SCALE_LEVEL frame_size_selector; + FRAME_SCALE_LEVEL next_frame_size_selector; + int frame_width[FRAME_SCALE_STEPS]; + int frame_height[FRAME_SCALE_STEPS]; + int rf_level_maxq[RATE_FACTOR_LEVELS]; } RATE_CONTROL; struct VP9_COMP; @@ -205,6 +234,8 @@ int vp9_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type, int qindex, double rate_target_ratio, vpx_bit_depth_t bit_depth); +int vp9_frame_type_qdelta(const struct VP9_COMP *cpi, int rf_level, int q); + void vp9_rc_update_framerate(struct VP9_COMP *cpi); void vp9_rc_set_gf_max_interval(const struct VP9_COMP *const cpi, diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index ba6d28e..79d118f 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1859,7 +1859,7 @@ static int64_t rd_pick_best_sub8x8_mode(VP9_COMP *cpi, MACROBLOCK *x, for (midx = 0; midx < INTER_MODES; ++midx) bsi->rdstat[iy][midx].brdcost = INT64_MAX; bsi->segment_rd = INT64_MAX; - return INT64_MAX;; + return INT64_MAX; } mode_idx = INTER_OFFSET(mode_selected); @@ -1882,7 +1882,7 @@ static int64_t rd_pick_best_sub8x8_mode(VP9_COMP *cpi, MACROBLOCK *x, for (midx = 0; midx < INTER_MODES; ++midx) bsi->rdstat[iy][midx].brdcost = INT64_MAX; bsi->segment_rd = INT64_MAX; - return INT64_MAX;; + return INT64_MAX; } } } /* for each label */ @@ -2105,24 +2105,27 @@ static void single_motion_search(VP9_COMP *cpi, MACROBLOCK *x, if (cpi->sf.adaptive_motion_search) { int bwl = b_width_log2_lookup[bsize]; int bhl = b_height_log2_lookup[bsize]; - int i; int tlevel = x->pred_mv_sad[ref] >> (bwl + bhl + 4); if (tlevel < 5) step_param += 2; - for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) { - if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) { - x->pred_mv[ref].row = 0; - x->pred_mv[ref].col = 0; - tmp_mv->as_int = INVALID_MV; - - if (scaled_ref_frame) { - int i; - for (i = 0; i < MAX_MB_PLANE; i++) - xd->plane[i].pre[0] = backup_yv12[i]; + // prev_mv_sad is not setup for dynamically scaled frames. + if (cpi->oxcf.resize_mode != RESIZE_DYNAMIC) { + int i; + for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) { + if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) { + x->pred_mv[ref].row = 0; + x->pred_mv[ref].col = 0; + tmp_mv->as_int = INVALID_MV; + + if (scaled_ref_frame) { + int i; + for (i = 0; i < MAX_MB_PLANE; ++i) + xd->plane[i].pre[0] = backup_yv12[i]; + } + return; } - return; } } } @@ -3518,6 +3521,8 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, best_mode_skippable |= !has_high_freq_coeff; } + assert(best_mode_index >= 0); + store_coding_context(x, ctx, best_mode_index, best_pred_diff, best_tx_diff, best_filter_diff, best_mode_skippable); } diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 8ba9adf..3515b6e 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -105,7 +105,9 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm, sf->tx_size_search_method = frame_is_boosted(cpi) ? USE_FULL_RD : USE_LARGESTALL; - sf->reference_masking = 1; + // Reference masking is not supported in dynamic scaling mode. + sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0; + sf->mode_search_skip_flags = (cm->frame_type == KEY_FRAME) ? 0 : FLAG_SKIP_INTRA_DIRMISMATCH | FLAG_SKIP_INTRA_BESTINTER | @@ -234,7 +236,10 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf, FLAG_SKIP_COMP_BESTINTRA | FLAG_SKIP_INTRA_LOWVAR; sf->adaptive_pred_interp_filter = 2; - sf->reference_masking = 1; + + // Reference masking is not supported in dynamic scaling mode. + sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0; + sf->disable_filter_search_var_thresh = 50; sf->comp_inter_joint_search_thresh = BLOCK_SIZES; sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX; -- 2.7.4