shithub: libvpx

Download patch

ref: 57c6bf291e41d4e857df621bd3a9d00341a23a02
parent: cdbd89197ec878c9c9fed8876c5c3f436ae8994d
author: Marco <marpan@google.com>
date: Tue Aug 2 13:37:32 EDT 2016

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

--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -846,7 +846,7 @@
     // 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 @@
       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 @@
     }
   }
 
-  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 @@
     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);
 
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3124,7 +3124,8 @@
   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 @@
       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;
 
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -735,7 +735,8 @@
 }
 
 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]));
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -1080,12 +1080,14 @@
   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 @@
     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,8 +1512,14 @@
     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) {
       continue;
@@ -1515,9 +1527,23 @@
 
     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 @@
         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 @@
          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 &&
--- 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 @@
   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 @@
     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,15 +1440,10 @@
   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) /
@@ -1444,9 +1450,6 @@
                 (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 @@
     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 @@
       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 @@
         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));
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -160,6 +160,7 @@
   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;
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -421,6 +421,10 @@
         (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;