| Index: webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
 | 
| diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
 | 
| index 2e510ec897fbb9f8c2c8e1b6b801107b475987a2..eb5d2bd3a1a1e2f3a1861c14e1655bb7c770980a 100644
 | 
| --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
 | 
| +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
 | 
| @@ -113,7 +113,6 @@ VP8Decoder* VP8Decoder::Create() {
 | 
|  
 | 
|  VP8EncoderImpl::VP8EncoderImpl()
 | 
|      : encoded_complete_callback_(nullptr),
 | 
| -      rate_allocator_(new SimulcastRateAllocator(codec_)),
 | 
|        inited_(false),
 | 
|        timestamp_(0),
 | 
|        feedback_mode_(false),
 | 
| @@ -175,27 +174,32 @@ int VP8EncoderImpl::Release() {
 | 
|    return ret_val;
 | 
|  }
 | 
|  
 | 
| -int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
 | 
| -                             uint32_t new_framerate) {
 | 
| -  if (!inited_) {
 | 
| +int VP8EncoderImpl::SetRateAllocation(const BitrateAllocation& bitrate,
 | 
| +                                      uint32_t new_framerate) {
 | 
| +  if (!inited_)
 | 
|      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
 | 
| -  }
 | 
| -  if (encoders_[0].err) {
 | 
| +
 | 
| +  if (encoders_[0].err)
 | 
|      return WEBRTC_VIDEO_CODEC_ERROR;
 | 
| -  }
 | 
| -  if (new_framerate < 1) {
 | 
| +
 | 
| +  if (new_framerate < 1)
 | 
|      return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
 | 
| +
 | 
| +  if (bitrate.get_sum_bps() == 0) {
 | 
| +    // Encoder paused, turn off all encoding.
 | 
| +    const int num_streams = static_cast<size_t>(encoders_.size());
 | 
| +    for (int i = 0; i < num_streams; ++i)
 | 
| +      SetStreamState(false, i);
 | 
| +    return WEBRTC_VIDEO_CODEC_OK;
 | 
|    }
 | 
| -  if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) {
 | 
| -    new_bitrate_kbit = codec_.maxBitrate;
 | 
| -  }
 | 
| -  if (new_bitrate_kbit < codec_.minBitrate) {
 | 
| -    new_bitrate_kbit = codec_.minBitrate;
 | 
| -  }
 | 
| -  if (codec_.numberOfSimulcastStreams > 0 &&
 | 
| -      new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) {
 | 
| -    new_bitrate_kbit = codec_.simulcastStream[0].minBitrate;
 | 
| -  }
 | 
| +
 | 
| +  // At this point, bitrate allocation should already match codec settings.
 | 
| +  if (codec_.maxBitrate > 0)
 | 
| +    RTC_DCHECK_LE(bitrate.get_sum_kbps(), codec_.maxBitrate);
 | 
| +  RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.minBitrate);
 | 
| +  if (codec_.numberOfSimulcastStreams > 0)
 | 
| +    RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.simulcastStream[0].minBitrate);
 | 
| +
 | 
|    codec_.maxFramerate = new_framerate;
 | 
|  
 | 
