Commit 0d085ebc authored by Adrian Grange's avatar Adrian Grange

Prepare for dynamic frame resizing in the recode loop

Prepare for the introduction of frame-size change
logic into the recode loop.

Separated the speed dependent features into
separate static and dynamic parts, the latter being
those features that are dependent on the frame size.

Change-Id: Ia693e28c5cf069a1a7bf12e49ecf83e440e1d313
parent 8e112d95
......@@ -1625,7 +1625,8 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
}
}
vp9_set_speed_features(cpi);
vp9_set_speed_features_framesize_independent(cpi);
vp9_set_speed_features_framesize_dependent(cpi);
// Allocate memory to store variances for a frame.
CHECK_MEM_ERROR(cm, cpi->source_diff_var,
......@@ -2309,7 +2310,6 @@ static void scale_and_extend_frame(const YV12_BUFFER_CONFIG *src,
static int recode_loop_test(const VP9_COMP *cpi,
int high_limit, int low_limit,
int q, int maxq, int minq) {
const VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
int force_recode = 0;
......@@ -2323,8 +2323,7 @@ static int recode_loop_test(const VP9_COMP *cpi,
// 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) &&
(cm->frame_type == KEY_FRAME ||
cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))) {
frame_is_kf_gf_arf(cpi))) {
// General over and under shoot tests
if ((rc->projected_frame_size > high_limit && q < maxq) ||
(rc->projected_frame_size < low_limit && q > minq)) {
......@@ -2505,8 +2504,10 @@ static void release_scaled_references(VP9_COMP *cpi) {
const int idx = cpi->scaled_ref_idx[i];
RefCntBuffer *const buf =
idx != INVALID_REF_BUFFER_IDX ? &cm->frame_bufs[idx] : NULL;
if (buf != NULL)
if (buf != NULL) {
--buf->ref_count;
cpi->scaled_ref_idx[i] = INVALID_REF_BUFFER_IDX;
}
}
}
......@@ -2617,13 +2618,27 @@ static void set_mv_search_params(VP9_COMP *cpi) {
}
}
static void set_size_independent_vars(VP9_COMP *cpi) {
vp9_set_speed_features_framesize_independent(cpi);
vp9_set_rd_speed_thresholds(cpi);
vp9_set_rd_speed_thresholds_sub8x8(cpi);
cpi->common.interp_filter = cpi->sf.default_interp_filter;
}
static void set_size_dependent_vars(VP9_COMP *cpi, int *q,
int *bottom_index, int *top_index) {
VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
// Setup variables that depend on the dimensions of the frame.
set_mv_search_params(cpi);
vp9_set_speed_features_framesize_dependent(cpi);
// Decide q and q bounds.
*q = vp9_rc_pick_q_and_bounds(cpi, bottom_index, top_index);
if (!frame_is_intra_only(cm)) {
vp9_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH);
}
// Configure experimental use of segmentation for enhanced coding of
// static regions if indicated.
......@@ -2656,19 +2671,6 @@ static void set_size_dependent_vars(VP9_COMP *cpi, int *q,
vp9_denoise(cpi->Source, cpi->Source, l);
}
#endif // CONFIG_VP9_POSTPROC
vp9_set_speed_features(cpi);
vp9_set_rd_speed_thresholds(cpi);
vp9_set_rd_speed_thresholds_sub8x8(cpi);
// Decide q and q bounds.
*q = vp9_rc_pick_q_and_bounds(cpi, bottom_index, top_index);
if (!frame_is_intra_only(cm)) {
cm->interp_filter = cpi->sf.default_interp_filter;
vp9_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH);
}
}
static void init_motion_estimation(VP9_COMP *cpi) {
......@@ -2681,36 +2683,28 @@ static void init_motion_estimation(VP9_COMP *cpi) {
}
}
extern void vbr_rate_correction(VP9_COMP *cpi,
int * this_frame_target,
const int64_t vbr_bits_off_target);
void set_frame_size(VP9_COMP *cpi) {
int ref_frame;
VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
MACROBLOCKD *const xd = &cpi->mb.e_mbd;
if ((oxcf->pass == 2) &&
(!cpi->use_svc ||
(is_two_pass_svc(cpi) &&
cpi->svc.encode_empty_frame_state != ENCODING))) {
int target_rate = rc->base_frame_target;
if (oxcf->rc_mode == VPX_VBR)
vbr_rate_correction(cpi, &target_rate, rc->vbr_bits_off_target);
vp9_rc_set_frame_target(cpi, target_rate);
}
if (oxcf->pass == 2 &&
cm->current_video_frame == 0 &&
oxcf->allow_spatial_resampling &&
oxcf->resize_mode == RESIZE_FIXED &&
oxcf->rc_mode == VPX_VBR) {
// Internal scaling is triggered on the first frame.
vp9_set_size_literal(cpi, oxcf->scaled_frame_width,
oxcf->scaled_frame_height);
}
if ((oxcf->pass == 2) &&
(!cpi->use_svc ||
(is_two_pass_svc(cpi) &&
cpi->svc.encode_empty_frame_state != ENCODING))) {
vp9_set_target_rate(cpi);
}
// Reset the frame pointers to the current frame size.
vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
......@@ -2748,9 +2742,8 @@ void set_frame_size(VP9_COMP *cpi) {
}
static void encode_without_recode_loop(VP9_COMP *cpi) {
int q;
int bottom_index, top_index; // Dummy.
VP9_COMMON *const cm = &cpi->common;
int q, bottom_index, top_index; // Dummy variables.
vp9_clear_system_state();
......@@ -2763,8 +2756,11 @@ static void encode_without_recode_loop(VP9_COMP *cpi) {
cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source,
&cpi->scaled_last_source);
vp9_scale_references(cpi);
if (frame_is_intra_only(cm) == 0) {
vp9_scale_references(cpi);
}
set_size_independent_vars(cpi);
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
vp9_set_quantizer(cm, q);
......@@ -2792,8 +2788,6 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
uint8_t *dest) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
int q;
int q_low, q_high;
int bottom_index, top_index;
int loop_count = 0;
int loop = 0;
......@@ -2801,31 +2795,42 @@ static void encode_with_recode_loop(VP9_COMP *cpi,
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);
do {
vp9_clear_system_state();
if (loop_count == 0) {
set_frame_size(cpi);
set_frame_size(cpi);
// Decide frame size bounds
vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
&frame_under_shoot_limit,
&frame_over_shoot_limit);
if (loop_count == 0 || frame_size_changed != 0) {
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
q_low = bottom_index;
q_high = top_index;
cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
&cpi->scaled_source);
// TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
set_mv_search_params(cpi);
}
if (cpi->unscaled_last_source != NULL)
cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source,
&cpi->scaled_last_source);
// Decide frame size bounds
vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
&frame_under_shoot_limit,
&frame_over_shoot_limit);
vp9_scale_references(cpi);
cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
&cpi->scaled_source);
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
if (cpi->unscaled_last_source != NULL)
cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source,
&cpi->scaled_last_source);
q_low = bottom_index;
q_high = top_index;
if (frame_is_intra_only(cm) == 0) {
if (loop_count > 0) {
release_scaled_references(cpi);
}
vp9_scale_references(cpi);
}
vp9_set_quantizer(cm, q);
......@@ -3272,7 +3277,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
if (cm->seg.update_map)
update_reference_segmentation_map(cpi);
release_scaled_references(cpi);
if (frame_is_intra_only(cm) == 0) {
release_scaled_references(cpi);
}
vp9_update_reference_frames(cpi);
for (t = TX_4X4; t <= TX_32X32; t++)
......@@ -3744,7 +3751,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cm->frame_contexts[cm->frame_context_idx] = *cm->fc;
// No frame encoded, or frame was dropped, release scaled references.
if (*size == 0) {
if ((*size == 0) && (frame_is_intra_only(cm) == 0)) {
release_scaled_references(cpi);
}
......
......@@ -110,6 +110,11 @@ typedef enum {
AQ_MODE_COUNT // This should always be the last member of the enum
} AQ_MODE;
typedef enum {
RESIZE_NONE = 0, // No frame resizing allowed (except for SVC).
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_TYPE;
typedef struct VP9EncoderConfig {
BITSTREAM_PROFILE profile;
......@@ -165,7 +170,7 @@ typedef struct VP9EncoderConfig {
AQ_MODE aq_mode; // Adaptive Quantization mode
// Internal frame size scaling.
int allow_spatial_resampling;
RESIZE_TYPE resize_mode;
int scaled_frame_width;
int scaled_frame_height;
......@@ -472,6 +477,12 @@ void vp9_set_svc(VP9_COMP *cpi, int use_svc);
int vp9_get_quantizer(struct VP9_COMP *cpi);
static INLINE int frame_is_kf_gf_arf(const VP9_COMP *cpi) {
return frame_is_intra_only(&cpi->common) ||
cpi->refresh_alt_ref_frame ||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
}
static INLINE int get_ref_frame_idx(const VP9_COMP *cpi,
MV_REFERENCE_FRAME ref_frame) {
if (ref_frame == LAST_FRAME) {
......
......@@ -338,9 +338,9 @@ static unsigned int highbd_get_prediction_error(BLOCK_SIZE bsize,
// Refine the motion search range according to the frame dimension
// for first pass test.
static int get_search_range(const VP9_COMMON *cm) {
static int get_search_range(const VP9_COMP *cpi) {
int sr = 0;
const int dim = MIN(cm->width, cm->height);
const int dim = MIN(cpi->initial_width, cpi->initial_height);
while ((dim << sr) < MAX_FULL_PEL_VAL)
++sr;
......@@ -360,7 +360,7 @@ static void first_pass_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
int step_param = 3;
int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param;
const int sr = get_search_range(&cpi->common);
const int sr = get_search_range(cpi);
step_param += sr;
further_steps -= sr;
......@@ -947,7 +947,8 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
// Initial estimate here uses sqrt(mbs) to define the min_err, where the
// number of mbs is proportional to the image area.
const int num_mbs =
cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs;
cpi->oxcf.resize_mode == RESIZE_FIXED ?
cpi->initial_mbs : cpi->common.MBs;
const double min_err = 200 * sqrt(num_mbs);
intra_factor = intra_factor / (double)num_mbs;
......@@ -1088,7 +1089,8 @@ static int get_twopass_worst_quality(const VP9_COMP *cpi,
return rc->worst_quality; // Highest value allowed
} else {
const int num_mbs =
cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs;
cpi->oxcf.resize_mode == RESIZE_FIXED ?
cpi->initial_mbs : cpi->common.MBs;
const double section_err = stats->coded_error / stats->count;
const double err_per_mb = section_err / num_mbs;
const double speed_term = 1.0 + 0.04 * oxcf->speed;
......@@ -1206,7 +1208,8 @@ void vp9_init_second_pass(VP9_COMP *cpi) {
static double get_sr_decay_rate(const VP9_COMP *cpi,
const FIRSTPASS_STATS *frame) {
const int num_mbs =
cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs;
cpi->oxcf.resize_mode == RESIZE_FIXED ?
cpi->initial_mbs : cpi->common.MBs;
double sr_diff =
(frame->sr_coded_error - frame->coded_error) / num_mbs;
double sr_decay = 1.0;
......@@ -1333,7 +1336,8 @@ static double calc_frame_boost(VP9_COMP *cpi,
cpi->common.bit_depth);
const double boost_q_correction = MIN((0.5 + (lq * 0.015)), 1.5);
const int num_mbs =
cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs;
cpi->oxcf.resize_mode == RESIZE_FIXED ?
cpi->initial_mbs : cpi->common.MBs;
// Underlying boost factor is based on inter error ratio.
frame_boost = (BASELINE_ERR_PER_MB * num_mbs) /
......@@ -1744,7 +1748,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// Motion breakout threshold for loop below depends on image size.
mv_ratio_accumulator_thresh =
(cpi->common.height + cpi->common.width) / 4.0;
(cpi->initial_height + cpi->initial_width) / 4.0;
// Set a maximum and minimum interval for the GF group.
// If the image appears almost completely static we can extend beyond this.
......@@ -1802,8 +1806,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// Monitor for static sections.
zero_motion_accumulator =
MIN(zero_motion_accumulator,
get_zero_motion_factor(cpi, &next_frame));
MIN(zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame));
// Break clause to detect very still sections after motion. For example,
// a static image after a fade or other transition.
......@@ -2237,36 +2240,6 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
twopass->modified_error_left -= kf_group_err;
}
#define VBR_PCT_ADJUSTMENT_LIMIT 50
// For VBR...adjustment to the frame target based on error from previous frames
void vbr_rate_correction(VP9_COMP *cpi,
int * this_frame_target,
const int64_t vbr_bits_off_target) {
int max_delta;
double position_factor = 1.0;
// How far through the clip are we.
// This number is used to damp the per frame rate correction.
// Range 0 - 1.0
if (cpi->twopass.total_stats.count) {
position_factor = sqrt((double)cpi->common.current_video_frame /
cpi->twopass.total_stats.count);
}
max_delta = (int)(position_factor *
((*this_frame_target * VBR_PCT_ADJUSTMENT_LIMIT) / 100));
// vbr_bits_off_target > 0 means we have extra bits to spend
if (vbr_bits_off_target > 0) {
*this_frame_target +=
(vbr_bits_off_target > max_delta) ? max_delta
: (int)vbr_bits_off_target;
} else {
*this_frame_target -=
(vbr_bits_off_target < -max_delta) ? max_delta
: (int)-vbr_bits_off_target;
}
}
// Define the reference buffers that will be updated post encode.
void configure_buffer_updates(VP9_COMP *cpi) {
TWO_PASS *const twopass = &cpi->twopass;
......
......@@ -1575,3 +1575,43 @@ void vp9_rc_update_framerate(VP9_COMP *cpi) {
vp9_rc_set_gf_max_interval(cpi, rc);
}
#define VBR_PCT_ADJUSTMENT_LIMIT 50
// For VBR...adjustment to the frame target based on error from previous frames
static void vbr_rate_correction(VP9_COMP *cpi,
int *this_frame_target,
int64_t vbr_bits_off_target) {
int max_delta;
double position_factor = 1.0;
// How far through the clip are we.
// This number is used to damp the per frame rate correction.
// Range 0 - 1.0
if (cpi->twopass.total_stats.count) {
position_factor = sqrt((double)cpi->common.current_video_frame /
cpi->twopass.total_stats.count);
}
max_delta = (int)(position_factor *
((*this_frame_target * VBR_PCT_ADJUSTMENT_LIMIT) / 100));
// vbr_bits_off_target > 0 means we have extra bits to spend
if (vbr_bits_off_target > 0) {
*this_frame_target +=
(vbr_bits_off_target > max_delta) ? max_delta
: (int)vbr_bits_off_target;
} else {
*this_frame_target -=
(vbr_bits_off_target < -max_delta) ? max_delta
: (int)-vbr_bits_off_target;
}
}
void vp9_set_target_rate(VP9_COMP *cpi) {
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 == VPX_VBR)
vbr_rate_correction(cpi, &target_rate, rc->vbr_bits_off_target);
vp9_rc_set_frame_target(cpi, target_rate);
}
......@@ -198,6 +198,8 @@ void vp9_rc_update_framerate(struct VP9_COMP *cpi);
void vp9_rc_set_gf_max_interval(const struct VP9_COMP *const cpi,
RATE_CONTROL *const rc);
void vp9_set_target_rate(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -591,18 +591,13 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
}
void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
const SPEED_FEATURES *const sf = &cpi->sf;
RD_OPT *const rd = &cpi->rd;
int i;
static const int thresh_mult[2][MAX_REFS] =
{{2500, 2500, 2500, 4500, 4500, 2500},
{2000, 2000, 2000, 4000, 4000, 2000}};
for (i = 0; i < MAX_REFS; ++i) {
rd->thresh_mult_sub8x8[i] =
(sf->disable_split_mask & (1 << i)) ?
INT_MAX : thresh_mult[cpi->oxcf.mode == BEST][i];
}
RD_OPT *const rd = &cpi->rd;
const int idx = cpi->oxcf.mode == BEST;
vpx_memcpy(rd->thresh_mult_sub8x8, thresh_mult[idx],
sizeof(thresh_mult[idx]));
}
void vp9_update_rd_thresh_fact(int (*factor_buf)[MAX_MODES], int rd_thresh,
......
This diff is collapsed.
......@@ -416,7 +416,8 @@ typedef struct SPEED_FEATURES {
struct VP9_COMP;
void vp9_set_speed_features(struct VP9_COMP *cpi);
void vp9_set_speed_features_framesize_independent(struct VP9_COMP *cpi);
void vp9_set_speed_features_framesize_dependent(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
......
......@@ -163,8 +163,8 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);
if (cfg->rc_resize_allowed == 1) {
RANGE_CHECK(cfg, rc_scaled_width, 1, cfg->g_w);
RANGE_CHECK(cfg, rc_scaled_height, 1, cfg->g_h);
RANGE_CHECK(cfg, rc_scaled_width, 0, cfg->g_w);
RANGE_CHECK(cfg, rc_scaled_height, 0, cfg->g_h);
}
RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
......@@ -398,9 +398,15 @@ static vpx_codec_err_t set_encoder_config(
oxcf->under_shoot_pct = cfg->rc_undershoot_pct;
oxcf->over_shoot_pct = cfg->rc_overshoot_pct;
oxcf->allow_spatial_resampling = cfg->rc_resize_allowed;
oxcf->scaled_frame_width = cfg->rc_scaled_width;
oxcf->scaled_frame_height = cfg->rc_scaled_height;
oxcf->scaled_frame_width = cfg->rc_scaled_width;
oxcf->scaled_frame_height = cfg->rc_scaled_height;
if (cfg->rc_resize_allowed == 1) {
oxcf->resize_mode =
(oxcf->scaled_frame_width == 0 || oxcf->scaled_frame_height == 0) ?
RESIZE_DYNAMIC : RESIZE_FIXED;
} else {
oxcf->resize_mode = RESIZE_NONE;
}
oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz;
oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
......@@ -1383,8 +1389,8 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
0, // rc_dropframe_thresh
0, // rc_resize_allowed
1, // rc_scaled_width
1, // rc_scaled_height
0, // rc_scaled_width
0, // rc_scaled_height
60, // rc_resize_down_thresold
30, // rc_resize_up_thresold
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment