| Index: webrtc/video/vie_encoder.cc
 | 
| diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc
 | 
| index 2287a7e3bb911b74d1889a3113b5c193a03d79b7..524c3482442c5d1370b8ba672d246e130ef14268 100644
 | 
| --- a/webrtc/video/vie_encoder.cc
 | 
| +++ b/webrtc/video/vie_encoder.cc
 | 
| @@ -72,6 +72,22 @@ uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) {
 | 
|    return std::numeric_limits<uint32_t>::max();
 | 
|  }
 | 
|  
 | 
| +bool IsResolutionScalingEnabled(
 | 
| +    VideoSendStream::DegradationPreference degradation_preference) {
 | 
| +  return degradation_preference ==
 | 
| +             VideoSendStream::DegradationPreference::kMaintainFramerate ||
 | 
| +         degradation_preference ==
 | 
| +             VideoSendStream::DegradationPreference::kBalanced;
 | 
| +}
 | 
| +
 | 
| +bool IsFramerateScalingEnabled(
 | 
| +    VideoSendStream::DegradationPreference degradation_preference) {
 | 
| +  return degradation_preference ==
 | 
| +             VideoSendStream::DegradationPreference::kMaintainResolution ||
 | 
| +         degradation_preference ==
 | 
| +             VideoSendStream::DegradationPreference::kBalanced;
 | 
| +}
 | 
| +
 | 
|  }  //  namespace
 | 
|  
 | 
