[svc] Finalize first version of 2nd pass rc
authorMinghai Shang <minghai@google.com>
Thu, 27 Mar 2014 23:59:44 +0000 (16:59 -0700)
committerMinghai Shang <minghai@google.com>
Fri, 28 Mar 2014 20:38:02 +0000 (13:38 -0700)
Change-Id: I366850015004644c4fc7feabe27a782fdd8d8718

test/svc_test.cc
vp9/encoder/vp9_firstpass.c
vp9/encoder/vp9_onyx_if.c
vp9/encoder/vp9_ratectrl.c
vp9/encoder/vp9_svc_layercontext.c
vp9/encoder/vp9_svc_layercontext.h

index 30508df..fb9277b 100644 (file)
@@ -419,9 +419,52 @@ TEST_F(SvcTest, SecondPassEncode) {
   fclose(stats_file);
   codec_enc_.rc_twopass_stats_in = stats_buf;
 
-  const vpx_codec_err_t res =
+  vpx_codec_err_t res =
       vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
   ASSERT_EQ(VPX_CODEC_OK, res);
+  codec_initialized_ = true;
+
+  libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
+                                     codec_enc_.g_timebase.den,
+                                     codec_enc_.g_timebase.num, 0, 30);
+  // FRAME 0
+  video.Begin();
+  // This frame is a keyframe.
+  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
+                       video.duration(), VPX_DL_GOOD_QUALITY);
+  ASSERT_EQ(VPX_CODEC_OK, res);
+  EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
+
+  vpx_codec_err_t res_dec = decoder_->DecodeFrame(
+      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
+      vpx_svc_get_frame_size(&svc_));
+  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
+
+  // FRAME 1
+  video.Next();
+  // This is a P-frame.
+  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
+                       video.duration(), VPX_DL_GOOD_QUALITY);
+  ASSERT_EQ(VPX_CODEC_OK, res);
+  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
+
+  res_dec = decoder_->DecodeFrame(
+      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
+      vpx_svc_get_frame_size(&svc_));
+  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
+
+  // FRAME 2
+  video.Next();
+  // This is a P-frame.
+  res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
+                       video.duration(), VPX_DL_GOOD_QUALITY);
+  ASSERT_EQ(VPX_CODEC_OK, res);
+  EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
+
+  res_dec = decoder_->DecodeFrame(
+      static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
+      vpx_svc_get_frame_size(&svc_));
+  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
 
   free(stats_buf.buf);
 }
index 8577951..6d36b7c 100644 (file)
@@ -946,104 +946,97 @@ void vp9_init_second_pass(VP9_COMP *cpi) {
   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;
+    twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
   }
 
-  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);
-    }
+  zero_stats(&twopass->total_stats);
+  zero_stats(&twopass->total_left_stats);
 
-    cpi->output_framerate = oxcf->framerate;
+  if (!twopass->stats_in_end)
+    return;
 
-    // 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;
+  twopass->total_stats = *twopass->stats_in_end;
+  twopass->total_left_stats = twopass->total_stats;
 
-    // This variable monitors how far behind the second ref update is lagging.
-    twopass->sr_update_lag = 1;
+  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.
 
-    // 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;
+  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[cpi->svc.spatial_layer_id].target_bandwidth /
+        10000000.0);
+  } else {
+    vp9_new_framerate(cpi, frame_rate);
+    twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+                                   oxcf->target_bandwidth / 10000000.0);
+  }
 
-      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);
-      }
+  cpi->output_framerate = oxcf->framerate;
 
-      twopass->avg_iiratio = sum_iiratio /
-          DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
+  // 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.
+  if (!is_spatial_svc) {
+    // We don't know the number of MBs for each layer at this point.
+    // So we will do it later.
+    twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+    twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+  }
 
-      reset_fpf_position(twopass, start_pos);
+  // 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;
+
+    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
@@ -1652,8 +1645,8 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
 
   // Calculate the bits to be allocated to the group as a whole.
   if (twopass->kf_group_bits > 0 && twopass->kf_group_error_left > 0) {
-    twopass->gf_group_bits = (int64_t)(cpi->twopass.kf_group_bits *
-                (gf_group_err / cpi->twopass.kf_group_error_left));
+    twopass->gf_group_bits = (int64_t)(twopass->kf_group_bits *
+                (gf_group_err / twopass->kf_group_error_left));
   } else {
     twopass->gf_group_bits = 0;
   }
@@ -2224,14 +2217,24 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
   struct twopass_rc *const twopass = &cpi->twopass;
-  const int frames_left = (int)(twopass->total_stats.count -
-                              cm->current_video_frame);
+  int frames_left;
   FIRSTPASS_STATS this_frame;
   FIRSTPASS_STATS this_frame_copy;
 
   double this_frame_intra_error;
   double this_frame_coded_error;
   int target;
+  LAYER_CONTEXT *lc = NULL;
+  int is_spatial_svc = (cpi->use_svc && cpi->svc.number_temporal_layers == 1);
+
+  if (is_spatial_svc) {
+    lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
+    frames_left = (int)(twopass->total_stats.count -
+                  lc->current_video_frame_in_layer);
+  } else {
+    frames_left = (int)(twopass->total_stats.count -
+                  cm->current_video_frame);
+  }
 
   if (!twopass->stats_in)
     return;
@@ -2244,9 +2247,15 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
 
   vp9_clear_system_state();
 
+  if (is_spatial_svc && twopass->kf_intra_err_min == 0) {
+    twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+    twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+  }
+
   if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
     twopass->active_worst_quality = cpi->oxcf.cq_level;
-  } else if (cm->current_video_frame == 0) {
+  } else if (cm->current_video_frame == 0 ||
+             (is_spatial_svc && lc->current_video_frame_in_layer == 0)) {
     // Special case code for first frame.
     const int section_target_bandwidth = (int)(twopass->bits_left /
                                                frames_left);
@@ -2269,6 +2278,11 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
     // Define next KF group and assign bits to it.
     this_frame_copy = this_frame;
     find_next_key_frame(cpi, &this_frame_copy);
+    // Don't place key frame in any enhancement layers in spatial svc
+    if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
+        cpi->svc.spatial_layer_id > 0) {
+      cm->frame_type = INTER_FRAME;
+    }
   } else {
     cm->frame_type = INTER_FRAME;
   }
index 96bd231..e5958db 100644 (file)
@@ -1230,7 +1230,8 @@ static void init_config(struct VP9_COMP *cpi, VP9_CONFIG *oxcf) {
 
   if ((cpi->svc.number_temporal_layers > 1 &&
       cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
-      (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
+      (cpi->svc.number_spatial_layers > 1 &&
+      cpi->oxcf.mode == MODE_SECONDPASS_BEST)) {
     vp9_init_layer_context(cpi);
   }
 
@@ -1795,13 +1796,15 @@ VP9_COMP *vp9_create_compressor(VP9_CONFIG *oxcf) {
           ++stats_copy[layer_id];
         }
       }
+
+      vp9_init_second_pass_spatial_svc(cpi);
     } else {
       cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf;
       cpi->twopass.stats_in = cpi->twopass.stats_in_start;
       cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1];
-    }
 
-    vp9_init_second_pass(cpi);
+      vp9_init_second_pass(cpi);
+    }
   }
 
   vp9_set_speed_features(cpi);
@@ -3242,6 +3245,15 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
     // Don't increment frame counters if this was an altref buffer
     // update not a real frame
     ++cm->current_video_frame;
+    if (cpi->use_svc) {
+      LAYER_CONTEXT *lc;
+      if (cpi->svc.number_temporal_layers > 1) {
+        lc = &cpi->svc.layer_context[cpi->svc.temporal_layer_id];
+      } else {
+        lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
+      }
+      ++lc->current_video_frame_in_layer;
+    }
   }
 
   // restore prev_mi
@@ -3397,6 +3409,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
   if (!cpi)
     return -1;
 
+  if (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2) {
+    vp9_restore_layer_context(cpi);
+  }
+
   vpx_usec_timer_start(&cmptimer);
 
   cpi->source = NULL;
@@ -3589,7 +3605,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
   if (cpi->pass == 1 &&
       (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
     Pass1Encode(cpi, size, dest, frame_flags);
-  } else if (cpi->pass == 2 && !cpi->use_svc) {
+  } else if (cpi->pass == 2 &&
+      (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
     Pass2Encode(cpi, size, dest, frame_flags);
   } else if (cpi->use_svc) {
     SvcEncode(cpi, size, dest, frame_flags);
@@ -3611,8 +3628,9 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
   }
 
   // Save layer specific state.
-  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_save_layer_context(cpi);
   }
 
index dd8a641..c62d312 100644 (file)
@@ -933,7 +933,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi,
                           active_best_quality, active_worst_quality);
     if (q > *top_index) {
       // Special case when we are targeting the max allowed rate.
-      if (cpi->rc.this_frame_target >= cpi->rc.max_frame_bandwidth)
+      if (rc->this_frame_target >= rc->max_frame_bandwidth)
         *top_index = q;
       else
         q = *top_index;
index 5d80d89..2b5639d 100644 (file)
@@ -30,9 +30,8 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
   for (layer = 0; layer < layer_end; ++layer) {
     LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
     RATE_CONTROL *const lrc = &lc->rc;
-
+    lc->current_video_frame_in_layer = 0;
     lrc->avg_frame_qindex[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
-    lrc->last_q[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
     lrc->ni_av_qi = q_trans[oxcf->worst_allowed_q];
     lrc->total_actual_bits = 0;
     lrc->total_target_vs_actual = 0;
@@ -47,8 +46,12 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
 
     if (cpi->svc.number_temporal_layers > 1) {
       lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+      lrc->last_q[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
     } else {
       lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
+      lrc->last_q[0] = q_trans[oxcf->best_allowed_q];
+      lrc->last_q[1] = q_trans[oxcf->best_allowed_q];
+      lrc->last_q[2] = q_trans[oxcf->best_allowed_q];
     }
 
     lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level),
@@ -105,14 +108,16 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
   }
 }
 
-static LAYER_CONTEXT *get_temporal_layer_context(SVC *svc) {
-  return &svc->layer_context[svc->temporal_layer_id];
+static LAYER_CONTEXT *get_layer_context(SVC *svc) {
+  return svc->number_temporal_layers > 1 ?
+         &svc->layer_context[svc->temporal_layer_id] :
+         &svc->layer_context[svc->spatial_layer_id];
 }
 
 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);
+  LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
   RATE_CONTROL *const lrc = &lc->rc;
 
   lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
@@ -133,9 +138,8 @@ void vp9_update_temporal_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];
+  LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
   RATE_CONTROL *const lrc = &lc->rc;
 
   lc->framerate = framerate;
@@ -145,14 +149,28 @@ void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
   lrc->max_frame_bandwidth = (int)(((int64_t)lrc->av_per_frame_bandwidth *
                                    oxcf->two_pass_vbrmax_section) / 100);
   lrc->max_gf_interval = 16;
+
+  lrc->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;
+
+  if (oxcf->play_alternate && oxcf->lag_in_frames) {
+    if (lrc->max_gf_interval > oxcf->lag_in_frames - 1)
+      lrc->max_gf_interval = oxcf->lag_in_frames - 1;
+
+    if (lrc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
+      lrc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
+  }
+
+  if (lrc->max_gf_interval > lrc->static_scene_max_gf_interval)
+    lrc->max_gf_interval = lrc->static_scene_max_gf_interval;
 }
 
 void vp9_restore_layer_context(VP9_COMP *const cpi) {
-  LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
+  LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
   const int old_frame_since_key = cpi->rc.frames_since_key;
   const int old_frame_to_key = cpi->rc.frames_to_key;
 
   cpi->rc = lc->rc;
+  cpi->twopass = lc->twopass;
   cpi->oxcf.target_bandwidth = lc->target_bandwidth;
   cpi->oxcf.starting_buffer_level = lc->starting_buffer_level;
   cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level;
@@ -160,18 +178,35 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) {
   cpi->output_framerate = lc->framerate;
   // Reset the frames_since_key and frames_to_key counters to their values
   // before the layer restore. Keep these defined for the stream (not layer).
-  cpi->rc.frames_since_key = old_frame_since_key;
-  cpi->rc.frames_to_key = old_frame_to_key;
+  if (cpi->svc.number_temporal_layers > 1) {
+    cpi->rc.frames_since_key = old_frame_since_key;
+    cpi->rc.frames_to_key = old_frame_to_key;
+  }
 }
 
 void vp9_save_layer_context(VP9_COMP *const cpi) {
   const VP9_CONFIG *const oxcf = &cpi->oxcf;
-  LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
+  LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
 
   lc->rc = cpi->rc;
+  lc->twopass = cpi->twopass;
   lc->target_bandwidth = (int)oxcf->target_bandwidth;
   lc->starting_buffer_level = oxcf->starting_buffer_level;
   lc->optimal_buffer_level = oxcf->optimal_buffer_level;
   lc->maximum_buffer_size = oxcf->maximum_buffer_size;
   lc->framerate = cpi->output_framerate;
 }
+
+void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
+  int i;
+  for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
+    struct twopass_rc *const twopass = &cpi->svc.layer_context[i].twopass;
+
+    cpi->svc.spatial_layer_id = i;
+    vp9_init_second_pass(cpi);
+
+    twopass->total_stats.spatial_layer_id = i;
+    twopass->total_left_stats.spatial_layer_id = i;
+  }
+  cpi->svc.spatial_layer_id = 0;
+}
index 2cd4e47..e859a2f 100644 (file)
@@ -29,6 +29,7 @@ typedef struct {
   int avg_frame_size;
   struct twopass_rc twopass;
   struct vpx_fixed_buf rc_twopass_stats_in;
+  unsigned int current_video_frame_in_layer;
 } LAYER_CONTEXT;
 
 typedef struct {
@@ -36,8 +37,8 @@ typedef struct {
   int temporal_layer_id;
   int number_spatial_layers;
   int number_temporal_layers;
-  // Layer context used for rate control in temporal CBR mode or spatial
-  // two pass mode. Defined for temporal or spatial layers for now.
+  // Layer context used for rate control in one pass temporal CBR mode or
+  // two pass spatial mode. Defined for temporal or spatial layers for now.
   // Does not support temporal combined with spatial RC.
   LAYER_CONTEXT layer_context[MAX(VPX_TS_MAX_LAYERS, VPX_SS_MAX_LAYERS)];
 } SVC;
@@ -66,6 +67,9 @@ void vp9_restore_layer_context(struct VP9_COMP *const cpi);
 // Save the layer context after encoding the frame.
 void vp9_save_layer_context(struct VP9_COMP *const cpi);
 
+// Initialize second pass rc for spatial svc.
+void vp9_init_second_pass_spatial_svc(struct VP9_COMP *cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif