1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_VIDEO_OVERUSE_FRAME_DETECTOR_H_ 12 #define WEBRTC_VIDEO_OVERUSE_FRAME_DETECTOR_H_ 13 14 #include "webrtc/base/constructormagic.h" 15 #include "webrtc/base/criticalsection.h" 16 #include "webrtc/base/scoped_ptr.h" 17 #include "webrtc/base/exp_filter.h" 18 #include "webrtc/base/thread_annotations.h" 19 #include "webrtc/base/thread_checker.h" 20 #include "webrtc/modules/include/module.h" 21 22 namespace webrtc { 23 24 class Clock; 25 26 // CpuOveruseObserver is called when a system overuse is detected and 27 // VideoEngine cannot keep up the encoding frequency. 28 class CpuOveruseObserver { 29 public: 30 // Called as soon as an overuse is detected. 31 virtual void OveruseDetected() = 0; 32 // Called periodically when the system is not overused any longer. 33 virtual void NormalUsage() = 0; 34 35 protected: 36 virtual ~CpuOveruseObserver() {} 37 }; 38 39 struct CpuOveruseOptions { 40 CpuOveruseOptions() 41 : low_encode_usage_threshold_percent(55), 42 high_encode_usage_threshold_percent(85), 43 frame_timeout_interval_ms(1500), 44 min_frame_samples(120), 45 min_process_count(3), 46 high_threshold_consecutive_count(2) {} 47 48 int low_encode_usage_threshold_percent; // Threshold for triggering underuse. 49 int high_encode_usage_threshold_percent; // Threshold for triggering overuse. 50 // General settings. 51 int frame_timeout_interval_ms; // The maximum allowed interval between two 52 // frames before resetting estimations. 53 int min_frame_samples; // The minimum number of frames required. 54 int min_process_count; // The number of initial process times required before 55 // triggering an overuse/underuse. 56 int high_threshold_consecutive_count; // The number of consecutive checks 57 // above the high threshold before 58 // triggering an overuse. 59 }; 60 61 struct CpuOveruseMetrics { 62 CpuOveruseMetrics() : encode_usage_percent(-1) {} 63 64 int encode_usage_percent; // Average encode time divided by the average time 65 // difference between incoming captured frames. 66 }; 67 68 class CpuOveruseMetricsObserver { 69 public: 70 virtual ~CpuOveruseMetricsObserver() {} 71 virtual void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) = 0; 72 }; 73 74 75 // Use to detect system overuse based on the send-side processing time of 76 // incoming frames. 77 class OveruseFrameDetector : public Module { 78 public: 79 OveruseFrameDetector(Clock* clock, 80 const CpuOveruseOptions& options, 81 CpuOveruseObserver* overuse_observer, 82 CpuOveruseMetricsObserver* metrics_observer); 83 ~OveruseFrameDetector(); 84 85 // Called for each captured frame. 86 void FrameCaptured(int width, int height, int64_t capture_time_ms); 87 88 // Called for each sent frame. 89 void FrameSent(int64_t capture_time_ms); 90 91 // Only public for testing. 92 int LastProcessingTimeMs() const; 93 int FramesInQueue() const; 94 95 // Implements Module. 96 int64_t TimeUntilNextProcess() override; 97 int32_t Process() override; 98 99 private: 100 class SendProcessingUsage; 101 class FrameQueue; 102 103 void UpdateCpuOveruseMetrics() EXCLUSIVE_LOCKS_REQUIRED(crit_); 104 105 // TODO(asapersson): This method is only used on one thread, so it shouldn't 106 // need a guard. 107 void AddProcessingTime(int elapsed_ms) EXCLUSIVE_LOCKS_REQUIRED(crit_); 108 109 // Only called on the processing thread. 110 bool IsOverusing(const CpuOveruseMetrics& metrics); 111 bool IsUnderusing(const CpuOveruseMetrics& metrics, int64_t time_now); 112 113 bool FrameTimeoutDetected(int64_t now) const EXCLUSIVE_LOCKS_REQUIRED(crit_); 114 bool FrameSizeChanged(int num_pixels) const EXCLUSIVE_LOCKS_REQUIRED(crit_); 115 116 void ResetAll(int num_pixels) EXCLUSIVE_LOCKS_REQUIRED(crit_); 117 118 // Protecting all members except const and those that are only accessed on the 119 // processing thread. 120 // TODO(asapersson): See if we can reduce locking. As is, video frame 121 // processing contends with reading stats and the processing thread. 122 mutable rtc::CriticalSection crit_; 123 124 const CpuOveruseOptions options_; 125 126 // Observer getting overuse reports. 127 CpuOveruseObserver* const observer_; 128 129 // Stats metrics. 130 CpuOveruseMetricsObserver* const metrics_observer_; 131 CpuOveruseMetrics metrics_ GUARDED_BY(crit_); 132 133 Clock* const clock_; 134 int64_t num_process_times_ GUARDED_BY(crit_); 135 136 int64_t last_capture_time_ GUARDED_BY(crit_); 137 138 // Number of pixels of last captured frame. 139 int num_pixels_ GUARDED_BY(crit_); 140 141 // These seven members are only accessed on the processing thread. 142 int64_t next_process_time_; 143 int64_t last_overuse_time_; 144 int checks_above_threshold_; 145 int num_overuse_detections_; 146 int64_t last_rampup_time_; 147 bool in_quick_rampup_; 148 int current_rampup_delay_ms_; 149 150 int64_t last_sample_time_ms_; // Only accessed by one thread. 151 152 // TODO(asapersson): Can these be regular members (avoid separate heap 153 // allocs)? 154 const rtc::scoped_ptr<SendProcessingUsage> usage_ GUARDED_BY(crit_); 155 const rtc::scoped_ptr<FrameQueue> frame_queue_ GUARDED_BY(crit_); 156 157 rtc::ThreadChecker processing_thread_; 158 159 RTC_DISALLOW_COPY_AND_ASSIGN(OveruseFrameDetector); 160 }; 161 162 } // namespace webrtc 163 164 #endif // WEBRTC_VIDEO_OVERUSE_FRAME_DETECTOR_H_ 165