aboutsummaryrefslogtreecommitdiff
path: root/webrtc/video_engine/overuse_frame_detector.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/video_engine/overuse_frame_detector.cc')
-rw-r--r--webrtc/video_engine/overuse_frame_detector.cc422
1 files changed, 0 insertions, 422 deletions
diff --git a/webrtc/video_engine/overuse_frame_detector.cc b/webrtc/video_engine/overuse_frame_detector.cc
deleted file mode 100644
index 47a6e496b9..0000000000
--- a/webrtc/video_engine/overuse_frame_detector.cc
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/video_engine/overuse_frame_detector.h"
-
-#include <assert.h>
-#include <math.h>
-
-#include <algorithm>
-#include <list>
-#include <map>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/exp_filter.h"
-#include "webrtc/base/logging.h"
-#include "webrtc/system_wrappers/include/clock.h"
-
-namespace webrtc {
-
-namespace {
-const int64_t kProcessIntervalMs = 5000;
-
-// Delay between consecutive rampups. (Used for quick recovery.)
-const int kQuickRampUpDelayMs = 10 * 1000;
-// Delay between rampup attempts. Initially uses standard, scales up to max.
-const int kStandardRampUpDelayMs = 40 * 1000;
-const int kMaxRampUpDelayMs = 240 * 1000;
-// Expontential back-off factor, to prevent annoying up-down behaviour.
-const double kRampUpBackoffFactor = 2.0;
-
-// Max number of overuses detected before always applying the rampup delay.
-const int kMaxOverusesBeforeApplyRampupDelay = 4;
-
-// The maximum exponent to use in VCMExpFilter.
-const float kSampleDiffMs = 33.0f;
-const float kMaxExp = 7.0f;
-
-} // namespace
-
-// Class for calculating the average encode time.
-class OveruseFrameDetector::EncodeTimeAvg {
- public:
- EncodeTimeAvg()
- : kWeightFactor(0.5f),
- kInitialAvgEncodeTimeMs(5.0f),
- filtered_encode_time_ms_(new rtc::ExpFilter(kWeightFactor)) {
- filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
- }
- ~EncodeTimeAvg() {}
-
- void AddSample(float encode_time_ms, int64_t diff_last_sample_ms) {
- float exp = diff_last_sample_ms / kSampleDiffMs;
- exp = std::min(exp, kMaxExp);
- filtered_encode_time_ms_->Apply(exp, encode_time_ms);
- }
-
- int Value() const {
- return static_cast<int>(filtered_encode_time_ms_->filtered() + 0.5);
- }
-
- private:
- const float kWeightFactor;
- const float kInitialAvgEncodeTimeMs;
- rtc::scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
-};
-
-// Class for calculating the processing usage on the send-side (the average
-// processing time of a frame divided by the average time difference between
-// captured frames).
-class OveruseFrameDetector::SendProcessingUsage {
- public:
- explicit SendProcessingUsage(const CpuOveruseOptions& options)
- : kWeightFactorFrameDiff(0.998f),
- kWeightFactorProcessing(0.995f),
- kInitialSampleDiffMs(40.0f),
- kMaxSampleDiffMs(45.0f),
- count_(0),
- options_(options),
- filtered_processing_ms_(new rtc::ExpFilter(kWeightFactorProcessing)),
- filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) {
- Reset();
- }
- ~SendProcessingUsage() {}
-
- void Reset() {
- count_ = 0;
- filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff);
- filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs);
- filtered_processing_ms_->Reset(kWeightFactorProcessing);
- filtered_processing_ms_->Apply(1.0f, InitialProcessingMs());
- }
-
- void AddCaptureSample(float sample_ms) {
- float exp = sample_ms / kSampleDiffMs;
- exp = std::min(exp, kMaxExp);
- filtered_frame_diff_ms_->Apply(exp, sample_ms);
- }
-
- void AddSample(float processing_ms, int64_t diff_last_sample_ms) {
- ++count_;
- float exp = diff_last_sample_ms / kSampleDiffMs;
- exp = std::min(exp, kMaxExp);
- filtered_processing_ms_->Apply(exp, processing_ms);
- }
-
- int Value() const {
- if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
- return static_cast<int>(InitialUsageInPercent() + 0.5f);
- }
- float frame_diff_ms = std::max(filtered_frame_diff_ms_->filtered(), 1.0f);
- frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
- float encode_usage_percent =
- 100.0f * filtered_processing_ms_->filtered() / frame_diff_ms;
- return static_cast<int>(encode_usage_percent + 0.5);
- }
-
- private:
- float InitialUsageInPercent() const {
- // Start in between the underuse and overuse threshold.
- return (options_.low_encode_usage_threshold_percent +
- options_.high_encode_usage_threshold_percent) / 2.0f;
- }
-
- float InitialProcessingMs() const {
- return InitialUsageInPercent() * kInitialSampleDiffMs / 100;
- }
-
- const float kWeightFactorFrameDiff;
- const float kWeightFactorProcessing;
- const float kInitialSampleDiffMs;
- const float kMaxSampleDiffMs;
- uint64_t count_;
- const CpuOveruseOptions options_;
- rtc::scoped_ptr<rtc::ExpFilter> filtered_processing_ms_;
- rtc::scoped_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
-};
-
-// Class for calculating the processing time of frames.
-class OveruseFrameDetector::FrameQueue {
- public:
- FrameQueue() : last_processing_time_ms_(-1) {}
- ~FrameQueue() {}
-
- // Called when a frame is captured.
- // Starts the measuring of the processing time of the frame.
- void Start(int64_t capture_time, int64_t now) {
- const size_t kMaxSize = 90; // Allows for processing time of 1.5s at 60fps.
- if (frame_times_.size() > kMaxSize) {
- LOG(LS_WARNING) << "Max size reached, removed oldest frame.";
- frame_times_.erase(frame_times_.begin());
- }
- if (frame_times_.find(capture_time) != frame_times_.end()) {
- // Frame should not exist.
- assert(false);
- return;
- }
- frame_times_[capture_time] = now;
- }
-
- // Called when the processing of a frame has finished.
- // Returns the processing time of the frame.
- int End(int64_t capture_time, int64_t now) {
- std::map<int64_t, int64_t>::iterator it = frame_times_.find(capture_time);
- if (it == frame_times_.end()) {
- return -1;
- }
- // Remove any old frames up to current.
- // Old frames have been skipped by the capture process thread.
- // TODO(asapersson): Consider measuring time from first frame in list.
- last_processing_time_ms_ = now - (*it).second;
- frame_times_.erase(frame_times_.begin(), ++it);
- return last_processing_time_ms_;
- }
-
- void Reset() { frame_times_.clear(); }
- int NumFrames() const { return static_cast<int>(frame_times_.size()); }
- int last_processing_time_ms() const { return last_processing_time_ms_; }
-
- private:
- // Captured frames mapped by the capture time.
- std::map<int64_t, int64_t> frame_times_;
- int last_processing_time_ms_;
-};
-
-
-OveruseFrameDetector::OveruseFrameDetector(
- Clock* clock,
- const CpuOveruseOptions& options,
- CpuOveruseObserver* observer,
- CpuOveruseMetricsObserver* metrics_observer)
- : options_(options),
- observer_(observer),
- metrics_observer_(metrics_observer),
- clock_(clock),
- num_process_times_(0),
- last_capture_time_(0),
- num_pixels_(0),
- next_process_time_(clock_->TimeInMilliseconds()),
- last_overuse_time_(0),
- checks_above_threshold_(0),
- num_overuse_detections_(0),
- last_rampup_time_(0),
- in_quick_rampup_(false),
- current_rampup_delay_ms_(kStandardRampUpDelayMs),
- last_encode_sample_ms_(0),
- last_sample_time_ms_(0),
- encode_time_(new EncodeTimeAvg()),
- usage_(new SendProcessingUsage(options)),
- frame_queue_(new FrameQueue()) {
- RTC_DCHECK(metrics_observer != nullptr);
- // Make sure stats are initially up-to-date. This simplifies unit testing
- // since we don't have to trigger an update using one of the methods which
- // would also alter the overuse state.
- UpdateCpuOveruseMetrics();
- processing_thread_.DetachFromThread();
-}
-
-OveruseFrameDetector::~OveruseFrameDetector() {
-}
-
-int OveruseFrameDetector::LastProcessingTimeMs() const {
- rtc::CritScope cs(&crit_);
- return frame_queue_->last_processing_time_ms();
-}
-
-int OveruseFrameDetector::FramesInQueue() const {
- rtc::CritScope cs(&crit_);
- return frame_queue_->NumFrames();
-}
-
-void OveruseFrameDetector::UpdateCpuOveruseMetrics() {
- metrics_.avg_encode_time_ms = encode_time_->Value();
- metrics_.encode_usage_percent = usage_->Value();
-
- metrics_observer_->CpuOveruseMetricsUpdated(metrics_);
-}
-
-int64_t OveruseFrameDetector::TimeUntilNextProcess() {
- RTC_DCHECK(processing_thread_.CalledOnValidThread());
- return next_process_time_ - clock_->TimeInMilliseconds();
-}
-
-bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const {
- if (num_pixels != num_pixels_) {
- return true;
- }
- return false;
-}
-
-bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const {
- if (last_capture_time_ == 0) {
- return false;
- }
- return (now - last_capture_time_) > options_.frame_timeout_interval_ms;
-}
-
-void OveruseFrameDetector::ResetAll(int num_pixels) {
- num_pixels_ = num_pixels;
- usage_->Reset();
- frame_queue_->Reset();
- last_capture_time_ = 0;
- num_process_times_ = 0;
- UpdateCpuOveruseMetrics();
-}
-
-void OveruseFrameDetector::FrameCaptured(int width,
- int height,
- int64_t capture_time_ms) {
- rtc::CritScope cs(&crit_);
-
- int64_t now = clock_->TimeInMilliseconds();
- if (FrameSizeChanged(width * height) || FrameTimeoutDetected(now)) {
- ResetAll(width * height);
- }
-
- if (last_capture_time_ != 0)
- usage_->AddCaptureSample(now - last_capture_time_);
-
- last_capture_time_ = now;
-
- if (options_.enable_extended_processing_usage) {
- frame_queue_->Start(capture_time_ms, now);
- }
-}
-
-void OveruseFrameDetector::FrameEncoded(int encode_time_ms) {
- rtc::CritScope cs(&crit_);
- int64_t now = clock_->TimeInMilliseconds();
- if (last_encode_sample_ms_ != 0) {
- int64_t diff_ms = now - last_encode_sample_ms_;
- encode_time_->AddSample(encode_time_ms, diff_ms);
- }
- last_encode_sample_ms_ = now;
-
- if (!options_.enable_extended_processing_usage) {
- AddProcessingTime(encode_time_ms);
- }
- UpdateCpuOveruseMetrics();
-}
-
-void OveruseFrameDetector::FrameSent(int64_t capture_time_ms) {
- rtc::CritScope cs(&crit_);
- if (!options_.enable_extended_processing_usage) {
- return;
- }
- int delay_ms = frame_queue_->End(capture_time_ms,
- clock_->TimeInMilliseconds());
- if (delay_ms > 0) {
- AddProcessingTime(delay_ms);
- }
- UpdateCpuOveruseMetrics();
-}
-
-void OveruseFrameDetector::AddProcessingTime(int elapsed_ms) {
- int64_t now = clock_->TimeInMilliseconds();
- if (last_sample_time_ms_ != 0) {
- int64_t diff_ms = now - last_sample_time_ms_;
- usage_->AddSample(elapsed_ms, diff_ms);
- }
- last_sample_time_ms_ = now;
-}
-
-int32_t OveruseFrameDetector::Process() {
- RTC_DCHECK(processing_thread_.CalledOnValidThread());
-
- int64_t now = clock_->TimeInMilliseconds();
-
- // Used to protect against Process() being called too often.
- if (now < next_process_time_)
- return 0;
-
- next_process_time_ = now + kProcessIntervalMs;
-
- CpuOveruseMetrics current_metrics;
- {
- rtc::CritScope cs(&crit_);
- ++num_process_times_;
-
- current_metrics = metrics_;
- if (num_process_times_ <= options_.min_process_count)
- return 0;
- }
-
- if (IsOverusing(current_metrics)) {
- // If the last thing we did was going up, and now have to back down, we need
- // to check if this peak was short. If so we should back off to avoid going
- // back and forth between this load, the system doesn't seem to handle it.
- bool check_for_backoff = last_rampup_time_ > last_overuse_time_;
- if (check_for_backoff) {
- if (now - last_rampup_time_ < kStandardRampUpDelayMs ||
- num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) {
- // Going up was not ok for very long, back off.
- current_rampup_delay_ms_ *= kRampUpBackoffFactor;
- if (current_rampup_delay_ms_ > kMaxRampUpDelayMs)
- current_rampup_delay_ms_ = kMaxRampUpDelayMs;
- } else {
- // Not currently backing off, reset rampup delay.
- current_rampup_delay_ms_ = kStandardRampUpDelayMs;
- }
- }
-
- last_overuse_time_ = now;
- in_quick_rampup_ = false;
- checks_above_threshold_ = 0;
- ++num_overuse_detections_;
-
- if (observer_ != NULL)
- observer_->OveruseDetected();
- } else if (IsUnderusing(current_metrics, now)) {
- last_rampup_time_ = now;
- in_quick_rampup_ = true;
-
- if (observer_ != NULL)
- observer_->NormalUsage();
- }
-
- int rampup_delay =
- in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
-
- LOG(LS_VERBOSE) << " Frame stats: "
- << " encode usage " << current_metrics.encode_usage_percent
- << " overuse detections " << num_overuse_detections_
- << " rampup delay " << rampup_delay;
-
- return 0;
-}
-
-bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
- bool overusing = false;
- if (options_.enable_encode_usage_method) {
- overusing = metrics.encode_usage_percent >=
- options_.high_encode_usage_threshold_percent;
- }
- if (overusing) {
- ++checks_above_threshold_;
- } else {
- checks_above_threshold_ = 0;
- }
- return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
-}
-
-bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics,
- int64_t time_now) {
- int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
- if (time_now < last_rampup_time_ + delay)
- return false;
-
- bool underusing = false;
- if (options_.enable_encode_usage_method) {
- underusing = metrics.encode_usage_percent <
- options_.low_encode_usage_threshold_percent;
- }
- return underusing;
-}
-} // namespace webrtc