diff options
author | Marco <marpan@google.com> | 2016-08-02 17:37:32 -0700 |
---|---|---|
committer | Marco <marpan@google.com> | 2016-10-11 10:13:17 -0700 |
commit | 57c6bf291e41d4e857df621bd3a9d00341a23a02 (patch) | |
tree | 9e9c404af11d007ecf6739106a70ce74caeecb70 /vp9 | |
parent | cdbd89197ec878c9c9fed8876c5c3f436ae8994d (diff) | |
download | libvpx-57c6bf291e41d4e857df621bd3a9d00341a23a02.tar libvpx-57c6bf291e41d4e857df621bd3a9d00341a23a02.tar.gz libvpx-57c6bf291e41d4e857df621bd3a9d00341a23a02.tar.bz2 libvpx-57c6bf291e41d4e857df621bd3a9d00341a23a02.zip |
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
Diffstat (limited to 'vp9')
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 20 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 6 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.h | 3 | ||||
-rw-r--r-- | vp9/encoder/vp9_pickmode.c | 63 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.c | 40 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.h | 1 | ||||
-rw-r--r-- | vp9/encoder/vp9_speed_features.c | 4 |
7 files changed, 110 insertions, 27 deletions
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 335faca82..0c34700fa 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -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); diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 12f02e7c5..d98c4938e 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -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; diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 66e41492b..77eb31cb3 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -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])); diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 76d2611d8..ce9007ac3 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -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 && diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index da1f2c84a..b5cfd5de6 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -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)); diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index 6006e9b05..70aef03ff 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -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; diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index ea8936091..6cbb59fa7 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -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; |