Merge "Fix show_existing_frame not decreasing frame buffer ref counter."
diff --git a/examples/vpx_temporal_svc_encoder.c b/examples/vpx_temporal_svc_encoder.c
index 9f32bd8..e4616ef 100644
--- a/examples/vpx_temporal_svc_encoder.c
+++ b/examples/vpx_temporal_svc_encoder.c
@@ -32,6 +32,14 @@
   exit(EXIT_FAILURE);
 }
 
+// Denoiser states, for temporal denoising.
+enum denoiserState {
+  kDenoiserOff,
+  kDenoiserOnYOnly,
+  kDenoiserOnYUV,
+  kDenoiserOnYUVAggressive  // Aggressive mode not implemented currently.
+};
+
 static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
 
 // For rate control encoding stats.
@@ -571,7 +579,7 @@
 
   if (strncmp(encoder->name, "vp8", 3) == 0) {
     vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed);
-    vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
+    vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOnYUV);
   } else if (strncmp(encoder->name, "vp9", 3) == 0) {
       vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
       vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
diff --git a/test/active_map_test.cc b/test/active_map_test.cc
index 6377e72..a9bb540 100644
--- a/test/active_map_test.cc
+++ b/test/active_map_test.cc
@@ -83,9 +83,6 @@
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 }
 
-#define VP9_FACTORY \
-  static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)
-
 VP9_INSTANTIATE_TEST_CASE(ActiveMapTest,
                           ::testing::Values(::libvpx_test::kRealTime),
                           ::testing::Range(0, 6));
diff --git a/test/cpu_speed_test.cc b/test/cpu_speed_test.cc
index 9dca601..4477bf0 100644
--- a/test/cpu_speed_test.cc
+++ b/test/cpu_speed_test.cc
@@ -139,5 +139,5 @@
     CpuSpeedTest,
     ::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood,
                       ::libvpx_test::kRealTime),
-    ::testing::Range(0, 8));
+    ::testing::Range(0, 9));
 }  // namespace
diff --git a/test/svc_test.cc b/test/svc_test.cc
index 417790b..e9cf38d 100644
--- a/test/svc_test.cc
+++ b/test/svc_test.cc
@@ -167,6 +167,24 @@
   codec_initialized_ = true;
 }
 
+TEST_F(SvcTest, SetAutoAltRefOption) {
+  svc_.spatial_layers = 5;
+  vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none");
+  EXPECT_EQ(VPX_CODEC_OK, res);
+  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
+  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
+
+  res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
+  EXPECT_EQ(VPX_CODEC_OK, res);
+  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
+  EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
+
+  vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
+  res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
+  EXPECT_EQ(VPX_CODEC_OK, res);
+  codec_initialized_ = true;
+}
+
 TEST_F(SvcTest, SetQuantizers) {
   vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30");
   EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
@@ -362,6 +380,7 @@
   codec_enc_.g_pass = VPX_RC_FIRST_PASS;
   vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
   vpx_svc_set_quantizers(&svc_, "40,30");
+  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
 
   vpx_codec_err_t res =
       vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
@@ -410,6 +429,9 @@
   vpx_codec_err_t res_dec;
   int frame_size;
   codec_enc_.g_pass = VPX_RC_LAST_PASS;
+  vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
+  vpx_svc_set_quantizers(&svc_, "40,30");
+  vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
   codec_enc_.rc_twopass_stats_in.buf = &stats_buf[0];
   codec_enc_.rc_twopass_stats_in.sz = stats_buf.size();
 
diff --git a/tools_common.c b/tools_common.c
index 4f2ac74..8825528 100644
--- a/tools_common.c
+++ b/tools_common.c
@@ -83,11 +83,12 @@
   struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
   int plane = 0;
   int shortread = 0;
+  const int bytespp = (input_ctx->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
 
   for (plane = 0; plane < 3; ++plane) {
     uint8_t *ptr;
-    const int w = (plane ? (1 + yuv_frame->d_w) / 2 : yuv_frame->d_w);
-    const int h = (plane ? (1 + yuv_frame->d_h) / 2 : yuv_frame->d_h);
+    const int w = vpx_img_plane_width(yuv_frame, plane);
+    const int h = vpx_img_plane_height(yuv_frame, plane);
     int r;
 
     /* Determine the correct plane based on the image format. The for-loop
@@ -108,7 +109,7 @@
     }
 
     for (r = 0; r < h; ++r) {
-      size_t needed = w;
+      size_t needed = w * bytespp;
       size_t buf_position = 0;
       const size_t left = detect->buf_read - detect->position;
       if (left > 0) {
diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h
index 119e40c..7d9441d 100644
--- a/vp8/common/onyx.h
+++ b/vp8/common/onyx.h
@@ -104,7 +104,17 @@
         struct vpx_rational  timebase;
         unsigned int target_bandwidth;    /* kilobits per second */
 
-        /* parameter used for applying pre processing blur: recommendation 0 */
+        /* Parameter used for applying denoiser.
+         * For temporal denoiser: noise_sensitivity = 0 means off,
+         * noise_sensitivity = 1 means temporal denoiser on for Y channel only,
+         * noise_sensitivity = 2 means temporal denoiser on for all channels.
+         * noise_sensitivity = 3 will be used for aggressive mode in future.
+         * Temporal denoiser is enabled via the build option
+         * CONFIG_TEMPORAL_DENOISING.
+         * For spatial denoiser: noise_sensitivity controls the amount of
+         * pre-processing blur: noise_sensitivity = 0 means off.
+         * Spatial denoiser invoked under !CONFIG_TEMPORAL_DENOISING.
+         */
         int noise_sensitivity;
 
         /* parameter used for sharpening output: recommendation 0: */
diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c
index 94aa2ca..0f0a36a 100644
--- a/vp8/encoder/denoising.c
+++ b/vp8/encoder/denoising.c
@@ -396,15 +396,14 @@
                              loop_filter_info_n *lfi_n,
                              int mb_row,
                              int mb_col,
-                             int block_index)
+                             int block_index,
+                             int uv_denoise)
 {
     int mv_row;
     int mv_col;
     unsigned int motion_magnitude2;
     unsigned int sse_thresh;
     int sse_diff_thresh = 0;
-    // Denoise the UV channel.
-    int apply_color_denoise = 0;
     // Spatial loop filter: only applied selectively based on
     // temporal filter state of block relative to top/left neighbors.
     int apply_spatial_loop_filter = 1;
@@ -529,7 +528,7 @@
         denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ?
             kFilterNonZeroMV : kFilterZeroMV;
         // Only denoise UV for zero motion, and if y channel was denoised.
-        if (apply_color_denoise &&
+        if (uv_denoise &&
             motion_magnitude2 == 0 &&
             decision == FILTER_BLOCK) {
           unsigned char *mc_running_avg_u =
@@ -566,7 +565,7 @@
                 denoiser->yv12_running_avg[INTRA_FRAME].y_stride);
         denoiser->denoise_state[block_index] = kNoFilter;
     }
-    if (apply_color_denoise) {
+    if (uv_denoise) {
       if (decision_u == COPY_BLOCK) {
         vp8_copy_mem8x8(
             x->block[16].src + *x->block[16].base_src, x->block[16].src_stride,
diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h
index 8f1bfa5..a1f195b 100644
--- a/vp8/encoder/denoising.h
+++ b/vp8/encoder/denoising.h
@@ -61,7 +61,8 @@
                              loop_filter_info_n *lfi_n,
                              int mb_row,
                              int mb_col,
-                             int block_index);
+                             int block_index,
+                             int uv_denoise);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index 3a78ee9..86108b7 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -1168,6 +1168,7 @@
 #if CONFIG_TEMPORAL_DENOISING
     if (cpi->oxcf.noise_sensitivity)
     {
+        int uv_denoise = (cpi->oxcf.noise_sensitivity == 2) ? 1 : 0;
         int block_index = mb_row * cpi->common.mb_cols + mb_col;
         if (x->best_sse_inter_mode == DC_PRED)
         {
@@ -1182,7 +1183,7 @@
         vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
                                 recon_yoffset, recon_uvoffset,
                                 &cpi->common.lf_info, mb_row, mb_col,
-                                block_index);
+                                block_index, uv_denoise);
 
 
         /* Reevaluate ZEROMV after denoising. */
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index 4465b5e..98d6016 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -2511,6 +2511,7 @@
 #if CONFIG_TEMPORAL_DENOISING
     if (cpi->oxcf.noise_sensitivity)
     {
+        int uv_denoise = (cpi->oxcf.noise_sensitivity == 2) ? 1 : 0;
         int block_index = mb_row * cpi->common.mb_cols + mb_col;
         if (x->best_sse_inter_mode == DC_PRED)
         {
@@ -2524,7 +2525,7 @@
         vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
                                 recon_yoffset, recon_uvoffset,
                                 &cpi->common.lf_info, mb_row, mb_col,
-                                block_index);
+                                block_index, uv_denoise);
 
 
         /* Reevaluate ZEROMV after denoising. */
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index 4f6f9fa..cbff86c 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -9,6 +9,7 @@
  */
 
 
+#include "./vpx_config.h"
 #include "vp8_rtcd.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/internal/vpx_codec_internal.h"
@@ -1290,6 +1291,7 @@
         VPX_VBR,            /* rc_end_usage */
 #if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
         {0},                /* rc_twopass_stats_in */
+        {0},                /* rc_firstpass_mb_stats_in */
 #endif
         256,                /* rc_target_bandwidth */
         4,                  /* rc_min_quantizer */
@@ -1314,6 +1316,9 @@
         "vp8.fpf"           /* first pass filename */
 #endif
         VPX_SS_DEFAULT_LAYERS, /* ss_number_layers */
+#ifdef CONFIG_SPATIAL_SVC
+        {0},
+#endif
         {0},                /* ss_target_bitrate */
         1,                  /* ts_number_layers */
         {0},                /* ts_target_bitrate */
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c
index b695ddc..fb3c236 100644
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -269,6 +269,7 @@
     img->stride[VPX_PLANE_U] = yv12->uv_stride;
     img->stride[VPX_PLANE_V] = yv12->uv_stride;
     img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
+    img->bit_depth = 8;
     img->bps = 12;
     img->user_priv = user_priv;
     img->img_data = yv12->buffer_alloc;
diff --git a/vp9/common/vp9_entropy.c b/vp9/common/vp9_entropy.c
index bc12f9a..3a54de2 100644
--- a/vp9/common/vp9_entropy.c
+++ b/vp9/common/vp9_entropy.c
@@ -15,6 +15,14 @@
 #include "vpx_mem/vpx_mem.h"
 #include "vpx/vpx_integer.h"
 
+const vp9_prob vp9_cat1_prob[] = { 159 };
+const vp9_prob vp9_cat2_prob[] = { 165, 145 };
+const vp9_prob vp9_cat3_prob[] = { 173, 148, 140 };
+const vp9_prob vp9_cat4_prob[] = { 176, 155, 140, 135 };
+const vp9_prob vp9_cat5_prob[] = { 180, 157, 141, 134, 130 };
+const vp9_prob vp9_cat6_prob[] = {
+    254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
+};
 
 const uint8_t vp9_coefband_trans_8x8plus[1024] = {
   0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h
index 3dc98a8..9622ca3 100644
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -43,6 +43,21 @@
 
 DECLARE_ALIGNED(16, extern const uint8_t, vp9_pt_energy_class[ENTROPY_TOKENS]);
 
+#define CAT1_MIN_VAL    5
+#define CAT2_MIN_VAL    7
+#define CAT3_MIN_VAL   11
+#define CAT4_MIN_VAL   19
+#define CAT5_MIN_VAL   35
+#define CAT6_MIN_VAL   67
+
+// Extra bit probabilities.
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob[1]);
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob[2]);
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob[3]);
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob[4]);
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob[5]);
+DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob[14]);
+
 #define EOB_MODEL_TOKEN 3
 extern const vp9_tree_index vp9_coefmodel_tree[];
 
diff --git a/vp9/decoder/vp9_detokenize.c b/vp9/decoder/vp9_detokenize.c
index 860da53..91cdf38 100644
--- a/vp9/decoder/vp9_detokenize.c
+++ b/vp9/decoder/vp9_detokenize.c
@@ -28,35 +28,6 @@
 #define CAT_THREE_CONTEXT_NODE      6
 #define CAT_FIVE_CONTEXT_NODE       7
 
-#define CAT1_MIN_VAL    5
-#define CAT2_MIN_VAL    7
-#define CAT3_MIN_VAL   11
-#define CAT4_MIN_VAL   19
-#define CAT5_MIN_VAL   35
-#define CAT6_MIN_VAL   67
-#define CAT1_PROB0    159
-#define CAT2_PROB0    145
-#define CAT2_PROB1    165
-
-#define CAT3_PROB0 140
-#define CAT3_PROB1 148
-#define CAT3_PROB2 173
-
-#define CAT4_PROB0 135
-#define CAT4_PROB1 140
-#define CAT4_PROB2 155
-#define CAT4_PROB3 176
-
-#define CAT5_PROB0 130
-#define CAT5_PROB1 134
-#define CAT5_PROB2 141
-#define CAT5_PROB3 157
-#define CAT5_PROB4 180
-
-static const vp9_prob cat6_prob[15] = {
-  254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0
-};
-
 #define INCREMENT_COUNT(token)                              \
   do {                                                      \
      if (!cm->frame_parallel_decoding_mode)                 \
@@ -96,7 +67,6 @@
   unsigned int (*eob_branch_count)[COEFF_CONTEXTS] =
       counts->eob_branch[tx_size][type][ref];
   uint8_t token_cache[32 * 32];
-  const uint8_t *cat6;
   const uint8_t *band_translate = get_band_translate(tx_size);
   const int dq_shift = (tx_size == TX_32X32);
   int v;
@@ -148,44 +118,55 @@
     if (!vp9_read(r, prob[HIGH_LOW_CONTEXT_NODE])) {
       if (!vp9_read(r, prob[CAT_ONE_CONTEXT_NODE])) {
         val = CAT1_MIN_VAL;
-        ADJUST_COEF(CAT1_PROB0, 0);
+        ADJUST_COEF(vp9_cat1_prob[0], 0);
         WRITE_COEF_CONTINUE(val, CATEGORY1_TOKEN);
       }
       val = CAT2_MIN_VAL;
-      ADJUST_COEF(CAT2_PROB1, 1);
-      ADJUST_COEF(CAT2_PROB0, 0);
+      ADJUST_COEF(vp9_cat2_prob[0], 1);
+      ADJUST_COEF(vp9_cat2_prob[1], 0);
       WRITE_COEF_CONTINUE(val, CATEGORY2_TOKEN);
     }
 
     if (!vp9_read(r, prob[CAT_THREEFOUR_CONTEXT_NODE])) {
       if (!vp9_read(r, prob[CAT_THREE_CONTEXT_NODE])) {
         val = CAT3_MIN_VAL;
-        ADJUST_COEF(CAT3_PROB2, 2);
-        ADJUST_COEF(CAT3_PROB1, 1);
-        ADJUST_COEF(CAT3_PROB0, 0);
+        ADJUST_COEF(vp9_cat3_prob[0], 2);
+        ADJUST_COEF(vp9_cat3_prob[1], 1);
+        ADJUST_COEF(vp9_cat3_prob[2], 0);
         WRITE_COEF_CONTINUE(val, CATEGORY3_TOKEN);
       }
       val = CAT4_MIN_VAL;
-      ADJUST_COEF(CAT4_PROB3, 3);
-      ADJUST_COEF(CAT4_PROB2, 2);
-      ADJUST_COEF(CAT4_PROB1, 1);
-      ADJUST_COEF(CAT4_PROB0, 0);
+      ADJUST_COEF(vp9_cat4_prob[0], 3);
+      ADJUST_COEF(vp9_cat4_prob[1], 2);
+      ADJUST_COEF(vp9_cat4_prob[2], 1);
+      ADJUST_COEF(vp9_cat4_prob[3], 0);
       WRITE_COEF_CONTINUE(val, CATEGORY4_TOKEN);
     }
 
     if (!vp9_read(r, prob[CAT_FIVE_CONTEXT_NODE])) {
       val = CAT5_MIN_VAL;
-      ADJUST_COEF(CAT5_PROB4, 4);
-      ADJUST_COEF(CAT5_PROB3, 3);
-      ADJUST_COEF(CAT5_PROB2, 2);
-      ADJUST_COEF(CAT5_PROB1, 1);
-      ADJUST_COEF(CAT5_PROB0, 0);
+      ADJUST_COEF(vp9_cat5_prob[0], 4);
+      ADJUST_COEF(vp9_cat5_prob[1], 3);
+      ADJUST_COEF(vp9_cat5_prob[2], 2);
+      ADJUST_COEF(vp9_cat5_prob[3], 1);
+      ADJUST_COEF(vp9_cat5_prob[4], 0);
       WRITE_COEF_CONTINUE(val, CATEGORY5_TOKEN);
     }
     val = 0;
-    cat6 = cat6_prob;
-    while (*cat6)
-      val = (val << 1) | vp9_read(r, *cat6++);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[0]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[1]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[2]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[3]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[4]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[5]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[6]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[7]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[8]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[9]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[10]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[11]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[12]);
+    val = (val << 1) | vp9_read(r, vp9_cat6_prob[13]);
     val += CAT6_MIN_VAL;
 
     WRITE_COEF_CONTINUE(val, CATEGORY6_TOKEN);
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index dc572aa..04d5181 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -200,12 +200,11 @@
     cpi->source_diff_var = NULL;
   }
 
-#if CONFIG_FP_MB_STATS
-  if (cpi->use_fp_mb_stats) {
-    vpx_free(cpi->twopass.this_frame_mb_stats.mb_stats);
-    cpi->twopass.this_frame_mb_stats.mb_stats = NULL;
+  for (i = 0; i < MAX_LAG_BUFFERS; ++i) {
+    vp9_free_frame_buffer(&cpi->svc.scaled_frames[i]);
   }
-#endif
+  vpx_memset(&cpi->svc.scaled_frames[0], 0,
+             MAX_LAG_BUFFERS * sizeof(cpi->svc.scaled_frames[0]));
 }
 
 static void save_coding_context(VP9_COMP *cpi) {
@@ -476,6 +475,15 @@
   MACROBLOCKD *const xd = &cpi->mb.e_mbd;
   vp9_update_frame_size(cm);
   init_macroblockd(cm, xd);
+
+  if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+    if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
+                                 cm->width, cm->height,
+                                 cm->subsampling_x, cm->subsampling_y,
+                                 VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
+      vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+                         "Failed to reallocate alt_ref_buffer");
+  }
 }
 
 void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
@@ -778,11 +786,11 @@
 #if CONFIG_FP_MB_STATS
   cpi->use_fp_mb_stats = 0;
   if (cpi->use_fp_mb_stats) {
-    // a place holder for the mb stats obtained from the first pass
-    CHECK_MEM_ERROR(cm, cpi->twopass.this_frame_mb_stats.mb_stats,
-                    vpx_calloc(cm->MBs * sizeof(FIRSTPASS_MB_STATS), 1));
+    // a place holder used to store the first pass mb stats in the first pass
+    CHECK_MEM_ERROR(cm, cpi->twopass.frame_mb_stats_buf,
+                    vpx_calloc(cm->MBs * sizeof(uint8_t), 1));
   } else {
-    cpi->twopass.this_frame_mb_stats.mb_stats = NULL;
+    cpi->twopass.frame_mb_stats_buf = NULL;
   }
 #endif
 
@@ -925,6 +933,21 @@
 
       vp9_init_second_pass_spatial_svc(cpi);
     } else {
+#if CONFIG_FP_MB_STATS
+      if (cpi->use_fp_mb_stats) {
+        const size_t psz = cpi->common.MBs * sizeof(uint8_t);
+        const int ps = (int)(oxcf->firstpass_mb_stats_in.sz / psz);
+
+        cpi->twopass.firstpass_mb_stats.mb_stats_start =
+            oxcf->firstpass_mb_stats_in.buf;
+        cpi->twopass.firstpass_mb_stats.mb_stats_in =
+            cpi->twopass.firstpass_mb_stats.mb_stats_start;
+        cpi->twopass.firstpass_mb_stats.mb_stats_end =
+            cpi->twopass.firstpass_mb_stats.mb_stats_start +
+            (ps - 1) * cpi->common.MBs * sizeof(uint8_t);
+      }
+#endif
+
       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];
@@ -1115,6 +1138,13 @@
     vpx_free(cpi->mbgraph_stats[i].mb_stats);
   }
 
+#if CONFIG_FP_MB_STATS
+  if (cpi->use_fp_mb_stats) {
+    vpx_free(cpi->twopass.frame_mb_stats_buf);
+    cpi->twopass.frame_mb_stats_buf = NULL;
+  }
+#endif
+
   vp9_remove_common(&cpi->common);
   vpx_free(cpi);
 
@@ -2486,7 +2516,7 @@
 static int get_arf_src_index(VP9_COMP *cpi) {
   RATE_CONTROL *const rc = &cpi->rc;
   int arf_src_index = 0;
-  if (is_altref_enabled(&cpi->oxcf)) {
+  if (is_altref_enabled(cpi)) {
     if (cpi->pass == 2) {
       const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
       if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
@@ -2565,13 +2595,27 @@
 #ifdef CONFIG_SPATIAL_SVC
     if (is_spatial_svc)
       cpi->source = vp9_svc_lookahead_peek(cpi, cpi->lookahead,
-                                           arf_src_index, 1);
+                                           arf_src_index, 0);
     else
 #endif
       cpi->source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
     if (cpi->source != NULL) {
       cpi->alt_ref_source = cpi->source;
 
+#ifdef CONFIG_SPATIAL_SVC
+      if (is_spatial_svc && cpi->svc.spatial_layer_id > 0) {
+        int i;
+        // Reference a hidden frame from a lower layer
+        for (i = cpi->svc.spatial_layer_id - 1; i >= 0; --i) {
+          if (cpi->oxcf.ss_play_alternate[i]) {
+            cpi->gld_fb_idx = cpi->svc.layer_context[i].alt_ref_idx;
+            break;
+          }
+        }
+      }
+      cpi->svc.layer_context[cpi->svc.spatial_layer_id].has_alt_frame = 1;
+#endif
+
       if (cpi->oxcf.arnr_max_frames > 0) {
         // Produce the filtered ARF frame.
         vp9_temporal_filter(cpi, arf_src_index);
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index 9f8b37f..1ad65b9 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -195,6 +195,7 @@
   int ts_number_layers;  // Number of temporal layers.
   // Bitrate allocation for spatial layers.
   int ss_target_bitrate[VPX_SS_MAX_LAYERS];
+  int ss_play_alternate[VPX_SS_MAX_LAYERS];
   // Bitrate allocation (CBR mode) and framerate factor, for temporal layers.
   int ts_target_bitrate[VPX_TS_MAX_LAYERS];
   int ts_rate_decimator[VPX_TS_MAX_LAYERS];
@@ -226,13 +227,13 @@
   struct vpx_fixed_buf         two_pass_stats_in;
   struct vpx_codec_pkt_list  *output_pkt_list;
 
+#if CONFIG_FP_MB_STATS
+  struct vpx_fixed_buf         firstpass_mb_stats_in;
+#endif
+
   vp8e_tuning tuning;
 } VP9EncoderConfig;
 
-static INLINE int is_altref_enabled(const VP9EncoderConfig *cfg) {
-  return cfg->mode != REALTIME && cfg->play_alternate && cfg->lag_in_frames > 0;
-}
-
 static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) {
   return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0;
 }
@@ -535,6 +536,13 @@
 
 void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags);
 
+static INLINE int is_altref_enabled(const VP9_COMP *const cpi) {
+  return cpi->oxcf.mode != REALTIME && cpi->oxcf.lag_in_frames > 0 &&
+         (cpi->oxcf.play_alternate &&
+          (!(cpi->use_svc && cpi->svc.number_temporal_layers == 1) ||
+           cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id]));
+}
+
 static INLINE void set_ref_ptrs(VP9_COMMON *cm, MACROBLOCKD *xd,
                                 MV_REFERENCE_FRAME ref0,
                                 MV_REFERENCE_FRAME ref1) {
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index ad73c4c..2a5f594 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -98,34 +98,6 @@
   return &p->stats_in[offset];
 }
 
-#if CONFIG_FP_MB_STATS
-static int input_mb_stats(FIRSTPASS_FRAME_MB_STATS *fp_frame_stats,
-                          const VP9_COMMON *const cm) {
-  FILE *fpfile;
-  int ret;
-
-  fpfile = fopen("firstpass_mb.stt", "r");
-  fseek(fpfile, cm->current_video_frame * cm->MBs * sizeof(FIRSTPASS_MB_STATS),
-        SEEK_SET);
-  ret = fread(fp_frame_stats->mb_stats, sizeof(FIRSTPASS_MB_STATS), cm->MBs,
-              fpfile);
-  fclose(fpfile);
-  if (ret < cm->MBs) {
-    return EOF;
-  }
-  return 1;
-}
-
-static void output_mb_stats(FIRSTPASS_FRAME_MB_STATS *fp_frame_stats,
-                          const VP9_COMMON *const cm) {
-  FILE *fpfile;
-
-  fpfile = fopen("firstpass_mb.stt", "a");
-  fwrite(fp_frame_stats->mb_stats, sizeof(FIRSTPASS_MB_STATS), cm->MBs, fpfile);
-  fclose(fpfile);
-}
-#endif
-
 static int input_stats(TWO_PASS *p, FIRSTPASS_STATS *fps) {
   if (p->stats_in >= p->stats_in_end)
     return EOF;
@@ -175,6 +147,27 @@
 #endif
 }
 
+#if CONFIG_FP_MB_STATS
+static int input_fpmb_stats(FIRSTPASS_MB_STATS *firstpass_mb_stats,
+                            VP9_COMMON *cm, uint8_t **this_frame_mb_stats) {
+  if (firstpass_mb_stats->mb_stats_in > firstpass_mb_stats->mb_stats_end)
+    return EOF;
+
+  *this_frame_mb_stats = firstpass_mb_stats->mb_stats_in;
+  firstpass_mb_stats->mb_stats_in += cm->MBs * sizeof(uint8_t);
+  return 1;
+}
+
+static void output_fpmb_stats(uint8_t *this_frame_mb_stats, VP9_COMMON *cm,
+                         struct vpx_codec_pkt_list *pktlist) {
+  struct vpx_codec_cx_pkt pkt;
+  pkt.kind = VPX_CODEC_FPMB_STATS_PKT;
+  pkt.data.firstpass_mb_stats.buf = this_frame_mb_stats;
+  pkt.data.firstpass_mb_stats.sz = cm->MBs * sizeof(uint8_t);
+  vpx_codec_pkt_list_add(pktlist, &pkt);
+}
+#endif
+
 static void zero_stats(FIRSTPASS_STATS *section) {
   section->frame      = 0.0;
   section->intra_error = 0.0;
@@ -473,7 +466,9 @@
   const YV12_BUFFER_CONFIG *first_ref_buf = lst_yv12;
 
 #if CONFIG_FP_MB_STATS
-  FIRSTPASS_FRAME_MB_STATS *this_frame_mb_stats = &twopass->this_frame_mb_stats;
+  if (cpi->use_fp_mb_stats) {
+    vp9_zero_array(cpi->twopass.frame_mb_stats_buf, cm->MBs);
+  }
 #endif
 
   vp9_clear_system_state();
@@ -486,24 +481,33 @@
     const YV12_BUFFER_CONFIG *scaled_ref_buf = NULL;
     twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
 
+    if (cpi->common.current_video_frame == 0) {
+      cpi->ref_frame_flags = 0;
+    } else {
+      LAYER_CONTEXT *lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
+      if (lc->current_video_frame_in_layer == 0)
+        cpi->ref_frame_flags = VP9_GOLD_FLAG;
+      else
+        cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
+    }
+
     vp9_scale_references(cpi);
 
     // Use either last frame or alt frame for motion search.
     if (cpi->ref_frame_flags & VP9_LAST_FLAG) {
       scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, LAST_FRAME);
       ref_frame = LAST_FRAME;
-    } else if (cpi->ref_frame_flags & VP9_ALT_FLAG) {
-      scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, ALTREF_FRAME);
-      ref_frame = ALTREF_FRAME;
+    } else if (cpi->ref_frame_flags & VP9_GOLD_FLAG) {
+      scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, GOLDEN_FRAME);
+      ref_frame = GOLDEN_FRAME;
     }
 
