[svc] Initialization of 2nd pass rc for svc two pass rc
authorMinghai Shang <minghai@google.com>
Thu, 27 Mar 2014 22:46:32 +0000 (15:46 -0700)
committerMinghai Shang <minghai@google.com>
Thu, 27 Mar 2014 22:46:32 +0000 (15:46 -0700)
Change-Id: If67ed8721f258883e41bab18f5c456505de68785

vp9/encoder/vp9_firstpass.c
vp9/encoder/vp9_onyx_if.c
vp9/encoder/vp9_svc_layercontext.c
vp9/encoder/vp9_svc_layercontext.h

index 61ca996..8577951 100644 (file)
@@ -257,12 +257,21 @@ static void avg_stats(FIRSTPASS_STATS *section) {
 // harder frames.
 static double calculate_modified_err(const VP9_COMP *cpi,
                                      const FIRSTPASS_STATS *this_frame) {
-  const struct twopass_rc *const twopass = &cpi->twopass;
-  const FIRSTPASS_STATS *const stats = &twopass->total_stats;
-  const double av_err = stats->ssim_weighted_pred_err / stats->count;
-  double modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
-                                           DOUBLE_DIVIDE_CHECK(av_err),
-                                       cpi->oxcf.two_pass_vbrbias / 100.0);
+  const struct twopass_rc *twopass = &cpi->twopass;
+  const FIRSTPASS_STATS *stats;
+  double av_err;
+  double modified_error;
+
+  if (cpi->svc.number_spatial_layers > 1 &&
+      cpi->svc.number_temporal_layers == 1) {
+    twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
+  }
+
+  stats = &twopass->total_stats;
+  av_err = stats->ssim_weighted_pred_err / stats->count;
+  modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
+                   DOUBLE_DIVIDE_CHECK(av_err),
+                   cpi->oxcf.two_pass_vbrbias / 100.0);
 
   return fclamp(modified_error,
                 twopass->modified_error_min, twopass->modified_error_max);
@@ -933,80 +942,108 @@ extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
 void vp9_init_second_pass(VP9_COMP *cpi) {
   FIRSTPASS_STATS this_frame;
   const FIRSTPASS_STATS *start_pos;
-  struct twopass_rc *const twopass = &cpi->twopass;
+  struct twopass_rc *twopass = &cpi->twopass;
   const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const int is_spatial_svc = (cpi->svc.number_spatial_layers > 1) &&
+                             (cpi->svc.number_temporal_layers == 1);
+  int layer = 0;
+  int layer_end = 1;
+  double frame_rate;
+
+  if (is_spatial_svc) {
+    layer_end = cpi->svc.number_spatial_layers;
+  }
 
-  zero_stats(&twopass->total_stats);
-  zero_stats(&twopass->total_left_stats);
+  for (layer = 0; layer < layer_end; ++layer) {
+    if (is_spatial_svc) {
+      twopass = &cpi->svc.layer_context[layer].twopass;
+      cpi->svc.spatial_layer_id = layer;
+    }
+    zero_stats(&twopass->total_stats);
+    zero_stats(&twopass->total_left_stats);
+    twopass->total_stats.spatial_layer_id = layer;
+    twopass->total_left_stats.spatial_layer_id = layer;
+
+    if (!twopass->stats_in_end)
+      continue;
+
+    twopass->total_stats = *twopass->stats_in_end;
+    twopass->total_left_stats = twopass->total_stats;
+
+    frame_rate = 10000000.0 * twopass->total_stats.count /
+                 twopass->total_stats.duration;
+    // Each frame can have a different duration, as the frame rate in the source
+    // isn't guaranteed to be constant. The frame rate prior to the first frame
+    // encoded in the second pass is a guess. However, the sum duration is not.
+    // It is calculated based on the actual durations of all frames from the
+    // first pass.
+    if (layer == 0) {
+      vp9_new_framerate(cpi, frame_rate);
+    }
+    if (is_spatial_svc) {
+      vp9_update_spatial_layer_framerate(cpi, frame_rate);
+      twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+                           cpi->svc.layer_context[layer].target_bandwidth /
+                           10000000.0);
+    } else {
+      twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+                                     oxcf->target_bandwidth / 10000000.0);
+    }
 
-  if (!twopass->stats_in_end)
-    return;
+    cpi->output_framerate = oxcf->framerate;
 
-  twopass->total_stats = *twopass->stats_in_end;
-  twopass->total_left_stats = twopass->total_stats;
-
-  // Each frame can have a different duration, as the frame rate in the source
-  // isn't guaranteed to be constant. The frame rate prior to the first frame
-  // encoded in the second pass is a guess. However, the sum duration is not.
-  // It is calculated based on the actual durations of all frames from the
-  // first pass.
-  vp9_new_framerate(cpi, 10000000.0 * twopass->total_stats.count /
-                        twopass->total_stats.duration);
-
-  cpi->output_framerate = oxcf->framerate;
-  twopass->bits_left = (int64_t)(twopass->total_stats.duration *
-                                 oxcf->target_bandwidth / 10000000.0);
-
-  // Calculate a minimum intra value to be used in determining the IIratio
-  // scores used in the second pass. We have this minimum to make sure
-  // that clips that are static but "low complexity" in the intra domain
-  // are still boosted appropriately for KF/GF/ARF.
-  twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
-  twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
-
-  // This variable monitors how far behind the second ref update is lagging.
-  twopass->sr_update_lag = 1;
-
-  // Scan the first pass file and calculate an average Intra / Inter error score
-  // ratio for the sequence.
-  {
-    double sum_iiratio = 0.0;
-    start_pos = twopass->stats_in;
+    // Calculate a minimum intra value to be used in determining the IIratio
+    // scores used in the second pass. We have this minimum to make sure
+    // that clips that are static but "low complexity" in the intra domain
+    // are still boosted appropriately for KF/GF/ARF.
+    twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+    twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
 
-    while (input_stats(twopass, &this_frame) != EOF) {
-      const double iiratio = this_frame.intra_error /
-                                 DOUBLE_DIVIDE_CHECK(this_frame.coded_error);
-      sum_iiratio += fclamp(iiratio, 1.0, 20.0);
-    }
+    // This variable monitors how far behind the second ref update is lagging.
+    twopass->sr_update_lag = 1;
 
-    twopass->avg_iiratio = sum_iiratio /
-        DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
+    // Scan the first pass file and calculate an average Intra / Inter error
+    // score ratio for the sequence.
+    {
+      double sum_iiratio = 0.0;
+      start_pos = twopass->stats_in;
 
-    reset_fpf_position(twopass, start_pos);
-  }
+      while (input_stats(twopass, &this_frame) != EOF) {
+        const double iiratio = this_frame.intra_error /
+                                   DOUBLE_DIVIDE_CHECK(this_frame.coded_error);
+        sum_iiratio += fclamp(iiratio, 1.0, 20.0);
+      }
 
-  // Scan the first pass file and calculate a modified total error based upon
-  // the bias/power function used to allocate bits.
-  {
-    double av_error = twopass->total_stats.ssim_weighted_pred_err /
-                      DOUBLE_DIVIDE_CHECK(twopass->total_stats.count);
+      twopass->avg_iiratio = sum_iiratio /
+          DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
 
-    start_pos = twopass->stats_in;
+      reset_fpf_position(twopass, start_pos);
+    }
 
-    twopass->modified_error_total = 0.0;
-    twopass->modified_error_min =
-      (av_error * oxcf->two_pass_vbrmin_section) / 100;
-    twopass->modified_error_max =
-      (av_error * oxcf->two_pass_vbrmax_section) / 100;
+    // Scan the first pass file and calculate a modified total error based upon
+    // the bias/power function used to allocate bits.
+    {
+      double av_error = twopass->total_stats.ssim_weighted_pred_err /
+                        DOUBLE_DIVIDE_CHECK(twopass->total_stats.count);
 
-    while (input_stats(twopass, &this_frame) != EOF) {
-      twopass->modified_error_total +=
-          calculate_modified_err(cpi, &this_frame);
-    }
-    twopass->modified_error_left = twopass->modified_error_total;
+      start_pos = twopass->stats_in;
 
-    reset_fpf_position(twopass, start_pos);
+      twopass->modified_error_total = 0.0;
+      twopass->modified_error_min =
+        (av_error * oxcf->two_pass_vbrmin_section) / 100;
+      twopass->modified_error_max =
+        (av_error * oxcf->two_pass_vbrmax_section) / 100;
+
+      while (input_stats(twopass, &this_frame) != EOF) {
+        twopass->modified_error_total +=
+            calculate_modified_err(cpi, &this_frame);
+      }
+      twopass->modified_error_left = twopass->modified_error_total;
+
+      reset_fpf_position(twopass, start_pos);
+    }
   }
+  cpi->svc.spatial_layer_id = 0;
 }
 
 // This function gives an estimate of how badly we believe the prediction