|    if (encoders_.size() == 1) {
 | 
| @@ -207,14 +211,14 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
 | 
|      // Only trigger keyframes if we are allowed to scale down.
 | 
|      if (configurations_[0].rc_resize_allowed) {
 | 
|        if (!down_scale_requested_) {
 | 
| -        if (k_pixels_per_frame > new_bitrate_kbit) {
 | 
| +        if (k_pixels_per_frame > bitrate.get_sum_kbps()) {
 | 
|            down_scale_requested_ = true;
 | 
| -          down_scale_bitrate_ = new_bitrate_kbit;
 | 
| +          down_scale_bitrate_ = bitrate.get_sum_kbps();
 | 
|            key_frame_request_[0] = true;
 | 
|          }
 | 
|        } else {
 | 
| -        if (new_bitrate_kbit > (2 * down_scale_bitrate_) ||
 | 
| -            new_bitrate_kbit < (down_scale_bitrate_ / 2)) {
 | 
| +        if (bitrate.get_sum_kbps() > (2 * down_scale_bitrate_) ||
 | 
| +            bitrate.get_sum_kbps() < (down_scale_bitrate_ / 2)) {
 | 
|            down_scale_requested_ = false;
 | 
|          }
 | 
|        }
 | 
| @@ -233,31 +237,18 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  std::vector<uint32_t> stream_bitrates =
 | 
| -      rate_allocator_->GetAllocation(new_bitrate_kbit);
 | 
|    size_t stream_idx = encoders_.size() - 1;
 | 
|    for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) {
 | 
| -    if (encoders_.size() > 1)
 | 
| -      SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
 | 
| -
 | 
| -    unsigned int target_bitrate = stream_bitrates[stream_idx];
 | 
| -    unsigned int max_bitrate = codec_.maxBitrate;
 | 
| -    int framerate = new_framerate;
 | 
| -    // TODO(holmer): This is a temporary hack for screensharing, where we
 | 
| -    // interpret the startBitrate as the encoder target bitrate. This is
 | 
| -    // to allow for a different max bitrate, so if the codec can't meet
 | 
| -    // the target we still allow it to overshoot up to the max before dropping
 | 
| -    // frames. This hack should be improved.
 | 
| -    if (codec_.targetBitrate > 0 &&
 | 
| -        (codec_.VP8()->numberOfTemporalLayers == 2 ||
 | 
| -         codec_.simulcastStream[0].numberOfTemporalLayers == 2)) {
 | 
| -      int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate);
 | 
| -      max_bitrate = std::min(codec_.maxBitrate, target_bitrate);
 | 
| -      target_bitrate = tl0_bitrate;
 | 
| -    }
 | 
| -    configurations_[i].rc_target_bitrate = target_bitrate;
 | 
| -    temporal_layers_[stream_idx]->ConfigureBitrates(
 | 
| -        target_bitrate, max_bitrate, framerate, &configurations_[i]);
 | 
| +    unsigned int target_bitrate_kbps =
 | 
| +        bitrate.GetSpatialLayerSum(stream_idx) / 1000;
 | 
| +
 | 
| +    bool send_stream = target_bitrate_kbps > 0;
 | 
| +    if (send_stream || encoders_.size() > 1)
 | 
| +      SetStreamState(send_stream, stream_idx);
 | 
| +
 | 
| +    configurations_[i].rc_target_bitrate = target_bitrate_kbps;
 | 
| +    temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]);
 | 
| +
 | 
|      if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) {
 | 
|        return WEBRTC_VIDEO_CODEC_ERROR;
 | 
|      }
 | 
| @@ -287,26 +278,17 @@ void VP8EncoderImpl::SetStreamState(bool send_stream,
 | 
|  void VP8EncoderImpl::SetupTemporalLayers(int num_streams,
 | 
|                                           int num_temporal_layers,
 | 
|                                           const VideoCodec& codec) {
 | 
| -  TemporalLayersFactory default_factory;
 | 
| +  RTC_DCHECK(codec.VP8().tl_factory != nullptr);
 | 
|    const TemporalLayersFactory* tl_factory = codec.VP8().tl_factory;
 | 
| -  if (!tl_factory)
 | 
| -    tl_factory = &default_factory;
 | 
|    if (num_streams == 1) {
 | 
| -    if (codec.mode == kScreensharing) {
 | 
| -      // Special mode when screensharing on a single stream.
 | 
| -      temporal_layers_.push_back(new ScreenshareLayers(
 | 
| -          num_temporal_layers, rand(), webrtc::Clock::GetRealTimeClock()));
 | 
| -    } else {
 | 
| -      temporal_layers_.push_back(
 | 
| -          tl_factory->Create(num_temporal_layers, rand()));
 | 
| -    }
 | 
| +    temporal_layers_.push_back(
 | 
| +        tl_factory->Create(0, num_temporal_layers, rand()));
 | 
|    } else {
 | 
|      for (int i = 0; i < num_streams; ++i) {
 | 
| -      // TODO(andresp): crash if layers is invalid.
 | 
| -      int layers = codec.simulcastStream[i].numberOfTemporalLayers;
 | 
| -      if (layers < 1)
 | 
| -        layers = 1;
 | 
| -      temporal_layers_.push_back(tl_factory->Create(layers, rand()));
 | 
| +      RTC_CHECK_GT(num_temporal_layers, 0);
 | 
| +      int layers = std::max(static_cast<uint8_t>(1),
 | 
| +                            codec.simulcastStream[i].numberOfTemporalLayers);
 | 
| +      temporal_layers_.push_back(tl_factory->Create(i, layers, rand()));
 | 
|      }
 | 
|    }
 | 
|  }
 | 
| @@ -351,10 +333,8 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
 | 
|    int num_temporal_layers =
 | 
|        doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers
 | 
|                        : inst->VP8().numberOfTemporalLayers;
 | 
| +  RTC_DCHECK_GT(num_temporal_layers, 0);
 | 
|  
 | 
| -  // TODO(andresp): crash if num temporal layers is bananas.
 | 
| -  if (num_temporal_layers < 1)
 | 
| -    num_temporal_layers = 1;
 | 
|    SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst);
 | 
|  
 | 
|    feedback_mode_ = inst->VP8().feedbackModeOn;
 | 
| @@ -362,7 +342,6 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
 | 
|    number_of_cores_ = number_of_cores;
 | 
