Merge "[spatial svc]Multiple frame context feature"
authorMinghai Shang <minghai@google.com>
Mon, 25 Aug 2014 21:29:49 +0000 (14:29 -0700)
committerGerrit Code Review <gerrit@gerrit.golo.chromium.org>
Mon, 25 Aug 2014 21:29:49 +0000 (14:29 -0700)
1  2 
test/svc_test.cc
vp9/encoder/vp9_bitstream.c
vp9/encoder/vp9_encoder.c
vp9/encoder/vp9_svc_layercontext.c
vp9/encoder/vp9_svc_layercontext.h
vp9/vp9_cx_iface.c

diff --combined test/svc_test.cc
@@@ -60,7 -60,7 +60,7 @@@ class SvcTest : public ::testing::Test 
      codec_enc_.kf_min_dist = 100;
      codec_enc_.kf_max_dist = 100;
  
 -    vpx_codec_dec_cfg_t dec_cfg = {0};
 +    vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();
      VP9CodecFactory codec_factory;
      decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
    }
        video.Next();
      }
  
-     // Flush encoder and test EOS packet
+     // Flush encoder and test EOS packet.
      res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
                           video.duration(), VPX_DL_GOOD_QUALITY);
      stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_);
          EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
        }
  
-       outputs[*frame_received].buf = malloc(frame_size);
+       outputs[*frame_received].buf = malloc(frame_size + 16);
        ASSERT_TRUE(outputs[*frame_received].buf != NULL);
        memcpy(outputs[*frame_received].buf, vpx_svc_get_buffer(&svc_),
               frame_size);
        video.Next();
      }
  
-     // Flush Encoder
+     // Flush encoder.
      res = vpx_svc_encode(&svc_, &codec_, NULL, 0,
                           video.duration(), VPX_DL_GOOD_QUALITY);
      EXPECT_EQ(VPX_CODEC_OK, res);
      StoreFrames(n, outputs, &frame_received);
  
-     EXPECT_EQ(frame_received, (size_t)n);
+     EXPECT_EQ(frame_received, static_cast<size_t>(n));
  
      ReleaseEncoder();
    }
        ++decoded_frames;
  
        DxDataIterator dec_iter = decoder_->GetDxData();
-       while (dec_iter.Next()) {
+       while (dec_iter.Next() != NULL) {
          ++received_frames;
        }
      }
  
    void DropEnhancementLayers(struct vpx_fixed_buf *const inputs,
                               const int num_super_frames,
-                              const int remained_layers) {
+                              const int remained_layers,
+                              const bool is_multiple_frame_context) {
      ASSERT_TRUE(inputs != NULL);
      ASSERT_GT(num_super_frames, 0);
      ASSERT_GT(remained_layers, 0);
        uint8_t *frame_data = static_cast<uint8_t *>(inputs[i].buf);
        uint8_t *frame_start = frame_data;
        for (frame = 0; frame < frame_count; ++frame) {
-         // Looking for a visible frame
+         // Looking for a visible frame.
          if (frame_data[0] & 0x02) {
            ++frames_found;
            if (frames_found == remained_layers)
          }
          frame_data += frame_sizes[frame];
        }
-       ASSERT_LT(frame, frame_count);
-       if (frame == frame_count - 1)
+       ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. "
+           << "remaining_layers: " << remained_layers
+           << "    super_frame: " << i
+           << "    is_multiple_frame_context: " << is_multiple_frame_context;
+       if (frame == frame_count - 1 && !is_multiple_frame_context)
          continue;
  
        frame_data += frame_sizes[frame];
+       // We need to add one more frame for multiple frame context.
+       if (is_multiple_frame_context)
+         ++frame;
        uint8_t marker =
            static_cast<const uint8_t *>(inputs[i].buf)[inputs[i].sz - 1];
        const uint32_t mag = ((marker >> 3) & 0x3) + 1;
        const size_t new_index_sz = 2 + mag * (frame + 1);
        marker &= 0x0f8;
        marker |= frame;
+       // Copy existing frame sizes.
+       memmove(frame_data + (is_multiple_frame_context ? 2 : 1),
+               frame_start + inputs[i].sz - index_sz + 1, new_index_sz - 2);
+       if (is_multiple_frame_context) {
+         // Add a one byte frame with flag show_existing frame.
+         *frame_data++ = 0x88 | (remained_layers - 1);
+       }
+       // New marker.
        frame_data[0] = marker;
-       memcpy(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1,
-              new_index_sz - 2);
-       frame_data[new_index_sz - 1] = marker;
-       inputs[i].sz = frame_data - frame_start + new_index_sz;
+       frame_data += (mag * (frame + 1) + 1);
+       if (is_multiple_frame_context) {
+         // Write the frame size for the one byte frame.
+         frame_data -= mag;
+         *frame_data++ = 1;
+         for (uint32_t j = 1; j < mag; ++j) {
+           *frame_data++ = 0;
+         }
+       }
+       *frame_data++ = marker;
+       inputs[i].sz = frame_data - frame_start;
+       if (is_multiple_frame_context) {
+         // Change the show frame flag to 0 for all frames.
+         for (int j = 0; j < frame; ++j) {
+           frame_start[0] &= ~2;
+           frame_start += frame_sizes[j];
+         }
+       }
      }
    }
  
@@@ -507,7 -540,7 +540,7 @@@ TEST_F(SvcTest, TwoPassEncode2LayersDec
    vpx_fixed_buf outputs[10];
    memset(&outputs[0], 0, sizeof(outputs));
    Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
-   DropEnhancementLayers(&outputs[0], 10, 1);
+   DropEnhancementLayers(&outputs[0], 10, 1, false);
    DecodeNFrames(&outputs[0], 10);
    FreeBitstreamBuffers(&outputs[0], 10);
  }
@@@ -525,13 -558,13 +558,13 @@@ TEST_F(SvcTest, TwoPassEncode5LayersDec
    Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]);
  
    DecodeNFrames(&outputs[0], 10);
-   DropEnhancementLayers(&outputs[0], 10, 4);
+   DropEnhancementLayers(&outputs[0], 10, 4, false);
    DecodeNFrames(&outputs[0], 10);
-   DropEnhancementLayers(&outputs[0], 10, 3);
+   DropEnhancementLayers(&outputs[0], 10, 3, false);
    DecodeNFrames(&outputs[0], 10);
-   DropEnhancementLayers(&outputs[0], 10, 2);
+   DropEnhancementLayers(&outputs[0], 10, 2, false);
    DecodeNFrames(&outputs[0], 10);
-   DropEnhancementLayers(&outputs[0], 10, 1);
+   DropEnhancementLayers(&outputs[0], 10, 1, false);
    DecodeNFrames(&outputs[0], 10);
  
    FreeBitstreamBuffers(&outputs[0], 10);
@@@ -568,12 -601,121 +601,121 @@@ TEST_F(SvcTest, TwoPassEncode3SNRLayers
    memset(&outputs[0], 0, sizeof(outputs));
    Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]);
    DecodeNFrames(&outputs[0], 20);
-   DropEnhancementLayers(&outputs[0], 20, 2);
+   DropEnhancementLayers(&outputs[0], 20, 2, false);
    DecodeNFrames(&outputs[0], 20);
-   DropEnhancementLayers(&outputs[0], 20, 1);
+   DropEnhancementLayers(&outputs[0], 20, 1, false);
    DecodeNFrames(&outputs[0], 20);
  
    FreeBitstreamBuffers(&outputs[0], 20);
  }
  