-    if (scaled_ref_buf != NULL) {
-      // Update the stride since we are using scaled reference buffer
+    if (scaled_ref_buf != NULL)
       first_ref_buf = scaled_ref_buf;
-      recon_y_stride = first_ref_buf->y_stride;
-      recon_uv_stride = first_ref_buf->uv_stride;
-      uv_mb_height = 16 >> (first_ref_buf->y_height > first_ref_buf->uv_height);
-    }
+
+    recon_y_stride = new_yv12->y_stride;
+    recon_uv_stride = new_yv12->uv_stride;
+    uv_mb_height = 16 >> (new_yv12->y_height > new_yv12->uv_height);
 
     // Disable golden frame for svc first pass for now.
     gld_yv12 = NULL;
@@ -605,12 +609,7 @@
 
 #if CONFIG_FP_MB_STATS
       if (cpi->use_fp_mb_stats) {
-        this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].mode =
-            DC_PRED;
-        this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].err =
-            this_error;
-        this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].mv.as_int
-            = 0;
+        // TODO(pengchong): store some related block statistics here
       }
 #endif
 
@@ -741,12 +740,7 @@
 
 #if CONFIG_FP_MB_STATS
           if (cpi->use_fp_mb_stats) {
-            this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].mode =
-                NEWMV;
-            this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].err =
-                motion_error;
-            this_frame_mb_stats->mb_stats[mb_row * cm->mb_cols + mb_col].mv.
-                as_int = mv.as_int;
+            // TODO(pengchong): save some related block statistics here
           }
 #endif
 
@@ -857,7 +851,7 @@
 
 #if CONFIG_FP_MB_STATS
     if (cpi->use_fp_mb_stats) {
-      output_mb_stats(this_frame_mb_stats, cm);
+      output_fpmb_stats(twopass->frame_mb_stats_buf, cm, cpi->output_pkt_list);
     }
 #endif
   }
@@ -909,6 +903,8 @@
   }
 
   ++cm->current_video_frame;
+  if (cpi->use_svc)
+    vp9_inc_frame_in_layer(&cpi->svc);
 }
 
 static double calc_correction_factor(double err_per_mb,
@@ -1506,7 +1502,7 @@
   double mv_in_out_accumulator = 0.0;
   double abs_mv_in_out_accumulator = 0.0;
   double mv_ratio_accumulator_thresh;
-  unsigned int allow_alt_ref = is_altref_enabled(oxcf);
+  unsigned int allow_alt_ref = is_altref_enabled(cpi);
 
   int f_boost = 0;
   int b_boost = 0;
@@ -2080,6 +2076,11 @@
     default:
       assert(0);
   }
+  if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+    cpi->refresh_golden_frame = 0;
+    if (cpi->alt_ref_source == NULL)
+      cpi->refresh_alt_ref_frame = 0;
+  }
 }
 
 
@@ -2122,6 +2123,18 @@
 #endif
     vp9_rc_set_frame_target(cpi, target_rate);
     cm->frame_type = INTER_FRAME;
+
+    if (is_spatial_svc) {
+      if (cpi->svc.spatial_layer_id == 0) {
+        lc->is_key_frame = 0;
+      } else {
+        lc->is_key_frame = cpi->svc.layer_context[0].is_key_frame;
+
+        if (lc->is_key_frame)
+          cpi->ref_frame_flags &= (~VP9_LAST_FLAG);
+      }
+    }
+
     return;
   }
 
@@ -2189,7 +2202,8 @@
     }
 
     rc->frames_till_gf_update_due = rc->baseline_gf_interval;
-    cpi->refresh_golden_frame = 1;
+    if (!is_spatial_svc)
+      cpi->refresh_golden_frame = 1;
   }
 
   {
@@ -2221,7 +2235,8 @@
 
 #if CONFIG_FP_MB_STATS
   if (cpi->use_fp_mb_stats) {
-    input_mb_stats(&twopass->this_frame_mb_stats, cm);
+    input_fpmb_stats(&twopass->firstpass_mb_stats, cm,
+                     &twopass->this_frame_mb_stats);
   }
 #endif
 }
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index 7e4c9ee..714a67f 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -20,14 +20,10 @@
 
 #if CONFIG_FP_MB_STATS
 typedef struct {
-  PREDICTION_MODE mode;
-  int err;
-  int_mv mv;
+  uint8_t *mb_stats_in;
+  uint8_t *mb_stats_start;
+  uint8_t *mb_stats_end;
 } FIRSTPASS_MB_STATS;
-
-typedef struct {
-  FIRSTPASS_MB_STATS *mb_stats;
-} FIRSTPASS_FRAME_MB_STATS;
 #endif
 
 typedef struct {
@@ -89,7 +85,9 @@
   double gf_intra_err_min;
 
 #if CONFIG_FP_MB_STATS
-  FIRSTPASS_FRAME_MB_STATS this_frame_mb_stats;
+  uint8_t *frame_mb_stats_buf;
+  uint8_t *this_frame_mb_stats;
+  FIRSTPASS_MB_STATS firstpass_mb_stats;
 #endif
 
   // Projected total bits available for a key frame group of frames
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 99f4897..7a9436a 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -679,7 +679,7 @@
 
     int rate2 = 0;
     int64_t dist2 = 0;
-    const int dst_stride = pd->dst.stride;
+    const int dst_stride = cpi->sf.reuse_inter_pred_sby ? bw : pd->dst.stride;
     const int src_stride = p->src.stride;
     int block_idx = 0;
 
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index e110983..aa8e4f0 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -1097,7 +1097,7 @@
 
   rc->total_target_vs_actual = rc->total_actual_bits - rc->total_target_bits;
 
-  if (is_altref_enabled(oxcf) && cpi->refresh_alt_ref_frame &&
+  if (is_altref_enabled(cpi) && cpi->refresh_alt_ref_frame &&
       (cm->frame_type != KEY_FRAME))
     // Update the alternate reference frame stats as appropriate.
     update_alt_ref_frame_stats(cpi);
@@ -1349,8 +1349,9 @@
   return target_index - qindex;
 }
 
-void vp9_rc_set_gf_max_interval(const VP9EncoderConfig *const oxcf,
+void vp9_rc_set_gf_max_interval(const VP9_COMP *const cpi,
                                 RATE_CONTROL *const rc) {
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   // Set Maximum gf/arf interval
   rc->max_gf_interval = 16;
 
@@ -1359,7 +1360,7 @@
   if (rc->static_scene_max_gf_interval > (MAX_LAG_BUFFERS * 2))
     rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2;
 
-  if (is_altref_enabled(oxcf)) {
+  if (is_altref_enabled(cpi)) {
     if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
       rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
   }
@@ -1392,5 +1393,5 @@
   rc->max_frame_bandwidth = MAX(MAX((cm->MBs * MAX_MB_RATE), MAXRATE_1080P),
                                     vbr_max_bits);
 
-  vp9_rc_set_gf_max_interval(oxcf, rc);
+  vp9_rc_set_gf_max_interval(cpi, rc);
 }
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index a15235c..456daf4 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -189,7 +189,7 @@
 
 void vp9_rc_update_framerate(struct VP9_COMP *cpi);
 
-void vp9_rc_set_gf_max_interval(const struct VP9EncoderConfig *const oxcf,
+void vp9_rc_set_gf_max_interval(const struct VP9_COMP *const cpi,
                                 RATE_CONTROL *const rc);
 
 #ifdef __cplusplus
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index f271182..450cab4 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -296,6 +296,7 @@
   }
   if (speed >= 8) {
     int i;
+    sf->max_intra_bsize = BLOCK_32X32;
     for (i = 0; i < BLOCK_SIZES; ++i)
       sf->inter_mode_mask[i] = INTER_NEAREST;
   }
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index 07c17b2..1eb4509 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -19,6 +19,7 @@
   const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   int layer;
   int layer_end;
+  int alt_ref_idx = svc->number_spatial_layers;
 
   svc->spatial_layer_id = 0;
   svc->temporal_layer_id = 0;
@@ -34,7 +35,6 @@
     RATE_CONTROL *const lrc = &lc->rc;
     int i;
     lc->current_video_frame_in_layer = 0;
-    lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q;
     lrc->ni_av_qi = oxcf->worst_allowed_q;
     lrc->total_actual_bits = 0;
     lrc->total_target_vs_actual = 0;
@@ -48,14 +48,24 @@
     for (i = 0; i < RATE_FACTOR_LEVELS; ++i) {
       lrc->rate_correction_factors[i] = 1.0;
     }
+    lc->layer_size = 0;
 
     if (svc->number_temporal_layers > 1) {
       lc->target_bandwidth = oxcf->ts_target_bitrate[layer];
       lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q;
+      lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q;
     } else {
       lc->target_bandwidth = oxcf->ss_target_bitrate[layer];
       lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q;
       lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q;
+      lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q +
+                                          oxcf->best_allowed_q) / 2;
+      lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q +
+                                            oxcf->best_allowed_q) / 2;
+      if (oxcf->ss_play_alternate[layer])
+        lc->alt_ref_idx = alt_ref_idx++;
+      else
+        lc->alt_ref_idx = -1;
     }
 
     lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level_ms),
@@ -153,7 +163,7 @@
                                    oxcf->two_pass_vbrmin_section / 100);
   lrc->max_frame_bandwidth = (int)(((int64_t)lrc->avg_frame_bandwidth *
                                    oxcf->two_pass_vbrmax_section) / 100);
-  vp9_rc_set_gf_max_interval(oxcf, lrc);
+  vp9_rc_set_gf_max_interval(cpi, lrc);
 }
 
 void vp9_restore_layer_context(VP9_COMP *const cpi) {
@@ -164,6 +174,7 @@
   cpi->rc = lc->rc;
   cpi->twopass = lc->twopass;
   cpi->oxcf.target_bandwidth = lc->target_bandwidth;
+  cpi->alt_ref_source = lc->alt_ref_source;
   // 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).
   if (cpi->svc.number_temporal_layers > 1) {
@@ -179,6 +190,7 @@
   lc->rc = cpi->rc;
   lc->twopass = cpi->twopass;
   lc->target_bandwidth = (int)oxcf->target_bandwidth;
+  lc->alt_ref_source = cpi->alt_ref_source;
 }
 
 void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
@@ -239,7 +251,7 @@
 static int copy_svc_params(VP9_COMP *const cpi, struct lookahead_entry *buf) {
   int layer_id;
   vpx_svc_parameters_t *layer_param;
-  vpx_enc_frame_flags_t flags;
+  LAYER_CONTEXT *lc;
 
   // Find the next layer to be encoded
   for (layer_id = 0; layer_id < cpi->svc.number_spatial_layers; ++layer_id) {
@@ -251,12 +263,46 @@
     return 1;
 
   layer_param = &buf->svc_params[layer_id];
-  buf->flags = flags = layer_param->flags;
   cpi->svc.spatial_layer_id = layer_param->spatial_layer;
   cpi->svc.temporal_layer_id = layer_param->temporal_layer;
-  cpi->lst_fb_idx = layer_param->lst_fb_idx;
-  cpi->gld_fb_idx = layer_param->gld_fb_idx;
-  cpi->alt_fb_idx = layer_param->alt_fb_idx;
+
+  cpi->lst_fb_idx = cpi->svc.spatial_layer_id;
+
+  if (cpi->svc.spatial_layer_id < 1)
+    cpi->gld_fb_idx = cpi->lst_fb_idx;
+  else
+    cpi->gld_fb_idx = cpi->svc.spatial_layer_id - 1;
+
+  lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
+
+  if (lc->current_video_frame_in_layer == 0) {
+    if (cpi->svc.spatial_layer_id >= 2)
+      cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2;
+    else
+      cpi->alt_fb_idx = cpi->lst_fb_idx;
+  } else {
+    if (cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id]) {
+      cpi->alt_fb_idx = lc->alt_ref_idx;
+      if (!lc->has_alt_frame)
+        cpi->ref_frame_flags &= (~VP9_ALT_FLAG);
+    } else {
+      // Find a proper alt_fb_idx for layers that don't have alt ref frame
+      if (cpi->svc.spatial_layer_id == 0) {
+        cpi->alt_fb_idx = cpi->lst_fb_idx;
+      } else {
+        LAYER_CONTEXT *lc_lower =
+            &cpi->svc.layer_context[cpi->svc.spatial_layer_id - 1];
+
+        if (cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id - 1] &&
+            lc_lower->alt_ref_source != NULL)
+          cpi->alt_fb_idx = lc_lower->alt_ref_idx;
+        else if (cpi->svc.spatial_layer_id >= 2)
+          cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2;
+        else
+          cpi->alt_fb_idx = cpi->lst_fb_idx;
+      }
+    }
+  }
 
   if (vp9_set_size_literal(cpi, layer_param->width, layer_param->height) != 0)
     return VPX_CODEC_INVALID_PARAM;
@@ -270,9 +316,7 @@
 
   vp9_set_high_precision_mv(cpi, 1);
 
-  // Retrieve the encoding flags for each layer and apply it to encoder.
-  // It includes reference frame flags and update frame flags.
-  vp9_apply_encoding_flags(cpi, flags);
+  cpi->alt_ref_source = get_layer_context(&cpi->svc)->alt_ref_source;
 
   return 0;
 }
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 3ebb831..7b533e4 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -29,6 +29,10 @@
   unsigned int current_video_frame_in_layer;
   int is_key_frame;
   vpx_svc_parameters_t svc_params_received;
+  struct lookahead_entry  *alt_ref_source;
+  int alt_ref_idx;
+  int has_alt_frame;
+  size_t layer_size;
 } LAYER_CONTEXT;
 
 typedef struct {
@@ -36,6 +40,11 @@
   int temporal_layer_id;
   int number_spatial_layers;
   int number_temporal_layers;
+
+  // Store scaled source frames to be used for temporal filter to generate
+  // a alt ref frame.
+  YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
+
   // 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.
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index caa831c..6af8510 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -432,12 +432,6 @@
   frames_to_blur_forward = ((frames_to_blur - 1) / 2);
   start_frame = distance + frames_to_blur_forward;
 
-  // Setup scaling factors. Scaling on each of the arnr frames not supported.
-  vp9_setup_scale_factors_for_frame(&sf,
-      get_frame_new_buffer(cm)->y_crop_width,
-      get_frame_new_buffer(cm)->y_crop_height,
-      cm->width, cm->height);
-
   // Setup frame pointers, NULL indicates frame not included in filter.
   vp9_zero(cpi->frames);
   for (frame = 0; frame < frames_to_blur; ++frame) {
@@ -447,6 +441,41 @@
     cpi->frames[frames_to_blur - 1 - frame] = &buf->img;
   }
 
+  // Setup scaling factors. Scaling on each of the arnr frames is not supported
+  if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+    // In spatial svc the scaling factors might be less then 1/2. So we will use
+    // non-normative scaling.
+    int frame_used = 0;
+    vp9_setup_scale_factors_for_frame(&sf,
+                                      get_frame_new_buffer(cm)->y_crop_width,
+                                      get_frame_new_buffer(cm)->y_crop_height,
+                                      get_frame_new_buffer(cm)->y_crop_width,
+                                      get_frame_new_buffer(cm)->y_crop_height);
+
+    for (frame = 0; frame < frames_to_blur; ++frame) {
+      if (cm->mi_cols * MI_SIZE != cpi->frames[frame]->y_width ||
+          cm->mi_rows * MI_SIZE != cpi->frames[frame]->y_height) {
+        if (vp9_realloc_frame_buffer(&cpi->svc.scaled_frames[frame_used],
+                                     cm->width, cm->height,
+                                     cm->subsampling_x, cm->subsampling_y,
+                                     VP9_ENC_BORDER_IN_PIXELS, NULL, NULL,
+                                     NULL))
+          vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+                             "Failed to reallocate alt_ref_buffer");
+
+        cpi->frames[frame] =
+            vp9_scale_if_required(cm, cpi->frames[frame],
+                                  &cpi->svc.scaled_frames[frame_used]);
+        ++frame_used;
+      }
+    }
+  } else {
+    vp9_setup_scale_factors_for_frame(&sf,
+                                      get_frame_new_buffer(cm)->y_crop_width,
+                                      get_frame_new_buffer(cm)->y_crop_height,
+                                      cm->width, cm->height);
+  }
+
   temporal_filter_iterate_c(cpi, frames_to_blur, frames_to_blur_backward,
                             strength, &sf);
 }
diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c
index dcca92d..6068b85 100644
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -55,15 +55,6 @@
   -CATEGORY5_TOKEN, -CATEGORY6_TOKEN   // 7 = CAT_FIVE
 };
 
-static const vp9_prob Pcat1[] = { 159};
-static const vp9_prob Pcat2[] = { 165, 145};
-static const vp9_prob Pcat3[] = { 173, 148, 140};
-static const vp9_prob Pcat4[] = { 176, 155, 140, 135};
-static const vp9_prob Pcat5[] = { 180, 157, 141, 134, 130};
-static const vp9_prob Pcat6[] = {
-  254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
-};
-
 static vp9_tree_index cat1[2], cat2[4], cat3[6], cat4[8], cat5[10], cat6[28];
 
 static void init_bit_tree(vp9_tree_index *p, int n) {
@@ -87,18 +78,18 @@
 }
 
 const vp9_extra_bit vp9_extra_bits[ENTROPY_TOKENS] = {
-  {0, 0, 0, 0},           // ZERO_TOKEN
-  {0, 0, 0, 1},           // ONE_TOKEN
-  {0, 0, 0, 2},           // TWO_TOKEN
-  {0, 0, 0, 3},           // THREE_TOKEN
-  {0, 0, 0, 4},           // FOUR_TOKEN
-  {cat1, Pcat1, 1, 5},    // CATEGORY1_TOKEN
-  {cat2, Pcat2, 2, 7},    // CATEGORY2_TOKEN
-  {cat3, Pcat3, 3, 11},   // CATEGORY3_TOKEN
-  {cat4, Pcat4, 4, 19},   // CATEGORY4_TOKEN
-  {cat5, Pcat5, 5, 35},   // CATEGORY5_TOKEN
-  {cat6, Pcat6, 14, 67},  // CATEGORY6_TOKEN
-  {0, 0, 0, 0}            // EOB_TOKEN
+  {0, 0, 0, 0},                              // ZERO_TOKEN
+  {0, 0, 0, 1},                              // ONE_TOKEN
+  {0, 0, 0, 2},                              // TWO_TOKEN
+  {0, 0, 0, 3},                              // THREE_TOKEN
+  {0, 0, 0, 4},                              // FOUR_TOKEN
+  {cat1, vp9_cat1_prob, 1,  CAT1_MIN_VAL},   // CATEGORY1_TOKEN
+  {cat2, vp9_cat2_prob, 2,  CAT2_MIN_VAL},   // CATEGORY2_TOKEN
+  {cat3, vp9_cat3_prob, 3,  CAT3_MIN_VAL},   // CATEGORY3_TOKEN
+  {cat4, vp9_cat4_prob, 4,  CAT4_MIN_VAL},   // CATEGORY4_TOKEN
+  {cat5, vp9_cat5_prob, 5,  CAT5_MIN_VAL},   // CATEGORY5_TOKEN
+  {cat6, vp9_cat6_prob, 14, CAT6_MIN_VAL},   // CATEGORY6_TOKEN
+  {0, 0, 0, 0}                               // EOB_TOKEN
 };
 
 struct vp9_token vp9_coef_encodings[ENTROPY_TOKENS];
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 24dcbfa..86d5595 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "./vpx_config.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/internal/vpx_codec_internal.h"
 #include "./vpx_version.h"
@@ -88,7 +89,7 @@
   size_t                  pending_frame_magnitude;
   vpx_image_t             preview_img;
   vp8_postproc_cfg_t      preview_ppcfg;
-  vpx_codec_pkt_list_decl(128) pkt_list;
+  vpx_codec_pkt_list_decl(256) pkt_list;
   unsigned int                 fixed_kf_cntr;
 };
 
@@ -174,6 +175,19 @@
   }
 
   RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
+
+#ifdef CONFIG_SPATIAL_SVC
+  if (cfg->ss_number_layers > 1) {
+    int i, alt_ref_sum = 0;
+    for (i = 0; i < cfg->ss_number_layers; ++i) {
+      if (cfg->ss_enable_auto_alt_ref[i])
+        ++alt_ref_sum;
+    }
+    if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers)
+      ERROR("Not enough ref buffers for svc alt ref frames");
+  }
+#endif
+
   RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
   if (cfg->ts_number_layers > 1) {
     unsigned int i;
@@ -260,6 +274,7 @@
         ERROR("rc_twopass_stats_in missing EOS stats packet");
     }
   }
+
   if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
       extra_cfg->bit_depth > BITS_8)
     ERROR("High bit-depth not supported in profile < 2");
@@ -362,6 +377,10 @@
   oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
   oxcf->output_pkt_list        =  extra_cfg->pkt_list;
 
+#if CONFIG_FP_MB_STATS
+  oxcf->firstpass_mb_stats_in  = cfg->rc_firstpass_mb_stats_in;
+#endif
+
   oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
   oxcf->arnr_strength   = extra_cfg->arnr_strength;
   oxcf->arnr_type       = extra_cfg->arnr_type;
@@ -382,8 +401,12 @@
 
   if (oxcf->ss_number_layers > 1) {
     int i;
-    for (i = 0; i < VPX_SS_MAX_LAYERS; ++i)
+    for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
       oxcf->ss_target_bitrate[i] =  1000 * cfg->ss_target_bitrate[i];
+#ifdef CONFIG_SPATIAL_SVC
+      oxcf->ss_play_alternate[i] =  cfg->ss_enable_auto_alt_ref[i];
+#endif
+    }
   } else if (oxcf->ss_number_layers == 1) {
     oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
   }
@@ -648,6 +671,7 @@
 
     priv->extra_cfg = extracfg_map[i].cfg;
     priv->extra_cfg.pkt_list = &priv->pkt_list.head;
+
      // Maximum buffer size approximated based on having multiple ARF.
     priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 8;
 
@@ -864,6 +888,11 @@
         vpx_codec_cx_pkt_t pkt;
         VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
 
+#ifdef CONFIG_SPATIAL_SVC
+        if (cpi->use_svc && cpi->svc.number_temporal_layers == 1)
+          cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size;
+#endif
+
         // Pack invisible frames with the next visible frame
         if (cpi->common.show_frame == 0
 #ifdef CONFIG_SPATIAL_SVC
@@ -936,6 +965,18 @@
         vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
         cx_data += size;
         cx_data_sz -= size;
+#ifdef CONFIG_SPATIAL_SVC
+        if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+          vpx_codec_cx_pkt_t pkt = {0};
+          int i;
+          pkt.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES;
+          for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
+            pkt.data.layer_sizes[i] = cpi->svc.layer_context[i].layer_size;
+            cpi->svc.layer_context[i].layer_size = 0;
+          }
+          vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+        }
+#endif
       }
     }
   }
@@ -1224,6 +1265,7 @@
       VPX_VBR,            // rc_end_usage
 #if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
       {NULL, 0},          // rc_twopass_stats_in
+      {NULL, 0},          // rc_firstpass_mb_stats_in
 #endif
       256,                // rc_target_bandwidth
       0,                  // rc_min_quantizer
@@ -1245,6 +1287,9 @@
       9999,               // kf_max_dist
 
       VPX_SS_DEFAULT_LAYERS,  // ss_number_layers
+#ifdef CONFIG_SPATIAL_SVC
+      {0},
+#endif
       {0},                    // ss_target_bitrate
       1,                      // ts_number_layers
       {0},                    // ts_target_bitrate
diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c
index 6c15f6e..93e86e3 100644
--- a/vpx/src/svc_encodeframe.c
+++ b/vpx/src/svc_encodeframe.c
@@ -21,10 +21,12 @@
 #include <string.h>
 #define VPX_DISABLE_CTRL_TYPECHECKS 1
 #define VPX_CODEC_DISABLE_COMPAT 1
+#include "./vpx_config.h"
 #include "vpx/svc_context.h"
 #include "vpx/vp8cx.h"
 #include "vpx/vpx_encoder.h"
 #include "vpx_mem/vpx_mem.h"
+#include "vp9/common/vp9_onyxc_int.h"
 
 #ifdef __MINGW32__
 #define strtok_r strtok_s
@@ -65,6 +67,7 @@
   int scaling_factor_num[VPX_SS_MAX_LAYERS];
   int scaling_factor_den[VPX_SS_MAX_LAYERS];
   int quantizer[VPX_SS_MAX_LAYERS];
+  int enable_auto_alt_ref[VPX_SS_MAX_LAYERS];
 
   // accumulated statistics
   double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS];   // total/Y/U/V
@@ -80,7 +83,6 @@
   int encode_frame_count;
   int frame_received;
   int frame_within_gop;
-  vpx_enc_frame_flags_t enc_frame_flags;
   int layers;
   int layer;
   int is_keyframe;
@@ -238,6 +240,59 @@
   return res;
 }
 
