Add a q index based frame superres mode Refactors and adds superres-mode 3 and associated paramters --superres-qthresh and --superres-kf-qthresh that are used to trigger superres mode when the qindex for any frame exceeds the thresholds provided for non-key and key-frames respenctively. The superres scale factor numerator is progressively reduced from 16 starting from that q threshold following a fixed slope. Change-Id: If1c782993667a6fbaaa01bbde77c4924008c0d28
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h index add20b0..89b7396 100644 --- a/aom/aom_encoder.h +++ b/aom/aom_encoder.h
@@ -395,7 +395,7 @@ * using restoration filters should allow it to outperform normal resizing. * * Mode 0 is SUPERRES_NONE, mode 1 is SUPERRES_FIXED, and mode 2 is - * SUPERRES_DYNAMIC. + * SUPERRES_RANDOM. */ unsigned int rc_superres_mode; @@ -407,7 +407,7 @@ * * Valid numerators are 8 to 16. * - * Ignored by SUPERRES_DYNAMIC. + * Used only by SUPERRES_FIXED. */ unsigned int rc_superres_numerator; @@ -421,6 +421,24 @@ */ unsigned int rc_superres_kf_numerator; + /*!\brief Frame super-resolution q threshold. + * + * The q level threshold after which superres is used. + * Valid values are 1 to 63. + * + * Used only by SUPERRES_QTHRESH + */ + unsigned int rc_superres_qthresh; + + /*!\brief Keyframe super-resolution q threshold. + * + * The q level threshold after which superres is used for key frames. + * Valid values are 1 to 63. + * + * Used only by SUPERRES_QTHRESH + */ + unsigned int rc_superres_kf_qthresh; + /*!\brief Rate control algorithm to use. * * Indicates whether the end usage of this stream is to be streamed over
diff --git a/aomenc.c b/aomenc.c index d9e1f73..fd334fa 100644 --- a/aomenc.c +++ b/aomenc.c
@@ -302,6 +302,11 @@ static const arg_def_t superres_kf_numerator = ARG_DEF(NULL, "superres-kf-numerator", 1, "Frame super-resolution keyframe numerator"); +static const arg_def_t superres_qthresh = ARG_DEF( + NULL, "superres-qthresh", 1, "Frame super-resolution qindex threshold"); +static const arg_def_t superres_kf_qthresh = + ARG_DEF(NULL, "superres-kf-qthresh", 1, + "Frame super-resolution keyframe qindex threshold"); #endif // CONFIG_FRAME_SUPERRES static const struct arg_enum_list end_usage_enum[] = { { "vbr", AOM_VBR }, { "cbr", AOM_CBR }, @@ -334,6 +339,8 @@ &superres_mode, &superres_numerator, &superres_kf_numerator, + &superres_qthresh, + &superres_kf_qthresh, #endif // CONFIG_FRAME_SUPERRES &end_usage, &target_bitrate, @@ -1055,6 +1062,10 @@ config->cfg.rc_superres_numerator = arg_parse_uint(&arg); } else if (arg_match(&arg, &superres_kf_numerator, argi)) { config->cfg.rc_superres_kf_numerator = arg_parse_uint(&arg); + } else if (arg_match(&arg, &superres_qthresh, argi)) { + config->cfg.rc_superres_qthresh = arg_parse_uint(&arg); + } else if (arg_match(&arg, &superres_kf_qthresh, argi)) { + config->cfg.rc_superres_kf_qthresh = arg_parse_uint(&arg); #endif // CONFIG_FRAME_SUPERRES } else if (arg_match(&arg, &end_usage, argi)) { config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); @@ -1267,6 +1278,8 @@ SHOW(rc_superres_mode); SHOW(rc_superres_numerator); SHOW(rc_superres_kf_numerator); + SHOW(rc_superres_qthresh); + SHOW(rc_superres_kf_qthresh); #endif // CONFIG_FRAME_SUPERRES SHOW(rc_end_usage); SHOW(rc_target_bitrate);
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index 0f5e5f7..fe1c7c2 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -8,7 +8,6 @@ * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ - #include <stdlib.h> #include <string.h> @@ -251,17 +250,19 @@ (MAX_LAG_BUFFERS - 1)); } - RANGE_CHECK_HI(cfg, rc_resize_mode, RESIZE_DYNAMIC); + RANGE_CHECK_HI(cfg, rc_resize_mode, RESIZE_MODES - 1); RANGE_CHECK(cfg, rc_resize_numerator, SCALE_DENOMINATOR / 2, SCALE_DENOMINATOR); RANGE_CHECK(cfg, rc_resize_kf_numerator, SCALE_DENOMINATOR / 2, SCALE_DENOMINATOR); #if CONFIG_FRAME_SUPERRES - RANGE_CHECK_HI(cfg, rc_superres_mode, SUPERRES_DYNAMIC); + RANGE_CHECK_HI(cfg, rc_superres_mode, SUPERRES_MODES - 1); RANGE_CHECK(cfg, rc_superres_numerator, SCALE_DENOMINATOR / 2, SCALE_DENOMINATOR); RANGE_CHECK(cfg, rc_superres_kf_numerator, SCALE_DENOMINATOR / 2, SCALE_DENOMINATOR); + RANGE_CHECK(cfg, rc_superres_qthresh, 1, 63); + RANGE_CHECK(cfg, rc_superres_kf_qthresh, 1, 63); #endif // CONFIG_FRAME_SUPERRES // AV1 does not support a lower bound on the keyframe interval in @@ -513,10 +514,20 @@ oxcf->superres_mode = (SUPERRES_MODE)cfg->rc_superres_mode; oxcf->superres_scale_numerator = (uint8_t)cfg->rc_superres_numerator; oxcf->superres_kf_scale_numerator = (uint8_t)cfg->rc_superres_kf_numerator; + oxcf->superres_qthresh = + extra_cfg->lossless ? 255 + : av1_quantizer_to_qindex(cfg->rc_superres_qthresh); + oxcf->superres_kf_qthresh = + extra_cfg->lossless + ? 255 + : av1_quantizer_to_qindex(cfg->rc_superres_kf_qthresh); if (oxcf->superres_mode == SUPERRES_FIXED && oxcf->superres_scale_numerator == SCALE_DENOMINATOR && oxcf->superres_kf_scale_numerator == SCALE_DENOMINATOR) oxcf->superres_mode = SUPERRES_NONE; + if (oxcf->superres_mode == SUPERRES_QTHRESH && + oxcf->superres_qthresh == 255 && oxcf->superres_kf_qthresh == 255) + oxcf->superres_mode = SUPERRES_NONE; #endif // CONFIG_FRAME_SUPERRES oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz; @@ -1617,6 +1628,8 @@ 0, // rc_superres_mode SCALE_DENOMINATOR, // rc_superres_numerator SCALE_DENOMINATOR, // rc_superres_kf_numerator + 63, // rc_superres_qthresh + 63, // rc_superres_kf_qthresh AOM_VBR, // rc_end_usage { NULL, 0 }, // rc_twopass_stats_in
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c index c878939..357543e 100644 --- a/av1/common/alloccommon.c +++ b/av1/common/alloccommon.c
@@ -19,6 +19,22 @@ #include "av1/common/entropymv.h" #include "av1/common/onyxc_int.h" +int av1_get_MBs(int width, int height) { + const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); + const int aligned_height = ALIGN_POWER_OF_TWO(height, 3); + const int mi_cols = aligned_width >> MI_SIZE_LOG2; + const int mi_rows = aligned_height >> MI_SIZE_LOG2; + +#if CONFIG_CB4X4 + const int mb_cols = (mi_cols + 2) >> 2; + const int mb_rows = (mi_rows + 2) >> 2; +#else + const int mb_cols = (mi_cols + 1) >> 1; + const int mb_rows = (mi_rows + 1) >> 1; +#endif + return mb_rows * mb_cols; +} + void av1_set_mb_mi(AV1_COMMON *cm, int width, int height) { // Ensure that the decoded width and height are both multiples of // 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if
diff --git a/av1/common/alloccommon.h b/av1/common/alloccommon.h index 51863cd..0d420f8 100644 --- a/av1/common/alloccommon.h +++ b/av1/common/alloccommon.h
@@ -37,6 +37,7 @@ void av1_free_state_buffers(struct AV1Common *cm); void av1_set_mb_mi(struct AV1Common *cm, int width, int height); +int av1_get_MBs(int width, int height); void av1_swap_current_and_last_seg_map(struct AV1Common *cm);
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 1176dcb..320a8c2 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -56,6 +56,7 @@ #if CONFIG_LOOP_RESTORATION #include "av1/encoder/pickrst.h" #endif // CONFIG_LOOP_RESTORATION +#include "av1/encoder/random.h" #include "av1/encoder/ratectrl.h" #include "av1/encoder/rd.h" #include "av1/encoder/segmentation.h" @@ -848,7 +849,7 @@ cpi->od_rc.framerate = cpi->framerate; od_enc_rc_resize(&cpi->od_rc); #else - av1_rc_update_framerate(cpi); + av1_rc_update_framerate(cpi, cpi->common.width, cpi->common.height); #endif } @@ -3934,7 +3935,8 @@ &cpi->od_rc, cpi->refresh_golden_frame, cpi->refresh_alt_ref_frame, frame_type, bottom_index, top_index); #else - *q = av1_rc_pick_q_and_bounds(cpi, bottom_index, top_index); + *q = av1_rc_pick_q_and_bounds(cpi, cm->width, cm->height, bottom_index, + top_index); #endif if (!frame_is_intra_only(cm)) { @@ -4076,7 +4078,7 @@ #if !CONFIG_XIPHRC if (cpi->oxcf.pass == 2) { - av1_set_target_rate(cpi); + av1_set_target_rate(cpi, cm->width, cm->height); } #endif @@ -4164,26 +4166,132 @@ set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME); } -static void setup_frame_size(AV1_COMP *cpi) { +static uint8_t calculate_next_resize_scale(const AV1_COMP *cpi) { + // Choose an arbitrary random number + static unsigned int seed = 56789; + const AV1EncoderConfig *oxcf = &cpi->oxcf; + if (oxcf->pass == 1) return SCALE_DENOMINATOR; + uint8_t new_num = SCALE_DENOMINATOR; + + switch (oxcf->resize_mode) { + case RESIZE_NONE: new_num = SCALE_DENOMINATOR; break; + case RESIZE_FIXED: + if (cpi->common.frame_type == KEY_FRAME) + new_num = oxcf->resize_kf_scale_numerator; + else + new_num = oxcf->resize_scale_numerator; + break; + case RESIZE_RANDOM: new_num = lcg_rand16(&seed) % 9 + 8; break; + default: assert(0); + } + return new_num; +} + +#if CONFIG_FRAME_SUPERRES +static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { + // Choose an arbitrary random number + static unsigned int seed = 34567; + const AV1EncoderConfig *oxcf = &cpi->oxcf; + if (oxcf->pass == 1) return SCALE_DENOMINATOR; + uint8_t new_num = SCALE_DENOMINATOR; + int bottom_index, top_index, q, qthresh; + + switch (oxcf->superres_mode) { + case SUPERRES_NONE: new_num = SCALE_DENOMINATOR; break; + case SUPERRES_FIXED: + if (cpi->common.frame_type == KEY_FRAME) + new_num = oxcf->superres_kf_scale_numerator; + else + new_num = oxcf->superres_scale_numerator; + break; + case SUPERRES_RANDOM: new_num = lcg_rand16(&seed) % 9 + 8; break; + case SUPERRES_QTHRESH: + qthresh = (cpi->common.frame_type == KEY_FRAME ? oxcf->superres_kf_qthresh + : oxcf->superres_qthresh); + av1_set_target_rate(cpi, cpi->oxcf.width, cpi->oxcf.height); + q = av1_rc_pick_q_and_bounds(cpi, cpi->oxcf.width, cpi->oxcf.height, + &bottom_index, &top_index); + if (q < qthresh) { + new_num = SCALE_DENOMINATOR; + } else { + new_num = SCALE_DENOMINATOR - 1 - ((q - qthresh) >> 3); + new_num = AOMMAX(SCALE_DENOMINATOR / 2, new_num); + // printf("SUPERRES: q %d, qthresh %d: num %d\n", q, qthresh, new_num); + } + break; + default: assert(0); + } + return new_num; +} + +static int validate_size_scales(RESIZE_MODE resize_mode, + SUPERRES_MODE superres_mode, + size_params_type *rsz) { + if (rsz->resize_num * rsz->superres_num * 2 > + SCALE_DENOMINATOR * SCALE_DENOMINATOR) + return 1; + if (resize_mode != RESIZE_RANDOM && superres_mode == SUPERRES_RANDOM) { + rsz->superres_num = + (SCALE_DENOMINATOR * SCALE_DENOMINATOR + 2 * rsz->resize_num - 1) / + (2 * rsz->resize_num); + } else if (resize_mode == RESIZE_RANDOM && superres_mode != SUPERRES_RANDOM) { + rsz->resize_num = + (SCALE_DENOMINATOR * SCALE_DENOMINATOR + 2 * rsz->superres_num - 1) / + (2 * rsz->superres_num); + } else if (resize_mode == RESIZE_RANDOM && superres_mode == SUPERRES_RANDOM) { + do { + if (rsz->resize_num < rsz->superres_num) + ++rsz->resize_num; + else + ++rsz->superres_num; + } while (rsz->resize_num * rsz->superres_num * 2 <= + SCALE_DENOMINATOR * SCALE_DENOMINATOR); + } else { + return 0; + } + return 1; +} +#endif // CONFIG_FRAME_SUPERRES + +size_params_type av1_calculate_next_size_params(AV1_COMP *cpi) { + const AV1EncoderConfig *oxcf = &cpi->oxcf; + size_params_type rsz = { + SCALE_DENOMINATOR, +#if CONFIG_FRAME_SUPERRES + SCALE_DENOMINATOR +#endif // CONFIG_FRAME_SUPERRES + }; + if (oxcf->pass == 1) return rsz; + rsz.resize_num = calculate_next_resize_scale(cpi); +#if CONFIG_FRAME_SUPERRES + rsz.superres_num = calculate_next_superres_scale(cpi); + if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, &rsz)) + assert(0 && "Invalid scale parameters"); +#endif // CONFIG_FRAME_SUPERRES + return rsz; +} + +static void setup_frame_size_from_params(AV1_COMP *cpi, size_params_type *rsz) { int encode_width = cpi->oxcf.width; int encode_height = cpi->oxcf.height; - - uint8_t resize_num = av1_calculate_next_resize_scale(cpi); - av1_calculate_scaled_size(&encode_width, &encode_height, resize_num); + av1_calculate_scaled_size(&encode_width, &encode_height, rsz->resize_num); #if CONFIG_FRAME_SUPERRES AV1_COMMON *cm = &cpi->common; cm->superres_upscaled_width = encode_width; cm->superres_upscaled_height = encode_height; - cm->superres_scale_numerator = - av1_calculate_next_superres_scale(cpi, encode_width, encode_height); - av1_calculate_scaled_size(&encode_width, &encode_height, - cm->superres_scale_numerator); + cm->superres_scale_numerator = rsz->superres_num; + av1_calculate_scaled_size(&encode_width, &encode_height, rsz->superres_num); #endif // CONFIG_FRAME_SUPERRES - set_frame_size(cpi, encode_width, encode_height); } +static void setup_frame_size(AV1_COMP *cpi) { + size_params_type rsz; + rsz = av1_calculate_next_size_params(cpi); + setup_frame_size_from_params(cpi, &rsz); +} + #if CONFIG_FRAME_SUPERRES static void superres_post_encode(AV1_COMP *cpi) { AV1_COMMON *cm = &cpi->common; @@ -4326,7 +4434,9 @@ aom_clear_system_state(); set_size_independent_vars(cpi); + setup_frame_size(cpi); + assert(cm->width == cpi->scaled_source.y_crop_width); assert(cm->height == cpi->scaled_source.y_crop_height); @@ -4397,14 +4507,14 @@ cpi->source->buf_8bit_valid = 0; #endif + aom_clear_system_state(); + setup_frame_size(cpi); + set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); + do { aom_clear_system_state(); - setup_frame_size(cpi); - if (loop_count == 0) { - set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); - // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed. set_mv_search_params(cpi); @@ -4572,20 +4682,22 @@ if (undershoot_seen || loop_at_this_size > 1) { // Update rate_correction_factor unless - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = (q_high + q_low + 1) / 2; } else { // Update rate_correction_factor unless - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - AOMMAX(q_high, top_index)); + AOMMAX(q_high, top_index), cm->width, + cm->height); while (q < q_low && retries < 10) { - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - AOMMAX(q_high, top_index)); + AOMMAX(q_high, top_index), cm->width, + cm->height); retries++; } } @@ -4596,12 +4708,12 @@ q_high = q > q_low ? q - 1 : q_low; if (overshoot_seen || loop_at_this_size > 1) { - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = (q_high + q_low) / 2; } else { - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - top_index); + top_index, cm->width, cm->height); // 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 @@ -4611,9 +4723,9 @@ } while (q > q_high && retries < 10) { - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - top_index); + top_index, cm->width, cm->height); retries++; } } @@ -5004,7 +5116,7 @@ // Since we allocate a spot for the OVERLAY frame in the gf group, we need // to do post-encoding update accordingly. if (cpi->rc.is_src_frame_alt_ref) { - av1_set_target_rate(cpi); + av1_set_target_rate(cpi, cm->width, cm->height); #if CONFIG_XIPHRC frame_type = cm->frame_type == INTER_FRAME ? OD_P_FRAME : OD_I_FRAME; drop_this_frame = od_enc_rc_update_state(
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index b26c241..9fc1f2d 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -134,14 +134,20 @@ #endif typedef enum { RESIZE_NONE = 0, // No frame resizing allowed. - RESIZE_FIXED = 1, // All frames are coded at the specified dimension. - RESIZE_DYNAMIC = 2 // Coded size of each frame is determined by the codec. + RESIZE_FIXED = 1, // All frames are coded at the specified scale. + RESIZE_RANDOM = 2, // All frames are coded at a random scale. + RESIZE_MODES } RESIZE_MODE; #if CONFIG_FRAME_SUPERRES typedef enum { - SUPERRES_NONE = 0, - SUPERRES_FIXED = 1, - SUPERRES_DYNAMIC = 2 + SUPERRES_NONE = 0, // No frame superres allowed + SUPERRES_FIXED = 1, // All frames are coded at the specified scale, + // and super-resolved. + SUPERRES_RANDOM = 2, // All frames are coded at a random scale, + // and super-resolved. + SUPERRES_QTHRESH = 3, // Superres scale for a frame is determined based on + // q_index + SUPERRES_MODES } SUPERRES_MODE; #endif // CONFIG_FRAME_SUPERRES @@ -224,6 +230,8 @@ SUPERRES_MODE superres_mode; uint8_t superres_scale_numerator; uint8_t superres_kf_scale_numerator; + int superres_qthresh; + int superres_kf_qthresh; #endif // CONFIG_FRAME_SUPERRES // Enable feature to reduce the frame quantization every x frames.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index b92befb..a90cb88 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -94,9 +94,11 @@ static int kf_high = 5000; static int kf_low = 400; -double av1_resize_rate_factor(const AV1_COMP *cpi) { - return (double)(cpi->oxcf.width * cpi->oxcf.height) / - (cpi->common.width * cpi->common.height); +// How many times less pixels there are to encode given the current scaling. +// Temporary replacement for rcf_mult and rate_thresh_mult. +static double resize_rate_factor(const AV1_COMP *cpi, int width, int height) { + (void)cpi; + return (double)(cpi->oxcf.width * cpi->oxcf.height) / (width * height); } // Functions to compute the active minq lookup table entries based on a @@ -372,7 +374,8 @@ } } -static double get_rate_correction_factor(const AV1_COMP *cpi) { +static double get_rate_correction_factor(const AV1_COMP *cpi, int width, + int height) { const RATE_CONTROL *const rc = &cpi->rc; double rcf; @@ -390,15 +393,16 @@ else rcf = rc->rate_correction_factors[INTER_NORMAL]; } - rcf *= av1_resize_rate_factor(cpi); + rcf *= resize_rate_factor(cpi, width, height); return fclamp(rcf, MIN_BPB_FACTOR, MAX_BPB_FACTOR); } -static void set_rate_correction_factor(AV1_COMP *cpi, double factor) { +static void set_rate_correction_factor(AV1_COMP *cpi, double factor, int width, + int height) { RATE_CONTROL *const rc = &cpi->rc; // Normalize RCF to account for the size-dependent scaling factor. - factor /= av1_resize_rate_factor(cpi); + factor /= resize_rate_factor(cpi, width, height); factor = fclamp(factor, MIN_BPB_FACTOR, MAX_BPB_FACTOR); @@ -418,11 +422,14 @@ } } -void av1_rc_update_rate_correction_factors(AV1_COMP *cpi) { +void av1_rc_update_rate_correction_factors(AV1_COMP *cpi, int width, + int height) { const AV1_COMMON *const cm = &cpi->common; int correction_factor = 100; - double rate_correction_factor = get_rate_correction_factor(cpi); + double rate_correction_factor = + get_rate_correction_factor(cpi, width, height); double adjustment_limit; + const int MBs = av1_get_MBs(width, height); int projected_size_based_on_q = 0; @@ -440,7 +447,7 @@ av1_cyclic_refresh_estimate_bits_at_q(cpi, rate_correction_factor); } else { projected_size_based_on_q = - av1_estimate_bits_at_q(cpi->common.frame_type, cm->base_qindex, cm->MBs, + av1_estimate_bits_at_q(cpi->common.frame_type, cm->base_qindex, MBs, rate_correction_factor, cm->bit_depth); } // Work out a size correction factor. @@ -486,21 +493,24 @@ rate_correction_factor = MIN_BPB_FACTOR; } - set_rate_correction_factor(cpi, rate_correction_factor); + set_rate_correction_factor(cpi, rate_correction_factor, width, height); } int av1_rc_regulate_q(const AV1_COMP *cpi, int target_bits_per_frame, - int active_best_quality, int active_worst_quality) { + int active_best_quality, int active_worst_quality, + int width, int height) { const AV1_COMMON *const cm = &cpi->common; int q = active_worst_quality; int last_error = INT_MAX; int i, target_bits_per_mb, bits_per_mb_at_this_q; - const double correction_factor = get_rate_correction_factor(cpi); + const int MBs = av1_get_MBs(width, height); + const double correction_factor = + get_rate_correction_factor(cpi, width, height); // Calculate required scaling factor based on target frame size and size of // frame produced using previous Q. target_bits_per_mb = - (int)((uint64_t)target_bits_per_frame << BPER_MB_NORMBITS) / cm->MBs; + (int)((uint64_t)(target_bits_per_frame) << BPER_MB_NORMBITS) / MBs; i = active_best_quality; @@ -651,8 +661,8 @@ return active_worst_quality; } -static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, - int *bottom_index, +static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width, + int height, int *bottom_index, int *top_index) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; @@ -682,7 +692,7 @@ rc, rc->avg_frame_qindex[KEY_FRAME], cm->bit_depth); // Allow somewhat lower kf minq with small image formats. - if ((cm->width * cm->height) <= (352 * 288)) { + if ((width * height) <= (352 * 288)) { q_adj_factor -= 0.25; } @@ -744,7 +754,7 @@ q = rc->last_boosted_qindex; } else { q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality, - active_worst_quality); + active_worst_quality, width, height); if (q > *top_index) { // Special case when we are targeting the max allowed rate if (rc->this_frame_target >= rc->max_frame_bandwidth) @@ -774,8 +784,8 @@ return active_cq_level; } -static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, - int *bottom_index, +static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width, + int height, int *bottom_index, int *top_index) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; @@ -808,7 +818,7 @@ rc, rc->avg_frame_qindex[KEY_FRAME], cm->bit_depth); // Allow somewhat lower kf minq with small image formats. - if ((cm->width * cm->height) <= (352 * 288)) { + if ((width * height) <= (352 * 288)) { q_adj_factor -= 0.25; } @@ -903,7 +913,7 @@ q = rc->last_boosted_qindex; } else { q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality, - active_worst_quality); + active_worst_quality, width, height); if (q > *top_index) { // Special case when we are targeting the max allowed rate if (rc->this_frame_target >= rc->max_frame_bandwidth) @@ -949,7 +959,8 @@ } #define STATIC_MOTION_THRESH 95 -static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int *bottom_index, +static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, + int height, int *bottom_index, int *top_index) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; @@ -996,7 +1007,7 @@ get_kf_active_quality(rc, active_worst_quality, cm->bit_depth); // Allow somewhat lower kf minq with small image formats. - if ((cm->width * cm->height) <= (352 * 288)) { + if ((width * height) <= (352 * 288)) { q_adj_factor -= 0.25; } @@ -1119,7 +1130,7 @@ } } else { q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality, - active_worst_quality); + active_worst_quality, width, height); if (q > active_worst_quality) { // Special case when we are targeting the max allowed rate. if (rc->this_frame_target >= rc->max_frame_bandwidth) @@ -1140,16 +1151,19 @@ return q; } -int av1_rc_pick_q_and_bounds(const AV1_COMP *cpi, int *bottom_index, - int *top_index) { +int av1_rc_pick_q_and_bounds(const AV1_COMP *cpi, int width, int height, + int *bottom_index, int *top_index) { int q; if (cpi->oxcf.pass == 0) { if (cpi->oxcf.rc_mode == AOM_CBR) - q = rc_pick_q_and_bounds_one_pass_cbr(cpi, bottom_index, top_index); + q = rc_pick_q_and_bounds_one_pass_cbr(cpi, width, height, bottom_index, + top_index); else - q = rc_pick_q_and_bounds_one_pass_vbr(cpi, bottom_index, top_index); + q = rc_pick_q_and_bounds_one_pass_vbr(cpi, width, height, bottom_index, + top_index); } else { - q = rc_pick_q_and_bounds_two_pass(cpi, bottom_index, top_index); + q = rc_pick_q_and_bounds_two_pass(cpi, width, height, bottom_index, + top_index); } return q; @@ -1171,7 +1185,8 @@ } } -void av1_rc_set_frame_target(AV1_COMP *cpi, int target) { +static void rc_set_frame_target(AV1_COMP *cpi, int target, int width, + int height) { const AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; @@ -1180,11 +1195,11 @@ // Modify frame size target when down-scaled. if (!av1_frame_unscaled(cm)) rc->this_frame_target = - (int)(rc->this_frame_target * av1_resize_rate_factor(cpi)); + (int)(rc->this_frame_target * resize_rate_factor(cpi, width, height)); // Target rate per SB64 (including partial SB64s. - rc->sb64_target_rate = (int)((int64_t)rc->this_frame_target * 64 * 64) / - (cm->width * cm->height); + rc->sb64_target_rate = + (int)((int64_t)rc->this_frame_target * 64 * 64) / (width * height); } static void update_alt_ref_frame_stats(AV1_COMP *cpi) { @@ -1258,7 +1273,7 @@ rc->projected_frame_size = (int)(bytes_used << 3); // Post encode loop adjustment of Q prediction. - av1_rc_update_rate_correction_factors(cpi); + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); // Keep a record of last Q and ambient average Q. if (cm->frame_type == KEY_FRAME) { @@ -1305,6 +1320,10 @@ // Rolling monitors of whether we are over or underspending used to help // regulate min and Max Q in two pass. + if (!av1_frame_unscaled(cm)) + rc->this_frame_target = + (int)(rc->this_frame_target / + resize_rate_factor(cpi, cm->width, cm->height)); if (cm->frame_type != KEY_FRAME) { rc->rolling_target_bits = ROUND_POWER_OF_TWO( rc->rolling_target_bits * 3 + rc->this_frame_target, 2); @@ -1349,6 +1368,12 @@ rc->frames_since_key++; rc->frames_to_key--; } + // if (cm->current_video_frame == 1 && cm->show_frame) + /* + rc->this_frame_target = + (int)(rc->this_frame_target / resize_rate_factor(cpi, cm->width, + cm->height)); + */ } void av1_rc_postencode_update_drop_frame(AV1_COMP *cpi) { @@ -1423,7 +1448,7 @@ target = calc_iframe_target_size_one_pass_vbr(cpi); else target = calc_pframe_target_size_one_pass_vbr(cpi); - av1_rc_set_frame_target(cpi, target); + rc_set_frame_target(cpi, target, cm->width, cm->height); } static int calc_pframe_target_size_one_pass_cbr(const AV1_COMP *cpi) { @@ -1525,7 +1550,7 @@ else target = calc_pframe_target_size_one_pass_cbr(cpi); - av1_rc_set_frame_target(cpi, target); + rc_set_frame_target(cpi, target, cm->width, cm->height); // TODO(afergs): Decide whether to scale up, down, or not at all } @@ -1610,11 +1635,11 @@ } } -void av1_rc_update_framerate(AV1_COMP *cpi) { - const AV1_COMMON *const cm = &cpi->common; +void av1_rc_update_framerate(AV1_COMP *cpi, int width, int height) { const AV1EncoderConfig *const oxcf = &cpi->oxcf; RATE_CONTROL *const rc = &cpi->rc; int vbr_max_bits; + const int MBs = av1_get_MBs(width, height); rc->avg_frame_bandwidth = (int)(oxcf->target_bandwidth / cpi->framerate); rc->min_frame_bandwidth = @@ -1634,7 +1659,7 @@ (int)(((int64_t)rc->avg_frame_bandwidth * oxcf->two_pass_vbrmax_section) / 100); rc->max_frame_bandwidth = - AOMMAX(AOMMAX((cm->MBs * MAX_MB_RATE), MAXRATE_1080P), vbr_max_bits); + AOMMAX(AOMMAX((MBs * MAX_MB_RATE), MAXRATE_1080P), vbr_max_bits); av1_rc_set_gf_interval_range(cpi, rc); } @@ -1683,68 +1708,12 @@ } } -void av1_set_target_rate(AV1_COMP *cpi) { +void av1_set_target_rate(AV1_COMP *cpi, int width, int height) { RATE_CONTROL *const rc = &cpi->rc; int target_rate = rc->base_frame_target; // Correction to rate target based on prior over or under shoot. if (cpi->oxcf.rc_mode == AOM_VBR || cpi->oxcf.rc_mode == AOM_CQ) vbr_rate_correction(cpi, &target_rate); - av1_rc_set_frame_target(cpi, target_rate); + rc_set_frame_target(cpi, target_rate, width, height); } - -uint8_t av1_calculate_next_resize_scale(const AV1_COMP *cpi) { - static unsigned int seed = 56789; - const AV1EncoderConfig *oxcf = &cpi->oxcf; - if (oxcf->pass == 1) return SCALE_DENOMINATOR; - uint8_t new_num = SCALE_DENOMINATOR; - - switch (oxcf->resize_mode) { - case RESIZE_NONE: new_num = SCALE_DENOMINATOR; break; - case RESIZE_FIXED: - if (cpi->common.frame_type == KEY_FRAME) - new_num = oxcf->resize_kf_scale_numerator; - else - new_num = oxcf->resize_scale_numerator; - break; - case RESIZE_DYNAMIC: - // RESIZE_DYNAMIC: Just random for now. - new_num = lcg_rand16(&seed) % 4 + 13; - break; - default: assert(0); - } - return new_num; -} - -#if CONFIG_FRAME_SUPERRES -// TODO(afergs): Rename av1_rc_update_superres_scale(...)? -uint8_t av1_calculate_next_superres_scale(const AV1_COMP *cpi, int width, - int height) { - static unsigned int seed = 34567; - const AV1EncoderConfig *oxcf = &cpi->oxcf; - if (oxcf->pass == 1) return SCALE_DENOMINATOR; - uint8_t new_num = SCALE_DENOMINATOR; - - switch (oxcf->superres_mode) { - case SUPERRES_NONE: new_num = SCALE_DENOMINATOR; break; - case SUPERRES_FIXED: - if (cpi->common.frame_type == KEY_FRAME) - new_num = oxcf->superres_kf_scale_numerator; - else - new_num = oxcf->superres_scale_numerator; - break; - case SUPERRES_DYNAMIC: - // SUPERRES_DYNAMIC: Just random for now. - new_num = lcg_rand16(&seed) % 9 + 8; - break; - default: assert(0); - } - - // Make sure overall reduction is no more than 1/2 of the source size. - av1_calculate_scaled_size(&width, &height, new_num); - if (width * 2 < oxcf->width || height * 2 < oxcf->height) - new_num = SCALE_DENOMINATOR; - - return new_num; -} -#endif // CONFIG_FRAME_SUPERRES
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h index 4ebdfad..b82d29f 100644 --- a/av1/encoder/ratectrl.h +++ b/av1/encoder/ratectrl.h
@@ -50,6 +50,13 @@ #endif // CONFIG_EXT_REFS typedef struct { + uint8_t resize_num; +#if CONFIG_FRAME_SUPERRES + uint8_t superres_num; +#endif // CONFIG_FRAME_SUPERRES +} size_params_type; + +typedef struct { // Rate targetting variables int base_frame_target; // A baseline frame target before adjustment // for previous under or over shoot. @@ -189,10 +196,6 @@ void av1_rc_get_one_pass_vbr_params(struct AV1_COMP *cpi); void av1_rc_get_one_pass_cbr_params(struct AV1_COMP *cpi); -// How many times less pixels there are to encode given the current scaling. -// Temporary replacement for rcf_mult and rate_thresh_mult. -double av1_resize_rate_factor(const struct AV1_COMP *cpi); - // Post encode update of the rate control parameters based // on bytes used void av1_rc_postencode_update(struct AV1_COMP *cpi, uint64_t bytes_used); @@ -201,7 +204,8 @@ // Updates rate correction factors // Changes only the rate correction factors in the rate control structure. -void av1_rc_update_rate_correction_factors(struct AV1_COMP *cpi); +void av1_rc_update_rate_correction_factors(struct AV1_COMP *cpi, int width, + int height); // Decide if we should drop this frame: For 1-pass CBR. // Changes only the decimation count in the rate control structure @@ -214,12 +218,13 @@ int *frame_over_shoot_limit); // Picks q and q bounds given the target for bits -int av1_rc_pick_q_and_bounds(const struct AV1_COMP *cpi, int *bottom_index, - int *top_index); +int av1_rc_pick_q_and_bounds(const struct AV1_COMP *cpi, int width, int height, + int *bottom_index, int *top_index); // Estimates q to achieve a target bits per frame int av1_rc_regulate_q(const struct AV1_COMP *cpi, int target_bits_per_frame, - int active_best_quality, int active_worst_quality); + int active_best_quality, int active_worst_quality, + int width, int height); // Estimates bits per mb for a given qindex and correction factor. int av1_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex, @@ -247,20 +252,15 @@ int av1_frame_type_qdelta(const struct AV1_COMP *cpi, int rf_level, int q); -void av1_rc_update_framerate(struct AV1_COMP *cpi); +void av1_rc_update_framerate(struct AV1_COMP *cpi, int width, int height); void av1_rc_set_gf_interval_range(const struct AV1_COMP *const cpi, RATE_CONTROL *const rc); -void av1_set_target_rate(struct AV1_COMP *cpi); +void av1_set_target_rate(struct AV1_COMP *cpi, int width, int height); int av1_resize_one_pass_cbr(struct AV1_COMP *cpi); -uint8_t av1_calculate_next_resize_scale(const struct AV1_COMP *cpi); -#if CONFIG_FRAME_SUPERRES -uint8_t av1_calculate_next_superres_scale(const struct AV1_COMP *cpi, int width, - int height); -#endif // CONFIG_FRAME_SUPERRES #ifdef __cplusplus } // extern "C" #endif
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 79e83a5..d31dd32 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -7067,7 +7067,7 @@ if (tlevel < 5) step_param += 2; // prev_mv_sad is not setup for dynamically scaled frames. - if (cpi->oxcf.resize_mode != RESIZE_DYNAMIC) { + if (cpi->oxcf.resize_mode != RESIZE_RANDOM) { 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]) {