|    timestamp_ = 0;
 | 
|    codec_ = *inst;
 | 
| -  rate_allocator_.reset(new SimulcastRateAllocator(codec_));
 | 
|  
 | 
|    // Code expects simulcastStream resolutions to be correct, make sure they are
 | 
|    // filled even when there are no simulcast layers.
 | 
| @@ -514,45 +493,44 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
 | 
|    vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1,
 | 
|                 NULL);
 | 
|  
 | 
| -  if (encoders_.size() == 1) {
 | 
| -    configurations_[0].rc_target_bitrate = inst->startBitrate;
 | 
| -    temporal_layers_[0]->ConfigureBitrates(inst->startBitrate, inst->maxBitrate,
 | 
| -                                           inst->maxFramerate,
 | 
| -                                           &configurations_[0]);
 | 
| -  } else {
 | 
| -    // Note the order we use is different from webm, we have lowest resolution
 | 
| -    // at position 0 and they have highest resolution at position 0.
 | 
| -    int stream_idx = encoders_.size() - 1;
 | 
| -    std::vector<uint32_t> stream_bitrates =
 | 
| -        rate_allocator_->GetAllocation(inst->startBitrate);
 | 
| +  // Note the order we use is different from webm, we have lowest resolution
 | 
| +  // at position 0 and they have highest resolution at position 0.
 | 
| +  int stream_idx = encoders_.size() - 1;
 | 
| +  SimulcastRateAllocator init_allocator(codec_, nullptr);
 | 
| +  BitrateAllocation allocation = init_allocator.GetAllocation(
 | 
| +      inst->startBitrate * 1000, inst->maxFramerate);
 | 
| +  std::vector<uint32_t> stream_bitrates;
 | 
| +  for (int i = 0; i == 0 || i < inst->numberOfSimulcastStreams; ++i) {
 | 
| +    uint32_t bitrate = allocation.GetSpatialLayerSum(i) / 1000;
 | 
| +    stream_bitrates.push_back(bitrate);
 | 
| +  }
 | 
| +
 | 
| +  configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx];
 | 
| +  temporal_layers_[stream_idx]->OnRatesUpdated(
 | 
| +      stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate);
 | 
| +  temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[0]);
 | 
| +  --stream_idx;
 | 
| +  for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) {
 | 
| +    memcpy(&configurations_[i], &configurations_[0],
 | 
| +           sizeof(configurations_[0]));
 | 
| +
 | 
| +    configurations_[i].g_w = inst->simulcastStream[stream_idx].width;
 | 
| +    configurations_[i].g_h = inst->simulcastStream[stream_idx].height;
 | 
| +
 | 
| +    // Use 1 thread for lower resolutions.
 | 
| +    configurations_[i].g_threads = 1;
 | 
| +
 | 
| +    // Setting alignment to 32 - as that ensures at least 16 for all
 | 
| +    // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
 | 
| +    // the y plane, but only half of it to the u and v planes.
 | 
| +    vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420,
 | 
| +                  inst->simulcastStream[stream_idx].width,
 | 
| +                  inst->simulcastStream[stream_idx].height, kVp832ByteAlign);
 | 
|      SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
 | 
| -    configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx];
 | 
| -    temporal_layers_[stream_idx]->ConfigureBitrates(
 | 
| -        stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate,
 | 
| -        &configurations_[0]);
 | 
| -    --stream_idx;
 | 
| -    for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) {
 | 
| -      memcpy(&configurations_[i], &configurations_[0],
 | 
| -             sizeof(configurations_[0]));
 | 
| -
 | 
| -      configurations_[i].g_w = inst->simulcastStream[stream_idx].width;
 | 
| -      configurations_[i].g_h = inst->simulcastStream[stream_idx].height;
 | 
| -
 | 
| -      // Use 1 thread for lower resolutions.
 | 
| -      configurations_[i].g_threads = 1;
 | 
| -
 | 
| -      // Setting alignment to 32 - as that ensures at least 16 for all
 | 
| -      // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
 | 
| -      // the y plane, but only half of it to the u and v planes.
 | 
| -      vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420,
 | 
| -                    inst->simulcastStream[stream_idx].width,
 | 
| -                    inst->simulcastStream[stream_idx].height, kVp832ByteAlign);
 | 
| -      SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
 | 
| -      configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx];
 | 
| -      temporal_layers_[stream_idx]->ConfigureBitrates(
 | 
| -          stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate,
 | 
| -          &configurations_[i]);
 | 
| -    }
 | 
| +    configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx];
 | 
| +    temporal_layers_[stream_idx]->OnRatesUpdated(
 | 
| +        stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate);
 | 
| +    temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]);
 | 
|    }
 | 
|  
 | 
|    rps_.Init();
 | 
| 
 |