+static vpx_codec_err_t parse_auto_alt_ref(SvcContext *svc_ctx,
+                                          const char *alt_ref_options) {
+  char *input_string;
+  char *token;
+  const char *delim = ",";
+  char *save_ptr;
+  int found = 0, enabled = 0;
+  int i, value;
+  vpx_codec_err_t res = VPX_CODEC_OK;
+  SvcInternal *const si = get_svc_internal(svc_ctx);
+
+  if (alt_ref_options == NULL || strlen(alt_ref_options) == 0) {
+    return VPX_CODEC_INVALID_PARAM;
+  } else {
+    input_string = strdup(alt_ref_options);
+  }
+
+  token = strtok_r(input_string, delim, &save_ptr);
+  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
+    if (token != NULL) {
+      value = atoi(token);
+      if (value < 0 || value > 1) {
+        svc_log(svc_ctx, SVC_LOG_ERROR,
+                "enable auto alt ref values: invalid value %s\n", token);
+        res = VPX_CODEC_INVALID_PARAM;
+        break;
+      }
+      token = strtok_r(NULL, delim, &save_ptr);
+      found = i + 1;
+    } else {
+      value = 0;
+    }
+    si->enable_auto_alt_ref[i] = value;
+    if (value > 0)
+      ++enabled;
+  }
+  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
+    svc_log(svc_ctx, SVC_LOG_ERROR,
+            "svc: quantizers: %d values required, but only %d specified\n",
+            svc_ctx->spatial_layers, found);
+    res = VPX_CODEC_INVALID_PARAM;
+  }
+  if (enabled > REF_FRAMES - svc_ctx->spatial_layers) {
+    svc_log(svc_ctx, SVC_LOG_ERROR,
+            "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
+            "enabled auto alt reference frame, but % layers are enabled\n",
+            REF_FRAMES - svc_ctx->spatial_layers, enabled);
+    res = VPX_CODEC_INVALID_PARAM;
+  }
+  free(input_string);
+  return res;
+}
+
 static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) {
   svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n",
           value);
@@ -335,6 +390,9 @@
     } else if (strcmp("quantizers", option_name) == 0) {
       res = parse_quantizer_values(svc_ctx, option_value);
       if (res != VPX_CODEC_OK) break;
+    } else if (strcmp("auto-alt-refs", option_name) == 0) {
+      res = parse_auto_alt_ref(svc_ctx, option_value);
+      if (res != VPX_CODEC_OK) break;
     } else {
       svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
       res = VPX_CODEC_INVALID_PARAM;
@@ -382,6 +440,7 @@
                              vpx_codec_iface_t *iface,
                              vpx_codec_enc_cfg_t *enc_cfg) {
   vpx_codec_err_t res;
+  int i;
   SvcInternal *const si = get_svc_internal(svc_ctx);
   if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
       enc_cfg == NULL) {
@@ -428,7 +487,6 @@
   // TODO(Minghai): Optimize the mechanism of allocating bits after
   // implementing svc two pass rate control.
   if (si->layers > 1) {
-    int i;
     float total = 0;
     float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
 
@@ -452,6 +510,9 @@
     }
   }
 
+  for (i = 0; i < si->layers; ++i)
+    enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i];
+
   // modify encoder configuration
   enc_cfg->ss_number_layers = si->layers;
   enc_cfg->ts_number_layers = 1;  // Temporal layers not used in this encoder.
@@ -482,106 +543,10 @@
 
   vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
   vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1);
-  vpx_codec_control(codec_ctx, VP8E_SET_ENABLEAUTOALTREF, 0);
 
   return VPX_CODEC_OK;
 }
 
-static void accumulate_frame_size_for_each_layer(SvcInternal *const si,
-                                                 const uint8_t *const buf,
-                                                 const size_t size) {
-  uint8_t marker = buf[size - 1];
-  if ((marker & 0xe0) == 0xc0) {
-    const uint32_t frames = (marker & 0x7) + 1;
-    const uint32_t mag = ((marker >> 3) & 0x3) + 1;
-    const size_t index_sz = 2 + mag * frames;
-
-    uint8_t marker2 = buf[size - index_sz];
-
-    if (size >= index_sz && marker2 == marker) {
-      // found a valid superframe index
-      uint32_t i, j;
-      const uint8_t *x = &buf[size - index_sz + 1];
-
-      // frames has a maximum of 8 and mag has a maximum of 4.
-      for (i = 0; i < frames; i++) {
-        uint32_t this_sz = 0;
-
-        for (j = 0; j < mag; j++)
-          this_sz |= (*x++) << (j * 8);
-        si->bytes_sum[i] += this_sz;
-      }
-    }
-  }
-}
-
-// SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h
-
-// encoder should reference the last frame
-#define USE_LAST (1 << 0)
-
-// encoder should reference the alt ref frame
-#define USE_ARF (1 << 1)
-
-// encoder should reference the golden frame
-#define USE_GF (1 << 2)
-
-// encoder should copy current frame to the last frame buffer
-#define UPDATE_LAST (1 << 3)
-
-// encoder should copy current frame to the alt ref frame buffer
-#define UPDATE_ARF (1 << 4)
-
-// encoder should copy current frame to the golden frame
-#define UPDATE_GF (1 << 5)
-
-static int map_vp8_flags(int svc_flags) {
-  int flags = 0;
-
-  if (!(svc_flags & USE_LAST)) flags |= VP8_EFLAG_NO_REF_LAST;
-  if (!(svc_flags & USE_ARF)) flags |= VP8_EFLAG_NO_REF_ARF;
-  if (!(svc_flags & USE_GF)) flags |= VP8_EFLAG_NO_REF_GF;
-
-  if (svc_flags & UPDATE_LAST) {
-    // last is updated automatically
-  } else {
-    flags |= VP8_EFLAG_NO_UPD_LAST;
-  }
-  if (svc_flags & UPDATE_ARF) {
-    flags |= VP8_EFLAG_FORCE_ARF;
-  } else {
-    flags |= VP8_EFLAG_NO_UPD_ARF;
-  }
-  if (svc_flags & UPDATE_GF) {
-    flags |= VP8_EFLAG_FORCE_GF;
-  } else {
-    flags |= VP8_EFLAG_NO_UPD_GF;
-  }
-  return flags;
-}
-
-static void calculate_enc_frame_flags(SvcContext *svc_ctx) {
-  vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
-  SvcInternal *const si = get_svc_internal(svc_ctx);
-  const int is_keyframe = (si->frame_within_gop == 0);
-
-  // keyframe layer zero is identical for all modes
-  if (is_keyframe && si->layer == 0) {
-    si->enc_frame_flags = VPX_EFLAG_FORCE_KF;
-    return;
-  }
-
-  if (si->layer == 0) {
-    flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
-  } else if (is_keyframe) {
-    flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
-  } else {
-    flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
-  }
-
-  si->enc_frame_flags = flags;
-}
-
 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
                                              int layer,
                                              unsigned int *width,
@@ -621,7 +586,6 @@
   memset(&svc_params, 0, sizeof(svc_params));
   svc_params.temporal_layer = 0;
   svc_params.spatial_layer = si->layer;
-  svc_params.flags = si->enc_frame_flags;
 
   layer = si->layer;
   if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
@@ -640,33 +604,6 @@
   }
 
   svc_params.distance_from_i_frame = si->frame_within_gop;
-
-  // Use buffer i for layer i LST
-  svc_params.lst_fb_idx = si->layer;
-
-  // Use buffer i-1 for layer i Alt (Inter-layer prediction)
-  svc_params.alt_fb_idx = (si->layer > 0) ? si->layer - 1 : 0;
-  svc_params.gld_fb_idx = svc_params.lst_fb_idx;
-
-  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
-          si->encode_frame_count, si->layer, svc_params.width,
-          svc_params.height, svc_params.min_quantizer);
-
-  if (svc_params.flags == VPX_EFLAG_FORCE_KF) {
-    svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n");
-  } else {
-    svc_log(
-        svc_ctx, SVC_LOG_DEBUG, "Using:    LST/GLD/ALT [%2d|%2d|%2d]\n",
-        svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx,
-        svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx,
-        svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx);
-    svc_log(
-        svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n",
-        svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx,
-        svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx,
-        svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx);
-  }
-
   vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
 }
 
@@ -705,7 +642,6 @@
   if (rawimg != NULL) {
     // encode each layer
     for (si->layer = 0; si->layer < si->layers; ++si->layer) {
-      calculate_enc_frame_flags(svc_ctx);
       set_svc_parameters(svc_ctx, codec_ctx);
     }
   }
@@ -723,8 +659,6 @@
         fd_list_add(&si->frame_list, fd_create(cx_pkt->data.frame.buf,
                                                cx_pkt->data.frame.sz,
                                                cx_pkt->data.frame.flags));
-        accumulate_frame_size_for_each_layer(si, cx_pkt->data.frame.buf,
-                                             cx_pkt->data.frame.sz);
 
         svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, "
                 "pts: %d\n", si->frame_received,
@@ -775,6 +709,12 @@
         si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz;
         break;
       }
+      case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: {
+        int i;
+        for (i = 0; i < si->layers; ++i)
+          si->bytes_sum[i] += cx_pkt->data.layer_sizes[i];
+        break;
+      }
       default: {
         break;
       }
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index 67cbdb1..36c587f 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -298,7 +298,6 @@
   unsigned int height;        /**< height of current spatial layer */
   int spatial_layer;          /**< current spatial layer number - 0 = base */
   int temporal_layer;         /**< current temporal layer number - 0 = base */