index e30f534..96bd231 100644 (file)
@@ -1228,8 +1228,9 @@ static void init_config(struct VP9_COMP *cpi, VP9_CONFIG *oxcf) {
   // Temporal scalability.
   cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
 
-  if (cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+  if ((cpi->svc.number_temporal_layers > 1 &&
+      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+      (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
     vp9_init_layer_context(cpi);
   }
 
@@ -1387,8 +1388,9 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9_CONFIG *oxcf) {
   }
   update_frame_size(cpi);
 
-  if (cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+  if ((cpi->svc.number_temporal_layers > 1 &&
+      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+      (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
     vp9_update_layer_context_change_config(cpi,
                                            (int)cpi->oxcf.target_bandwidth);
   }
@@ -3527,7 +3529,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
 
   if (cpi->svc.number_temporal_layers > 1 &&
       cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
-    vp9_update_layer_framerate(cpi);
+    vp9_update_temporal_layer_framerate(cpi);
     vp9_restore_layer_context(cpi);
   }
 
index 4ccc2bd..5d80d89 100644 (file)
 void vp9_init_layer_context(VP9_COMP *const cpi) {
   const VP9_CONFIG *const oxcf = &cpi->oxcf;
   int layer;
+  int layer_end;
 
   cpi->svc.spatial_layer_id = 0;
   cpi->svc.temporal_layer_id = 0;
-  for (layer = 0; layer < cpi->svc.number_temporal_layers; ++layer) {
+
+  if (cpi->svc.number_temporal_layers > 1) {
+    layer_end = cpi->svc.number_temporal_layers;
+  } else {
+    layer_end = cpi->svc.number_spatial_layers;
+  }
+
+  for (layer = 0; layer < layer_end; ++layer) {
     LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
     RATE_CONTROL *const lrc = &lc->rc;
 
@@ -36,7 +44,13 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
     lrc->decimation_factor = 0;
     lrc->rate_correction_factor = 1.0;
     lrc->key_frame_rate_correction_factor = 1.0;
-    lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+
+    if (cpi->svc.number_temporal_layers > 1) {
+      lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+    } else {
+      lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
+    }
+
     lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level),
                                     lc->target_bandwidth, 1000);
     lrc->bits_off_target = lrc->buffer_level;
@@ -49,12 +63,24 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
   const VP9_CONFIG *const oxcf = &cpi->oxcf;
   const RATE_CONTROL *const rc = &cpi->rc;
   int layer;
+  int layer_end;
   float bitrate_alloc = 1.0;
 
-  for (layer = 0; layer < cpi->svc.number_temporal_layers; ++layer) {
+  if (cpi->svc.number_temporal_layers > 1) {
+    layer_end = cpi->svc.number_temporal_layers;
+  } else {
+    layer_end = cpi->svc.number_spatial_layers;
+  }
+
+  for (layer = 0; layer < layer_end; ++layer) {
     LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
     RATE_CONTROL *const lrc = &lc->rc;
-    lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+
+    if (cpi->svc.number_temporal_layers > 1) {
+      lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+    } else {
+      lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
+    }
     bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
     // Update buffer-related quantities.
     lc->starting_buffer_level =
@@ -66,7 +92,11 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
     lrc->bits_off_target = MIN(lrc->bits_off_target, lc->maximum_buffer_size);
     lrc->buffer_level = MIN(lrc->buffer_level, lc->maximum_buffer_size);
     // Update framerate-related quantities.
-    lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
+    if (cpi->svc.number_temporal_layers > 1) {
+      lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
+    } else {
+      lc->framerate = oxcf->framerate;
+    }
     lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
     lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
     // Update qp-related quantities.
@@ -79,7 +109,7 @@ static LAYER_CONTEXT *get_temporal_layer_context(SVC *svc) {
   return &svc->layer_context[svc->temporal_layer_id];
 }
 
-void vp9_update_layer_framerate(VP9_COMP *const cpi) {
+void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
   const int layer = cpi->svc.temporal_layer_id;
   const VP9_CONFIG *const oxcf = &cpi->oxcf;
   LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
@@ -102,6 +132,21 @@ void vp9_update_layer_framerate(VP9_COMP *const cpi) {
   }
 }
 
+void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
+  int layer = cpi->svc.spatial_layer_id;
+  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
+  RATE_CONTROL *const lrc = &lc->rc;
+
+  lc->framerate = framerate;
+  lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+  lrc->min_frame_bandwidth = (int)(lrc->av_per_frame_bandwidth *
+                                   oxcf->two_pass_vbrmin_section / 100);
+  lrc->max_frame_bandwidth = (int)(((int64_t)lrc->av_per_frame_bandwidth *
+                                   oxcf->two_pass_vbrmax_section) / 100);
+  lrc->max_gf_interval = 16;
+}
+
 void vp9_restore_layer_context(VP9_COMP *const cpi) {
   LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
   const int old_frame_since_key = cpi->rc.frames_since_key;
index afbbdf0..2cd4e47 100644 (file)
@@ -52,8 +52,12 @@ void vp9_update_layer_context_change_config(struct VP9_COMP *const cpi,
                                             const int target_bandwidth);
 
 // Prior to encoding the frame, update framerate-related quantities
-// for the current layer.
-void vp9_update_layer_framerate(struct VP9_COMP *const cpi);
+// for the current temporal layer.
+void vp9_update_temporal_layer_framerate(struct VP9_COMP *const cpi);
+
+// Update framerate-related quantities for the current spatial layer.
+void vp9_update_spatial_layer_framerate(struct VP9_COMP *const cpi,
+                                        double framerate);
 
 // Prior to encoding the frame, set the layer context, for the current layer
 // to be encoded, to the cpi struct.