| Index: webrtc/video/vie_encoder.cc
 | 
| diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc
 | 
| index 63b1c80fefbe9b0f0f8afaf95a83dd0f140a3540..d82e4fc7a2b2ef4fd6f9b4205a3c40f5263f3f45 100644
 | 
| --- a/webrtc/video/vie_encoder.cc
 | 
| +++ b/webrtc/video/vie_encoder.cc
 | 
| @@ -44,24 +44,12 @@ const int64_t kFrameLogIntervalMs = 60000;
 | 
|  // See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
 | 
|  const int kMinPixelsPerFrame = 320 * 180;
 | 
|  const int kMinFramerateFps = 2;
 | 
| +const int kMaxFramerateFps = 120;
 | 
|  
 | 
|  // The maximum number of frames to drop at beginning of stream
 | 
|  // to try and achieve desired bitrate.
 | 
|  const int kMaxInitialFramedrop = 4;
 | 
|  
 | 
| -// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
 | 
| -// pipelining encoders better (multiple input frames before something comes
 | 
| -// out). This should effectively turn off CPU adaptations for systems that
 | 
| -// remotely cope with the load right now.
 | 
| -CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
 | 
| -  CpuOveruseOptions options;
 | 
| -  if (full_overuse_time) {
 | 
| -    options.low_encode_usage_threshold_percent = 150;
 | 
| -    options.high_encode_usage_threshold_percent = 200;
 | 
| -  }
 | 
| -  return options;
 | 
| -}
 | 
| -
 | 