|  class ViEEncoder::ConfigureEncoderTask : public rtc::QueuedTask {
 | 
| @@ -419,8 +435,7 @@ void ViEEncoder::SetBitrateObserver(
 | 
|  
 | 
|  void ViEEncoder::SetSource(
 | 
|      rtc::VideoSourceInterface<VideoFrame>* source,
 | 
| -    const VideoSendStream::VideoSendStream::DegradationPreference&
 | 
| -        degradation_preference) {
 | 
| +    const VideoSendStream::DegradationPreference& degradation_preference) {
 | 
|    RTC_DCHECK_RUN_ON(&thread_checker_);
 | 
|    source_proxy_->SetSource(source, degradation_preference);
 | 
|    encoder_queue_.PostTask([this, degradation_preference] {
 | 
| @@ -546,27 +561,24 @@ void ViEEncoder::ConfigureQualityScaler() {
 | 
|    const bool quality_scaling_allowed =
 | 
|        degradation_preference_allows_scaling && scaling_settings.enabled;
 | 
|  
 | 
| -  const std::vector<int>& scale_counters = GetScaleCounters();
 | 
| -  stats_proxy_->SetCpuScalingStats(
 | 
| -      degradation_preference_allows_scaling ? scale_counters[kCpu] : -1);
 | 
| -  stats_proxy_->SetQualityScalingStats(
 | 
| -      quality_scaling_allowed ? scale_counters[kQuality] : -1);
 | 
| -
 | 
|    if (quality_scaling_allowed) {
 | 
| -    // Abort if quality scaler has already been configured.
 | 
| -    if (quality_scaler_.get() != nullptr)
 | 
| -      return;
 | 
| -    // Drop frames and scale down until desired quality is achieved.
 | 
| -    if (scaling_settings.thresholds) {
 | 
| -      quality_scaler_.reset(
 | 
| -          new QualityScaler(this, *(scaling_settings.thresholds)));
 | 
| -    } else {
 | 
| -      quality_scaler_.reset(new QualityScaler(this, codec_type_));
 | 
| +    if (quality_scaler_.get() == nullptr) {
 | 
| +      // Quality scaler has not already been configured.
 | 
| +      // Drop frames and scale down until desired quality is achieved.
 | 
| +      if (scaling_settings.thresholds) {
 | 
| +        quality_scaler_.reset(
 | 
| +            new QualityScaler(this, *(scaling_settings.thresholds)));
 | 
| +      } else {
 | 
| +        quality_scaler_.reset(new QualityScaler(this, codec_type_));
 | 
| +      }
 | 
|      }
 | 
|    } else {
 | 
|      quality_scaler_.reset(nullptr);
 | 
|      initial_rampup_ = kMaxInitialFramedrop;
 | 
|    }
 | 
| +
 | 
| +  stats_proxy_->SetAdaptationStats(GetActiveCounts(kCpu),
 | 
| +                                   GetActiveCounts(kQuality));
 | 
|  }
 | 
|  
 | 
|  void ViEEncoder::OnFrame(const VideoFrame& video_frame) {
 | 
| @@ -799,6 +811,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
 | 
|        last_frame_info_->pixel_count(),
 | 
|        stats_proxy_->GetStats().input_frame_rate,
 | 
|        AdaptationRequest::Mode::kAdaptDown};
 | 
| +
 | 
|    bool downgrade_requested =
 | 
|        last_adaptation_request_ &&
 | 
|        last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
 | 
| @@ -836,8 +849,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
 | 
|    }
 | 
|  
 | 
|    if (reason == kCpu) {
 | 
| -    const int cpu_scale_counter = GetScaleCounters()[reason];
 | 
| -    if (cpu_scale_counter >= max_downgrades)
 | 
| +    if (GetConstAdaptCounter().TotalCount(kCpu) >= max_downgrades)
 | 
|        return;
 | 
|    }
 | 
|  
 | 
| @@ -850,11 +862,13 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
 | 
|          return;
 | 
|        }
 | 
|        LOG(LS_INFO) << "Scaling down resolution.";
 | 
| +      GetAdaptCounter().IncrementResolution(reason, 1);
 | 
|        break;
 | 
|      case VideoSendStream::DegradationPreference::kMaintainResolution:
 | 
|        source_proxy_->RequestFramerateLowerThan(
 | 
|            adaptation_request.framerate_fps_);
 | 
|        LOG(LS_INFO) << "Scaling down framerate.";
 | 
| +      GetAdaptCounter().IncrementFramerate(reason, 1);
 | 
|        break;
 | 
|      case VideoSendStream::DegradationPreference::kDegradationDisabled:
 | 
|        RTC_NOTREACHED();
 | 
| @@ -862,32 +876,20 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
 | 
|  
 | 
|    last_adaptation_request_.emplace(adaptation_request);
 | 
|  
 | 
| -  IncrementScaleCounter(reason, 1);
 | 
| -
 | 
| -  // Update stats.
 | 
| -  const std::vector<int>& scale_counters = GetScaleCounters();
 | 
| -  switch (reason) {
 | 
| -    case kQuality:
 | 
| -      stats_proxy_->OnQualityRestrictedResolutionChanged(
 | 
| -          scale_counters[reason]);
 | 
| -      break;
 | 
| -    case kCpu:
 | 
| -      stats_proxy_->OnCpuRestrictedResolutionChanged(true);
 | 
| -      break;
 | 
| -  }
 | 
| +  UpdateAdaptationStats(reason);
 | 
|  
 | 
| -  for (size_t i = 0; i < kScaleReasonSize; ++i) {
 | 
| -    LOG(LS_INFO) << "Scaled " << scale_counters[i]
 | 
| -                 << " times for reason: " << (i ? "cpu" : "quality");
 | 
| -  }
 | 
| +  LOG(LS_INFO) << GetConstAdaptCounter().ToString();
 | 
|  }
 | 
|  
 | 
|  void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|    RTC_DCHECK_RUN_ON(&encoder_queue_);
 | 
| -  int scale_counter = GetScaleCounters()[reason];
 | 
| -  if (scale_counter == 0)
 | 
| +
 | 
| +  const AdaptCounter& adapt_counter = GetConstAdaptCounter();
 | 
| +  int num_downgrades = adapt_counter.TotalCount(reason);
 | 
| +  if (num_downgrades == 0)
 | 
|      return;
 | 
| -  RTC_DCHECK_GT(scale_counter, 0);
 | 
| +  RTC_DCHECK_GT(num_downgrades, 0);
 | 
| +
 | 
|    AdaptationRequest adaptation_request = {
 | 
|        last_frame_info_->pixel_count(),
 | 
|        stats_proxy_->GetStats().input_frame_rate,
 | 
| @@ -896,6 +898,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|    bool adapt_up_requested =
 | 
|        last_adaptation_request_ &&
 | 
|        last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp;
 | 
| +
 | 
|    switch (degradation_preference_) {
 | 
|      case VideoSendStream::DegradationPreference::kBalanced:
 | 
|        FALLTHROUGH();
 | 
| @@ -916,20 +919,11 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|        return;
 | 
|    }
 | 
|  
 | 
| -  // Decrease counter of how many times we have scaled down, for this
 | 
| -  // degradation preference mode and reason.
 | 
| -  IncrementScaleCounter(reason, -1);
 | 
| -
 | 
| -  // Get a sum of how many times have scaled down, in total, for this
 | 
| -  // degradation preference mode. If it is 0, remove any restraints.
 | 
| -  const std::vector<int>& scale_counters = GetScaleCounters();
 | 
| -  const int scale_sum =
 | 
| -      std::accumulate(scale_counters.begin(), scale_counters.end(), 0);
 | 
|    switch (degradation_preference_) {
 | 
|      case VideoSendStream::DegradationPreference::kBalanced:
 | 
|        FALLTHROUGH();
 | 
|      case VideoSendStream::DegradationPreference::kMaintainFramerate:
 | 
| -      if (scale_sum == 0) {
 | 
| +      if (adapt_counter.TotalCount() == 1) {
 | 
|          LOG(LS_INFO) << "Removing resolution down-scaling setting.";
 | 
|          source_proxy_->RequestHigherResolutionThan(
 | 
|              std::numeric_limits<int>::max());
 | 
| @@ -938,9 +932,10 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|              adaptation_request.input_pixel_count_);
 | 
|          LOG(LS_INFO) << "Scaling up resolution.";
 | 
|        }
 | 
| +      GetAdaptCounter().IncrementResolution(reason, -1);
 | 
|        break;
 | 
|      case VideoSendStream::DegradationPreference::kMaintainResolution:
 | 
| -      if (scale_sum == 0) {
 | 
| +      if (adapt_counter.TotalCount() == 1) {
 | 
|          LOG(LS_INFO) << "Removing framerate down-scaling setting.";
 | 
|          source_proxy_->RequestHigherFramerateThan(
 | 
|              std::numeric_limits<int>::max());
 | 
| @@ -949,6 +944,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|              adaptation_request.framerate_fps_);
 | 
|          LOG(LS_INFO) << "Scaling up framerate.";
 | 
|        }
 | 
| +      GetAdaptCounter().IncrementFramerate(reason, -1);
 | 
|        break;
 | 
|      case VideoSendStream::DegradationPreference::kDegradationDisabled:
 | 
|        RTC_NOTREACHED();
 | 
| @@ -956,40 +952,120 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
 | 
|  
 | 
|    last_adaptation_request_.emplace(adaptation_request);
 | 
|  
 | 
| -  // Update stats.
 | 
| +  UpdateAdaptationStats(reason);
 | 
| +
 | 
| +  LOG(LS_INFO) << adapt_counter.ToString();
 | 
| +}
 | 
| +
 | 
| +void ViEEncoder::UpdateAdaptationStats(AdaptReason reason) {
 | 
|    switch (reason) {
 | 
| +    case kCpu:
 | 
| +      stats_proxy_->OnCpuAdaptationChanged(GetActiveCounts(kCpu),
 | 
| +                                           GetActiveCounts(kQuality));
 | 
| +      break;
 | 
|      case kQuality:
 | 
| -      stats_proxy_->OnQualityRestrictedResolutionChanged(
 | 
| -          scale_counters[reason]);
 | 
| +      stats_proxy_->OnQualityAdaptationChanged(GetActiveCounts(kCpu),
 | 
| +                                               GetActiveCounts(kQuality));
 | 
|        break;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +ViEEncoder::AdaptCounts ViEEncoder::GetActiveCounts(AdaptReason reason) {
 | 
| +  ViEEncoder::AdaptCounts counts = GetConstAdaptCounter().Counts(reason);
 | 
| +  switch (reason) {
 | 
|      case kCpu:
 | 
| -      stats_proxy_->OnCpuRestrictedResolutionChanged(scale_counters[reason] >
 | 
| -                                                     0);
 | 
| +      if (!IsFramerateScalingEnabled(degradation_preference_))
 | 
| +        counts.fps = -1;
 | 
| +      if (!IsResolutionScalingEnabled(degradation_preference_))
 | 
| +        counts.resolution = -1;
 | 
| +      break;
 | 
| +    case kQuality:
 | 
| +      if (!IsFramerateScalingEnabled(degradation_preference_) ||
 | 
| +          !quality_scaler_) {
 | 
| +        counts.fps = -1;
 | 
| +      }
 | 
| +      if (!IsResolutionScalingEnabled(degradation_preference_) ||
 | 
| +          !quality_scaler_) {
 | 
| +        counts.resolution = -1;
 | 
| +      }
 | 
|        break;
 | 
|    }
 | 
| +  return counts;
 | 
| +}
 | 
|  
 | 
| -  for (size_t i = 0; i < kScaleReasonSize; ++i) {
 | 
| -    LOG(LS_INFO) << "Scaled " << scale_counters[i]
 | 
| -                 << " times for reason: " << (i ? "cpu" : "quality");
 | 
| -  }
 | 
| +ViEEncoder::AdaptCounter& ViEEncoder::GetAdaptCounter() {
 | 
| +  return adapt_counters_[degradation_preference_];
 | 
|  }
 | 
|  
 | 
| -const std::vector<int>& ViEEncoder::GetScaleCounters() {
 | 
| -  auto it = scale_counters_.find(degradation_preference_);
 | 
| -  if (it == scale_counters_.end()) {
 | 
| -    scale_counters_[degradation_preference_].resize(kScaleReasonSize);
 | 
| -    return scale_counters_[degradation_preference_];
 | 
| -  }
 | 
| -  return it->second;
 | 
| +const ViEEncoder::AdaptCounter& ViEEncoder::GetConstAdaptCounter() {
 | 
| +  return adapt_counters_[degradation_preference_];
 | 
| +}
 | 
| +
 | 
| +// Class holding adaptation information.
 | 
| +ViEEncoder::AdaptCounter::AdaptCounter() {
 | 
| +  fps_counters_.resize(kScaleReasonSize);
 | 
| +  resolution_counters_.resize(kScaleReasonSize);
 | 
| +}
 | 
| +
 | 
| +ViEEncoder::AdaptCounter::~AdaptCounter() {}
 | 
| +
 | 
| +std::string ViEEncoder::AdaptCounter::ToString() const {
 | 
| +  std::stringstream ss;
 | 
| +  ss << "Downgrade counts: fps: {" << ToString(fps_counters_);
 | 
| +  ss << "}, resolution: {" << ToString(resolution_counters_) << "}";
 | 
| +  return ss.str();
 | 
| +}
 | 
| +
 | 
| +ViEEncoder::AdaptCounts ViEEncoder::AdaptCounter::Counts(int reason) const {
 | 
| +  AdaptCounts counts;
 | 
| +  counts.fps = fps_counters_[reason];
 | 
| +  counts.resolution = resolution_counters_[reason];
 | 
| +  return counts;
 | 
| +}
 | 
| +
 | 
| +void ViEEncoder::AdaptCounter::IncrementFramerate(int reason, int delta) {
 | 
| +  fps_counters_[reason] += delta;
 | 
| +}
 | 
| +
 | 
| +void ViEEncoder::AdaptCounter::IncrementResolution(int reason, int delta) {
 | 
| +  resolution_counters_[reason] += delta;
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::FramerateCount() const {
 | 
| +  return Count(fps_counters_);
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::ResolutionCount() const {
 | 
| +  return Count(resolution_counters_);
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::TotalCount() const {
 | 
| +  return FramerateCount() + ResolutionCount();
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::FramerateCount(int reason) const {
 | 
| +  return fps_counters_[reason];
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::ResolutionCount(int reason) const {
 | 
| +  return resolution_counters_[reason];
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::TotalCount(int reason) const {
 | 
| +  return FramerateCount(reason) + ResolutionCount(reason);
 | 
| +}
 | 
| +
 | 
| +int ViEEncoder::AdaptCounter::Count(const std::vector<int>& counters) const {
 | 
| +  return std::accumulate(counters.begin(), counters.end(), 0);
 | 
|  }
 | 
|  
 | 
| -void ViEEncoder::IncrementScaleCounter(int reason, int delta) {
 | 
| -  // Get the counters and validate. This may also lazily initialize the state.
 | 
| -  const std::vector<int>& counter = GetScaleCounters();
 | 
| -  if (delta < 0) {
 | 
| -    RTC_DCHECK_GE(counter[reason], delta);
 | 
| +std::string ViEEncoder::AdaptCounter::ToString(
 | 
| +    const std::vector<int>& counters) const {
 | 
| +  std::stringstream ss;
 | 
| +  for (size_t reason = 0; reason < kScaleReasonSize; ++reason) {
 | 
| +    ss << (reason ? " cpu" : "quality") << ":" << counters[reason];
 | 
|    }
 | 
| -  scale_counters_[degradation_preference_][reason] += delta;
 | 
| +  return ss.str();
 | 
|  }
 | 
|  
 | 
|  }  // namespace webrtc
 | 
| 
 |