summaryrefslogtreecommitdiff
path: root/vp9
diff options
context:
space:
mode:
authorMarco <marpan@google.com>2016-08-02 17:37:32 -0700
committerMarco <marpan@google.com>2016-10-11 10:13:17 -0700
commit57c6bf291e41d4e857df621bd3a9d00341a23a02 (patch)
tree9e9c404af11d007ecf6739106a70ce74caeecb70 /vp9
parentcdbd89197ec878c9c9fed8876c5c3f436ae8994d (diff)
downloadlibvpx-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.c20
-rw-r--r--vp9/encoder/vp9_encoder.c6
-rw-r--r--vp9/encoder/vp9_encoder.h3
-rw-r--r--vp9/encoder/vp9_pickmode.c63
-rw-r--r--vp9/encoder/vp9_ratectrl.c40
-rw-r--r--vp9/encoder/vp9_ratectrl.h1
-rw-r--r--vp9/encoder/vp9_speed_features.c4
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;