|  uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) {
 | 
|    if (kbps > 0) {
 | 
|      if (kbps < 300 /* qvga */) {
 | 
| @@ -207,7 +195,7 @@ class ViEEncoder::VideoSourceProxy {
 | 
|        degradation_preference_ = degradation_preference;
 | 
|        old_source = source_;
 | 
|        source_ = source;
 | 
| -      wants = GetActiveSinkWants();
 | 
| +      wants = GetActiveSinkWantsInternal();
 | 
|      }
 | 
|  
 | 
|      if (old_source != source && old_source != nullptr) {
 | 
| @@ -228,26 +216,9 @@ class ViEEncoder::VideoSourceProxy {
 | 
|        source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
 | 
|    }
 | 
|  
 | 
| -  rtc::VideoSinkWants GetActiveSinkWants() EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
 | 
| -    rtc::VideoSinkWants wants = sink_wants_;
 | 
| -    // Clear any constraints from the current sink wants that don't apply to
 | 
| -    // the used degradation_preference.
 | 
| -    switch (degradation_preference_) {
 | 
| -      case VideoSendStream::DegradationPreference::kBalanced:
 | 
| -        break;
 | 
| -      case VideoSendStream::DegradationPreference::kMaintainFramerate:
 | 
| -        wants.max_framerate_fps = std::numeric_limits<int>::max();
 | 
| -        break;
 | 
| -      case VideoSendStream::DegradationPreference::kMaintainResolution:
 | 
| -        wants.max_pixel_count = std::numeric_limits<int>::max();
 | 
| -        wants.target_pixel_count.reset();
 | 
| -        break;
 | 
| -      case VideoSendStream::DegradationPreference::kDegradationDisabled:
 | 
| -        wants.max_pixel_count = std::numeric_limits<int>::max();
 | 
| -        wants.target_pixel_count.reset();
 | 
| -        wants.max_framerate_fps = std::numeric_limits<int>::max();
 | 
| -    }
 | 
| -    return wants;
 | 
| +  rtc::VideoSinkWants GetActiveSinkWants() {
 | 
| +    rtc::CritScope lock(&crit_);
 | 
| +    return GetActiveSinkWantsInternal();
 | 
|    }
 | 
|  
 | 
|    void ResetPixelFpsCount() {
 | 
| @@ -277,14 +248,15 @@ class ViEEncoder::VideoSourceProxy {
 | 
|      LOG(LS_INFO) << "Scaling down resolution, max pixels: " << pixels_wanted;
 | 
|      sink_wants_.max_pixel_count = pixels_wanted;
 | 
|      sink_wants_.target_pixel_count = rtc::Optional<int>();
 | 
| -    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants());
 | 
| +    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal());
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| -  bool RequestFramerateLowerThan(int fps) {
 | 
| +  int RequestFramerateLowerThan(int fps) {
 | 
|      // Called on the encoder task queue.
 | 
|      // The input video frame rate will be scaled down to 2/3, rounding down.
 | 
| -    return RestrictFramerate((fps * 2) / 3);
 | 
| +    int framerate_wanted = (fps * 2) / 3;
 | 
| +    return RestrictFramerate(framerate_wanted) ? framerate_wanted : -1;
 | 
|    }
 | 
|  
 | 
|    bool RequestHigherResolutionThan(int pixel_count) {
 | 
| @@ -317,18 +289,22 @@ class ViEEncoder::VideoSourceProxy {
 | 
|            rtc::Optional<int>((pixel_count * 5) / 3);
 | 
|      }
 | 
|      LOG(LS_INFO) << "Scaling up resolution, max pixels: " << max_pixels_wanted;
 | 
| -    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants());
 | 
| +    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal());
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| -  bool RequestHigherFramerateThan(int fps) {
 | 
| +  // Request upgrade in framerate. Returns the new requested frame, or -1 if
 | 
| +  // no change requested. Note that maxint may be returned if limits due to
 | 
| +  // adaptation requests are removed completely. In that case, consider
 | 
| +  // |max_framerate_| to be the current limit (assuming the capturer complies).
 | 
| +  int RequestHigherFramerateThan(int fps) {
 | 
|      // Called on the encoder task queue.
 | 
|      // The input frame rate will be scaled up to the last step, with rounding.
 | 
|      int framerate_wanted = fps;
 | 
|      if (fps != std::numeric_limits<int>::max())
 | 
|        framerate_wanted = (fps * 3) / 2;
 | 
|  
 | 
| -    return IncreaseFramerate(framerate_wanted);
 | 
| +    return IncreaseFramerate(framerate_wanted) ? framerate_wanted : -1;
 | 
|    }
 | 
|  
 | 
|    bool RestrictFramerate(int fps) {
 | 
| @@ -343,7 +319,7 @@ class ViEEncoder::VideoSourceProxy {
 | 
|  
 | 
|      LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted;
 | 
|      sink_wants_.max_framerate_fps = fps_wanted;
 | 
| -    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants());
 | 
| +    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal());
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| @@ -359,11 +335,34 @@ class ViEEncoder::VideoSourceProxy {
 | 
|  
 | 
|      LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted;
 | 
|      sink_wants_.max_framerate_fps = fps_wanted;
 | 
| -    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWants());
 | 
| +    source_->AddOrUpdateSink(vie_encoder_, GetActiveSinkWantsInternal());
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
|   private:
 | 
| +  rtc::VideoSinkWants GetActiveSinkWantsInternal()
 | 
| +      EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
 | 
| +    rtc::VideoSinkWants wants = sink_wants_;
 | 
| +    // Clear any constraints from the current sink wants that don't apply to
 | 
| +    // the used degradation_preference.
 | 
| +    switch (degradation_preference_) {
 | 
| +      case VideoSendStream::DegradationPreference::kBalanced:
 | 
| +        break;
 | 
| +      case VideoSendStream::DegradationPreference::kMaintainFramerate:
 | 
| +        wants.max_framerate_fps = std::numeric_limits<int>::max();
 | 
| +        break;
 | 
| +      case VideoSendStream::DegradationPreference::kMaintainResolution:
 | 
| +        wants.max_pixel_count = std::numeric_limits<int>::max();
 | 
| +        wants.target_pixel_count.reset();
 | 
| +        break;
 | 
| +      case VideoSendStream::DegradationPreference::kDegradationDisabled:
 | 
| +        wants.max_pixel_count = std::numeric_limits<int>::max();
 | 
| +        wants.target_pixel_count.reset();
 | 
| +        wants.max_framerate_fps = std::numeric_limits<int>::max();
 | 
| +    }
 | 
| +    return wants;
 | 
| +  }
 | 
| +
 | 
|    rtc::CriticalSection crit_;
 | 
|    rtc::SequencedTaskChecker main_checker_;
 | 
|    ViEEncoder* const vie_encoder_;
 | 
| @@ -379,7 +378,8 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
 | 
|                         SendStatisticsProxy* stats_proxy,
 | 
|                         const VideoSendStream::Config::EncoderSettings& settings,
 | 
|                         rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback,
 | 
| -                       EncodedFrameObserver* encoder_timing)
 | 
| +                       EncodedFrameObserver* encoder_timing,
 | 
| +                       std::unique_ptr<OveruseFrameDetector> overuse_detector)
 | 
|      : shutdown_event_(true /* manual_reset */, false),
 | 
|        number_of_cores_(number_of_cores),
 | 
|        initial_rampup_(0),
 | 
| @@ -389,13 +389,18 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
 | 
|        codec_type_(PayloadNameToCodecType(settings.payload_name)
 | 
|                        .value_or(VideoCodecType::kVideoCodecUnknown)),
 | 
|        video_sender_(Clock::GetRealTimeClock(), this, this),
 | 
| -      overuse_detector_(GetCpuOveruseOptions(settings.full_overuse_time),
 | 
| -                        this,
 | 
| -                        encoder_timing,
 | 
| -                        stats_proxy),
 | 
| +      overuse_detector_(
 | 
| +          overuse_detector.get()
 | 
| +              ? overuse_detector.release()
 | 
| +              : new OveruseFrameDetector(
 | 
| +                    GetCpuOveruseOptions(settings.full_overuse_time),
 | 
| +                    this,
 | 
| +                    encoder_timing,
 | 
| +                    stats_proxy)),
 | 
|        stats_proxy_(stats_proxy),
 | 
|        pre_encode_callback_(pre_encode_callback),
 | 
|        module_process_thread_(nullptr),
 | 
| +      max_framerate_(-1),
 | 
|        pending_encoder_reconfiguration_(false),
 | 
|        encoder_start_bitrate_bps_(0),
 | 
|        max_data_payload_length_(0),
 | 
| @@ -416,7 +421,7 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
 | 
|    RTC_DCHECK(stats_proxy);
 | 
|    encoder_queue_.PostTask([this] {
 | 
|      RTC_DCHECK_RUN_ON(&encoder_queue_);
 | 
| -    overuse_detector_.StartCheckForOveruse();
 | 
| +    overuse_detector_->StartCheckForOveruse();
 | 
|      video_sender_.RegisterExternalEncoder(
 | 
|          settings_.encoder, settings_.payload_type, settings_.internal_source);
 | 
|    });
 | 
| @@ -428,12 +433,25 @@ ViEEncoder::~ViEEncoder() {
 | 
|        << "Must call ::Stop() before destruction.";
 | 
|  }
 | 
|  
 | 
| +// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
 | 
| +// pipelining encoders better (multiple input frames before something comes
 | 
| +// out). This should effectively turn off CPU adaptations for systems that
 | 
| +// remotely cope with the load right now.
 | 
| +CpuOveruseOptions ViEEncoder::GetCpuOveruseOptions(bool full_overuse_time) {
 | 
| +  CpuOveruseOptions options;
 | 
| +  if (full_overuse_time) {
 | 
| +    options.low_encode_usage_threshold_percent = 150;
 | 
| +    options.high_encode_usage_threshold_percent = 200;
 | 
| +  }
 | 
| +  return options;
 | 
| +}
 | 
| +
 | 
|  void ViEEncoder::Stop() {
 | 
|    RTC_DCHECK_RUN_ON(&thread_checker_);
 | 
|    source_proxy_->SetSource(nullptr, VideoSendStream::DegradationPreference());
 | 
|    encoder_queue_.PostTask([this] {
 | 
|      RTC_DCHECK_RUN_ON(&encoder_queue_);
 | 
| -    overuse_detector_.StopCheckForOveruse();
 | 
| +    overuse_detector_->StopCheckForOveruse();
 | 
|      rate_allocator_.reset();
 | 
|      bitrate_observer_ = nullptr;
 | 
|      video_sender_.RegisterExternalEncoder(nullptr, settings_.payload_type,
 | 
| @@ -493,6 +511,12 @@ void ViEEncoder::SetSource(
 | 
|      bool allow_scaling = IsResolutionScalingEnabled(degradation_preference_);
 | 
|      initial_rampup_ = allow_scaling ? 0 : kMaxInitialFramedrop;
 | 
|      ConfigureQualityScaler();
 | 
| +    if (!IsFramerateScalingEnabled(degradation_preference) &&
 | 
| +        max_framerate_ != -1) {
 | 
| +      // If frame rate scaling is no longer allowed, remove any potential
 | 
| +      // allowance for longer frame intervals.
 | 
| +      overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
 | 
| +    }
 | 
|    });
 | 
|  }
 | 
|  
 | 
| @@ -562,6 +586,8 @@ void ViEEncoder::ReconfigureEncoder() {
 | 
|        std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
 | 
|    codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
 | 
|    codec.expect_encode_from_texture = last_frame_info_->is_texture;
 | 
| +  max_framerate_ = codec.maxFramerate;
 | 
| +  RTC_DCHECK_LE(max_framerate_, kMaxFramerateFps);
 | 
|  
 | 
|    bool success = video_sender_.RegisterSendCodec(
 | 
|                       &codec, number_of_cores_,
 | 
| @@ -574,19 +600,31 @@ void ViEEncoder::ReconfigureEncoder() {
 | 
|    video_sender_.UpdateChannelParemeters(rate_allocator_.get(),
 | 
|                                          bitrate_observer_);
 | 
|  
 | 
| -  int framerate = stats_proxy_->GetSendFrameRate();
 | 
| -  if (framerate == 0)
 | 
| -    framerate = codec.maxFramerate;
 | 
| +  // Get the current actual framerate, as measured by the stats proxy. This is
 | 
| +  // used to get the correct bitrate layer allocation.
 | 
| +  int current_framerate = stats_proxy_->GetSendFrameRate();
 | 
| +  if (current_framerate == 0)
 | 
| +    current_framerate = codec.maxFramerate;
 | 
|    stats_proxy_->OnEncoderReconfigured(
 | 
| -      encoder_config_, rate_allocator_.get()
 | 
| -                           ? rate_allocator_->GetPreferredBitrateBps(framerate)
 | 
| -                           : codec.maxBitrate);
 | 
| +      encoder_config_,
 | 
| +      rate_allocator_.get()
 | 
| +          ? rate_allocator_->GetPreferredBitrateBps(current_framerate)
 | 
| +          : codec.maxBitrate);
 | 
|  
 | 
|    pending_encoder_reconfiguration_ = false;
 | 
|  
 | 
|    sink_->OnEncoderConfigurationChanged(
 | 
|        std::move(streams), encoder_config_.min_transmit_bitrate_bps);
 | 
|  
 | 
| +  // Get the current target framerate, ie the maximum framerate as specified by
 | 
| +  // the current codec configuration, or any limit imposed by cpu adaption in
 | 
| +  // maintain-resolution or balanced mode. This is used to make sure overuse
 | 
| +  // detection doesn't needlessly trigger in low and/or variable framerate
 | 
| +  // scenarios.
 | 
| +  int target_framerate = std::min(
 | 
| +      max_framerate_, source_proxy_->GetActiveSinkWants().max_framerate_fps);
 | 
| +  overuse_detector_->OnTargetFramerateUpdated(target_framerate);
 | 
| +
 | 
|    ConfigureQualityScaler();
 | 
|  }
 | 
|  
 | 
| @@ -735,7 +773,7 @@ void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
 | 
|    TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
 | 
|                            "Encode");
 | 
|  
 | 
| -  overuse_detector_.FrameCaptured(video_frame, time_when_posted_us);
 | 
| +  overuse_detector_->FrameCaptured(video_frame, time_when_posted_us);
 | 
|  
 | 
|    video_sender_.AddVideoFrame(video_frame, nullptr);
 | 
|  }
 | 
| @@ -766,7 +804,7 @@ EncodedImageCallback::Result ViEEncoder::OnEncodedImage(
 | 
|    const int qp = encoded_image.qp_;
 | 
|    encoder_queue_.PostTask([this, timestamp, time_sent_us, qp] {
 | 
|      RTC_DCHECK_RUN_ON(&encoder_queue_);
 | 
| -    overuse_detector_.FrameSent(timestamp, time_sent_us);
 | 
| +    overuse_detector_->FrameSent(timestamp, time_sent_us);
 | 
|      if (quality_scaler_ && qp >= 0)
 | 
|        quality_scaler_->ReportQP(qp);
 | 
|    });
 | 
| @@ -901,14 +939,18 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
 | 
|        }
 | 
|        GetAdaptCounter().IncrementResolution(reason);
 | 
|        break;
 | 
| -    case VideoSendStream::DegradationPreference::kMaintainResolution:
 | 
| +    case VideoSendStream::DegradationPreference::kMaintainResolution: {
 | 
|        // Scale down framerate.
 | 
| -      if (!source_proxy_->RequestFramerateLowerThan(
 | 
| -              adaptation_request.framerate_fps_)) {
 | 
| +      const int requested_framerate = source_proxy_->RequestFramerateLowerThan(
 | 
| +          adaptation_request.framerate_fps_);
 | 
| +      if (requested_framerate == -1)
 | 
|          return;
 | 
| -      }
 | 
| +      RTC_DCHECK_NE(max_framerate_, -1);
 | 
| +      overuse_detector_->OnTargetFramerateUpdated(
 | 
| +          std::min(max_framerate_, requested_framerate));
 | 
|        GetAdaptCounter().IncrementFramerate(reason);
 | 
|        break;
 | 
| +    }
 | 
|      case VideoSendStream::DegradationPreference::kDegradationDisabled:
 | 
|        RTC_NOTREACHED();
 | 
|    }
 | 
| @@ -985,8 +1027,15 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|          LOG(LS_INFO) << "Removing framerate down-scaling setting.";
 | 
|          fps = std::numeric_limits<int>::max();
 | 
|        }
 | 
| -      if (!source_proxy_->RequestHigherFramerateThan(fps))
 | 
| +
 | 
| +      const int requested_framerate =
 | 
| +          source_proxy_->RequestHigherFramerateThan(fps);
 | 
| +      if (requested_framerate == -1) {
 | 
| +        overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
 | 
|          return;
 | 
| +      }
 | 
| +      overuse_detector_->OnTargetFramerateUpdated(
 | 
| +          std::min(max_framerate_, requested_framerate));
 | 
|        GetAdaptCounter().DecrementFramerate(reason);
 | 
|        break;
 | 
|      }
 | 
| 
 |