| Index: webrtc/media/engine/webrtcvideoengine2.cc | 
| diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc | 
| index 3a3961c3980ef312d1af1ba26afb4a4ffa72875f..5176c115b70d8224978abad1c1555e327c9e39e6 100644 | 
| --- a/webrtc/media/engine/webrtcvideoengine2.cc | 
| +++ b/webrtc/media/engine/webrtcvideoengine2.cc | 
| @@ -14,7 +14,6 @@ | 
| #include <algorithm> | 
| #include <set> | 
| #include <string> | 
| -#include <utility> | 
|  | 
| #include "webrtc/base/copyonwritebuffer.h" | 
| #include "webrtc/base/logging.h" | 
| @@ -323,83 +322,12 @@ | 
| } | 
| return 1; | 
| } | 
| - | 
| -class EncoderStreamFactory | 
| -    : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface { | 
| - public: | 
| -  EncoderStreamFactory(std::string codec_name, | 
| -                       int max_qp, | 
| -                       int max_framerate, | 
| -                       bool is_screencast, | 
| -                       bool conference_mode) | 
| -      : codec_name_(codec_name), | 
| -        max_qp_(max_qp), | 
| -        max_framerate_(max_framerate), | 
| -        is_screencast_(is_screencast), | 
| -        conference_mode_(conference_mode) {} | 
| - | 
| - private: | 
| -  std::vector<webrtc::VideoStream> CreateEncoderStreams( | 
| -      int width, | 
| -      int height, | 
| -      const webrtc::VideoEncoderConfig& encoder_config) override { | 
| -    RTC_DCHECK(encoder_config.number_of_streams > 1 ? !is_screencast_ : true); | 
| -    if (encoder_config.number_of_streams > 1) { | 
| -      return GetSimulcastConfig(encoder_config.number_of_streams, width, height, | 
| -                                encoder_config.max_bitrate_bps, max_qp_, | 
| -                                max_framerate_); | 
| -    } | 
| - | 
| -    // For unset max bitrates set default bitrate for non-simulcast. | 
| -    int max_bitrate_bps = | 
| -        (encoder_config.max_bitrate_bps > 0) | 
| -            ? encoder_config.max_bitrate_bps | 
| -            : GetMaxDefaultVideoBitrateKbps(width, height) * 1000; | 
| - | 
| -    webrtc::VideoStream stream; | 
| -    stream.width = width; | 
| -    stream.height = height; | 
| -    stream.max_framerate = max_framerate_; | 
| -    stream.min_bitrate_bps = kMinVideoBitrateKbps * 1000; | 
| -    stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate_bps; | 
| -    stream.max_qp = max_qp_; | 
| - | 
| -    // Conference mode screencast uses 2 temporal layers split at 100kbit. | 
| -    if (conference_mode_ && is_screencast_) { | 
| -      ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault(); | 
| -      // For screenshare in conference mode, tl0 and tl1 bitrates are | 
| -      // piggybacked | 
| -      // on the VideoCodec struct as target and max bitrates, respectively. | 
| -      // See eg. webrtc::VP8EncoderImpl::SetRates(). | 
| -      stream.target_bitrate_bps = config.tl0_bitrate_kbps * 1000; | 
| -      stream.max_bitrate_bps = config.tl1_bitrate_kbps * 1000; | 
| -      stream.temporal_layer_thresholds_bps.clear(); | 
| -      stream.temporal_layer_thresholds_bps.push_back(config.tl0_bitrate_kbps * | 
| -                                                     1000); | 
| -    } | 
| - | 
| -    if (CodecNamesEq(codec_name_, kVp9CodecName) && !is_screencast_) { | 
| -      stream.temporal_layer_thresholds_bps.resize( | 
| -          GetDefaultVp9TemporalLayers() - 1); | 
| -    } | 
| - | 
| -    std::vector<webrtc::VideoStream> streams; | 
| -    streams.push_back(stream); | 
| -    return streams; | 
| -  } | 
| - | 
| -  const std::string codec_name_; | 
| -  const int max_qp_; | 
| -  const int max_framerate_; | 
| -  const bool is_screencast_; | 
| -  const bool conference_mode_; | 
| -}; | 
| - | 
| }  // namespace | 
|  | 
| // Constants defined in webrtc/media/engine/constants.h | 
| // TODO(pbos): Move these to a separate constants.cc file. | 
| -const int kMinVideoBitrateKbps = 30; | 
| +const int kMinVideoBitrate = 30; | 
| +const int kStartVideoBitrate = 300; | 
|  | 
| const int kVideoMtu = 1200; | 
| const int kVideoRtpBufferSize = 65536; | 
| @@ -470,10 +398,61 @@ | 
| return codecs; | 
| } | 
|  | 
| +std::vector<webrtc::VideoStream> | 
| +WebRtcVideoChannel2::WebRtcVideoSendStream::CreateSimulcastVideoStreams( | 
| +    const VideoCodec& codec, | 
| +    const VideoOptions& options, | 
| +    int max_bitrate_bps, | 
| +    size_t num_streams) { | 
| +  int max_qp = kDefaultQpMax; | 
| +  codec.GetParam(kCodecParamMaxQuantization, &max_qp); | 
| + | 
| +  return GetSimulcastConfig( | 
| +      num_streams, codec.width, codec.height, max_bitrate_bps, max_qp, | 
| +      codec.framerate != 0 ? codec.framerate : kDefaultVideoMaxFramerate); | 
| +} | 
| + | 
| +std::vector<webrtc::VideoStream> | 
| +WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoStreams( | 
| +    const VideoCodec& codec, | 
| +    const VideoOptions& options, | 
| +    int max_bitrate_bps, | 
| +    size_t num_streams) { | 
| +  int codec_max_bitrate_kbps; | 
| +  if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps)) { | 
| +    max_bitrate_bps = codec_max_bitrate_kbps * 1000; | 
| +  } | 
| +  if (num_streams != 1) { | 
| +    return CreateSimulcastVideoStreams(codec, options, max_bitrate_bps, | 
| +                                       num_streams); | 
| +  } | 
| + | 
| +  // For unset max bitrates set default bitrate for non-simulcast. | 
| +  if (max_bitrate_bps <= 0) { | 
| +    max_bitrate_bps = | 
| +        GetMaxDefaultVideoBitrateKbps(codec.width, codec.height) * 1000; | 
| +  } | 
| + | 
| +  webrtc::VideoStream stream; | 
| +  stream.width = codec.width; | 
| +  stream.height = codec.height; | 
| +  stream.max_framerate = | 
| +      codec.framerate != 0 ? codec.framerate : kDefaultVideoMaxFramerate; | 
| + | 
| +  stream.min_bitrate_bps = kMinVideoBitrate * 1000; | 
| +  stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate_bps; | 
| + | 
| +  int max_qp = kDefaultQpMax; | 
| +  codec.GetParam(kCodecParamMaxQuantization, &max_qp); | 
| +  stream.max_qp = max_qp; | 
| +  std::vector<webrtc::VideoStream> streams; | 
| +  streams.push_back(stream); | 
| +  return streams; | 
| +} | 
| + | 
| rtc::scoped_refptr<webrtc::VideoEncoderConfig::EncoderSpecificSettings> | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::ConfigureVideoEncoderSettings( | 
| const VideoCodec& codec) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| bool is_screencast = parameters_.options.is_screencast.value_or(false); | 
| // No automatic resizing when using simulcast or screencast. | 
| bool automatic_resize = | 
| @@ -1564,7 +1543,6 @@ | 
| : config(std::move(config)), | 
| options(options), | 
| max_bitrate_bps(max_bitrate_bps), | 
| -      conference_mode(false), | 
| codec_settings(codec_settings) {} | 
|  | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder::AllocatedEncoder( | 
| @@ -1609,6 +1587,7 @@ | 
| encoder_sink_(nullptr), | 
| parameters_(std::move(config), options, max_bitrate_bps, codec_settings), | 
| rtp_parameters_(CreateRtpParametersWithOneEncoding()), | 
| +      pending_encoder_reconfiguration_(false), | 
| allocated_encoder_(nullptr, webrtc::kVideoCodecUnknown, false), | 
| sending_(false), | 
| last_frame_timestamp_us_(0) { | 
| @@ -1676,6 +1655,7 @@ | 
| last_frame_info_.height = video_frame.height(); | 
| last_frame_info_.rotation = video_frame.rotation(); | 
| last_frame_info_.is_texture = video_frame.is_texture(); | 
| +    pending_encoder_reconfiguration_ = true; | 
|  | 
| LOG(LS_INFO) << "Video frame parameters changed: dimensions=" | 
| << last_frame_info_.width << "x" << last_frame_info_.height | 
| @@ -1690,13 +1670,22 @@ | 
|  | 
| last_frame_timestamp_us_ = video_frame.timestamp_us(); | 
|  | 
| +  if (pending_encoder_reconfiguration_) { | 
| +    ReconfigureEncoder(); | 
| +    pending_encoder_reconfiguration_ = false; | 
| +  } | 
| + | 
| +  // Not sending, abort after reconfiguration. Reconfiguration should still | 
| +  // occur to permit sending this input as quickly as possible once we start | 
| +  // sending (without having to reconfigure then). | 
| +  if (!sending_) { | 
| +    return; | 
| +  } | 
| + | 
| ++frame_count_; | 
| if (cpu_restricted_counter_ > 0) | 
| ++cpu_restricted_frame_count_; | 
|  | 
| -  // Forward frame to the encoder regardless if we are sending or not. This is | 
| -  // to ensure that the encoder can be reconfigured with the correct frame size | 
| -  // as quickly as possible. | 
| encoder_sink_->OnFrame(video_frame); | 
| } | 
|  | 
| @@ -1705,7 +1694,7 @@ | 
| const VideoOptions* options, | 
| rtc::VideoSourceInterface<cricket::VideoFrame>* source) { | 
| TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::SetVideoSend"); | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 
| // Ignore |options| pointer if |enable| is false. | 
| bool options_present = enable && options; | 
| @@ -1714,47 +1703,50 @@ | 
| DisconnectSource(); | 
| } | 
|  | 
| -  if (options_present) { | 
| -    VideoOptions old_options = parameters_.options; | 
| -    parameters_.options.SetAll(*options); | 
| -    // If options has changed and SetCodec has been called. | 
| -    if (parameters_.options != old_options && stream_) { | 
| -      ReconfigureEncoder(); | 
| -    } | 
| -  } | 
| - | 
| -  if (source_changing) { | 
| +  if (options_present || source_changing) { | 
| rtc::CritScope cs(&lock_); | 
| -    if (source == nullptr && encoder_sink_ != nullptr && | 
| -        last_frame_info_.width > 0) { | 
| -      LOG(LS_VERBOSE) << "Disabling capturer, sending black frame."; | 
| -      // Force this black frame not to be dropped due to timestamp order | 
| -      // check. As IncomingCapturedFrame will drop the frame if this frame's | 
| -      // timestamp is less than or equal to last frame's timestamp, it is | 
| -      // necessary to give this black frame a larger timestamp than the | 
| -      // previous one. | 
| -      last_frame_timestamp_us_ += rtc::kNumMicrosecsPerMillisec; | 
| -      rtc::scoped_refptr<webrtc::I420Buffer> black_buffer( | 
| -          webrtc::I420Buffer::Create(last_frame_info_.width, | 
| -                                     last_frame_info_.height)); | 
| -      black_buffer->SetToBlack(); | 
| - | 
| -      encoder_sink_->OnFrame(webrtc::VideoFrame( | 
| -          black_buffer, last_frame_info_.rotation, last_frame_timestamp_us_)); | 
| -    } | 
| -    source_ = source; | 
| -  } | 
| - | 
| + | 
| +    if (options_present) { | 
| +      VideoOptions old_options = parameters_.options; | 
| +      parameters_.options.SetAll(*options); | 
| +      // Reconfigure encoder settings on the next frame or stream | 
| +      // recreation if the options changed. | 
| +      if (parameters_.options != old_options) { | 
| +        pending_encoder_reconfiguration_ = true; | 
| +      } | 
| +    } | 
| + | 
| +    if (source_changing) { | 
| +      if (source == nullptr && encoder_sink_ != nullptr) { | 
| +        LOG(LS_VERBOSE) << "Disabling capturer, sending black frame."; | 
| +        // Force this black frame not to be dropped due to timestamp order | 
| +        // check. As IncomingCapturedFrame will drop the frame if this frame's | 
| +        // timestamp is less than or equal to last frame's timestamp, it is | 
| +        // necessary to give this black frame a larger timestamp than the | 
| +        // previous one. | 
| +        last_frame_timestamp_us_ += rtc::kNumMicrosecsPerMillisec; | 
| +        rtc::scoped_refptr<webrtc::I420Buffer> black_buffer( | 
| +            webrtc::I420Buffer::Create(last_frame_info_.width, | 
| +                                       last_frame_info_.height)); | 
| +        black_buffer->SetToBlack(); | 
| + | 
| +        encoder_sink_->OnFrame(webrtc::VideoFrame( | 
| +            black_buffer, last_frame_info_.rotation, last_frame_timestamp_us_)); | 
| +      } | 
| +      source_ = source; | 
| +    } | 
| +  } | 
| + | 
| +  // |source_->AddOrUpdateSink| may not be called while holding |lock_| since | 
| +  // that might cause a lock order inversion. | 
| if (source_changing && source_) { | 
| -    // |source_->AddOrUpdateSink| may not be called while holding |lock_| since | 
| -    // that might cause a lock order inversion. | 
| source_->AddOrUpdateSink(this, sink_wants_); | 
| } | 
| return true; | 
| } | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::DisconnectSource() { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| if (source_ == nullptr) { | 
| return; | 
| } | 
| @@ -1789,7 +1781,6 @@ | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoder( | 
| const VideoCodec& codec) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| webrtc::VideoCodecType type = CodecTypeFromName(codec.name); | 
|  | 
| // Do not re-create encoders of the same type. | 
| @@ -1824,7 +1815,6 @@ | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::DestroyVideoEncoder( | 
| AllocatedEncoder* encoder) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| if (encoder->external) { | 
| external_encoder_factory_->DestroyVideoEncoder(encoder->external_encoder); | 
| } | 
| @@ -1833,9 +1823,8 @@ | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec( | 
| const VideoCodecSettings& codec_settings) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| parameters_.encoder_config = CreateVideoEncoderConfig(codec_settings.codec); | 
| -  RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0u); | 
| +  RTC_DCHECK(!parameters_.encoder_config.streams.empty()); | 
|  | 
| AllocatedEncoder new_encoder = CreateVideoEncoder(codec_settings.codec); | 
| parameters_.config.encoder_settings.encoder = new_encoder.encoder; | 
| @@ -1876,38 +1865,41 @@ | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters( | 
| const ChangedSendParameters& params) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| -  // |recreate_stream| means construction-time parameters have changed and the | 
| -  // sending stream needs to be reset with the new config. | 
| -  bool recreate_stream = false; | 
| -  if (params.rtcp_mode) { | 
| -    parameters_.config.rtp.rtcp_mode = *params.rtcp_mode; | 
| -    recreate_stream = true; | 
| -  } | 
| -  if (params.rtp_header_extensions) { | 
| -    parameters_.config.rtp.extensions = *params.rtp_header_extensions; | 
| -    recreate_stream = true; | 
| -  } | 
| -  if (params.max_bandwidth_bps) { | 
| -    parameters_.max_bitrate_bps = *params.max_bandwidth_bps; | 
| -    ReconfigureEncoder(); | 
| -  } | 
| -  if (params.conference_mode) { | 
| -    parameters_.conference_mode = *params.conference_mode; | 
| -  } | 
| - | 
| -  // Set codecs and options. | 
| -  if (params.codec) { | 
| -    SetCodec(*params.codec); | 
| -    recreate_stream = false;  // SetCodec has already recreated the stream. | 
| -  } else if (params.conference_mode && parameters_.codec_settings) { | 
| -    SetCodec(*parameters_.codec_settings); | 
| -    recreate_stream = false;  // SetCodec has already recreated the stream. | 
| -  } | 
| -  if (recreate_stream) { | 
| -    LOG(LS_INFO) << "RecreateWebRtcStream (send) because of SetSendParameters"; | 
| -    RecreateWebRtcStream(); | 
| -  } | 
| +  { | 
| +    rtc::CritScope cs(&lock_); | 
| +    // |recreate_stream| means construction-time parameters have changed and the | 
| +    // sending stream needs to be reset with the new config. | 
| +    bool recreate_stream = false; | 
| +    if (params.rtcp_mode) { | 
| +      parameters_.config.rtp.rtcp_mode = *params.rtcp_mode; | 
| +      recreate_stream = true; | 
| +    } | 
| +    if (params.rtp_header_extensions) { | 
| +      parameters_.config.rtp.extensions = *params.rtp_header_extensions; | 
| +      recreate_stream = true; | 
| +    } | 
| +    if (params.max_bandwidth_bps) { | 
| +      parameters_.max_bitrate_bps = *params.max_bandwidth_bps; | 
| +      pending_encoder_reconfiguration_ = true; | 
| +    } | 
| +    if (params.conference_mode) { | 
| +      parameters_.conference_mode = *params.conference_mode; | 
| +    } | 
| + | 
| +    // Set codecs and options. | 
| +    if (params.codec) { | 
| +      SetCodec(*params.codec); | 
| +      recreate_stream = false;  // SetCodec has already recreated the stream. | 
| +    } else if (params.conference_mode && parameters_.codec_settings) { | 
| +      SetCodec(*parameters_.codec_settings); | 
| +      recreate_stream = false;  // SetCodec has already recreated the stream. | 
| +    } | 
| +    if (recreate_stream) { | 
| +      LOG(LS_INFO) | 
| +          << "RecreateWebRtcStream (send) because of SetSendParameters"; | 
| +      RecreateWebRtcStream(); | 
| +    } | 
| +  }  // release |lock_| | 
|  | 
| // |source_->AddOrUpdateSink| may not be called while holding |lock_| since | 
| // that might cause a lock order inversion. | 
| @@ -1922,19 +1914,18 @@ | 
|  | 
| bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpParameters( | 
| const webrtc::RtpParameters& new_parameters) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| if (!ValidateRtpParameters(new_parameters)) { | 
| return false; | 
| } | 
|  | 
| -  bool reconfigure_encoder = new_parameters.encodings[0].max_bitrate_bps != | 
| -                             rtp_parameters_.encodings[0].max_bitrate_bps; | 
| +  rtc::CritScope cs(&lock_); | 
| +  if (new_parameters.encodings[0].max_bitrate_bps != | 
| +      rtp_parameters_.encodings[0].max_bitrate_bps) { | 
| +    pending_encoder_reconfiguration_ = true; | 
| +  } | 
| rtp_parameters_ = new_parameters; | 
| // Codecs are currently handled at the WebRtcVideoChannel2 level. | 
| rtp_parameters_.codecs.clear(); | 
| -  if (reconfigure_encoder) { | 
| -    ReconfigureEncoder(); | 
| -  } | 
| // Encoding may have been activated/deactivated. | 
| UpdateSendState(); | 
| return true; | 
| @@ -1942,7 +1933,7 @@ | 
|  | 
| webrtc::RtpParameters | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::GetRtpParameters() const { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  rtc::CritScope cs(&lock_); | 
| return rtp_parameters_; | 
| } | 
|  | 
| @@ -1957,7 +1948,6 @@ | 
| } | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::UpdateSendState() { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| // TODO(deadbeef): Need to handle more than one encoding in the future. | 
| RTC_DCHECK(rtp_parameters_.encodings.size() == 1u); | 
| if (sending_ && rtp_parameters_.encodings[0].active) { | 
| @@ -1973,7 +1963,6 @@ | 
| webrtc::VideoEncoderConfig | 
| WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig( | 
| const VideoCodec& codec) const { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| webrtc::VideoEncoderConfig encoder_config; | 
| bool is_screencast = parameters_.options.is_screencast.value_or(false); | 
| if (is_screencast) { | 
| @@ -1987,39 +1976,60 @@ | 
| webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo; | 
| } | 
|  | 
| +  // Restrict dimensions according to codec max. | 
| +  int width = last_frame_info_.width; | 
| +  int height = last_frame_info_.height; | 
| +  if (!is_screencast) { | 
| +    if (codec.width < width) | 
| +      width = codec.width; | 
| +    if (codec.height < height) | 
| +      height = codec.height; | 
| +  } | 
| + | 
| +  VideoCodec clamped_codec = codec; | 
| +  clamped_codec.width = width; | 
| +  clamped_codec.height = height; | 
| + | 
| // By default, the stream count for the codec configuration should match the | 
| // number of negotiated ssrcs. But if the codec is blacklisted for simulcast | 
| // or a screencast, only configure a single stream. | 
| -  encoder_config.number_of_streams = parameters_.config.rtp.ssrcs.size(); | 
| +  size_t stream_count = parameters_.config.rtp.ssrcs.size(); | 
| if (IsCodecBlacklistedForSimulcast(codec.name) || is_screencast) { | 
| -    encoder_config.number_of_streams = 1; | 
| +    stream_count = 1; | 
| } | 
|  | 
| int stream_max_bitrate = | 
| MinPositive(rtp_parameters_.encodings[0].max_bitrate_bps, | 
| parameters_.max_bitrate_bps); | 
| - | 
| -  int codec_max_bitrate_kbps; | 
| -  if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps)) { | 
| -    stream_max_bitrate = codec_max_bitrate_kbps * 1000; | 
| -  } | 
| -  encoder_config.max_bitrate_bps = stream_max_bitrate; | 
| - | 
| -  int max_qp = kDefaultQpMax; | 
| -  codec.GetParam(kCodecParamMaxQuantization, &max_qp); | 
| -  int max_framerate = | 
| -      codec.framerate != 0 ? codec.framerate : kDefaultVideoMaxFramerate; | 
| - | 
| -  encoder_config.video_stream_factory = | 
| -      new rtc::RefCountedObject<EncoderStreamFactory>( | 
| -          codec.name, max_qp, max_framerate, is_screencast, | 
| -          parameters_.conference_mode); | 
| +  encoder_config.streams = CreateVideoStreams( | 
| +      clamped_codec, parameters_.options, stream_max_bitrate, stream_count); | 
| +  encoder_config.expect_encode_from_texture = last_frame_info_.is_texture; | 
| + | 
| +  // Conference mode screencast uses 2 temporal layers split at 100kbit. | 
| +  if (parameters_.conference_mode && is_screencast && | 
| +      encoder_config.streams.size() == 1) { | 
| +    ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault(); | 
| + | 
| +    // For screenshare in conference mode, tl0 and tl1 bitrates are piggybacked | 
| +    // on the VideoCodec struct as target and max bitrates, respectively. | 
| +    // See eg. webrtc::VP8EncoderImpl::SetRates(). | 
| +    encoder_config.streams[0].target_bitrate_bps = | 
| +        config.tl0_bitrate_kbps * 1000; | 
| +    encoder_config.streams[0].max_bitrate_bps = config.tl1_bitrate_kbps * 1000; | 
| +    encoder_config.streams[0].temporal_layer_thresholds_bps.clear(); | 
| +    encoder_config.streams[0].temporal_layer_thresholds_bps.push_back( | 
| +        config.tl0_bitrate_kbps * 1000); | 
| +  } | 
| +  if (CodecNamesEq(codec.name, kVp9CodecName) && !is_screencast && | 
| +      encoder_config.streams.size() == 1) { | 
| +    encoder_config.streams[0].temporal_layer_thresholds_bps.resize( | 
| +        GetDefaultVp9TemporalLayers() - 1); | 
| +  } | 
| return encoder_config; | 
| } | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::ReconfigureEncoder() { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| -  RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0u); | 
| +  RTC_DCHECK(!parameters_.encoder_config.streams.empty()); | 
|  | 
| RTC_CHECK(parameters_.codec_settings); | 
| VideoCodecSettings codec_settings = *parameters_.codec_settings; | 
| @@ -2038,7 +2048,7 @@ | 
| } | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSend(bool send) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  rtc::CritScope cs(&lock_); | 
| sending_ = send; | 
| UpdateSendState(); | 
| } | 
| @@ -2068,62 +2078,63 @@ | 
| this, load)); | 
| return; | 
| } | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| if (!source_) { | 
| return; | 
| } | 
| - | 
| -  LOG(LS_INFO) << "OnLoadUpdate " << load << ", is_screencast: " | 
| -               << (parameters_.options.is_screencast | 
| -                       ? (*parameters_.options.is_screencast ? "true" : "false") | 
| -                       : "unset"); | 
| -  // Do not adapt resolution for screen content as this will likely result in | 
| -  // blurry and unreadable text. | 
| -  if (parameters_.options.is_screencast.value_or(false)) | 
| -    return; | 
| - | 
| -  rtc::Optional<int> max_pixel_count; | 
| -  rtc::Optional<int> max_pixel_count_step_up; | 
| -  if (load == kOveruse) { | 
| +  { | 
| rtc::CritScope cs(&lock_); | 
| -    if (cpu_restricted_counter_ >= kMaxCpuDowngrades) { | 
| +    LOG(LS_INFO) << "OnLoadUpdate " << load << ", is_screencast: " | 
| +                 << (parameters_.options.is_screencast | 
| +                         ? (*parameters_.options.is_screencast ? "true" | 
| +                                                               : "false") | 
| +                         : "unset"); | 
| +    // Do not adapt resolution for screen content as this will likely result in | 
| +    // blurry and unreadable text. | 
| +    if (parameters_.options.is_screencast.value_or(false)) | 
| return; | 
| -    } | 
| -    // The input video frame size will have a resolution with less than or | 
| -    // equal to |max_pixel_count| depending on how the source can scale the | 
| -    // input frame size. | 
| -    max_pixel_count = rtc::Optional<int>( | 
| -        (last_frame_info_.height * last_frame_info_.width * 3) / 5); | 
| -    // Increase |number_of_cpu_adapt_changes_| if | 
| -    // sink_wants_.max_pixel_count will be changed since | 
| -    // last time |source_->AddOrUpdateSink| was called. That is, this will | 
| -    // result in a new request for the source to change resolution. | 
| -    if (!sink_wants_.max_pixel_count || | 
| -        *sink_wants_.max_pixel_count > *max_pixel_count) { | 
| -      ++number_of_cpu_adapt_changes_; | 
| -      ++cpu_restricted_counter_; | 
| -    } | 
| -  } else { | 
| -    RTC_DCHECK(load == kUnderuse); | 
| -    rtc::CritScope cs(&lock_); | 
| -    // The input video frame size will have a resolution with "one step up" | 
| -    // pixels than |max_pixel_count_step_up| where "one step up" depends on | 
| -    // how the source can scale the input frame size. | 
| -    max_pixel_count_step_up = | 
| -        rtc::Optional<int>(last_frame_info_.height * last_frame_info_.width); | 
| -    // Increase |number_of_cpu_adapt_changes_| if | 
| -    // sink_wants_.max_pixel_count_step_up will be changed since | 
| -    // last time |source_->AddOrUpdateSink| was called. That is, this will | 
| -    // result in a new request for the source to change resolution. | 
| -    if (sink_wants_.max_pixel_count || | 
| -        (sink_wants_.max_pixel_count_step_up && | 
| -         *sink_wants_.max_pixel_count_step_up < *max_pixel_count_step_up)) { | 
| -      ++number_of_cpu_adapt_changes_; | 
| -      --cpu_restricted_counter_; | 
| -    } | 
| -  } | 
| -  sink_wants_.max_pixel_count = max_pixel_count; | 
| -  sink_wants_.max_pixel_count_step_up = max_pixel_count_step_up; | 
| + | 
| +    rtc::Optional<int> max_pixel_count; | 
| +    rtc::Optional<int> max_pixel_count_step_up; | 
| +    if (load == kOveruse) { | 
| +      if (cpu_restricted_counter_ >= kMaxCpuDowngrades) { | 
| +        return; | 
| +      } | 
| +      // The input video frame size will have a resolution with less than or | 
| +      // equal to |max_pixel_count| depending on how the source can scale the | 
| +      // input frame size. | 
| +      max_pixel_count = rtc::Optional<int>( | 
| +          (last_frame_info_.height * last_frame_info_.width * 3) / 5); | 
| +      // Increase |number_of_cpu_adapt_changes_| if | 
| +      // sink_wants_.max_pixel_count will be changed since | 
| +      // last time |source_->AddOrUpdateSink| was called. That is, this will | 
| +      // result in a new request for the source to change resolution. | 
| +      if (!sink_wants_.max_pixel_count || | 
| +          *sink_wants_.max_pixel_count > *max_pixel_count) { | 
| +        ++number_of_cpu_adapt_changes_; | 
| +        ++cpu_restricted_counter_; | 
| +      } | 
| +    } else { | 
| +      RTC_DCHECK(load == kUnderuse); | 
| +      // The input video frame size will have a resolution with "one step up" | 
| +      // pixels than |max_pixel_count_step_up| where "one step up" depends on | 
| +      // how the source can scale the input frame size. | 
| +      max_pixel_count_step_up = | 
| +          rtc::Optional<int>(last_frame_info_.height * last_frame_info_.width); | 
| +      // Increase |number_of_cpu_adapt_changes_| if | 
| +      // sink_wants_.max_pixel_count_step_up will be changed since | 
| +      // last time |source_->AddOrUpdateSink| was called. That is, this will | 
| +      // result in a new request for the source to change resolution. | 
| +      if (sink_wants_.max_pixel_count || | 
| +          (sink_wants_.max_pixel_count_step_up && | 
| +           *sink_wants_.max_pixel_count_step_up < *max_pixel_count_step_up)) { | 
| +        ++number_of_cpu_adapt_changes_; | 
| +        --cpu_restricted_counter_; | 
| +      } | 
| +    } | 
| +    sink_wants_.max_pixel_count = max_pixel_count; | 
| +    sink_wants_.max_pixel_count_step_up = max_pixel_count_step_up; | 
| +  } | 
| // |source_->AddOrUpdateSink| may not be called while holding |lock_| since | 
| // that might cause a lock order inversion. | 
| source_->AddOrUpdateSink(this, sink_wants_); | 
| @@ -2132,17 +2143,21 @@ | 
| VideoSenderInfo WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo( | 
| bool log_stats) { | 
| VideoSenderInfo info; | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| -  for (uint32_t ssrc : parameters_.config.rtp.ssrcs) | 
| -    info.add_ssrc(ssrc); | 
| - | 
| -  if (parameters_.codec_settings) | 
| -    info.codec_name = parameters_.codec_settings->codec.name; | 
| - | 
| -  if (stream_ == NULL) | 
| -    return info; | 
| - | 
| -  webrtc::VideoSendStream::Stats stats = stream_->GetStats(); | 
| +  webrtc::VideoSendStream::Stats stats; | 
| +  RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| +  { | 
| +    rtc::CritScope cs(&lock_); | 
| +    for (uint32_t ssrc : parameters_.config.rtp.ssrcs) | 
| +      info.add_ssrc(ssrc); | 
| + | 
| +    if (parameters_.codec_settings) | 
| +      info.codec_name = parameters_.codec_settings->codec.name; | 
| + | 
| +    if (stream_ == NULL) | 
| +      return info; | 
| + | 
| +    stats = stream_->GetStats(); | 
| +  } | 
|  | 
| if (log_stats) | 
| LOG(LS_INFO) << stats.ToString(rtc::TimeMillis()); | 
| @@ -2203,7 +2218,7 @@ | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::FillBandwidthEstimationInfo( | 
| BandwidthEstimationInfo* bwe_info) { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| +  rtc::CritScope cs(&lock_); | 
| if (stream_ == NULL) { | 
| return; | 
| } | 
| @@ -2219,7 +2234,6 @@ | 
| } | 
|  | 
| void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() { | 
| -  RTC_DCHECK_RUN_ON(&thread_checker_); | 
| if (stream_ != NULL) { | 
| call_->DestroyVideoSendStream(stream_); | 
| } | 
| @@ -2243,6 +2257,7 @@ | 
| stream_->SetSource(this); | 
|  | 
| parameters_.encoder_config.encoder_specific_settings = NULL; | 
| +  pending_encoder_reconfiguration_ = false; | 
|  | 
| // Call stream_->Start() if necessary conditions are met. | 
| UpdateSendState(); | 
|  |