cpi->mi_ssim_rdmult_scaling_factors = NULL;
#if CONFIG_RATE_CTRL
- free_partition_info(cpi);
+ if (cpi->oxcf.use_simple_encode_api) {
+ free_partition_info(cpi);
+ free_motion_vector_info(cpi);
+ free_fp_motion_vector_info(cpi);
+ free_tpl_stats_info(cpi);
+ }
#endif
vp9_free_ref_frame_buffers(cm->buffer_pool);
vp9_noise_estimate_init(&cpi->noise_estimate, cm->width, cm->height);
}
-static void set_rc_buffer_sizes(RATE_CONTROL *rc,
- const VP9EncoderConfig *oxcf) {
+void vp9_check_reset_rc_flag(VP9_COMP *cpi) {
+ RATE_CONTROL *rc = &cpi->rc;
+
+ if (cpi->common.current_video_frame >
+ (unsigned int)cpi->svc.number_spatial_layers) {
+ if (cpi->use_svc) {
+ vp9_svc_check_reset_layer_rc_flag(cpi);
+ } else {
+ if (rc->avg_frame_bandwidth > (3 * rc->last_avg_frame_bandwidth >> 1) ||
+ rc->avg_frame_bandwidth < (rc->last_avg_frame_bandwidth >> 1)) {
+ rc->rc_1_frame = 0;
+ rc->rc_2_frame = 0;
+ rc->bits_off_target = rc->optimal_buffer_level;
+ rc->buffer_level = rc->optimal_buffer_level;
+ }
+ }
+ }
+}
+
+void vp9_set_rc_buffer_sizes(VP9_COMP *cpi) {
+ RATE_CONTROL *rc = &cpi->rc;
+ const VP9EncoderConfig *oxcf = &cpi->oxcf;
+
const int64_t bandwidth = oxcf->target_bandwidth;
const int64_t starting = oxcf->starting_buffer_level_ms;
const int64_t optimal = oxcf->optimal_buffer_level_ms;
(optimal == 0) ? bandwidth / 8 : optimal * bandwidth / 1000;
rc->maximum_buffer_size =
(maximum == 0) ? bandwidth / 8 : maximum * bandwidth / 1000;
+
+ // Under a configuration change, where maximum_buffer_size may change,
+ // keep buffer level clipped to the maximum allowed buffer size.
+ rc->bits_off_target = VPXMIN(rc->bits_off_target, rc->maximum_buffer_size);
+ rc->buffer_level = VPXMIN(rc->buffer_level, rc->maximum_buffer_size);
}
#if CONFIG_VP9_HIGHBITDEPTH
}
cpi->encode_breakout = cpi->oxcf.encode_breakout;
- set_rc_buffer_sizes(rc, &cpi->oxcf);
-
- // Under a configuration change, where maximum_buffer_size may change,
- // keep buffer level clipped to the maximum allowed buffer size.
- rc->bits_off_target = VPXMIN(rc->bits_off_target, rc->maximum_buffer_size);
- rc->buffer_level = VPXMIN(rc->buffer_level, rc->maximum_buffer_size);
+ vp9_set_rc_buffer_sizes(cpi);
// Set up frame rate and related parameters rate control values.
vp9_new_framerate(cpi, cpi->framerate);
(int)cpi->oxcf.target_bandwidth);
}
- // Check for resetting the rc flags (rc_1_frame, rc_2_frame) if the
- // configuration change has a large change in avg_frame_bandwidth.
- // For SVC check for resetting based on spatial layer average bandwidth.
- // Also reset buffer level to optimal level.
- if (cm->current_video_frame > 0) {
- if (cpi->use_svc) {
- vp9_svc_check_reset_layer_rc_flag(cpi);
- } else {
- if (rc->avg_frame_bandwidth > (3 * rc->last_avg_frame_bandwidth >> 1) ||
- rc->avg_frame_bandwidth < (rc->last_avg_frame_bandwidth >> 1)) {
- rc->rc_1_frame = 0;
- rc->rc_2_frame = 0;
- rc->bits_off_target = rc->optimal_buffer_level;
- rc->buffer_level = rc->optimal_buffer_level;
- }
- }
- }
+ vp9_check_reset_rc_flag(cpi);
cpi->alt_ref_source = NULL;
rc->is_src_frame_alt_ref = 0;
cm, cm->frame_contexts,
(FRAME_CONTEXT *)vpx_calloc(FRAME_CONTEXTS, sizeof(*cm->frame_contexts)));
+ cpi->compute_frame_low_motion_onepass = 1;
cpi->use_svc = 0;
cpi->resize_state = ORIG;
cpi->external_resize = 0;
cpi->frame_info = vp9_get_frame_info(oxcf);
vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
+ vp9_init_rd_parameters(cpi);
- cm->current_video_frame = 0;
+ init_frame_indexes(cm);
cpi->partition_search_skippable_frame = 0;
cpi->tile_data = NULL;
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
+ {
+ vpx_codec_err_t codec_status = vp9_extrc_init(&cpi->ext_ratectrl);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status, "vp9_extrc_init() failed");
+ }
+ }
+
#if !CONFIG_REALTIME_ONLY
if (oxcf->pass == 1) {
vp9_init_first_pass(cpi);
#if CONFIG_RATE_CTRL
encode_command_init(&cpi->encode_command);
- partition_info_init(cpi);
+ if (oxcf->use_simple_encode_api) {
+ partition_info_init(cpi);
+ motion_vector_info_init(cpi);
+ fp_motion_vector_info_init(cpi);
+ tpl_stats_info_init(cpi);
+ }
#endif
return cpi;
}
#endif
+ vp9_extrc_delete(&cpi->ext_ratectrl);
+
vp9_remove_common(cm);
vp9_free_ref_frame_buffers(cm->buffer_pool);
#if CONFIG_VP9_POSTPROC
return;
}
+ if (cpi->loopfilter_ctrl == NO_LOOPFILTER ||
+ (!is_reference_frame && cpi->loopfilter_ctrl == LOOPFILTER_REFERENCE)) {
+ lf->filter_level = 0;
+ vpx_extend_frame_inner_borders(cm->frame_to_show);
+ return;
+ }
+
if (xd->lossless) {
lf->filter_level = 0;
lf->last_filt_level = 0;
cpi->rc.force_max_q = 0;
}
+ if (cpi->use_svc) {
+ cpi->svc.base_qindex[cpi->svc.spatial_layer_id] = *q;
+ }
+
if (!frame_is_intra_only(cm)) {
vp9_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH);
}
}
#endif // !CONFIG_REALTIME_ONLY
- if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR && !cpi->use_svc &&
+ if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR &&
oxcf->resize_mode == RESIZE_DYNAMIC && cpi->resize_pending != 0) {
- oxcf->scaled_frame_width =
- (oxcf->width * cpi->resize_scale_num) / cpi->resize_scale_den;
- oxcf->scaled_frame_height =
- (oxcf->height * cpi->resize_scale_num) / cpi->resize_scale_den;
- // There has been a change in frame size.
- vp9_set_size_literal(cpi, oxcf->scaled_frame_width,
- oxcf->scaled_frame_height);
+ // For SVC scaled width/height will have been set (svc->resize_set=1)
+ // in get_svc_params based on the layer width/height.
+ if (!cpi->use_svc || !cpi->svc.resize_set) {
+ oxcf->scaled_frame_width =
+ (oxcf->width * cpi->resize_scale_num) / cpi->resize_scale_den;
+ oxcf->scaled_frame_height =
+ (oxcf->height * cpi->resize_scale_num) / cpi->resize_scale_den;
+ // There has been a change in frame size.
+ vp9_set_size_literal(cpi, oxcf->scaled_frame_width,
+ oxcf->scaled_frame_height);
+ }
// TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
set_mv_search_params(cpi);
set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME);
}
-#if CONFIG_CONSISTENT_RECODE
+#if CONFIG_CONSISTENT_RECODE || CONFIG_RATE_CTRL
static void save_encode_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
const int tile_cols = 1 << cm->log2_tile_cols;
}
}
}
-#endif
+#endif // CONFIG_CONSISTENT_RECODE || CONFIG_RATE_CTRL
static INLINE void set_raw_source_frame(VP9_COMP *cpi) {
#ifdef ENABLE_KF_DENOISE
// For 1 pass CBR SVC, only ZEROMV is allowed for spatial reference frame
// when svc->force_zero_mode_spatial_ref = 1. Under those conditions we can
// avoid this frame-level upsampling (for non intra_only frames).
+ // For SVC single_layer mode, dynamic resize is allowed and we need to
+ // scale references for this case.
if (frame_is_intra_only(cm) == 0 &&
- !(is_one_pass_cbr_svc(cpi) && svc->force_zero_mode_spatial_ref)) {
+ ((svc->single_layer_svc && cpi->oxcf.resize_mode == RESIZE_DYNAMIC) ||
+ !(is_one_pass_cbr_svc(cpi) && svc->force_zero_mode_spatial_ref))) {
vp9_scale_references(cpi);
}
// Update some stats from cyclic refresh, and check for golden frame update.
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled &&
- !frame_is_intra_only(cm))
+ !frame_is_intra_only(cm) && cpi->cyclic_refresh->content_mode)
vp9_cyclic_refresh_postencode(cpi);
// Update the skip mb flag probabilities based on the distribution
return 1;
}
+static int get_ref_frame_flags(const VP9_COMP *cpi) {
+ const int *const map = cpi->common.ref_frame_map;
+ const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
+ const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
+ const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
+ int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
+
+ if (gold_is_last) flags &= ~VP9_GOLD_FLAG;
+
+ if (cpi->rc.frames_till_gf_update_due == INT_MAX &&
+ (cpi->svc.number_temporal_layers == 1 &&
+ cpi->svc.number_spatial_layers == 1))
+ flags &= ~VP9_GOLD_FLAG;
+
+ if (alt_is_last) flags &= ~VP9_ALT_FLAG;
+
+ if (gold_is_alt) flags &= ~VP9_ALT_FLAG;
+
+ return flags;
+}
+
#if !CONFIG_REALTIME_ONLY
#define MAX_QSTEP_ADJ 4
static int get_qstep_adj(int rate_excess, int rate_limit) {
return VPXMIN(qstep, MAX_QSTEP_ADJ);
}
-static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size,
- uint8_t *dest) {
+#if CONFIG_RATE_CTRL
+static void init_rq_history(RATE_QINDEX_HISTORY *rq_history) {
+ rq_history->recode_count = 0;
+ rq_history->q_index_high = 255;
+ rq_history->q_index_low = 0;
+}
+
+static void update_rq_history(RATE_QINDEX_HISTORY *rq_history, int target_bits,
+ int actual_bits, int q_index) {
+ rq_history->q_index_history[rq_history->recode_count] = q_index;
+ rq_history->rate_history[rq_history->recode_count] = actual_bits;
+ if (actual_bits <= target_bits) {
+ rq_history->q_index_high = q_index;
+ }
+ if (actual_bits >= target_bits) {
+ rq_history->q_index_low = q_index;
+ }
+ rq_history->recode_count += 1;
+}
+
+static int guess_q_index_from_model(const RATE_QSTEP_MODEL *rq_model,
+ int target_bits) {
+ // The model predicts bits as follows.
+ // target_bits = bias - ratio * log2(q_step)
+ // Given the target_bits, we compute the q_step as follows.
+ double q_step;
+ assert(rq_model->ratio > 0);
+ q_step = pow(2.0, (rq_model->bias - target_bits) / rq_model->ratio);
+ // TODO(angiebird): Make this function support highbitdepth.
+ return vp9_convert_q_to_qindex(q_step, VPX_BITS_8);
+}
+
+static int guess_q_index_linear(int prev_q_index, int target_bits,
+ int actual_bits, int gap) {
+ int q_index = prev_q_index;
+ if (actual_bits < target_bits) {
+ q_index -= gap;
+ q_index = VPXMAX(q_index, 0);
+ } else {
+ q_index += gap;
+ q_index = VPXMIN(q_index, 255);
+ }
+ return q_index;
+}
+
+static double get_bits_percent_diff(int target_bits, int actual_bits) {
+ double diff;
+ target_bits = VPXMAX(target_bits, 1);
+ diff = abs(target_bits - actual_bits) * 1. / target_bits;
+ return diff * 100;
+}
+
+static int rq_model_predict_q_index(const RATE_QSTEP_MODEL *rq_model,
+ const RATE_QINDEX_HISTORY *rq_history,
+ int target_bits) {
+ int q_index = 128;
+ if (rq_history->recode_count > 0) {
+ const int actual_bits =
+ rq_history->rate_history[rq_history->recode_count - 1];
+ const int prev_q_index =
+ rq_history->q_index_history[rq_history->recode_count - 1];
+ const double percent_diff = get_bits_percent_diff(target_bits, actual_bits);
+ if (percent_diff > 50) {
+ // Binary search.
+ // When the actual_bits and target_bits are far apart, binary search
+ // q_index is faster.
+ q_index = (rq_history->q_index_low + rq_history->q_index_high) / 2;
+ } else {
+ if (rq_model->ready) {
+ q_index = guess_q_index_from_model(rq_model, target_bits);
+ } else {
+ // TODO(angiebird): Find a better way to set the gap.
+ q_index =
+ guess_q_index_linear(prev_q_index, target_bits, actual_bits, 20);
+ }
+ }
+ } else {
+ if (rq_model->ready) {
+ q_index = guess_q_index_from_model(rq_model, target_bits);
+ }
+ }
+
+ assert(rq_history->q_index_low <= rq_history->q_index_high);
+ if (q_index <= rq_history->q_index_low) {
+ q_index = rq_history->q_index_low + 1;
+ }
+ if (q_index >= rq_history->q_index_high) {
+ q_index = rq_history->q_index_high - 1;
+ }
+ return q_index;
+}
+
+static void rq_model_update(const RATE_QINDEX_HISTORY *rq_history,
+ int target_bits, RATE_QSTEP_MODEL *rq_model) {
+ const int recode_count = rq_history->recode_count;
+ const double delta = 0.00001;
+ if (recode_count >= 2) {
+ const int q_index1 = rq_history->q_index_history[recode_count - 2];
+ const int q_index2 = rq_history->q_index_history[recode_count - 1];
+ const int r1 = rq_history->rate_history[recode_count - 2];
+ const int r2 = rq_history->rate_history[recode_count - 1];
+ int valid = 0;
+ // lower q_index should yield higher bit rate
+ if (q_index1 < q_index2) {
+ valid = r1 > r2;
+ } else if (q_index1 > q_index2) {
+ valid = r1 < r2;
+ }
+ // Only update the model when the q_index and rate behave normally.
+ if (valid) {
+ // Fit the ratio and bias of rq_model based on last two recode histories.
+ const double s1 = vp9_convert_qindex_to_q(q_index1, VPX_BITS_8);
+ const double s2 = vp9_convert_qindex_to_q(q_index2, VPX_BITS_8);
+ if (fabs(log2(s1) - log2(s2)) > delta) {
+ rq_model->ratio = (r2 - r1) / (log2(s1) - log2(s2));
+ rq_model->bias = r1 + (rq_model->ratio) * log2(s1);
+ if (rq_model->ratio > delta && rq_model->bias > delta) {
+ rq_model->ready = 1;
+ }
+ }
+ }
+ } else if (recode_count == 1) {
+ if (rq_model->ready) {
+ // Update the ratio only when the initial model exists and we only have
+ // one recode history.
+ const int prev_q = rq_history->q_index_history[recode_count - 1];
+ const double prev_q_step = vp9_convert_qindex_to_q(prev_q, VPX_BITS_8);
+ if (fabs(log2(prev_q_step)) > delta) {
+ const int actual_bits = rq_history->rate_history[recode_count - 1];
+ rq_model->ratio =
+ rq_model->ratio + (target_bits - actual_bits) / log2(prev_q_step);
+ }
+ }
+ }
+}
+#endif // CONFIG_RATE_CTRL
+
+static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
+#if CONFIG_RATE_CTRL
+ ,
+ RATE_QINDEX_HISTORY *rq_history
+#endif // CONFIG_RATE_CTRL
+) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
int frame_over_shoot_limit;
int frame_under_shoot_limit;
int q = 0, q_low = 0, q_high = 0;
+ int last_q_attempt = 0;
int enable_acl;
#ifdef AGGRESSIVE_VBR
int qrange_adj = 1;
#endif
+ // A flag which indicates whether we are recoding the current frame
+ // when the current frame size is larger than the max frame size in the
+ // external rate control model.
+ // This flag doesn't have any impact when external rate control is not used.
+ int ext_rc_recode = 0;
+ // Maximal frame size allowed by the external rate control.
+ // case: 0, we ignore the max frame size limit, and encode with the qindex
+ // passed in by the external rate control model.
+ // case: -1, we take VP9's decision for the max frame size.
+ int ext_rc_max_frame_size = 0;
+ const int orig_rc_max_frame_bandwidth = rc->max_frame_bandwidth;
+
+#if CONFIG_RATE_CTRL
+ const FRAME_UPDATE_TYPE update_type =
+ cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index];
+ const ENCODE_FRAME_TYPE frame_type = get_encode_frame_type(update_type);
+ RATE_QSTEP_MODEL *rq_model = &cpi->rq_model[frame_type];
+ init_rq_history(rq_history);
+#endif // CONFIG_RATE_CTRL
+
if (cm->show_existing_frame) {
rc->this_frame_target = 0;
if (is_psnr_calc_enabled(cpi)) set_raw_source_frame(cpi);
#if CONFIG_RATE_CTRL
// TODO(angiebird): This is a hack for making sure the encoder use the
// external_quantize_index exactly. Avoid this kind of hack later.
- if (cpi->encode_command.use_external_quantize_index) {
- q = cpi->encode_command.external_quantize_index;
+ if (cpi->oxcf.use_simple_encode_api) {
+ if (cpi->encode_command.use_external_target_frame_bits) {
+ q = rq_model_predict_q_index(rq_model, rq_history,
+ rc->this_frame_target);
+ }
+ if (cpi->encode_command.use_external_quantize_index) {
+ q = cpi->encode_command.external_quantize_index;
+ }
+ }
+#endif // CONFIG_RATE_CTRL
+ if (cpi->ext_ratectrl.ready && !ext_rc_recode) {
+ vpx_codec_err_t codec_status;
+ const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+ vpx_rc_encodeframe_decision_t encode_frame_decision;
+ FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_group->index];
+ const int ref_frame_flags = get_ref_frame_flags(cpi);
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES];
+ const RefCntBuffer *curr_frame_buf =
+ get_ref_cnt_buffer(cm, cm->new_fb_idx);
+ get_ref_frame_bufs(cpi, ref_frame_bufs);
+ codec_status = vp9_extrc_get_encodeframe_decision(
+ &cpi->ext_ratectrl, curr_frame_buf->frame_index,
+ cm->current_frame_coding_index, gf_group->index, update_type,
+ ref_frame_bufs, ref_frame_flags, &encode_frame_decision);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_get_encodeframe_decision() failed");
+ }
+ q = encode_frame_decision.q_index;
+ ext_rc_max_frame_size = encode_frame_decision.max_frame_size;
}
-#endif
vp9_set_quantizer(cpi, q);
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
}
+ if (cpi->ext_ratectrl.ready) {
+ last_q_attempt = q;
+ // In general, for the external rate control, we take the qindex provided
+ // as input and encode the frame with this qindex faithfully. However,
+ // in some extreme scenarios, the provided qindex leads to a massive
+ // overshoot of frame size. In this case, we fall back to VP9's decision
+ // to pick a new qindex and recode the frame. We return the new qindex
+ // through the API to the external model.
+ if (ext_rc_max_frame_size == 0) {
+ break;
+ } else if (ext_rc_max_frame_size == -1) {
+ if (rc->projected_frame_size < rc->max_frame_bandwidth) {
+ break;
+ }
+ } else {
+ if (rc->projected_frame_size < ext_rc_max_frame_size) {
+ break;
+ }
+ }
+ rc->max_frame_bandwidth = ext_rc_max_frame_size;
+ // If the current frame size exceeds the ext_rc_max_frame_size,
+ // we adjust the worst qindex to meet the frame size constraint.
+ q_high = 255;
+ ext_rc_recode = 1;
+ }
#if CONFIG_RATE_CTRL
- // This part needs to be after save_coding_context() because
- // restore_coding_context will be called in the end of this function.
- // TODO(angiebird): This is a hack for making sure the encoder use the
- // external_quantize_index exactly. Avoid this kind of hack later.
- if (cpi->encode_command.use_external_quantize_index) {
- break;
+ if (cpi->oxcf.use_simple_encode_api) {
+ // This part needs to be after save_coding_context() because
+ // restore_coding_context will be called in the end of this function.
+ // TODO(angiebird): This is a hack for making sure the encoder use the
+ // external_quantize_index exactly. Avoid this kind of hack later.
+ if (cpi->encode_command.use_external_quantize_index) {
+ break;
+ }
+
+ if (cpi->encode_command.use_external_target_frame_bits) {
+ const double percent_diff = get_bits_percent_diff(
+ rc->this_frame_target, rc->projected_frame_size);
+ update_rq_history(rq_history, rc->this_frame_target,
+ rc->projected_frame_size, q);
+ loop_count += 1;
+
+ rq_model_update(rq_history, rc->this_frame_target, rq_model);
+
+ // Check if we hit the target bitrate.
+ if (percent_diff <=
+ cpi->encode_command.target_frame_bits_error_percent ||
+ rq_history->recode_count >= RATE_CTRL_MAX_RECODE_NUM ||
+ rq_history->q_index_low >= rq_history->q_index_high) {
+ break;
+ }
+
+ loop = 1;
+ restore_coding_context(cpi);
+ continue;
+ }
}
-#endif
+#endif // CONFIG_RATE_CTRL
if (oxcf->rc_mode == VPX_Q) {
loop = 0;
rc->projected_frame_size < rc->max_frame_bandwidth)
loop = 0;
+ // Special handling of external max frame size constraint
+ if (ext_rc_recode) {
+ // If the largest q is not able to meet the max frame size limit,
+ // do nothing.
+ if (rc->projected_frame_size > ext_rc_max_frame_size &&
+ last_q_attempt == 255) {
+ break;
+ }
+ // If VP9's q selection leads to a smaller q, we force it to use
+ // a larger q to better approximate the external max frame size
+ // constraint.
+ if (rc->projected_frame_size > ext_rc_max_frame_size &&
+ q <= last_q_attempt) {
+ q = VPXMIN(255, last_q_attempt + 1);
+ }
+ }
+
if (loop) {
++loop_count;
++loop_at_this_size;
if (loop) restore_coding_context(cpi);
} while (loop);
+ rc->max_frame_bandwidth = orig_rc_max_frame_bandwidth;
+
#ifdef AGGRESSIVE_VBR
if (two_pass_first_group_inter(cpi)) {
cpi->twopass.active_worst_quality =
}
#endif // !CONFIG_REALTIME_ONLY
-static int get_ref_frame_flags(const VP9_COMP *cpi) {
- const int *const map = cpi->common.ref_frame_map;
- const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
- const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
- const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
- int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
-
- if (gold_is_last) flags &= ~VP9_GOLD_FLAG;
-
- if (cpi->rc.frames_till_gf_update_due == INT_MAX &&
- (cpi->svc.number_temporal_layers == 1 &&
- cpi->svc.number_spatial_layers == 1))
- flags &= ~VP9_GOLD_FLAG;
-
- if (alt_is_last) flags &= ~VP9_ALT_FLAG;
-
- if (gold_is_alt) flags &= ~VP9_ALT_FLAG;
-
- return flags;
-}
-
static void set_ext_overrides(VP9_COMP *cpi) {
// Overrides the defaults with the externally supplied values with
// vp9_update_reference() and vp9_update_entropy() calls
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
ref_buffer->frame_index =
cm->current_video_frame + gf_group->arf_src_offset[gf_group->index];
+ ref_buffer->frame_coding_index = cm->current_frame_coding_index;
}
}
cpi->norm_wiener_variance = VPXMAX(1, cpi->norm_wiener_variance);
}
-static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size,
- uint8_t *dest,
- unsigned int *frame_flags) {
+#if !CONFIG_REALTIME_ONLY
+static void update_encode_frame_result_basic(
+ FRAME_UPDATE_TYPE update_type, int show_idx, int quantize_index,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
+ encode_frame_result->show_idx = show_idx;
+ encode_frame_result->update_type = update_type;
+ encode_frame_result->quantize_index = quantize_index;
+}
+
+#if CONFIG_RATE_CTRL
+static void yv12_buffer_to_image_buffer(const YV12_BUFFER_CONFIG *yv12_buffer,
+ IMAGE_BUFFER *image_buffer) {
+ const uint8_t *src_buf_ls[3] = { yv12_buffer->y_buffer, yv12_buffer->u_buffer,
+ yv12_buffer->v_buffer };
+ const int src_stride_ls[3] = { yv12_buffer->y_stride, yv12_buffer->uv_stride,
+ yv12_buffer->uv_stride };
+ const int w_ls[3] = { yv12_buffer->y_crop_width, yv12_buffer->uv_crop_width,
+ yv12_buffer->uv_crop_width };
+ const int h_ls[3] = { yv12_buffer->y_crop_height, yv12_buffer->uv_crop_height,
+ yv12_buffer->uv_crop_height };
+ int plane;
+ for (plane = 0; plane < 3; ++plane) {
+ const int src_stride = src_stride_ls[plane];
+ const int w = w_ls[plane];
+ const int h = h_ls[plane];
+ const uint8_t *src_buf = src_buf_ls[plane];
+ uint8_t *dst_buf = image_buffer->plane_buffer[plane];
+ int r;
+ assert(image_buffer->plane_width[plane] == w);
+ assert(image_buffer->plane_height[plane] == h);
+ for (r = 0; r < h; ++r) {
+ memcpy(dst_buf, src_buf, sizeof(*src_buf) * w);
+ src_buf += src_stride;
+ dst_buf += w;
+ }
+ }
+}
+// This function will update extra information specific for simple_encode APIs
+static void update_encode_frame_result_simple_encode(
+ int ref_frame_flags, FRAME_UPDATE_TYPE update_type,
+ const YV12_BUFFER_CONFIG *source_frame, const RefCntBuffer *coded_frame_buf,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int quantize_index,
+ uint32_t bit_depth, uint32_t input_bit_depth, const FRAME_COUNTS *counts,
+ const PARTITION_INFO *partition_info,
+ const MOTION_VECTOR_INFO *motion_vector_info,
+ const TplDepStats *tpl_stats_info,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
+ PSNR_STATS psnr;
+ update_encode_frame_result_basic(update_type, coded_frame_buf->frame_index,
+ quantize_index, encode_frame_result);
+#if CONFIG_VP9_HIGHBITDEPTH
+ vpx_calc_highbd_psnr(source_frame, &coded_frame_buf->buf, &psnr, bit_depth,
+ input_bit_depth);
+#else // CONFIG_VP9_HIGHBITDEPTH
+ (void)bit_depth;
+ (void)input_bit_depth;
+ vpx_calc_psnr(source_frame, &coded_frame_buf->buf, &psnr);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ encode_frame_result->frame_coding_index = coded_frame_buf->frame_coding_index;
+
+ vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
+ encode_frame_result->ref_frame_coding_indexes,
+ encode_frame_result->ref_frame_valid_list);
+
+ encode_frame_result->psnr = psnr.psnr[0];
+ encode_frame_result->sse = psnr.sse[0];
+ encode_frame_result->frame_counts = *counts;
+ encode_frame_result->partition_info = partition_info;
+ encode_frame_result->motion_vector_info = motion_vector_info;
+ encode_frame_result->tpl_stats_info = tpl_stats_info;
+ if (encode_frame_result->coded_frame.allocated) {
+ yv12_buffer_to_image_buffer(&coded_frame_buf->buf,
+ &encode_frame_result->coded_frame);
+ }
+}
+#endif // CONFIG_RATE_CTRL
+#endif // !CONFIG_REALTIME_ONLY
+
+static void encode_frame_to_data_rate(
+ VP9_COMP *cpi, size_t *size, uint8_t *dest, unsigned int *frame_flags,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
struct segmentation *const seg = &cm->seg;
#if CONFIG_CONSISTENT_RECODE
// Backup to ensure consistency between recodes
save_encode_params(cpi);
+#elif CONFIG_RATE_CTRL
+ if (cpi->oxcf.use_simple_encode_api) {
+ save_encode_params(cpi);
+ }
#endif
if (cpi->sf.recode_loop == DISALLOW_RECODE) {
if (!encode_without_recode_loop(cpi, size, dest)) return;
} else {
#if !CONFIG_REALTIME_ONLY
+#if CONFIG_RATE_CTRL
+ encode_with_recode_loop(cpi, size, dest, &encode_frame_result->rq_history);
+#else // CONFIG_RATE_CTRL
encode_with_recode_loop(cpi, size, dest);
-#endif
+#endif // CONFIG_RATE_CTRL
+#endif // !CONFIG_REALTIME_ONLY
}
// TODO(jingning): When using show existing frame mode, we assume that the
// build the bitstream
vp9_pack_bitstream(cpi, dest, size);
+ {
+ const RefCntBuffer *coded_frame_buf =
+ get_ref_cnt_buffer(cm, cm->new_fb_idx);
+ vpx_codec_err_t codec_status = vp9_extrc_update_encodeframe_result(
+ &cpi->ext_ratectrl, (*size) << 3, cpi->Source, &coded_frame_buf->buf,
+ cm->bit_depth, cpi->oxcf.input_bit_depth, cm->base_qindex);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_update_encodeframe_result() failed");
+ }
+ }
+#if CONFIG_REALTIME_ONLY
+ (void)encode_frame_result;
+ assert(encode_frame_result == NULL);
+#else // CONFIG_REALTIME_ONLY
+ if (encode_frame_result != NULL) {
+ const RefCntBuffer *coded_frame_buf =
+ get_ref_cnt_buffer(cm, cm->new_fb_idx);
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES];
+ FRAME_UPDATE_TYPE update_type =
+ cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index];
+ int quantize_index = vp9_get_quantizer(cpi);
+ get_ref_frame_bufs(cpi, ref_frame_bufs);
+ // update_encode_frame_result() depends on twopass.gf_group.index and
+ // cm->new_fb_idx, cpi->Source, cpi->lst_fb_idx, cpi->gld_fb_idx and
+ // cpi->alt_fb_idx are updated for current frame and have
+ // not been updated for the next frame yet.
+ // The update locations are as follows.
+ // 1) twopass.gf_group.index is initialized at define_gf_group by vp9_zero()
+ // for the first frame in the gf_group and is updated for the next frame at
+ // vp9_twopass_postencode_update().
+ // 2) cpi->Source is updated at the beginning of vp9_get_compressed_data()
+ // 3) cm->new_fb_idx is updated at the beginning of
+ // vp9_get_compressed_data() by get_free_fb(cm).
+ // 4) cpi->lst_fb_idx/gld_fb_idx/alt_fb_idx will be updated for the next
+ // frame at vp9_update_reference_frames().
+ // This function needs to be called before vp9_update_reference_frames().
+ // TODO(angiebird): Improve the codebase to make the update of frame
+ // dependent variables more robust.
+
+ update_encode_frame_result_basic(update_type, coded_frame_buf->frame_index,
+ quantize_index, encode_frame_result);
+#if CONFIG_RATE_CTRL
+ if (cpi->oxcf.use_simple_encode_api) {
+ const int ref_frame_flags = get_ref_frame_flags(cpi);
+ update_encode_frame_result_simple_encode(
+ ref_frame_flags,
+ cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
+ cpi->Source, coded_frame_buf, ref_frame_bufs, quantize_index,
+ cm->bit_depth, cpi->oxcf.input_bit_depth, cpi->td.counts,
+ cpi->partition_info, cpi->motion_vector_info, cpi->tpl_stats_info,
+ encode_frame_result);
+ }
+#endif // CONFIG_RATE_CTRL
+ }
+#endif // CONFIG_REALTIME_ONLY
+
if (cpi->rc.use_post_encode_drop && cm->base_qindex < cpi->rc.worst_quality &&
cpi->svc.spatial_layer_id == 0 && post_encode_drop_cbr(cpi, size)) {
restore_coding_context(cpi);
vp9_rc_postencode_update(cpi, *size);
+ if (cpi->compute_frame_low_motion_onepass && oxcf->pass == 0 &&
+ !frame_is_intra_only(cm) &&
+ (!cpi->use_svc ||
+ (cpi->use_svc &&
+ !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame &&
+ cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1))) {
+ vp9_compute_frame_low_motion(cpi);
+ }
+
*size = VPXMAX(1, *size);
#if 0
if (cm->show_frame) {
vp9_swap_mi_and_prev_mi(cm);
- // Don't increment frame counters if this was an altref buffer
- // update not a real frame
- ++cm->current_video_frame;
if (cpi->use_svc) vp9_inc_frame_in_layer(cpi);
}
+ update_frame_indexes(cm, cm->show_frame);
if (cpi->use_svc) {
cpi->svc
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
vp9_rc_get_svc_params(cpi);
- encode_frame_to_data_rate(cpi, size, dest, frame_flags);
+ encode_frame_to_data_rate(cpi, size, dest, frame_flags,
+ /*encode_frame_result = */ NULL);
}
static void Pass0Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
} else {
vp9_rc_get_one_pass_vbr_params(cpi);
}
- encode_frame_to_data_rate(cpi, size, dest, frame_flags);
+ encode_frame_to_data_rate(cpi, size, dest, frame_flags,
+ /*encode_frame_result = */ NULL);
}
#if !CONFIG_REALTIME_ONLY
static void Pass2Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags) {
+ unsigned int *frame_flags,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
+
+ if (cpi->common.current_frame_coding_index == 0) {
+ VP9_COMMON *cm = &cpi->common;
+ const vpx_codec_err_t codec_status = vp9_extrc_send_firstpass_stats(
+ &cpi->ext_ratectrl, &cpi->twopass.first_pass_info);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_send_firstpass_stats() failed");
+ }
+ }
#if CONFIG_MISMATCH_DEBUG
mismatch_move_frame_idx_w();
#endif
- encode_frame_to_data_rate(cpi, size, dest, frame_flags);
+ encode_frame_to_data_rate(cpi, size, dest, frame_flags, encode_frame_result);
}
#endif // !CONFIG_REALTIME_ONLY
}
}
+#if CONFIG_RATE_CTRL
+static void accumulate_frame_tpl_stats(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+ int show_frame_count = 0;
+ int frame_idx;
+ // Accumulate tpl stats for each frame in the current group of picture.
+ for (frame_idx = 1; frame_idx < gf_group->gf_group_size; ++frame_idx) {
+ TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx];
+ TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
+ const int tpl_stride = tpl_frame->stride;
+ int64_t intra_cost_base = 0;
+ int64_t inter_cost_base = 0;
+ int64_t mc_dep_cost_base = 0;
+ int64_t mc_ref_cost_base = 0;
+ int64_t mc_flow_base = 0;
+ int row, col;
+
+ if (!tpl_frame->is_valid) continue;
+
+ for (row = 0; row < cm->mi_rows && tpl_frame->is_valid; ++row) {
+ for (col = 0; col < cm->mi_cols; ++col) {
+ TplDepStats *this_stats = &tpl_stats[row * tpl_stride + col];
+ intra_cost_base += this_stats->intra_cost;
+ inter_cost_base += this_stats->inter_cost;
+ mc_dep_cost_base += this_stats->mc_dep_cost;
+ mc_ref_cost_base += this_stats->mc_ref_cost;
+ mc_flow_base += this_stats->mc_flow;
+ }
+ }
+
+ cpi->tpl_stats_info[show_frame_count].intra_cost = intra_cost_base;
+ cpi->tpl_stats_info[show_frame_count].inter_cost = inter_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_dep_cost = mc_dep_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_ref_cost = mc_ref_cost_base;
+ cpi->tpl_stats_info[show_frame_count].mc_flow = mc_flow_base;
+
+ ++show_frame_count;
+ }
+}
+#endif // CONFIG_RATE_CTRL
+
static void setup_tpl_stats(VP9_COMP *cpi) {
GF_PICTURE gf_picture[MAX_ARF_GOP_SIZE];
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
dump_tpl_stats(cpi, tpl_group_frames, gf_group, gf_picture, cpi->tpl_bsize);
#endif // DUMP_TPL_STATS
#endif // CONFIG_NON_GREEDY_MV
-}
-static void init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
- encode_frame_result->show_idx = -1; // Actual encoding doesn't happen.
-}
-
-#if !CONFIG_REALTIME_ONLY
#if CONFIG_RATE_CTRL
-static void copy_frame_counts(const FRAME_COUNTS *input_counts,
- FRAME_COUNTS *output_counts) {
- int i, j, k, l, m, n;
- for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
- for (j = 0; j < INTRA_MODES; ++j) {
- output_counts->y_mode[i][j] = input_counts->y_mode[i][j];
- }
- }
- for (i = 0; i < INTRA_MODES; ++i) {
- for (j = 0; j < INTRA_MODES; ++j) {
- output_counts->uv_mode[i][j] = input_counts->uv_mode[i][j];
- }
+ if (cpi->oxcf.use_simple_encode_api) {
+ accumulate_frame_tpl_stats(cpi);
}
- for (i = 0; i < PARTITION_CONTEXTS; ++i) {
- for (j = 0; j < PARTITION_TYPES; ++j) {
- output_counts->partition[i][j] = input_counts->partition[i][j];
- }
- }
- for (i = 0; i < TX_SIZES; ++i) {
- for (j = 0; j < PLANE_TYPES; ++j) {
- for (k = 0; k < REF_TYPES; ++k) {
- for (l = 0; l < COEF_BANDS; ++l) {
- for (m = 0; m < COEFF_CONTEXTS; ++m) {
- output_counts->eob_branch[i][j][k][l][m] =
- input_counts->eob_branch[i][j][k][l][m];
- for (n = 0; n < UNCONSTRAINED_NODES + 1; ++n) {
- output_counts->coef[i][j][k][l][m][n] =
- input_counts->coef[i][j][k][l][m][n];
- }
- }
- }
- }
- }
- }
- for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
- for (j = 0; j < SWITCHABLE_FILTERS; ++j) {
- output_counts->switchable_interp[i][j] =
- input_counts->switchable_interp[i][j];
- }
- }
- for (i = 0; i < INTER_MODE_CONTEXTS; ++i) {
- for (j = 0; j < INTER_MODES; ++j) {
- output_counts->inter_mode[i][j] = input_counts->inter_mode[i][j];
- }
- }
- for (i = 0; i < INTRA_INTER_CONTEXTS; ++i) {
- for (j = 0; j < 2; ++j) {
- output_counts->intra_inter[i][j] = input_counts->intra_inter[i][j];
- }
- }
- for (i = 0; i < COMP_INTER_CONTEXTS; ++i) {
- for (j = 0; j < 2; ++j) {
- output_counts->comp_inter[i][j] = input_counts->comp_inter[i][j];
- }
- }
- for (i = 0; i < REF_CONTEXTS; ++i) {
- for (j = 0; j < 2; ++j) {
- for (k = 0; k < 2; ++k) {
- output_counts->single_ref[i][j][k] = input_counts->single_ref[i][j][k];
- }
- }
- }
- for (i = 0; i < REF_CONTEXTS; ++i) {
- for (j = 0; j < 2; ++j) {
- output_counts->comp_ref[i][j] = input_counts->comp_ref[i][j];
- }
- }
- for (i = 0; i < SKIP_CONTEXTS; ++i) {
- for (j = 0; j < 2; ++j) {
- output_counts->skip[i][j] = input_counts->skip[i][j];
- }
- }
- for (i = 0; i < TX_SIZE_CONTEXTS; i++) {
- for (j = 0; j < TX_SIZES; j++) {
- output_counts->tx.p32x32[i][j] = input_counts->tx.p32x32[i][j];
- }
- for (j = 0; j < TX_SIZES - 1; j++) {
- output_counts->tx.p16x16[i][j] = input_counts->tx.p16x16[i][j];
- }
- for (j = 0; j < TX_SIZES - 2; j++) {
- output_counts->tx.p8x8[i][j] = input_counts->tx.p8x8[i][j];
- }
- }
- for (i = 0; i < TX_SIZES; i++) {
- output_counts->tx.tx_totals[i] = input_counts->tx.tx_totals[i];
- }
- for (i = 0; i < MV_JOINTS; i++) {
- output_counts->mv.joints[i] = input_counts->mv.joints[i];
- }
- for (k = 0; k < 2; k++) {
- nmv_component_counts *const comps = &output_counts->mv.comps[k];
- const nmv_component_counts *const comps_t = &input_counts->mv.comps[k];
- for (i = 0; i < 2; i++) {
- comps->sign[i] = comps_t->sign[i];
- comps->class0_hp[i] = comps_t->class0_hp[i];
- comps->hp[i] = comps_t->hp[i];
- }
- for (i = 0; i < MV_CLASSES; i++) {
- comps->classes[i] = comps_t->classes[i];
- }
- for (i = 0; i < CLASS0_SIZE; i++) {
- comps->class0[i] = comps_t->class0[i];
- for (j = 0; j < MV_FP_SIZE; j++) {
- comps->class0_fp[i][j] = comps_t->class0_fp[i][j];
- }
- }
- for (i = 0; i < MV_OFFSET_BITS; i++) {
- for (j = 0; j < 2; j++) {
- comps->bits[i][j] = comps_t->bits[i][j];
- }
+#endif // CONFIG_RATE_CTRL
+}
+
+void vp9_get_ref_frame_info(FRAME_UPDATE_TYPE update_type, int ref_frame_flags,
+ RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES],
+ int *ref_frame_coding_indexes,
+ int *ref_frame_valid_list) {
+ if (update_type != KF_UPDATE) {
+ const VP9_REFFRAME inter_ref_flags[MAX_INTER_REF_FRAMES] = { VP9_LAST_FLAG,
+ VP9_GOLD_FLAG,
+ VP9_ALT_FLAG };
+ int i;
+ for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
+ assert(ref_frame_bufs[i] != NULL);
+ ref_frame_coding_indexes[i] = ref_frame_bufs[i]->frame_coding_index;
+ ref_frame_valid_list[i] = (ref_frame_flags & inter_ref_flags[i]) != 0;
}
- for (i = 0; i < MV_FP_SIZE; i++) {
- comps->fp[i] = comps_t->fp[i];
+ } else {
+ // No reference frame is available when this is a key frame.
+ int i;
+ for (i = 0; i < MAX_INTER_REF_FRAMES; ++i) {
+ ref_frame_coding_indexes[i] = -1;
+ ref_frame_valid_list[i] = 0;
}
}
}
-#endif // CONFIG_RATE_CTRL
-static void update_encode_frame_result(
- int show_idx, FRAME_UPDATE_TYPE update_type,
- const YV12_BUFFER_CONFIG *source_frame,
- const YV12_BUFFER_CONFIG *coded_frame, int quantize_index,
- uint32_t bit_depth, uint32_t input_bit_depth, const FRAME_COUNTS *counts,
- ENCODE_FRAME_RESULT *encode_frame_result) {
+void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
+ encode_frame_result->show_idx = -1; // Actual encoding doesn't happen.
#if CONFIG_RATE_CTRL
- PSNR_STATS psnr;
-#if CONFIG_VP9_HIGHBITDEPTH
- vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
- input_bit_depth);
-#else // CONFIG_VP9_HIGHBITDEPTH
- (void)bit_depth;
- (void)input_bit_depth;
- vpx_calc_psnr(source_frame, coded_frame, &psnr);
-#endif // CONFIG_VP9_HIGHBITDEPTH
- encode_frame_result->psnr = psnr.psnr[0];
- encode_frame_result->sse = psnr.sse[0];
- copy_frame_counts(counts, &encode_frame_result->frame_counts);
-#else // CONFIG_RATE_CTRL
- (void)bit_depth;
- (void)input_bit_depth;
- (void)source_frame;
- (void)coded_frame;
- (void)counts;
+ encode_frame_result->frame_coding_index = -1;
+ vp9_zero(encode_frame_result->coded_frame);
+ encode_frame_result->coded_frame.allocated = 0;
+ init_rq_history(&encode_frame_result->rq_history);
#endif // CONFIG_RATE_CTRL
- encode_frame_result->show_idx = show_idx;
- encode_frame_result->update_type = update_type;
- encode_frame_result->quantize_index = quantize_index;
}
-#endif // !CONFIG_REALTIME_ONLY
int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
size_t *size, uint8_t *dest, int64_t *time_stamp,
int arf_src_index;
const int gf_group_index = cpi->twopass.gf_group.index;
int i;
- init_encode_frame_result(encode_frame_result);
if (is_one_pass_cbr_svc(cpi)) {
vp9_one_pass_cbr_svc_start_layer(cpi);
cm->new_fb_idx = get_free_fb(cm);
if (cm->new_fb_idx == INVALID_IDX) return -1;
-
cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
-
+ // If the frame buffer for current frame is the same as previous frame, MV in
+ // the base layer shouldn't be used as it'll cause data race.
+ if (cpi->svc.spatial_layer_id > 0 && cm->cur_frame == cm->prev_frame) {
+ cpi->svc.use_base_mv = 0;
+ }
// Start with a 0 size frame.
*size = 0;
cpi->td.mb.fp_src_pred = 0;
#if CONFIG_REALTIME_ONLY
+ (void)encode_frame_result;
if (cpi->use_svc) {
SvcEncode(cpi, size, dest, frame_flags);
} else {
cpi->td.mb.inv_txfm_add = lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
vp9_first_pass(cpi, source);
} else if (oxcf->pass == 2 && !cpi->use_svc) {
- Pass2Encode(cpi, size, dest, frame_flags);
- // update_encode_frame_result() depends on twopass.gf_group.index and
- // cm->new_fb_idx and cpi->Source are updated for current properly and have
- // not been updated for the next frame yet.
- // The update locations are as follows.
- // 1) twopass.gf_group.index is initialized at define_gf_group by vp9_zero()
- // for the first frame in the gf_group and is updated for the next frame at
- // vp9_twopass_postencode_update().
- // 2) cpi->Source is updated at the beginning of this function, i.e.
- // vp9_get_compressed_data()
- // 3) cm->new_fb_idx is updated at the beginning of this function by
- // get_free_fb(cm)
- // TODO(angiebird): Improve the codebase to make the update of frame
- // dependent variables more robust.
- update_encode_frame_result(
- source->show_idx,
- cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
- cpi->Source, get_frame_new_buffer(cm), vp9_get_quantizer(cpi),
- cpi->oxcf.input_bit_depth, cm->bit_depth, cpi->td.counts,
- encode_frame_result);
+ Pass2Encode(cpi, size, dest, frame_flags, encode_frame_result);
vp9_twopass_postencode_update(cpi);
} else if (cpi->use_svc) {
SvcEncode(cpi, size, dest, frame_flags);