-  int flags;                  /**< encode frame flags */
   int max_quantizer;          /**< max quantizer for current layer */
   int min_quantizer;          /**< min quantizer for current layer */
   int distance_from_i_frame;  /**< frame number within current gop */
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index 571ad3f..345c73b 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -155,7 +155,11 @@
   enum vpx_codec_cx_pkt_kind {
     VPX_CODEC_CX_FRAME_PKT,    /**< Compressed video frame */
     VPX_CODEC_STATS_PKT,       /**< Two-pass statistics for this frame */
+    VPX_CODEC_FPMB_STATS_PKT,  /**< first pass mb statistics for this frame */
     VPX_CODEC_PSNR_PKT,        /**< PSNR statistics for this frame */
+#ifdef CONFIG_SPATIAL_SVC
+    VPX_CODEC_SPATIAL_SVC_LAYER_SIZES, /**< Sizes for each layer in this frame*/
+#endif
     VPX_CODEC_CUSTOM_PKT = 256 /**< Algorithm extensions  */
   };
 
@@ -185,12 +189,16 @@
 
       } frame;  /**< data for compressed frame packet */
       struct vpx_fixed_buf twopass_stats;  /**< data for two-pass packet */
+      struct vpx_fixed_buf firstpass_mb_stats; /**< first pass mb packet */
       struct vpx_psnr_pkt {
         unsigned int samples[4];  /**< Number of samples, total/y/u/v */
         uint64_t     sse[4];      /**< sum squared error, total/y/u/v */
         double       psnr[4];     /**< PSNR, total/y/u/v */
       } psnr;                       /**< data for PSNR packet */
       struct vpx_fixed_buf raw;     /**< data for arbitrary packets */
+#ifdef CONFIG_SPATIAL_SVC
+      size_t layer_sizes[VPX_SS_MAX_LAYERS];
+#endif
 
       /* This packet size is fixed to allow codecs to extend this
        * interface without having to manage storage for raw packets,
@@ -446,6 +454,12 @@
      */
     struct vpx_fixed_buf   rc_twopass_stats_in;
 
+    /*!\brief first pass mb stats buffer.
+     *
+     * A buffer containing all of the first pass mb stats packets produced
+     * in the first pass, concatenated.
+     */
+    struct vpx_fixed_buf   rc_firstpass_mb_stats_in;
 
     /*!\brief Target data rate
      *
@@ -623,6 +637,15 @@
      */
     unsigned int           ss_number_layers;
 
+#ifdef CONFIG_SPATIAL_SVC
+    /*!\brief Enable auto alt reference flags for each spatial layer.
+     *
+     * These values specify if auto alt reference frame is enabled for each
+     * spatial layer.
+     */
+    int                    ss_enable_auto_alt_ref[VPX_SS_MAX_LAYERS];
+#endif
+
     /*!\brief Target bitrate for each spatial layer.
      *
      * These values specify the target coding bitrate to be used for each
diff --git a/vpxdec.c b/vpxdec.c
index 1213ab6..5c98d26 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -875,6 +875,7 @@
           }
           scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width,
                                      display_height, 16);
+          scaled_img->bit_depth = img->bit_depth;
         }
 
         if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
@@ -901,7 +902,7 @@
                                         vpx_input_ctx.width,
                                         vpx_input_ctx.height,
                                         &vpx_input_ctx.framerate,
-                                        img->fmt, 8);
+                                        img->fmt, img->bit_depth);
             if (do_md5) {
               MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
             } else {
diff --git a/vpxenc.c b/vpxenc.c
index 60ba547..78a1c90 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -141,6 +141,10 @@
                                                   "Pass to execute (1/2)");
 static const arg_def_t fpf_name         = ARG_DEF(NULL, "fpf", 1,
                                                   "First pass statistics file name");
+#if CONFIG_FP_MB_STATS
+static const arg_def_t fpmbf_name         = ARG_DEF(NULL, "fpmbf", 1,
+                                      "First pass block statistics file name");
+#endif
 static const arg_def_t limit = ARG_DEF(NULL, "limit", 1,
                                        "Stop encoding after n input frames");
 static const arg_def_t skip = ARG_DEF(NULL, "skip", 1,
@@ -572,6 +576,9 @@
   struct vpx_codec_enc_cfg  cfg;
   const char               *out_fn;
   const char               *stats_fn;
+#if CONFIG_FP_MB_STATS
+  const char               *fpmb_stats_fn;
+#endif
   stereo_format_t           stereo_fmt;
   int                       arg_ctrls[ARG_CTRL_CNT_MAX][2];
   int                       arg_ctrl_cnt;
@@ -597,6 +604,9 @@
   uint64_t                  cx_time;
   size_t                    nbytes;
   stats_io_t                stats;
+#if CONFIG_FP_MB_STATS
+  stats_io_t                fpmb_stats;
+#endif
   struct vpx_image         *img;
   vpx_codec_ctx_t           decoder;
   int                       mismatch_seen;
@@ -873,6 +883,10 @@
       config->out_fn = arg.val;
     } else if (arg_match(&arg, &fpf_name, argi)) {
       config->stats_fn = arg.val;
+#if CONFIG_FP_MB_STATS
+    } else if (arg_match(&arg, &fpmbf_name, argi)) {
+      config->fpmb_stats_fn = arg.val;
+#endif
     } else if (arg_match(&arg, &use_ivf, argi)) {
       config->write_webm = 0;
     } else if (arg_match(&arg, &threads, argi)) {
@@ -965,8 +979,8 @@
               break;
 
           /* Update/insert */
-          assert(j < ARG_CTRL_CNT_MAX);
-          if (j < ARG_CTRL_CNT_MAX) {
+          assert(j < (int)ARG_CTRL_CNT_MAX);
+          if (j < (int)ARG_CTRL_CNT_MAX) {
             config->arg_ctrls[j][0] = ctrl_args_map[i];
             config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg);
             if (j == config->arg_ctrl_cnt)
@@ -1029,6 +1043,17 @@
         fatal("Stream %d: duplicate stats file (from stream %d)",
               streami->index, stream->index);
     }
+
+#if CONFIG_FP_MB_STATS
+    /* Check for two streams sharing a mb stats file. */
+    if (streami != stream) {
+      const char *a = stream->config.fpmb_stats_fn;
+      const char *b = streami->config.fpmb_stats_fn;
+      if (a && b && !strcmp(a, b))
+        fatal("Stream %d: duplicate mb stats file (from stream %d)",
+              streami->index, stream->index);
+    }
+#endif
   }
 }
 
@@ -1200,11 +1225,27 @@
       fatal("Failed to open statistics store");
   }
 
+#if CONFIG_FP_MB_STATS
+  if (stream->config.fpmb_stats_fn) {
+    if (!stats_open_file(&stream->fpmb_stats,
+                         stream->config.fpmb_stats_fn, pass))
+      fatal("Failed to open mb statistics store");
+  } else {
+    if (!stats_open_mem(&stream->fpmb_stats, pass))
+      fatal("Failed to open mb statistics store");
+  }
+#endif
+
   stream->config.cfg.g_pass = global->passes == 2
                               ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS
                             : VPX_RC_ONE_PASS;
-  if (pass)
+  if (pass) {
     stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats);
+#if CONFIG_FP_MB_STATS
+    stream->config.cfg.rc_firstpass_mb_stats_in =
+        stats_get(&stream->fpmb_stats);
+#endif
+  }
 
   stream->cx_time = 0;
   stream->nbytes = 0;
@@ -1388,6 +1429,14 @@
                     pkt->data.twopass_stats.sz);
         stream->nbytes += pkt->data.raw.sz;
         break;
+#if CONFIG_FP_MB_STATS
+      case VPX_CODEC_FPMB_STATS_PKT:
+        stats_write(&stream->fpmb_stats,
+                    pkt->data.firstpass_mb_stats.buf,
+                    pkt->data.firstpass_mb_stats.sz);
+        stream->nbytes += pkt->data.raw.sz;
+        break;
+#endif
       case VPX_CODEC_PSNR_PKT:
 
         if (global->show_psnr) {
@@ -1517,7 +1566,7 @@
   vpx_image_t raw;
   int frame_avail, got_data;
 
-  struct VpxInputContext input = {0};
+  struct VpxInputContext input;
   struct VpxEncoderConfig global;
   struct stream_state *streams = NULL;
   char **argv, **argi;
@@ -1525,6 +1574,7 @@
   int stream_cnt = 0;
   int res = 0;
 
+  memset(&input, 0, sizeof(input));
   exec_name = argv_[0];
 
   if (argc < 3)
@@ -1777,6 +1827,10 @@
 
     FOREACH_STREAM(stats_close(&stream->stats, global.passes - 1));
 
+#if CONFIG_FP_MB_STATS
+    FOREACH_STREAM(stats_close(&stream->fpmb_stats, global.passes - 1));
+#endif
+
     if (global.pass)
       break;
   }
diff --git a/y4minput.c b/y4minput.c
index b005b71..520c332 100644
--- a/y4minput.c
+++ b/y4minput.c
@@ -683,6 +683,7 @@
 static void y4m_convert_mono_420jpeg(y4m_input *_y4m, unsigned char *_dst,
                                      unsigned char *_aux) {
   int c_sz;
+  (void)_aux;
   _dst += _y4m->pic_w * _y4m->pic_h;
   c_sz = ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
          ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
@@ -692,6 +693,9 @@
 /*No conversion function needed.*/
 static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
                              unsigned char *_aux) {
+  (void)_y4m;
+  (void)_dst;
+  (void)_aux;
 }
 
 int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,