+ TEST_F(SvcTest, SetMultipleFrameContextOption) {
+   svc_.spatial_layers = 5;
+   vpx_codec_err_t res =
+       vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
+   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);
+   svc_.spatial_layers = 2;
+   res = vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
+   InitializeEncoder();
+ }
+ TEST_F(SvcTest, TwoPassEncode2LayersWithMultipleFrameContext) {
+   // First pass encode
+   std::string stats_buf;
+   Pass1EncodeNFrames(10, 2, &stats_buf);
+   // Second pass encode
+   codec_enc_.g_pass = VPX_RC_LAST_PASS;
+   codec_enc_.g_error_resilient = 0;
+   vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
+   vpx_fixed_buf outputs[10];
+   memset(&outputs[0], 0, sizeof(outputs));
+   Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+   DropEnhancementLayers(&outputs[0], 10, 2, true);
+   DecodeNFrames(&outputs[0], 10);
+   FreeBitstreamBuffers(&outputs[0], 10);
+ }
+ TEST_F(SvcTest, TwoPassEncode2LayersWithMultipleFrameContextDecodeBaselayer) {
+   // First pass encode
+   std::string stats_buf;
+   Pass1EncodeNFrames(10, 2, &stats_buf);
+   // Second pass encode
+   codec_enc_.g_pass = VPX_RC_LAST_PASS;
+   codec_enc_.g_error_resilient = 0;
+   vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
+   vpx_fixed_buf outputs[10];
+   memset(&outputs[0], 0, sizeof(outputs));
+   Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+   DropEnhancementLayers(&outputs[0], 10, 1, true);
+   DecodeNFrames(&outputs[0], 10);
+   FreeBitstreamBuffers(&outputs[0], 10);
+ }
+ TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContext) {
+   // First pass encode
+   std::string stats_buf;
+   vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
+   Pass1EncodeNFrames(10, 2, &stats_buf);
+   // Second pass encode
+   codec_enc_.g_pass = VPX_RC_LAST_PASS;
+   codec_enc_.g_error_resilient = 0;
+   vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 "
+                       "multi-frame-contexts=1");
+   vpx_fixed_buf outputs[10];
+   memset(&outputs[0], 0, sizeof(outputs));
+   Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+   DropEnhancementLayers(&outputs[0], 10, 2, true);
+   DecodeNFrames(&outputs[0], 10);
+   FreeBitstreamBuffers(&outputs[0], 10);
+ }
+ TEST_F(SvcTest, TwoPassEncode3SNRLayersWithMultipleFrameContextDecode321Layer) {
+   // First pass encode
+   std::string stats_buf;
+   vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
+   Pass1EncodeNFrames(10, 3, &stats_buf);
+   // Second pass encode
+   codec_enc_.g_pass = VPX_RC_LAST_PASS;
+   codec_enc_.g_error_resilient = 0;
+   vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 "
+                       "multi-frame-contexts=1");
+   vpx_fixed_buf outputs[10];
+   memset(&outputs[0], 0, sizeof(outputs));
+   Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]);
+   vpx_fixed_buf outputs_new[10];
+   for (int i = 0; i < 10; ++i) {
+     outputs_new[i].buf = malloc(outputs[i].sz + 16);
+     ASSERT_TRUE(outputs_new[i].buf != NULL);
+     memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+     outputs_new[i].sz = outputs[i].sz;
+   }
+   DropEnhancementLayers(&outputs_new[0], 10, 3, true);
+   DecodeNFrames(&outputs_new[0], 10);
+   for (int i = 0; i < 10; ++i) {
+     memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+     outputs_new[i].sz = outputs[i].sz;
+   }
+   DropEnhancementLayers(&outputs_new[0], 10, 2, true);
+   DecodeNFrames(&outputs_new[0], 10);
+   for (int i = 0; i < 10; ++i) {
+     memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+     outputs_new[i].sz = outputs[i].sz;
+   }
+   DropEnhancementLayers(&outputs_new[0], 10, 1, true);
+   DecodeNFrames(&outputs_new[0], 10);
+   FreeBitstreamBuffers(&outputs[0], 10);
+   FreeBitstreamBuffers(&outputs_new[0], 10);
+ }
  }  // namespace
@@@ -421,13 -421,11 +421,13 @@@ static void write_modes_sb(VP9_COMP *cp
    const int bs = (1 << bsl) / 4;
    PARTITION_TYPE partition;
    BLOCK_SIZE subsize;
 -  const MODE_INFO *m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
 +  const MODE_INFO *m = NULL;
  
    if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
      return;
  
 +  m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
 +
    partition = partition_lookup[bsl][m->mbmi.sb_type];
    write_partition(cm, xd, bs, mi_row, mi_col, partition, bsize, w);
    subsize = get_subsize(bsize, partition);
@@@ -1083,7 -1081,16 +1083,16 @@@ static void write_uncompressed_header(V
      write_bitdepth_colorspace_sampling(cm, wb);
      write_frame_size(cm, wb);
    } else {
-     if (!cm->show_frame)
+     // In spatial svc if it's not error_resilient_mode then we need to code all
+     // visible frames as invisible. But we need to keep the show_frame flag so
+     // that the publisher could know whether it is supposed to be visible.
+     // So we will code the show_frame flag as it is. Then code the intra_only
+     // bit here. This will make the bitstream incompatible. In the player we
+     // will change to show_frame flag to 0, then add an one byte frame with
+     // show_existing_frame flag which tells the decoder which frame we want to
+     // show.
+     if (!cm->show_frame ||
+         (is_spatial_svc(cpi) && cm->error_resilient_mode == 0))
        vp9_wb_write_bit(wb, cm->intra_only);
  
      if (!cm->error_resilient_mode)
@@@ -167,26 -167,6 +167,26 @@@ static void dealloc_compressor_data(VP9
    vpx_free(cpi->complexity_map);
    cpi->complexity_map = NULL;
  
 +  vpx_free(cpi->nmvcosts[0]);
 +  vpx_free(cpi->nmvcosts[1]);
 +  cpi->nmvcosts[0] = NULL;
 +  cpi->nmvcosts[1] = NULL;
 +
 +  vpx_free(cpi->nmvcosts_hp[0]);
 +  vpx_free(cpi->nmvcosts_hp[1]);
 +  cpi->nmvcosts_hp[0] = NULL;
 +  cpi->nmvcosts_hp[1] = NULL;
 +
 +  vpx_free(cpi->nmvsadcosts[0]);
 +  vpx_free(cpi->nmvsadcosts[1]);
 +  cpi->nmvsadcosts[0] = NULL;
 +  cpi->nmvsadcosts[1] = NULL;
 +
 +  vpx_free(cpi->nmvsadcosts_hp[0]);
 +  vpx_free(cpi->nmvsadcosts_hp[1]);
 +  cpi->nmvsadcosts_hp[0] = NULL;
 +  cpi->nmvsadcosts_hp[1] = NULL;
 +
    vp9_cyclic_refresh_free(cpi->cyclic_refresh);
    cpi->cyclic_refresh = NULL;
  
@@@ -232,15 -212,8 +232,15 @@@ static void save_coding_context(VP9_COM
    // intended for use in a re-code loop in vp9_compress_frame where the
    // quantizer value is adjusted between loop iterations.
    vp9_copy(cc->nmvjointcost,  cpi->mb.nmvjointcost);
 -  vp9_copy(cc->nmvcosts,  cpi->mb.nmvcosts);
 -  vp9_copy(cc->nmvcosts_hp,  cpi->mb.nmvcosts_hp);
 +
 +  vpx_memcpy(cc->nmvcosts[0], cpi->nmvcosts[0],
 +             MV_VALS * sizeof(*cpi->nmvcosts[0]));
 +  vpx_memcpy(cc->nmvcosts[1], cpi->nmvcosts[1],
 +             MV_VALS * sizeof(*cpi->nmvcosts[1]));
 +  vpx_memcpy(cc->nmvcosts_hp[0], cpi->nmvcosts_hp[0],
 +             MV_VALS * sizeof(*cpi->nmvcosts_hp[0]));
 +  vpx_memcpy(cc->nmvcosts_hp[1], cpi->nmvcosts_hp[1],
 +             MV_VALS * sizeof(*cpi->nmvcosts_hp[1]));
  
    vp9_copy(cc->segment_pred_probs, cm->seg.pred_probs);
  
@@@ -260,15 -233,8 +260,15 @@@ static void restore_coding_context(VP9_
    // Restore key state variables to the snapshot state stored in the
    // previous call to vp9_save_coding_context.
    vp9_copy(cpi->mb.nmvjointcost, cc->nmvjointcost);
 -  vp9_copy(cpi->mb.nmvcosts, cc->nmvcosts);
 -  vp9_copy(cpi->mb.nmvcosts_hp, cc->nmvcosts_hp);
 +
 +  vpx_memcpy(cpi->nmvcosts[0], cc->nmvcosts[0],
 +             MV_VALS * sizeof(*cc->nmvcosts[0]));
 +  vpx_memcpy(cpi->nmvcosts[1], cc->nmvcosts[1],
 +             MV_VALS * sizeof(*cc->nmvcosts[1]));
 +  vpx_memcpy(cpi->nmvcosts_hp[0], cc->nmvcosts_hp[0],
 +             MV_VALS * sizeof(*cc->nmvcosts_hp[0]));
 +  vpx_memcpy(cpi->nmvcosts_hp[1], cc->nmvcosts_hp[1],
 +             MV_VALS * sizeof(*cc->nmvcosts_hp[1]));
  
    vp9_copy(cm->seg.pred_probs, cc->segment_pred_probs);
  
@@@ -519,10 -485,18 +519,10 @@@ static void update_frame_size(VP9_COMP 
  }
  
  void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
 -  cpi->oxcf.framerate = framerate < 0.1 ? 30 : framerate;
 +  cpi->framerate = framerate < 0.1 ? 30 : framerate;
    vp9_rc_update_framerate(cpi);
  }
  
 -int64_t vp9_rescale(int64_t val, int64_t num, int denom) {
 -  int64_t llnum = num;
 -  int64_t llden = denom;
 -  int64_t llval = val;
 -
 -  return (llval * llnum / llden);
 -}
 -
  static void set_tile_limits(VP9_COMP *cpi) {
    VP9_COMMON *const cm = &cpi->common;
  
@@@ -544,7 -518,6 +544,7 @@@ static void init_config(struct VP9_COM
    VP9_COMMON *const cm = &cpi->common;
  
    cpi->oxcf = *oxcf;
 +  cpi->framerate = oxcf->init_framerate;
  
    cm->profile = oxcf->profile;
    cm->bit_depth = oxcf->bit_depth;
    // Temporal scalability.
    cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
  
 -  if ((cpi->svc.number_temporal_layers > 1 &&
 -      cpi->oxcf.rc_mode == VPX_CBR) ||
 -      (cpi->svc.number_spatial_layers > 1 &&
 -      cpi->oxcf.mode == TWO_PASS_SECOND_BEST)) {
 +  if ((cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) ||
 +      (cpi->svc.number_spatial_layers > 1 && cpi->oxcf.pass == 2)) {
      vp9_init_layer_context(cpi);
    }
  
    set_tile_limits(cpi);
  }
  
 +static void set_rc_buffer_sizes(RATE_CONTROL *rc,
 +                                const VP9EncoderConfig *oxcf) {
 +  const int64_t bandwidth = oxcf->target_bandwidth;
 +  const int64_t starting = oxcf->starting_buffer_level_ms;
 +  const int64_t optimal = oxcf->optimal_buffer_level_ms;
 +  const int64_t maximum = oxcf->maximum_buffer_size_ms;
 +
 +  rc->starting_buffer_level = starting * bandwidth / 1000;
 +  rc->optimal_buffer_level = (optimal == 0) ? bandwidth / 8
 +                                            : optimal * bandwidth / 1000;
 +  rc->maximum_buffer_size = (maximum == 0) ? bandwidth / 8
 +                                           : maximum * bandwidth / 1000;
 +}
 +
  void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
    VP9_COMMON *const cm = &cpi->common;
    RATE_CONTROL *const rc = &cpi->rc;
    }
    cpi->encode_breakout = cpi->oxcf.encode_breakout;
  
 -  // local file playback mode == really big buffer
 -  if (cpi->oxcf.rc_mode == VPX_VBR) {
 -    cpi->oxcf.starting_buffer_level_ms = 60000;
 -    cpi->oxcf.optimal_buffer_level_ms = 60000;
 -    cpi->oxcf.maximum_buffer_size_ms = 240000;
 -  }
 -
 -  rc->starting_buffer_level = vp9_rescale(cpi->oxcf.starting_buffer_level_ms,
 -                                          cpi->oxcf.target_bandwidth, 1000);
 +  set_rc_buffer_sizes(rc, &cpi->oxcf);
  
 -  // Set or reset optimal and maximum buffer levels.
 -  if (cpi->oxcf.optimal_buffer_level_ms == 0)
 -    rc->optimal_buffer_level = cpi->oxcf.target_bandwidth / 8;
 -  else
 -    rc->optimal_buffer_level = vp9_rescale(cpi->oxcf.optimal_buffer_level_ms,
 -                                           cpi->oxcf.target_bandwidth, 1000);
 -
 -  if (cpi->oxcf.maximum_buffer_size_ms == 0)
 -    rc->maximum_buffer_size = cpi->oxcf.target_bandwidth / 8;
 -  else
 -    rc->maximum_buffer_size = vp9_rescale(cpi->oxcf.maximum_buffer_size_ms,
 -                                          cpi->oxcf.target_bandwidth, 1000);
    // Under a configuration change, where maximum_buffer_size may change,
    // keep buffer level clipped to the maximum allowed buffer size.
    rc->bits_off_target = MIN(rc->bits_off_target, rc->maximum_buffer_size);
    rc->buffer_level = MIN(rc->buffer_level, rc->maximum_buffer_size);
  
    // Set up frame rate and related parameters rate control values.
 -  vp9_new_framerate(cpi, cpi->oxcf.framerate);
 +  vp9_new_framerate(cpi, cpi->framerate);
  
    // Set absolute upper and lower quality limits
    rc->worst_quality = cpi->oxcf.worst_allowed_q;
@@@ -749,6 -730,11 +749,6 @@@ VP9_COMP *vp9_create_compressor(VP9Enco
    vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
  
    cm->current_video_frame = 0;
 -
 -  cpi->gold_is_last = 0;
 -  cpi->alt_is_last = 0;
 -  cpi->gold_is_alt = 0;
 -
    cpi->skippable_frame = 0;
  
    // Create the encoder segmentation map and set all entries to 0
    CHECK_MEM_ERROR(cm, cpi->coding_context.last_frame_seg_map_copy,
                    vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
  
 +  CHECK_MEM_ERROR(cm, cpi->nmvcosts[0],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvcosts[0])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvcosts[1],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvcosts[1])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvcosts_hp[0],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvcosts_hp[0])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvcosts_hp[1],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvcosts_hp[1])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvsadcosts[0],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvsadcosts[0])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvsadcosts[1],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvsadcosts[1])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvsadcosts_hp[0],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvsadcosts_hp[0])));
 +  CHECK_MEM_ERROR(cm, cpi->nmvsadcosts_hp[1],
 +                  vpx_calloc(MV_VALS, sizeof(*cpi->nmvsadcosts_hp[1])));
 +
    for (i = 0; i < (sizeof(cpi->mbgraph_stats) /
                     sizeof(cpi->mbgraph_stats[0])); i++) {
      CHECK_MEM_ERROR(cm, cpi->mbgraph_stats[i].mb_stats,
    cpi->first_time_stamp_ever = INT64_MAX;
  
    cal_nmvjointsadcost(cpi->mb.nmvjointsadcost);
 -  cpi->mb.nmvcost[0] = &cpi->mb.nmvcosts[0][MV_MAX];
 -  cpi->mb.nmvcost[1] = &cpi->mb.nmvcosts[1][MV_MAX];
 -  cpi->mb.nmvsadcost[0] = &cpi->mb.nmvsadcosts[0][MV_MAX];
 -  cpi->mb.nmvsadcost[1] = &cpi->mb.nmvsadcosts[1][MV_MAX];
 +  cpi->mb.nmvcost[0] = &cpi->nmvcosts[0][MV_MAX];
 +  cpi->mb.nmvcost[1] = &cpi->nmvcosts[1][MV_MAX];
 +  cpi->mb.nmvsadcost[0] = &cpi->nmvsadcosts[0][MV_MAX];
 +  cpi->mb.nmvsadcost[1] = &cpi->nmvsadcosts[1][MV_MAX];
    cal_nmvsadcosts(cpi->mb.nmvsadcost);
  
 -  cpi->mb.nmvcost_hp[0] = &cpi->mb.nmvcosts_hp[0][MV_MAX];
 -  cpi->mb.nmvcost_hp[1] = &cpi->mb.nmvcosts_hp[1][MV_MAX];
 -  cpi->mb.nmvsadcost_hp[0] = &cpi->mb.nmvsadcosts_hp[0][MV_MAX];
 -  cpi->mb.nmvsadcost_hp[1] = &cpi->mb.nmvsadcosts_hp[1][MV_MAX];
 +  cpi->mb.nmvcost_hp[0] = &cpi->nmvcosts_hp[0][MV_MAX];
 +  cpi->mb.nmvcost_hp[1] = &cpi->nmvcosts_hp[1][MV_MAX];
 +  cpi->mb.nmvsadcost_hp[0] = &cpi->nmvsadcosts_hp[0][MV_MAX];
 +  cpi->mb.nmvsadcost_hp[1] = &cpi->nmvsadcosts_hp[1][MV_MAX];
    cal_nmvsadcosts_hp(cpi->mb.nmvsadcost_hp);
  
  #if CONFIG_VP9_TEMPORAL_DENOISING
    kf_list = fopen("kf_list.stt", "w");
  #endif
  
 -  cpi->output_pkt_list = oxcf->output_pkt_list;
 -
    cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
  
    if (oxcf->pass == 1) {
        vp9_sub_pixel_avg_variance4x4,
        vp9_sad4x4x3, vp9_sad4x4x8, vp9_sad4x4x4d)
  
 -  cpi->full_search_sad = vp9_full_search_sad;
 -  cpi->diamond_search_sad = vp9_diamond_search_sad;
 -  cpi->refining_search_sad = vp9_refining_search_sad;
 -
    /* vp9_init_quantizer() is first called here. Add check in
     * vp9_frame_init_quantizer() so that vp9_init_quantizer is only
     * called later when needed. This will avoid unnecessary calls of
@@@ -1688,8 -1663,8 +1688,8 @@@ static void output_frame_level_debug_st
          cpi->rc.total_actual_bits, cm->base_qindex,
          vp9_convert_qindex_to_q(cm->base_qindex),
          (double)vp9_dc_quant(cm->base_qindex, 0) / 4.0,
 +        vp9_convert_qindex_to_q(cpi->twopass.active_worst_quality),
          cpi->rc.avg_q,
 -        vp9_convert_qindex_to_q(cpi->rc.ni_av_qi),
          vp9_convert_qindex_to_q(cpi->oxcf.cq_level),
          cpi->refresh_last_frame, cpi->refresh_golden_frame,
          cpi->refresh_alt_ref_frame, cm->frame_type, cpi->rc.gfu_boost,
@@@ -1944,27 -1919,36 +1944,27 @@@ static void encode_with_recode_loop(VP9
    } while (loop);
  }
  
 -static void get_ref_frame_flags(VP9_COMP *cpi) {
 -  if (cpi->refresh_last_frame & cpi->refresh_golden_frame)
 -    cpi->gold_is_last = 1;
 -  else if (cpi->refresh_last_frame ^ cpi->refresh_golden_frame)
 -    cpi->gold_is_last = 0;
 -
 -  if (cpi->refresh_last_frame & cpi->refresh_alt_ref_frame)
 -    cpi->alt_is_last = 1;
 -  else if (cpi->refresh_last_frame ^ cpi->refresh_alt_ref_frame)
 -    cpi->alt_is_last = 0;
 +static int get_ref_frame_flags(const VP9_COMP *cpi) {
 +  const int *const map = cpi->common.ref_frame_map;
 +  const int gold_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
 +  const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
 +  const int gold_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
 +  int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
  
 -  if (cpi->refresh_alt_ref_frame & cpi->refresh_golden_frame)
 -    cpi->gold_is_alt = 1;
 -  else if (cpi->refresh_alt_ref_frame ^ cpi->refresh_golden_frame)
 -    cpi->gold_is_alt = 0;
 -
 -  cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
 -
 -  if (cpi->gold_is_last)
 -    cpi->ref_frame_flags &= ~VP9_GOLD_FLAG;
 +  if (gold_is_last)
 +    flags &= ~VP9_GOLD_FLAG;
  
    if (cpi->rc.frames_till_gf_update_due == INT_MAX &&
        !is_spatial_svc(cpi))
 -    cpi->ref_frame_flags &= ~VP9_GOLD_FLAG;
 +    flags &= ~VP9_GOLD_FLAG;
  
 -  if (cpi->alt_is_last)
 -    cpi->ref_frame_flags &= ~VP9_ALT_FLAG;
 +  if (alt_is_last)
 +    flags &= ~VP9_ALT_FLAG;
  
 -  if (cpi->gold_is_alt)
 -    cpi->ref_frame_flags &= ~VP9_ALT_FLAG;
 +  if (gold_is_alt)
 +    flags &= ~VP9_ALT_FLAG;
 +
 +  return flags;
  }
  
  static void set_ext_overrides(VP9_COMP *cpi) {
@@@ -2033,41 -2017,19 +2033,41 @@@ static void set_arf_sign_bias(VP9_COMP 
    cm->ref_frame_sign_bias[ALTREF_FRAME] = arf_sign_bias;
  }
  
 +static void set_mv_search_params(VP9_COMP *cpi) {
 +  const VP9_COMMON *const cm = &cpi->common;
 +  const unsigned int max_mv_def = MIN(cm->width, cm->height);
 +
 +  // Default based on max resolution.
 +  cpi->mv_step_param = vp9_init_search_range(max_mv_def);
 +
 +  if (cpi->sf.mv.auto_mv_step_size) {
 +    if (frame_is_intra_only(cm)) {
 +      // Initialize max_mv_magnitude for use in the first INTER frame
 +      // after a key/intra-only frame.
 +      cpi->max_mv_magnitude = max_mv_def;
 +    } else {
 +      if (cm->show_frame)
 +        // Allow mv_steps to correspond to twice the max mv magnitude found
 +        // in the previous frame, capped by the default max_mv_magnitude based
 +        // on resolution.
 +        cpi->mv_step_param =
 +            vp9_init_search_range(MIN(max_mv_def, 2 * cpi->max_mv_magnitude));
 +      cpi->max_mv_magnitude = 0;
 +    }
 +  }
 +}
 +
  static void encode_frame_to_data_rate(VP9_COMP *cpi,
                                        size_t *size,
                                        uint8_t *dest,
                                        unsigned int *frame_flags) {
    VP9_COMMON *const cm = &cpi->common;
 +  struct segmentation *const seg = &cm->seg;
    TX_SIZE t;
    int q;
    int top_index;
    int bottom_index;
  
 -  const SPEED_FEATURES *const sf = &cpi->sf;
 -  const unsigned int max_mv_def = MIN(cm->width, cm->height);
 -  struct segmentation *const seg = &cm->seg;
    set_ext_overrides(cpi);
  
    cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
    // Set default state for segment based loop filter update flags.
    cm->lf.mode_ref_delta_update = 0;
  
 -  // Initialize cpi->mv_step_param to default based on max resolution.
 -  cpi->mv_step_param = vp9_init_search_range(max_mv_def);
 -  // Initialize cpi->max_mv_magnitude and cpi->mv_step_param if appropriate.
 -  if (sf->mv.auto_mv_step_size) {
 -    if (frame_is_intra_only(cm)) {
 -      // Initialize max_mv_magnitude for use in the first INTER frame
 -      // after a key/intra-only frame.
 -      cpi->max_mv_magnitude = max_mv_def;
 -    } else {
 -      if (cm->show_frame)
 -        // Allow mv_steps to correspond to twice the max mv magnitude found
 -        // in the previous frame, capped by the default max_mv_magnitude based
 -        // on resolution.
 -        cpi->mv_step_param = vp9_init_search_range(MIN(max_mv_def, 2 *
 -                                 cpi->max_mv_magnitude));
 -      cpi->max_mv_magnitude = 0;
 -    }
 -  }
 +  set_mv_search_params(cpi);
  
    // Set various flags etc to special state if it is a key frame.
    if (frame_is_intra_only(cm)) {
        cm->reset_frame_context = 2;
      }
    }
+   if (is_spatial_svc(cpi) && cm->error_resilient_mode == 0) {
+     cm->frame_context_idx = cpi->svc.spatial_layer_id;
+     // The probs will be updated based on the frame type of its previous
+     // frame if frame_parallel_decoding_mode is 0. The type may vary for
+     // the frame after a key frame in base layer since we may drop enhancement
+     // layers. So set frame_parallel_decoding_mode to 1 in this case.
+     if (cpi->svc.spatial_layer_id == 0 &&
+         cpi->svc.layer_context[0].last_frame_type == KEY_FRAME)
+       cm->frame_parallel_decoding_mode = 1;
+     else
+       cm->frame_parallel_decoding_mode = 0;
+   }
  
    // Configure experimental use of segmentation for enhanced coding of
    // static regions if indicated.
    else
      cpi->frame_flags &= ~FRAMEFLAGS_ALTREF;
  
 -  get_ref_frame_flags(cpi);
 +  cpi->ref_frame_flags = get_ref_frame_flags(cpi);
  
    cm->last_frame_type = cm->frame_type;
    vp9_rc_postencode_update(cpi, *size);
    cm->last_height = cm->height;
  
    // reset to normal state now that we are done.
-   if (!cm->show_existing_frame)
-     cm->last_show_frame = cm->show_frame;
+   if (!cm->show_existing_frame) {
+     if (is_spatial_svc(cpi) && cm->error_resilient_mode == 0)
+       cm->last_show_frame = 0;
+     else
+       cm->last_show_frame = cm->show_frame;
+   }
  
    if (cm->show_frame) {
      vp9_swap_mi_and_prev_mi(cm);
      if (cpi->use_svc)
        vp9_inc_frame_in_layer(&cpi->svc);
    }
+   if (is_spatial_svc(cpi))
+     cpi->svc.layer_context[cpi->svc.spatial_layer_id].last_frame_type =
+         cm->frame_type;
  }
  
  static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
@@@ -2424,19 -2424,18 +2445,19 @@@ static int frame_is_reference(const VP9
           cm->seg.update_data;
  }
  
 -void adjust_frame_rate(VP9_COMP *cpi) {
 +void adjust_frame_rate(VP9_COMP *cpi,
 +                       const struct lookahead_entry *source) {
    int64_t this_duration;
    int step = 0;
  
 -  if (cpi->source->ts_start == cpi->first_time_stamp_ever) {
 -    this_duration = cpi->source->ts_end - cpi->source->ts_start;
 +  if (source->ts_start == cpi->first_time_stamp_ever) {
 +    this_duration = source->ts_end - source->ts_start;
      step = 1;
    } else {
      int64_t last_duration = cpi->last_end_time_stamp_seen
          - cpi->last_time_stamp_seen;
  
 -    this_duration = cpi->source->ts_end - cpi->last_end_time_stamp_seen;
 +    this_duration = source->ts_end - cpi->last_end_time_stamp_seen;
  
      // do a step update if the duration changes by 10%
      if (last_duration)
        // Average this frame's rate into the last second's average
        // frame rate. If we haven't seen 1 second yet, then average
        // over the whole interval seen.
 -      const double interval = MIN((double)(cpi->source->ts_end
 +      const double interval = MIN((double)(source->ts_end
                                     - cpi->first_time_stamp_ever), 10000000.0);
 -      double avg_duration = 10000000.0 / cpi->oxcf.framerate;
 +      double avg_duration = 10000000.0 / cpi->framerate;
        avg_duration *= (interval - avg_duration + this_duration);
        avg_duration /= interval;
  
        vp9_new_framerate(cpi, 10000000.0 / avg_duration);
      }
    }
 -  cpi->last_time_stamp_seen = cpi->source->ts_start;
 -  cpi->last_end_time_stamp_seen = cpi->source->ts_end;
 +  cpi->last_time_stamp_seen = source->ts_start;
 +  cpi->last_end_time_stamp_seen = source->ts_end;
  }
  
  // Returns 0 if this is not an alt ref else the offset of the source frame
@@@ -2481,8 -2480,7 +2502,8 @@@ static int get_arf_src_index(VP9_COMP *
    return arf_src_index;
  }
  
 -static void check_src_altref(VP9_COMP *cpi) {
 +static void check_src_altref(VP9_COMP *cpi,
 +                             const struct lookahead_entry *source) {
    RATE_CONTROL *const rc = &cpi->rc;
  
    if (cpi->oxcf.pass == 2) {
        (gf_group->update_type[gf_group->index] == OVERLAY_UPDATE);
    } else {
      rc->is_src_frame_alt_ref = cpi->alt_ref_source &&
 -                               (cpi->source == cpi->alt_ref_source);
 +                               (source == cpi->alt_ref_source);
    }
  
    if (rc->is_src_frame_alt_ref) {
  int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
                              size_t *size, uint8_t *dest,
                              int64_t *time_stamp, int64_t *time_end, int flush) {
 +  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
    VP9_COMMON *const cm = &cpi->common;
    MACROBLOCKD *const xd = &cpi->mb.e_mbd;
    RATE_CONTROL *const rc = &cpi->rc;
    struct vpx_usec_timer  cmptimer;
    YV12_BUFFER_CONFIG *force_src_buffer = NULL;
 +  struct lookahead_entry *last_source = NULL;
 +  struct lookahead_entry *source = NULL;
    MV_REFERENCE_FRAME ref_frame;
    int arf_src_index;
  
 -  if (!cpi)
 -    return -1;
 -
 -  if (is_spatial_svc(cpi) && cpi->oxcf.pass == 2) {
 +  if (is_spatial_svc(cpi) && oxcf->pass == 2) {
  #if CONFIG_SPATIAL_SVC
      vp9_svc_lookahead_peek(cpi, cpi->lookahead, 0, 1);
  #endif
  
    vpx_usec_timer_start(&cmptimer);
  
 -  cpi->source = NULL;
 -  cpi->last_source = NULL;
 -
    vp9_set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV);
  
    // Normal defaults
  
  #if CONFIG_SPATIAL_SVC
      if (is_spatial_svc(cpi))
 -      cpi->source = vp9_svc_lookahead_peek(cpi, cpi->lookahead,
 -                                           arf_src_index, 0);
 +      source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, 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;
 +      source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
 +    if (source != NULL) {
 +      cpi->alt_ref_source = source;
  
  #if CONFIG_SPATIAL_SVC
        if (is_spatial_svc(cpi) && 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]) {
 +          if (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) {
 +      if (oxcf->arnr_max_frames > 0) {
          // Produce the filtered ARF frame.
          vp9_temporal_filter(cpi, arf_src_index);
          vp9_extend_frame_borders(&cpi->alt_ref_buffer);
      }
    }
  
 -  if (!cpi->source) {
 +  if (!source) {
      // Get last frame source.
      if (cm->current_video_frame > 0) {
  #if CONFIG_SPATIAL_SVC
        if (is_spatial_svc(cpi))
 -        cpi->last_source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, -1, 0);
 +        last_source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, -1, 0);
        else
  #endif
 -        cpi->last_source = vp9_lookahead_peek(cpi->lookahead, -1);
 -      if (cpi->last_source == NULL)
 +        last_source = vp9_lookahead_peek(cpi->lookahead, -1);
 +      if (last_source == NULL)
          return -1;
      }
  
      // Read in the source frame.
  #if CONFIG_SPATIAL_SVC
      if (is_spatial_svc(cpi))
 -      cpi->source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
 +      source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
      else
  #endif
 -      cpi->source = vp9_lookahead_pop(cpi->lookahead, flush);
 -    if (cpi->source != NULL) {
 +      source = vp9_lookahead_pop(cpi->lookahead, flush);
 +    if (source != NULL) {
        cm->show_frame = 1;
        cm->intra_only = 0;
  
        // Check to see if the frame should be encoded as an arf overlay.
 -      check_src_altref(cpi);
 +      check_src_altref(cpi, source);
      }
    }
  
 -  if (cpi->source) {
 +  if (source) {
      cpi->un_scaled_source = cpi->Source = force_src_buffer ? force_src_buffer
 -                                                           : &cpi->source->img;
 +                                                           : &source->img;
  
 -    if (cpi->last_source != NULL) {
 -      cpi->unscaled_last_source = &cpi->last_source->img;
 -    } else {
 -      cpi->unscaled_last_source = NULL;
 -    }
 +    cpi->unscaled_last_source = last_source != NULL ? &last_source->img : NULL;
  
 -    *time_stamp = cpi->source->ts_start;
 -    *time_end = cpi->source->ts_end;
 -    *frame_flags =
 -        (cpi->source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
 +    *time_stamp = source->ts_start;
 +    *time_end = source->ts_end;
 +    *frame_flags = (source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
  
    } else {
      *size = 0;
 -    if (flush && cpi->oxcf.pass == 1 && !cpi->twopass.first_pass_done) {
 +    if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
        vp9_end_first_pass(cpi);    /* get last stats packet */
        cpi->twopass.first_pass_done = 1;
      }
      return -1;
    }
  
 -  if (cpi->source->ts_start < cpi->first_time_stamp_ever) {
 -    cpi->first_time_stamp_ever = cpi->source->ts_start;
 -    cpi->last_end_time_stamp_seen = cpi->source->ts_start;
 +  if (source->ts_start < cpi->first_time_stamp_ever) {
 +    cpi->first_time_stamp_ever = source->ts_start;
 +    cpi->last_end_time_stamp_seen = source->ts_start;
    }
  
    // Clear down mmx registers
  
    // adjust frame rates based on timestamps given
    if (cm->show_frame) {
 -    adjust_frame_rate(cpi);
 +    adjust_frame_rate(cpi, source);
    }
  
    if (cpi->svc.number_temporal_layers > 1 &&
 -      cpi->oxcf.rc_mode == VPX_CBR) {
 +      oxcf->rc_mode == VPX_CBR) {
      vp9_update_temporal_layer_framerate(cpi);
      vp9_restore_layer_context(cpi);
    }
    if (!cpi->use_svc && cpi->multi_arf_allowed) {
      if (cm->frame_type == KEY_FRAME) {
        init_buffer_indices(cpi);
 -    } else if (cpi->oxcf.pass == 2) {
 +    } else if (oxcf->pass == 2) {
        const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
        cpi->alt_fb_idx = gf_group->arf_ref_idx[gf_group->index];
      }
  
    cpi->frame_flags = *frame_flags;
  
 -  if (cpi->oxcf.pass == 2 &&
 +  if (oxcf->pass == 2 &&
        cm->current_video_frame == 0 &&
 -      cpi->oxcf.allow_spatial_resampling &&
 -      cpi->oxcf.rc_mode == VPX_VBR) {
 +      oxcf->allow_spatial_resampling &&
 +      oxcf->rc_mode == VPX_VBR) {
      // Internal scaling is triggered on the first frame.
 -    vp9_set_size_literal(cpi, cpi->oxcf.scaled_frame_width,
 -                         cpi->oxcf.scaled_frame_height);
 +    vp9_set_size_literal(cpi, oxcf->scaled_frame_width,
 +                         oxcf->scaled_frame_height);
    }
  
    // Reset the frame pointers to the current frame size
  
    set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME);
  
 -  if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
 +  if (oxcf->aq_mode == VARIANCE_AQ) {
      vp9_vaq_init();
    }
  
 -  if (cpi->oxcf.pass == 1 &&
 +  if (oxcf->pass == 1 &&
        (!cpi->use_svc || is_spatial_svc(cpi))) {
 -    const int lossless = is_lossless_requested(&cpi->oxcf);
 +    const int lossless = is_lossless_requested(oxcf);
      cpi->mb.fwd_txm4x4 = lossless ? vp9_fwht4x4 : vp9_fdct4x4;
      cpi->mb.itxm_add = lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
 -    vp9_first_pass(cpi);
 -  } else if (cpi->oxcf.pass == 2 &&
 +    vp9_first_pass(cpi, source);
 +  } else if (oxcf->pass == 2 &&
        (!cpi->use_svc || is_spatial_svc(cpi))) {
      Pass2Encode(cpi, size, dest, frame_flags);
    } else if (cpi->use_svc) {
  
    // Save layer specific state.
    if ((cpi->svc.number_temporal_layers > 1 &&
 -      cpi->oxcf.rc_mode == VPX_CBR) ||
 -      (cpi->svc.number_spatial_layers > 1 && cpi->oxcf.pass == 2)) {
 +      oxcf->rc_mode == VPX_CBR) ||
 +      (cpi->svc.number_spatial_layers > 1 && oxcf->pass == 2)) {
      vp9_save_layer_context(cpi);
    }
  
    vpx_usec_timer_mark(&cmptimer);
    cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer);
  
 -  if (cpi->b_calculate_psnr && cpi->oxcf.pass != 1 && cm->show_frame)
 +  if (cpi->b_calculate_psnr && oxcf->pass != 1 && cm->show_frame)
      generate_psnr_packet(cpi);
  
  #if CONFIG_INTERNAL_STATS
  
 -  if (cpi->oxcf.pass != 1) {
 +  if (oxcf->pass != 1) {
      cpi->bytes += (int)(*size);
  
      if (cm->show_frame) {
            cpi->totalp_sq_error += psnr2.sse[0];
            cpi->totalp_samples += psnr2.samples[0];
  
 -          frame_ssim2 = vp9_calc_ssim(orig, recon, 1, &weight);
 +          frame_ssim2 = vp9_calc_ssim(orig, recon, &weight);
  
            cpi->summed_quality += frame_ssim2 * weight;
            cpi->summed_weights += weight;
  
 -          frame_ssim2 = vp9_calc_ssim(orig, &cm->post_proc_buffer, 1, &weight);
 +          frame_ssim2 = vp9_calc_ssim(orig, &cm->post_proc_buffer, &weight);
  
            cpi->summedp_quality += frame_ssim2 * weight;
            cpi->summedp_weights += weight;
@@@ -36,6 -36,7 +36,7 @@@ void vp9_init_layer_context(VP9_COMP *c
      int i;
      lc->current_video_frame_in_layer = 0;
      lc->layer_size = 0;
+     lc->last_frame_type = FRAME_TYPES;
      lrc->ni_av_qi = oxcf->worst_allowed_q;
      lrc->total_actual_bits = 0;
      lrc->total_target_vs_actual = 0;
@@@ -69,8 -70,8 +70,8 @@@
        lc->gold_ref_idx = -1;
      }
  
 -    lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level_ms),
 -                                    lc->target_bandwidth, 1000);
 +    lrc->buffer_level = oxcf->starting_buffer_level_ms *
 +                            lc->target_bandwidth / 1000;
      lrc->bits_off_target = lrc->buffer_level;
    }
  
@@@ -116,9 -117,9 +117,9 @@@ void vp9_update_layer_context_change_co
      lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size);
      // Update framerate-related quantities.
      if (svc->number_temporal_layers > 1) {
 -      lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
 +      lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer];
      } else {
 -      lc->framerate = oxcf->framerate;
 +      lc->framerate = cpi->framerate;
      }
      lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
      lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
@@@ -141,7 -142,7 +142,7 @@@ void vp9_update_temporal_layer_framerat
    RATE_CONTROL *const lrc = &lc->rc;
    const int layer = svc->temporal_layer_id;
  
 -  lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
 +  lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer];
    lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
    lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
    // Update the average layer frame size (non-cumulative per-frame-bw).
      lc->avg_frame_size = lrc->avg_frame_bandwidth;
    } else {
      const double prev_layer_framerate =
 -        oxcf->framerate / oxcf->ts_rate_decimator[layer - 1];
 +        cpi->framerate / oxcf->ts_rate_decimator[layer - 1];
      const int prev_layer_target_bandwidth = oxcf->ts_target_bitrate[layer - 1];
      lc->avg_frame_size =
          (int)((lc->target_bandwidth - prev_layer_target_bandwidth) /
@@@ -25,9 -25,10 +25,10 @@@ typedef struct 
    double framerate;
    int avg_frame_size;
    TWO_PASS twopass;
 -  struct vpx_fixed_buf rc_twopass_stats_in;
 +  vpx_fixed_buf_t rc_twopass_stats_in;
    unsigned int current_video_frame_in_layer;
    int is_key_frame;
+   FRAME_TYPE last_frame_type;
    vpx_svc_parameters_t svc_params_received;
    struct lookahead_entry  *alt_ref_source;
    int alt_ref_idx;
diff --combined vp9/vp9_cx_iface.c
@@@ -21,6 -21,7 +21,6 @@@
  #include "vp9/vp9_iface_common.h"
  
  struct vp9_extracfg {
 -  struct vpx_codec_pkt_list *pkt_list;
    int                         cpu_used;  // available cpu percentage in 1/16
    unsigned int                enable_auto_alt_ref;
    unsigned int                noise_sensitivity;
    vp9e_tune_content           content;
  };
  
 -struct extraconfig_map {
 -  unsigned int usage;
 -  struct vp9_extracfg cfg;
 -};
 -
 -static const struct extraconfig_map extracfg_map[] = {
 -  {
 -    0,
 -    { // NOLINT
 -      NULL,
 -      0,                          // cpu_used
 -      1,                          // enable_auto_alt_ref
 -      0,                          // noise_sensitivity
 -      0,                          // sharpness
 -      0,                          // static_thresh
 -      0,                          // tile_columns
 -      0,                          // tile_rows
 -      7,                          // arnr_max_frames
 -      5,                          // arnr_strength
 -      3,                          // arnr_type
 -      VP8_TUNE_PSNR,              // tuning
 -      10,                         // cq_level
 -      0,                          // rc_max_intra_bitrate_pct
 -      0,                          // lossless
 -      0,                          // frame_parallel_decoding_mode
 -      NO_AQ,                      // aq_mode
 -      0,                          // frame_periodic_delta_q
 -      BITS_8,                     // Bit depth
 -      VP9E_CONTENT_DEFAULT        // content
 -    }
 -  }
 +static struct vp9_extracfg default_extra_cfg = {
 +  0,                          // cpu_used
 +  1,                          // enable_auto_alt_ref
 +  0,                          // noise_sensitivity
 +  0,                          // sharpness
 +  0,                          // static_thresh
 +  0,                          // tile_columns
 +  0,                          // tile_rows
 +  7,                          // arnr_max_frames
 +  5,                          // arnr_strength
 +  3,                          // arnr_type
 +  VP8_TUNE_PSNR,              // tuning
 +  10,                         // cq_level
 +  0,                          // rc_max_intra_bitrate_pct
 +  0,                          // lossless
 +  0,                          // frame_parallel_decoding_mode
 +  NO_AQ,                      // aq_mode
 +  0,                          // frame_periodic_delta_q
 +  BITS_8,                     // Bit depth
 +  VP9E_CONTENT_DEFAULT        // content
  };
  
  struct vpx_codec_alg_priv {
@@@ -176,6 -188,8 +176,8 @@@ static vpx_codec_err_t validate_config(
      if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers)
        ERROR("Not enough ref buffers for svc alt ref frames");
    }
+   if (cfg->ss_number_layers > 3 && cfg->g_error_resilient == 0)
+     ERROR("Multiple frame contexts are not supported for more than 3 layers");
  #endif
  
    RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
@@@ -313,26 -327,26 +315,26 @@@ static vpx_codec_err_t set_encoder_conf
      VP9EncoderConfig *oxcf,
      const vpx_codec_enc_cfg_t *cfg,
      const struct vp9_extracfg *extra_cfg) {
 +  const int is_vbr = cfg->rc_end_usage == VPX_VBR;
    oxcf->profile = cfg->g_profile;
    oxcf->width   = cfg->g_w;
    oxcf->height  = cfg->g_h;
    oxcf->bit_depth = extra_cfg->bit_depth;
    // guess a frame rate if out of whack, use 30
 -  oxcf->framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
 -  if (oxcf->framerate > 180)
 -    oxcf->framerate = 30;
 +  oxcf->init_framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
 +  if (oxcf->init_framerate > 180)
 +    oxcf->init_framerate = 30;
 +
 +  oxcf->mode = GOOD;
  
    switch (cfg->g_pass) {
      case VPX_RC_ONE_PASS:
 -      oxcf->mode = ONE_PASS_GOOD;
        oxcf->pass = 0;
        break;
      case VPX_RC_FIRST_PASS:
 -      oxcf->mode = TWO_PASS_FIRST;
        oxcf->pass = 1;
        break;
      case VPX_RC_LAST_PASS:
 -      oxcf->mode = TWO_PASS_SECOND_BEST;
        oxcf->pass = 2;
        break;
    }
    oxcf->scaled_frame_width       = cfg->rc_scaled_width;
    oxcf->scaled_frame_height      = cfg->rc_scaled_height;
  
 -  oxcf->maximum_buffer_size_ms   = cfg->rc_buf_sz;
 -  oxcf->starting_buffer_level_ms = cfg->rc_buf_initial_sz;
 -  oxcf->optimal_buffer_level_ms  = cfg->rc_buf_optimal_sz;
 +  oxcf->maximum_buffer_size_ms   = is_vbr ? 240000 : cfg->rc_buf_sz;
 +  oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
 +  oxcf->optimal_buffer_level_ms  = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
  
    oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
  
    oxcf->sharpness              =  extra_cfg->sharpness;
  
    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;
@@@ -646,6 -661,8 +648,6 @@@ static vpx_codec_err_t encoder_init(vpx
    (void)data;
  
    if (ctx->priv == NULL) {
 -    int i;
 -    vpx_codec_enc_cfg_t *cfg;
      struct vpx_codec_alg_priv *priv = calloc(1, sizeof(*priv));
  
      if (priv == NULL)
  
      ctx->priv = &priv->base;
      ctx->priv->sz = sizeof(*ctx->priv);
 -    ctx->priv->iface = ctx->iface;
      ctx->priv->alg_priv = priv;
      ctx->priv->init_flags = ctx->init_flags;
      ctx->priv->enc.total_encoders = 1;
        ctx->config.enc = &ctx->priv->alg_priv->cfg;
      }
  
 -    cfg = &ctx->priv->alg_priv->cfg;
 -
 -    // Select the extra vp6 configuration table based on the current
 -    // usage value. If the current usage value isn't found, use the
 -    // values for usage case 0.
 -    for (i = 0;
 -         extracfg_map[i].usage && extracfg_map[i].usage != cfg->g_usage;
 -         ++i) {}
 -
 -    priv->extra_cfg = extracfg_map[i].cfg;
 -    priv->extra_cfg.pkt_list = &priv->pkt_list.head;
 +    priv->extra_cfg = default_extra_cfg;
  
      vp9_initialize_enc();
  
                           &ctx->priv->alg_priv->cfg,
                           &ctx->priv->alg_priv->extra_cfg);
        cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
 -      if (cpi == NULL)
 +      if (cpi == NULL) {
          res = VPX_CODEC_MEM_ERROR;
 -      else
 +      } else {
 +        cpi->output_pkt_list = &priv->pkt_list.head;
          ctx->priv->alg_priv->cpi = cpi;
 +      }
      }
    }
  
@@@ -694,36 -720,31 +696,36 @@@ static vpx_codec_err_t encoder_destroy(
    return VPX_CODEC_OK;
  }
  
 -static void pick_quickcompress_mode(vpx_codec_alg_priv_t  *ctx,
 +static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
                                      unsigned long duration,
                                      unsigned long deadline) {
 -  // Use best quality mode if no deadline is given.
 -  MODE new_qc = ONE_PASS_BEST;
 -
 -  if (deadline) {
 -    // Convert duration parameter from stream timebase to microseconds
 -    const uint64_t duration_us = (uint64_t)duration * 1000000 *
 -                               (uint64_t)ctx->cfg.g_timebase.num /
 -                               (uint64_t)ctx->cfg.g_timebase.den;
 -
 -    // If the deadline is more that the duration this frame is to be shown,
 -    // use good quality mode. Otherwise use realtime mode.
 -    new_qc = (deadline > duration_us) ? ONE_PASS_GOOD : REALTIME;
 -  }
 +  MODE new_mode = BEST;
  
 -  if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS)
 -    new_qc = TWO_PASS_FIRST;
 -  else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS)
 -    new_qc = (new_qc == ONE_PASS_BEST) ? TWO_PASS_SECOND_BEST
 -                                          : TWO_PASS_SECOND_GOOD;
 +  switch (ctx->cfg.g_pass) {
 +    case VPX_RC_ONE_PASS:
 +      if (deadline > 0) {
 +        const vpx_codec_enc_cfg_t *const cfg = &ctx->cfg;
 +
 +        // Convert duration parameter from stream timebase to microseconds.
 +        const uint64_t duration_us = (uint64_t)duration * 1000000 *
 +           (uint64_t)cfg->g_timebase.num /(uint64_t)cfg->g_timebase.den;
 +
 +        // If the deadline is more that the duration this frame is to be shown,
 +        // use good quality mode. Otherwise use realtime mode.
 +        new_mode = (deadline > duration_us) ? GOOD : REALTIME;
 +      } else {
 +        new_mode = BEST;
 +      }
 +      break;
 +    case VPX_RC_FIRST_PASS:
 +      break;
 +    case VPX_RC_LAST_PASS:
 +      new_mode = deadline > 0 ? GOOD : BEST;
 +      break;
 +  }
  
 -  if (ctx->oxcf.mode != new_qc) {
 -    ctx->oxcf.mode = new_qc;
 +  if (ctx->oxcf.mode != new_mode) {
 +    ctx->oxcf.mode = new_mode;
      vp9_change_config(ctx->cpi, &ctx->oxcf);
    }
  }
@@@ -789,7 -810,7 +791,7 @@@ static int write_superframe_index(vpx_c
  }
  
  // vp9 uses 10,000,000 ticks/second as time stamp
 -#define TICKS_PER_SEC 10000000
 +#define TICKS_PER_SEC 10000000LL
  
  static int64_t timebase_units_to_ticks(const vpx_rational_t *timebase,
                                         int64_t n) {
@@@ -978,9 -999,8 +980,9 @@@ static vpx_codec_err_t encoder_encode(v
          cx_data_sz -= size;
  #if CONFIG_SPATIAL_SVC
          if (is_spatial_svc(cpi)) {
 -          vpx_codec_cx_pkt_t pkt = {0};
 +          vpx_codec_cx_pkt_t pkt;
            int i;
 +          vp9_zero(pkt);
            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;
@@@ -1332,11 -1352,11 +1334,11 @@@ CODEC_INTERFACE(vpx_codec_vp9_cx) = 
    encoder_destroy,    // vpx_codec_destroy_fn_t
    encoder_ctrl_maps,  // vpx_codec_ctrl_fn_map_t
    {  // NOLINT
 -    NOT_IMPLEMENTED,  // vpx_codec_peek_si_fn_t
 -    NOT_IMPLEMENTED,  // vpx_codec_get_si_fn_t
 -    NOT_IMPLEMENTED,  // vpx_codec_decode_fn_t
 -    NOT_IMPLEMENTED,  // vpx_codec_frame_get_fn_t
 -    NOT_IMPLEMENTED   // vpx_codec_set_fb_fn_t
 +    NULL,  // vpx_codec_peek_si_fn_t
 +    NULL,  // vpx_codec_get_si_fn_t
 +    NULL,  // vpx_codec_decode_fn_t
 +    NULL,  // vpx_codec_frame_get_fn_t
 +    NULL   // vpx_codec_set_fb_fn_t
    },
    {  // NOLINT
      1,                      // 1 cfg map
      encoder_encode,         // vpx_codec_encode_fn_t
      encoder_get_cxdata,     // vpx_codec_get_cx_data_fn_t
      encoder_set_config,     // vpx_codec_enc_config_set_fn_t
 -    NOT_IMPLEMENTED,        // vpx_codec_get_global_headers_fn_t
 +    NULL,        // vpx_codec_get_global_headers_fn_t
      encoder_get_preview,    // vpx_codec_get_preview_frame_fn_t
 -    NOT_IMPLEMENTED         // vpx_codec_enc_mr_get_mem_loc_fn_t
 +    NULL         // vpx_codec_enc_mr_get_mem_loc_fn_t
    }
  };