Commit 57c6bf29 authored by Marco's avatar Marco

1 pass vbr: Allow for lookahead alt-ref in real-time mode.

For 1 pass vbr real-time mode:
Allow for the usage of alt-ref frame when non-zero lag-in-frames is used.
Use non-filtered alt-ref, and select usage based on fast scene/content
analysis/detection within the lag of frames.

Positive gains on ytlive set: overall avgPSNR ~3-4%.
Several clips are up between 5-14%, a few clips are neutral/small change.

Current speed decrease is about ~5-10%.

Use the flag USE_ALTREF_FOR_ONE_PASS to enable this feature
(off by default for now).

Change-Id: I802d2bf3d44f9cf01f6d15c76be9c90192314769
parent cdbd8919
......@@ -846,7 +846,7 @@ static int choose_partitioning(VP9_COMP *cpi, const TileInfo *const tile,
// that the temporal reference frame will always be of type LAST_FRAME.
// TODO(marpan): If that assumption is broken, we need to revisit this code.
MODE_INFO *mi = xd->mi[0];
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
const YV12_BUFFER_CONFIG *yv12_g = NULL;
unsigned int y_sad_g, y_sad_thr;
......@@ -871,9 +871,18 @@ static int choose_partitioning(VP9_COMP *cpi, const TileInfo *const tile,
y_sad_g = UINT_MAX;
}
vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
&cm->frame_refs[LAST_FRAME - 1].sf);
mi->ref_frame[0] = LAST_FRAME;
if (cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR &&
cpi->rc.is_src_frame_alt_ref) {
yv12 = get_ref_frame_buffer(cpi, ALTREF_FRAME);
vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
&cm->frame_refs[ALTREF_FRAME - 1].sf);
mi->ref_frame[0] = ALTREF_FRAME;
y_sad_g = UINT_MAX;
} else {
vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
&cm->frame_refs[LAST_FRAME - 1].sf);
mi->ref_frame[0] = LAST_FRAME;
}
mi->ref_frame[1] = NONE;
mi->sb_type = BLOCK_64X64;
mi->mv[0].as_int = 0;
......@@ -1863,7 +1872,7 @@ static void update_state_rt(VP9_COMP *cpi, ThreadData *td,
}
}
if (cm->use_prev_frame_mvs ||
if (cm->use_prev_frame_mvs || !cm->error_resilient_mode ||
(cpi->svc.use_base_mv && cpi->svc.number_spatial_layers > 1 &&
cpi->svc.spatial_layer_id != cpi->svc.number_spatial_layers - 1)) {
MV_REF *const frame_mvs =
......@@ -4048,6 +4057,7 @@ static void encode_frame_internal(VP9_COMP *cpi) {
vp9_zero(x->zcoeff_blk);
if (cm->frame_type != KEY_FRAME && cpi->rc.frames_since_golden == 0 &&
!(cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR) &&
!cpi->use_svc)
cpi->ref_frame_flags &= (~VP9_GOLD_FLAG);
......
......@@ -3124,7 +3124,8 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
if (cpi->oxcf.pass == 0 && cpi->oxcf.mode == REALTIME &&
cpi->oxcf.speed >= 5 && cpi->resize_state == 0 &&
(cpi->oxcf.content == VP9E_CONTENT_SCREEN ||
cpi->oxcf.rc_mode == VPX_VBR))
cpi->oxcf.rc_mode == VPX_VBR) &&
cm->show_frame)
vp9_avg_source_sad(cpi);
// For 1 pass SVC, since only ZEROMV is allowed for upsampled reference
......@@ -4477,7 +4478,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cpi->svc.layer_context[cpi->svc.spatial_layer_id].has_alt_frame = 1;
#endif
if ((oxcf->arnr_max_frames > 0) && (oxcf->arnr_strength > 0)) {
if ((oxcf->mode != REALTIME) && (oxcf->arnr_max_frames > 0) &&
(oxcf->arnr_strength > 0)) {
int bitrate = cpi->rc.avg_frame_bandwidth / 40;
int not_low_bitrate = bitrate > ALT_REF_AQ_LOW_BITRATE_BOUNDARY;
......
......@@ -735,7 +735,8 @@ static INLINE int is_one_pass_cbr_svc(const struct VP9_COMP *const cpi) {
}
static INLINE int is_altref_enabled(const VP9_COMP *const cpi) {
return cpi->oxcf.mode != REALTIME && cpi->oxcf.lag_in_frames > 0 &&
return !(cpi->oxcf.mode == REALTIME && cpi->oxcf.rc_mode == VPX_CBR) &&
cpi->oxcf.lag_in_frames > 0 &&
(cpi->oxcf.enable_auto_arf &&
(!is_two_pass_svc(cpi) ||
cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id]));
......
......@@ -1080,12 +1080,14 @@ typedef struct {
PREDICTION_MODE pred_mode;
} REF_MODE;
#define RT_INTER_MODES 8
#define RT_INTER_MODES 12
static const REF_MODE ref_mode_set[RT_INTER_MODES] = {
{ LAST_FRAME, ZEROMV }, { LAST_FRAME, NEARESTMV },
{ GOLDEN_FRAME, ZEROMV }, { LAST_FRAME, NEARMV },
{ LAST_FRAME, NEWMV }, { GOLDEN_FRAME, NEARESTMV },
{ GOLDEN_FRAME, NEARMV }, { GOLDEN_FRAME, NEWMV }
{ GOLDEN_FRAME, NEARMV }, { GOLDEN_FRAME, NEWMV },
{ ALTREF_FRAME, ZEROMV }, { ALTREF_FRAME, NEARESTMV },
{ ALTREF_FRAME, NEARMV }, { ALTREF_FRAME, NEWMV }
};
static const REF_MODE ref_mode_set_svc[RT_INTER_MODES] = {
{ LAST_FRAME, ZEROMV }, { GOLDEN_FRAME, ZEROMV },
......@@ -1467,6 +1469,10 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
usable_ref_frame = GOLDEN_FRAME;
}
if (cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR &&
(cpi->rc.alt_ref_gf_group || cpi->rc.is_src_frame_alt_ref))
usable_ref_frame = ALTREF_FRAME;
// For svc mode, on spatial_layer_id > 0: if the reference has different scale
// constrain the inter mode to only test zero motion.
if (cpi->use_svc && svc->force_zero_mode_spatial_ref &&
......@@ -1506,7 +1512,13 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
int this_early_term = 0;
PREDICTION_MODE this_mode = ref_mode_set[idx].pred_mode;
if (cpi->use_svc) this_mode = ref_mode_set_svc[idx].pred_mode;
ref_frame = ref_mode_set[idx].ref_frame;
if (cpi->use_svc) {
this_mode = ref_mode_set_svc[idx].pred_mode;
ref_frame = ref_mode_set_svc[idx].ref_frame;
}
if (ref_frame > usable_ref_frame) continue;
if (sf->short_circuit_flat_blocks && x->source_variance == 0 &&
this_mode != NEARESTMV) {
......@@ -1515,9 +1527,23 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
if (!(cpi->sf.inter_mode_mask[bsize] & (1 << this_mode))) continue;
ref_frame = ref_mode_set[idx].ref_frame;
if (cpi->use_svc) {
ref_frame = ref_mode_set_svc[idx].ref_frame;
if (cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR) {
if (cpi->rc.is_src_frame_alt_ref &&
(ref_frame != ALTREF_FRAME ||
frame_mv[this_mode][ref_frame].as_int != 0))
continue;
if (cpi->rc.alt_ref_gf_group &&
cpi->rc.frames_since_golden > (cpi->rc.baseline_gf_interval >> 1) &&
ref_frame == GOLDEN_FRAME &&
frame_mv[this_mode][ref_frame].as_int != 0)
continue;
if (cpi->rc.alt_ref_gf_group &&
cpi->rc.frames_since_golden < (cpi->rc.baseline_gf_interval >> 1) &&
ref_frame == ALTREF_FRAME &&
frame_mv[this_mode][ref_frame].as_int != 0)
continue;
}
if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue;
......@@ -1543,13 +1569,27 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
continue;
}
if (!force_skip_low_temp_var &&
if (sf->reference_masking &&
!(frame_mv[this_mode][ref_frame].as_int == 0 &&
ref_frame == LAST_FRAME)) {
i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME;
if ((cpi->ref_frame_flags & flag_list[i]) && sf->reference_masking)
if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1))
if (usable_ref_frame < ALTREF_FRAME) {
if (!force_skip_low_temp_var) {
i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME;
if ((cpi->ref_frame_flags & flag_list[i]))
if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1))
ref_frame_skip_mask |= (1 << ref_frame);
}
} else if (!cpi->rc.is_src_frame_alt_ref &&
!(frame_mv[this_mode][ref_frame].as_int == 0 &&
ref_frame == ALTREF_FRAME)) {
int ref1 = (ref_frame == GOLDEN_FRAME) ? LAST_FRAME : GOLDEN_FRAME;
int ref2 = (ref_frame == ALTREF_FRAME) ? LAST_FRAME : ALTREF_FRAME;
if (((cpi->ref_frame_flags & flag_list[ref1]) &&
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref1] << 1))) ||
((cpi->ref_frame_flags & flag_list[ref2]) &&
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref2] << 1))))
ref_frame_skip_mask |= (1 << ref_frame);
}
}
if (ref_frame_skip_mask & (1 << ref_frame)) continue;
......@@ -1884,6 +1924,9 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
svc_force_zero_mode[best_ref_frame - 1]);
inter_mode_thresh = (inter_mode_thresh << 1) + inter_mode_thresh;
}
if (cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR &&
cpi->rc.is_src_frame_alt_ref)
perform_intra_pred = 0;
// Perform intra prediction search, if the best SAD is above a certain
// threshold.
if ((!force_skip_low_temp_var || bsize < BLOCK_32X32) && perform_intra_pred &&
......
......@@ -45,6 +45,9 @@
#define FRAME_OVERHEAD_BITS 200
// Use this macro to turn on/off use of alt-refs in one-pass mode.
#define USE_ALTREF_FOR_ONE_PASS 0
#if CONFIG_VP9_HIGHBITDEPTH
#define ASSIGN_MINQ_TABLE(bit_depth, name) \
do { \
......@@ -327,6 +330,7 @@ void vp9_rc_init(const VP9EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) {
rc->prev_avg_source_sad_lag = 0;
rc->high_source_sad = 0;
rc->high_source_sad_lagindex = -1;
rc->alt_ref_gf_group = 0;
rc->fac_active_worst_inter = 150;
rc->fac_active_worst_gf = 100;
rc->force_qpmin = 0;
......@@ -561,6 +565,13 @@ int vp9_rc_regulate_q(const VP9_COMP *cpi, int target_bits_per_frame,
q = clamp(q, VPXMIN(cpi->rc.q_1_frame, cpi->rc.q_2_frame),
VPXMAX(cpi->rc.q_1_frame, cpi->rc.q_2_frame));
}
#if USE_ALTREF_FOR_ONE_PASS
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_VBR &&
cpi->oxcf.lag_in_frames > 0 && cpi->rc.is_src_frame_alt_ref &&
!cpi->rc.alt_ref_gf_group) {
q = VPXMIN(q, (q + cpi->rc.last_boosted_qindex) >> 1);
}
#endif
return q;
}
......@@ -1429,24 +1440,16 @@ void vp9_rc_postencode_update_drop_frame(VP9_COMP *cpi) {
cpi->rc.rc_1_frame = 0;
}
// Use this macro to turn on/off use of alt-refs in one-pass mode.
#define USE_ALTREF_FOR_ONE_PASS 1
static int calc_pframe_target_size_one_pass_vbr(const VP9_COMP *const cpi) {
const RATE_CONTROL *const rc = &cpi->rc;
int target;
const int af_ratio = rc->af_ratio_onepass_vbr;
#if USE_ALTREF_FOR_ONE_PASS
target =
int target =
(!rc->is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))
? (rc->avg_frame_bandwidth * rc->baseline_gf_interval * af_ratio) /
(rc->baseline_gf_interval + af_ratio - 1)
: (rc->avg_frame_bandwidth * rc->baseline_gf_interval) /
(rc->baseline_gf_interval + af_ratio - 1);
#else
target = rc->avg_frame_bandwidth;
#endif
return vp9_rc_clamp_pframe_target_size(cpi, target);
}
......@@ -1526,6 +1529,7 @@ void vp9_rc_get_one_pass_vbr_params(VP9_COMP *cpi) {
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
cpi->refresh_golden_frame = 1;
rc->source_alt_ref_pending = USE_ALTREF_FOR_ONE_PASS;
rc->alt_ref_gf_group = USE_ALTREF_FOR_ONE_PASS;
}
if (cm->frame_type == KEY_FRAME)
target = calc_iframe_target_size_one_pass_vbr(cpi);
......@@ -2135,6 +2139,23 @@ void adjust_gf_boost_lag_one_pass_vbr(VP9_COMP *cpi, uint64_t avg_sad_current) {
rc->af_ratio_onepass_vbr = 5;
rc->gfu_boost = DEFAULT_GF_BOOST >> 2;
}
#if USE_ALTREF_FOR_ONE_PASS
// Don't use alt-ref if there is a scene cut within the group,
// or content is not low.
if ((rc->high_source_sad_lagindex > 0 &&
rc->high_source_sad_lagindex <= rc->frames_till_gf_update_due) ||
(avg_source_sad_lag > 3 * sad_thresh1 >> 3)) {
rc->source_alt_ref_pending = 0;
rc->alt_ref_gf_group = 0;
} else {
rc->source_alt_ref_pending = 1;
rc->alt_ref_gf_group = 1;
// If alt-ref is used for this gf group, limit the interval.
if (rc->baseline_gf_interval > 10 &&
rc->baseline_gf_interval < rc->frames_to_key)
rc->baseline_gf_interval = 10;
}
#endif
target = calc_pframe_target_size_one_pass_vbr(cpi);
vp9_rc_set_frame_target(cpi, target);
}
......@@ -2263,6 +2284,7 @@ void vp9_avg_source_sad(VP9_COMP *cpi) {
cpi->ext_refresh_frame_flags_pending == 0) {
int target;
cpi->refresh_golden_frame = 1;
rc->source_alt_ref_pending = USE_ALTREF_FOR_ONE_PASS;
rc->gfu_boost = DEFAULT_GF_BOOST >> 1;
rc->baseline_gf_interval =
VPXMIN(20, VPXMAX(10, rc->baseline_gf_interval));
......
......@@ -160,6 +160,7 @@ typedef struct {
uint64_t avg_source_sad[MAX_LAG_BUFFERS];
uint64_t prev_avg_source_sad_lag;
int high_source_sad_lagindex;
int alt_ref_gf_group;
int high_source_sad;
int count_last_scene_change;
int avg_frame_low_motion;
......
......@@ -421,6 +421,10 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf, int speed,
(frames_since_key % (sf->last_partitioning_redo_frequency << 1) == 1);
sf->max_delta_qindex = is_keyframe ? 20 : 15;
sf->partition_search_type = REFERENCE_PARTITION;
if (cpi->oxcf.rc_mode == VPX_VBR && cpi->oxcf.lag_in_frames > 0 &&
cpi->rc.is_src_frame_alt_ref) {
sf->partition_search_type = VAR_BASED_PARTITION;
}
sf->use_nonrd_pick_mode = 1;
sf->allow_skip_recode = 0;
sf->inter_mode_mask[BLOCK_32X32] = INTER_NEAREST_NEW_ZERO;
......
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