From 8a8c3ef2aec8fa18ba83937580112d456c2a966a Mon Sep 17 00:00:00 2001 From: "asapersson@webrtc.org" Date: Thu, 20 Mar 2014 13:15:01 +0000 Subject: [PATCH] Add ability to configure cpu overuse options via an API. BUG=1577 R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/9299006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5736 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/video_engine/include/vie_base.h | 60 ++++++ webrtc/video_engine/overuse_frame_detector.cc | 107 +++++----- webrtc/video_engine/overuse_frame_detector.h | 61 ++---- .../overuse_frame_detector_unittest.cc | 197 +++++++++++++----- webrtc/video_engine/vie_base_impl.cc | 29 +++ webrtc/video_engine/vie_base_impl.h | 2 + webrtc/video_engine/vie_capturer.cc | 11 +- webrtc/video_engine/vie_capturer.h | 2 + 8 files changed, 315 insertions(+), 154 deletions(-) diff --git a/webrtc/video_engine/include/vie_base.h b/webrtc/video_engine/include/vie_base.h index cd5f3856e1..64c53ec908 100644 --- a/webrtc/video_engine/include/vie_base.h +++ b/webrtc/video_engine/include/vie_base.h @@ -43,6 +43,59 @@ class CpuOveruseObserver { virtual ~CpuOveruseObserver() {} }; +// Limits on standard deviation for under/overuse. +#ifdef WEBRTC_ANDROID +const float kOveruseStdDevMs = 32.0f; +const float kNormalUseStdDevMs = 27.0f; +#elif WEBRTC_LINUX +const float kOveruseStdDevMs = 20.0f; +const float kNormalUseStdDevMs = 14.0f; +#elif WEBRTC_MAC +const float kOveruseStdDevMs = 27.0f; +const float kNormalUseStdDevMs = 21.0f; +#elif WEBRTC_WIN +const float kOveruseStdDevMs = 20.0f; +const float kNormalUseStdDevMs = 14.0f; +#else +const float kOveruseStdDevMs = 30.0f; +const float kNormalUseStdDevMs = 20.0f; +#endif + +struct CpuOveruseOptions { + CpuOveruseOptions() + : enable_capture_jitter_method(true), + low_capture_jitter_threshold_ms(kNormalUseStdDevMs), + high_capture_jitter_threshold_ms(kOveruseStdDevMs), + frame_timeout_interval_ms(1500), + min_frame_samples(120), + min_process_count(3), + high_threshold_consecutive_count(2) {} + + // Method based on inter-arrival jitter of captured frames. + bool enable_capture_jitter_method; + float low_capture_jitter_threshold_ms; // Threshold for triggering underuse. + float high_capture_jitter_threshold_ms; // Threshold for triggering overuse. + // General settings. + int frame_timeout_interval_ms; // The maximum allowed interval between two + // frames before resetting estimations. + int min_frame_samples; // The minimum number of frames required. + int min_process_count; // The number of initial process times required before + // triggering an overuse/underuse. + int high_threshold_consecutive_count; // The number of consecutive checks + // above the high threshold before + // triggering an overuse. + + bool Equals(const CpuOveruseOptions& o) const { + return enable_capture_jitter_method == o.enable_capture_jitter_method && + low_capture_jitter_threshold_ms == o.low_capture_jitter_threshold_ms && + high_capture_jitter_threshold_ms == + o.high_capture_jitter_threshold_ms && + frame_timeout_interval_ms == o.frame_timeout_interval_ms && + min_frame_samples == o.min_frame_samples && + min_process_count == o.min_process_count && + high_threshold_consecutive_count == o.high_threshold_consecutive_count; + } +}; class WEBRTC_DLLEXPORT VideoEngine { public: @@ -120,6 +173,13 @@ class WEBRTC_DLLEXPORT ViEBase { virtual int RegisterCpuOveruseObserver(int channel, CpuOveruseObserver* observer) = 0; + // Sets options for cpu overuse detector. + // TODO(asapersson): Remove default implementation. + virtual int SetCpuOveruseOptions(int channel, + const CpuOveruseOptions& options) { + return -1; + } + // Gets cpu overuse measures. // capture_jitter_ms: The current estimated jitter in ms based on incoming // captured frames. diff --git a/webrtc/video_engine/overuse_frame_detector.cc b/webrtc/video_engine/overuse_frame_detector.cc index 21aa7690b1..bc283e27c2 100644 --- a/webrtc/video_engine/overuse_frame_detector.cc +++ b/webrtc/video_engine/overuse_frame_detector.cc @@ -20,7 +20,6 @@ #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/trace.h" -#include "webrtc/video_engine/include/vie_base.h" namespace webrtc { @@ -29,20 +28,8 @@ namespace webrtc { namespace { const int64_t kProcessIntervalMs = 5000; -// Number of initial process times before reporting. -const int64_t kMinProcessCountBeforeReporting = 3; - -const int64_t kFrameTimeoutIntervalMs = 1500; - -// Consecutive checks above threshold to trigger overuse. -const int kConsecutiveChecksAboveThreshold = 2; - -// Minimum samples required to perform a check. -const size_t kMinFrameSampleCount = 120; - // Weight factor to apply to the standard deviation. const float kWeightFactor = 0.997f; - // Weight factor to apply to the average. const float kWeightFactorMean = 0.98f; @@ -68,23 +55,28 @@ Statistics::Statistics() : count_(0), filtered_samples_(new VCMExpFilter(kWeightFactorMean)), filtered_variance_(new VCMExpFilter(kWeightFactor)) { + Reset(); +} + +void Statistics::SetOptions(const CpuOveruseOptions& options) { + options_ = options; } void Statistics::Reset() { sum_ = 0.0; count_ = 0; + filtered_variance_->Reset(kWeightFactor); + filtered_variance_->Apply(1.0f, InitialVariance()); } void Statistics::AddSample(float sample_ms) { sum_ += sample_ms; ++count_; - if (count_ < kMinFrameSampleCount) { + if (count_ < static_cast(options_.min_frame_samples)) { // Initialize filtered samples. filtered_samples_->Reset(kWeightFactorMean); filtered_samples_->Apply(1.0f, InitialMean()); - filtered_variance_->Reset(kWeightFactor); - filtered_variance_->Apply(1.0f, InitialVariance()); return; } @@ -103,7 +95,8 @@ float Statistics::InitialMean() const { float Statistics::InitialVariance() const { // Start in between the underuse and overuse threshold. - float average_stddev = (kNormalUseStdDevMs + kOveruseStdDevMs)/2.0f; + float average_stddev = (options_.low_capture_jitter_threshold_ms + + options_.high_capture_jitter_threshold_ms) / 2.0f; return average_stddev * average_stddev; } @@ -237,13 +230,8 @@ class OveruseFrameDetector::CaptureQueueDelay { scoped_ptr filtered_delay_ms_per_s_; }; -OveruseFrameDetector::OveruseFrameDetector(Clock* clock, - float normaluse_stddev_ms, - float overuse_stddev_ms) +OveruseFrameDetector::OveruseFrameDetector(Clock* clock) : crit_(CriticalSectionWrapper::CreateCriticalSection()), - normaluse_stddev_ms_(normaluse_stddev_ms), - overuse_stddev_ms_(overuse_stddev_ms), - min_process_count_before_reporting_(kMinProcessCountBeforeReporting), observer_(NULL), clock_(clock), next_process_time_(clock_->TimeInMilliseconds()), @@ -255,7 +243,6 @@ OveruseFrameDetector::OveruseFrameDetector(Clock* clock, in_quick_rampup_(false), current_rampup_delay_ms_(kStandardRampUpDelayMs), num_pixels_(0), - last_capture_jitter_ms_(-1), last_encode_sample_ms_(0), encode_time_(new EncodeTimeAvg()), encode_usage_(new EncodeUsage()), @@ -270,6 +257,22 @@ void OveruseFrameDetector::SetObserver(CpuOveruseObserver* observer) { observer_ = observer; } +void OveruseFrameDetector::SetOptions(const CpuOveruseOptions& options) { + assert(options.min_frame_samples > 0); + CriticalSectionScoped cs(crit_.get()); + if (options_.Equals(options)) { + return; + } + options_ = options; + capture_deltas_.SetOptions(options); + ResetAll(num_pixels_); +} + +int OveruseFrameDetector::CaptureJitterMs() const { + CriticalSectionScoped cs(crit_.get()); + return static_cast(capture_deltas_.StdDev() + 0.5); +} + int OveruseFrameDetector::AvgEncodeTimeMs() const { CriticalSectionScoped cs(crit_.get()); return encode_time_->filtered_encode_time_ms(); @@ -295,25 +298,34 @@ int32_t OveruseFrameDetector::TimeUntilNextProcess() { return next_process_time_ - clock_->TimeInMilliseconds(); } -bool OveruseFrameDetector::DetectFrameTimeout(int64_t now) const { +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_) > kFrameTimeoutIntervalMs; + return (now - last_capture_time_) > options_.frame_timeout_interval_ms; +} + +void OveruseFrameDetector::ResetAll(int num_pixels) { + num_pixels_ = num_pixels; + capture_deltas_.Reset(); + capture_queue_delay_->ClearFrames(); + last_capture_time_ = 0; + num_process_times_ = 0; } void OveruseFrameDetector::FrameCaptured(int width, int height) { CriticalSectionScoped cs(crit_.get()); int64_t now = clock_->TimeInMilliseconds(); - int num_pixels = width * height; - if (num_pixels != num_pixels_ || DetectFrameTimeout(now)) { - // Frame size changed, reset statistics. - num_pixels_ = num_pixels; - capture_deltas_.Reset(); - last_capture_time_ = 0; - capture_queue_delay_->ClearFrames(); - num_process_times_ = 0; + if (FrameSizeChanged(width * height) || FrameTimeoutDetected(now)) { + ResetAll(width * height); } if (last_capture_time_ != 0) { @@ -341,11 +353,6 @@ void OveruseFrameDetector::FrameEncoded(int encode_time_ms) { last_encode_sample_ms_ = time; } -int OveruseFrameDetector::last_capture_jitter_ms() const { - CriticalSectionScoped cs(crit_.get()); - return last_capture_jitter_ms_; -} - int32_t OveruseFrameDetector::Process() { CriticalSectionScoped cs(crit_.get()); @@ -359,13 +366,9 @@ int32_t OveruseFrameDetector::Process() { next_process_time_ = now + kProcessIntervalMs; ++num_process_times_; - // Don't trigger overuse unless we've seen a certain number of frames. - if (capture_deltas_.Count() < kMinFrameSampleCount) - return 0; - capture_queue_delay_->CalculateDelayChange(diff_ms); - if (num_process_times_ <= min_process_count_before_reporting_) { + if (num_process_times_ <= options_.min_process_count) { return 0; } @@ -410,21 +413,21 @@ int32_t OveruseFrameDetector::Process() { capture_deltas_.Mean(), capture_deltas_.StdDev(), in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_, - overuse_stddev_ms_, - normaluse_stddev_ms_); + options_.high_capture_jitter_threshold_ms, + options_.low_capture_jitter_threshold_ms); - last_capture_jitter_ms_ = static_cast(capture_deltas_.StdDev() + 0.5); return 0; } bool OveruseFrameDetector::IsOverusing() { - if (capture_deltas_.StdDev() >= overuse_stddev_ms_) { + bool overusing = options_.enable_capture_jitter_method && + (capture_deltas_.StdDev() >= options_.high_capture_jitter_threshold_ms); + if (overusing) { ++checks_above_threshold_; } else { checks_above_threshold_ = 0; } - - return checks_above_threshold_ >= kConsecutiveChecksAboveThreshold; + return checks_above_threshold_ >= options_.high_threshold_consecutive_count; } bool OveruseFrameDetector::IsUnderusing(int64_t time_now) { @@ -432,6 +435,8 @@ bool OveruseFrameDetector::IsUnderusing(int64_t time_now) { if (time_now < last_rampup_time_ + delay) return false; - return capture_deltas_.StdDev() < normaluse_stddev_ms_; + bool underusing = options_.enable_capture_jitter_method && + (capture_deltas_.StdDev() < options_.low_capture_jitter_threshold_ms); + return underusing; } } // namespace webrtc diff --git a/webrtc/video_engine/overuse_frame_detector.h b/webrtc/video_engine/overuse_frame_detector.h index c87fe3644d..92a2d14a3f 100644 --- a/webrtc/video_engine/overuse_frame_detector.h +++ b/webrtc/video_engine/overuse_frame_detector.h @@ -14,7 +14,7 @@ #include "webrtc/modules/interface/module.h" #include "webrtc/system_wrappers/interface/constructor_magic.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" -#include "webrtc/test/testsupport/gtest_prod_util.h" +#include "webrtc/video_engine/include/vie_base.h" namespace webrtc { @@ -23,24 +23,6 @@ class CpuOveruseObserver; class CriticalSectionWrapper; class VCMExpFilter; -// Limits on standard deviation for under/overuse. -#ifdef WEBRTC_ANDROID -const float kOveruseStdDevMs = 32.0f; -const float kNormalUseStdDevMs = 27.0f; -#elif WEBRTC_LINUX -const float kOveruseStdDevMs = 20.0f; -const float kNormalUseStdDevMs = 14.0f; -#elif WEBRTC_MAC -const float kOveruseStdDevMs = 27.0f; -const float kNormalUseStdDevMs = 21.0f; -#elif WEBRTC_WIN -const float kOveruseStdDevMs = 20.0f; -const float kNormalUseStdDevMs = 14.0f; -#else -const float kOveruseStdDevMs = 30.0f; -const float kNormalUseStdDevMs = 20.0f; -#endif - // TODO(pbos): Move this somewhere appropriate. class Statistics { public: @@ -48,6 +30,7 @@ class Statistics { void AddSample(float sample_ms); void Reset(); + void SetOptions(const CpuOveruseOptions& options); float Mean() const; float StdDev() const; @@ -59,6 +42,7 @@ class Statistics { float sum_; uint64_t count_; + CpuOveruseOptions options_; scoped_ptr filtered_samples_; scoped_ptr filtered_variance_; }; @@ -66,15 +50,16 @@ class Statistics { // Use to detect system overuse based on jitter in incoming frames. class OveruseFrameDetector : public Module { public: - explicit OveruseFrameDetector(Clock* clock, - float normaluse_stddev_ms, - float overuse_stddev_ms); + explicit OveruseFrameDetector(Clock* clock); ~OveruseFrameDetector(); // Registers an observer receiving overuse and underuse callbacks. Set // 'observer' to NULL to disable callbacks. void SetObserver(CpuOveruseObserver* observer); + // Sets options for overuse detection. + void SetOptions(const CpuOveruseOptions& options); + // Called for each captured frame. void FrameCaptured(int width, int height); @@ -85,8 +70,8 @@ class OveruseFrameDetector : public Module { void FrameEncoded(int encode_time_ms); // Accessors. - // The last estimated jitter based on the incoming captured frames. - int last_capture_jitter_ms() const; + // The estimated jitter based on incoming captured frames. + int CaptureJitterMs() const; // Running average of reported encode time (FrameEncoded()). // Only used for stats. @@ -111,19 +96,6 @@ class OveruseFrameDetector : public Module { virtual int32_t Process() OVERRIDE; private: - FRIEND_TEST_ALL_PREFIXES(OveruseFrameDetectorTest, TriggerOveruse); - FRIEND_TEST_ALL_PREFIXES(OveruseFrameDetectorTest, OveruseAndRecover); - FRIEND_TEST_ALL_PREFIXES(OveruseFrameDetectorTest, DoubleOveruseAndRecover); - FRIEND_TEST_ALL_PREFIXES( - OveruseFrameDetectorTest, TriggerNormalUsageWithMinProcessCount); - FRIEND_TEST_ALL_PREFIXES( - OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage); - FRIEND_TEST_ALL_PREFIXES(OveruseFrameDetectorTest, LastCaptureJitter); - - void set_min_process_count_before_reporting(int64_t count) { - min_process_count_before_reporting_ = count; - } - class EncodeTimeAvg; class EncodeUsage; class CaptureQueueDelay; @@ -131,20 +103,19 @@ class OveruseFrameDetector : public Module { bool IsOverusing(); bool IsUnderusing(int64_t time_now); - bool DetectFrameTimeout(int64_t now) const; + bool FrameTimeoutDetected(int64_t now) const; + bool FrameSizeChanged(int num_pixels) const; + + void ResetAll(int num_pixels); // Protecting all members. scoped_ptr crit_; - // Limits on standard deviation for under/overuse. - const float normaluse_stddev_ms_; - const float overuse_stddev_ms_; - - int64_t min_process_count_before_reporting_; - // Observer getting overuse reports. CpuOveruseObserver* observer_; + CpuOveruseOptions options_; + Clock* clock_; int64_t next_process_time_; int64_t num_process_times_; @@ -162,8 +133,6 @@ class OveruseFrameDetector : public Module { // Number of pixels of last captured frame. int num_pixels_; - int last_capture_jitter_ms_; - int64_t last_encode_sample_ms_; scoped_ptr encode_time_; scoped_ptr encode_usage_; diff --git a/webrtc/video_engine/overuse_frame_detector_unittest.cc b/webrtc/video_engine/overuse_frame_detector_unittest.cc index 8d45fdb23c..5d9cedb5fa 100644 --- a/webrtc/video_engine/overuse_frame_detector_unittest.cc +++ b/webrtc/video_engine/overuse_frame_detector_unittest.cc @@ -17,6 +17,12 @@ #include "webrtc/video_engine/overuse_frame_detector.h" namespace webrtc { +namespace { + const int kWidth = 640; + const int kHeight = 480; + const int kFrameInterval33ms = 33; + const int kProcessIntervalMs = 5000; +} // namespace class MockCpuOveruseObserver : public CpuOveruseObserver { public: @@ -27,113 +33,201 @@ class MockCpuOveruseObserver : public CpuOveruseObserver { MOCK_METHOD0(NormalUsage, void()); }; +class CpuOveruseObserverImpl : public CpuOveruseObserver { + public: + CpuOveruseObserverImpl() : + overuse_(0), + normaluse_(0) {} + virtual ~CpuOveruseObserverImpl() {} + + void OveruseDetected() { ++overuse_; } + void NormalUsage() { ++normaluse_; } + + int overuse_; + int normaluse_; +}; + class OveruseFrameDetectorTest : public ::testing::Test { protected: virtual void SetUp() { clock_.reset(new SimulatedClock(1234)); observer_.reset(new MockCpuOveruseObserver()); - overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), - 10.0f, - 15.0f)); + overuse_detector_.reset(new OveruseFrameDetector(clock_.get())); + + options_.low_capture_jitter_threshold_ms = 10.0f; + options_.high_capture_jitter_threshold_ms = 15.0f; + options_.min_process_count = 0; + overuse_detector_->SetOptions(options_); overuse_detector_->SetObserver(observer_.get()); } - void InsertFramesWithInterval(size_t num_frames, int interval_ms) { + int InitialJitter() { + return ((options_.low_capture_jitter_threshold_ms + + options_.high_capture_jitter_threshold_ms) / 2.0f) + 0.5; + } + + void InsertFramesWithInterval( + size_t num_frames, int interval_ms, int width, int height) { while (num_frames-- > 0) { clock_->AdvanceTimeMilliseconds(interval_ms); - overuse_detector_->FrameCaptured(640, 480); + overuse_detector_->FrameCaptured(width, height); } } - void TriggerOveruse() { - int regular_frame_interval_ms = 33; - - EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); - - InsertFramesWithInterval(200, regular_frame_interval_ms); - InsertFramesWithInterval(50, 110); - overuse_detector_->Process(); - - InsertFramesWithInterval(200, regular_frame_interval_ms); - InsertFramesWithInterval(50, 110); - overuse_detector_->Process(); + void TriggerOveruse(int num_times) { + for (int i = 0; i < num_times; ++i) { + InsertFramesWithInterval(200, kFrameInterval33ms, kWidth, kHeight); + InsertFramesWithInterval(50, 110, kWidth, kHeight); + overuse_detector_->Process(); + } } void TriggerNormalUsage() { - int regular_frame_interval_ms = 33; - - EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); - - InsertFramesWithInterval(900, regular_frame_interval_ms); + InsertFramesWithInterval(900, kFrameInterval33ms, kWidth, kHeight); overuse_detector_->Process(); } + CpuOveruseOptions options_; scoped_ptr clock_; scoped_ptr observer_; scoped_ptr overuse_detector_; }; TEST_F(OveruseFrameDetectorTest, TriggerOveruse) { - overuse_detector_->set_min_process_count_before_reporting(0); - TriggerOveruse(); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); + TriggerOveruse(options_.high_threshold_consecutive_count); } TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) { - overuse_detector_->set_min_process_count_before_reporting(0); - TriggerOveruse(); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); + TriggerOveruse(options_.high_threshold_consecutive_count); + EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); + TriggerNormalUsage(); +} + +TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverNoObserver) { + overuse_detector_->SetObserver(NULL); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); + TriggerOveruse(options_.high_threshold_consecutive_count); + EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); + TriggerNormalUsage(); +} + +TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverDisabled) { + options_.enable_capture_jitter_method = false; + overuse_detector_->SetOptions(options_); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); + TriggerOveruse(options_.high_threshold_consecutive_count); + EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); TriggerNormalUsage(); } TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) { - overuse_detector_->set_min_process_count_before_reporting(0); - TriggerOveruse(); - TriggerOveruse(); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(2); + TriggerOveruse(options_.high_threshold_consecutive_count); + TriggerOveruse(options_.high_threshold_consecutive_count); + EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); TriggerNormalUsage(); } TEST_F(OveruseFrameDetectorTest, TriggerNormalUsageWithMinProcessCount) { - overuse_detector_->set_min_process_count_before_reporting(1); - InsertFramesWithInterval(900, 33); + CpuOveruseObserverImpl overuse_observer_; + overuse_detector_->SetObserver(&overuse_observer_); + options_.min_process_count = 1; + overuse_detector_->SetOptions(options_); + InsertFramesWithInterval(900, kFrameInterval33ms, kWidth, kHeight); overuse_detector_->Process(); - EXPECT_EQ(-1, overuse_detector_->last_capture_jitter_ms()); - clock_->AdvanceTimeMilliseconds(5000); + EXPECT_EQ(0, overuse_observer_.normaluse_); + clock_->AdvanceTimeMilliseconds(kProcessIntervalMs); overuse_detector_->Process(); - EXPECT_GT(overuse_detector_->last_capture_jitter_ms(), 0); + EXPECT_EQ(1, overuse_observer_.normaluse_); } TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) { - overuse_detector_->set_min_process_count_before_reporting(0); EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); - - for(size_t i = 0; i < 64; ++i) - TriggerOveruse(); + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(64); + for(size_t i = 0; i < 64; ++i) { + TriggerOveruse(options_.high_threshold_consecutive_count); + } } -TEST_F(OveruseFrameDetectorTest, LastCaptureJitter) { - overuse_detector_->set_min_process_count_before_reporting(0); - EXPECT_EQ(-1, overuse_detector_->last_capture_jitter_ms()); - TriggerOveruse(); - EXPECT_GT(overuse_detector_->last_capture_jitter_ms(), 0); +TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) { + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); + options_.high_threshold_consecutive_count = 2; + overuse_detector_->SetOptions(options_); + TriggerOveruse(2); +} + +TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) { + EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); + options_.high_threshold_consecutive_count = 2; + overuse_detector_->SetOptions(options_); + TriggerOveruse(1); +} + +TEST_F(OveruseFrameDetectorTest, CaptureJitter) { + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); + InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); + EXPECT_NE(InitialJitter(), overuse_detector_->CaptureJitterMs()); +} + +TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterResolutionChange) { + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); + InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); + EXPECT_NE(InitialJitter(), overuse_detector_->CaptureJitterMs()); + // Verify reset. + InsertFramesWithInterval(1, kFrameInterval33ms, kWidth, kHeight + 1); + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); +} + +TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterFrameTimeout) { + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); + InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); + EXPECT_NE(InitialJitter(), overuse_detector_->CaptureJitterMs()); + InsertFramesWithInterval( + 1, options_.frame_timeout_interval_ms, kWidth, kHeight); + EXPECT_NE(InitialJitter(), overuse_detector_->CaptureJitterMs()); + // Verify reset. + InsertFramesWithInterval( + 1, options_.frame_timeout_interval_ms + 1, kWidth, kHeight); + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); +} + +TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterChangingThreshold) { + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); + options_.high_capture_jitter_threshold_ms = 90.0f; + overuse_detector_->SetOptions(options_); + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); + options_.low_capture_jitter_threshold_ms = 30.0f; + overuse_detector_->SetOptions(options_); + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); +} + +TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdatingCaptureJitter) { + options_.min_frame_samples = 40; + overuse_detector_->SetOptions(options_); + InsertFramesWithInterval(40, kFrameInterval33ms, kWidth, kHeight); + EXPECT_EQ(InitialJitter(), overuse_detector_->CaptureJitterMs()); } TEST_F(OveruseFrameDetectorTest, NoCaptureQueueDelay) { EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 0); - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); overuse_detector_->FrameProcessingStarted(); EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 0); } TEST_F(OveruseFrameDetectorTest, CaptureQueueDelay) { - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(100); overuse_detector_->FrameProcessingStarted(); EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 100); } TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayMultipleFrames) { - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(10); - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(20); overuse_detector_->FrameProcessingStarted(); @@ -143,9 +237,9 @@ TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayMultipleFrames) { } TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayResetAtResolutionSwitch) { - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(10); - overuse_detector_->FrameCaptured(321, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight + 1); clock_->AdvanceTimeMilliseconds(20); overuse_detector_->FrameProcessingStarted(); @@ -153,7 +247,7 @@ TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayResetAtResolutionSwitch) { } TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayNoMatchingCapturedFrame) { - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(100); overuse_detector_->FrameProcessingStarted(); EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 100); @@ -174,12 +268,11 @@ TEST_F(OveruseFrameDetectorTest, EncodedFrame) { TEST_F(OveruseFrameDetectorTest, EncodedUsage) { for (int i = 0; i < 30; i++) { - overuse_detector_->FrameCaptured(320, 180); + overuse_detector_->FrameCaptured(kWidth, kHeight); clock_->AdvanceTimeMilliseconds(5); overuse_detector_->FrameEncoded(5); clock_->AdvanceTimeMilliseconds(33-5); } EXPECT_EQ(15, overuse_detector_->EncodeUsagePercent()); } - } // namespace webrtc diff --git a/webrtc/video_engine/vie_base_impl.cc b/webrtc/video_engine/vie_base_impl.cc index 0b2f007027..0d602216f3 100644 --- a/webrtc/video_engine/vie_base_impl.cc +++ b/webrtc/video_engine/vie_base_impl.cc @@ -118,6 +118,35 @@ int ViEBaseImpl::RegisterCpuOveruseObserver(int video_channel, return 0; } +int ViEBaseImpl::SetCpuOveruseOptions(int video_channel, + const CpuOveruseOptions& options) { + ViEChannelManagerScoped cs(*(shared_data_.channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + WEBRTC_TRACE(kTraceError, + kTraceVideo, + ViEId(shared_data_.instance_id()), + "%s: channel %d doesn't exist", + __FUNCTION__, + video_channel); + shared_data_.SetLastError(kViEBaseInvalidChannelId); + return -1; + } + ViEEncoder* vie_encoder = cs.Encoder(video_channel); + assert(vie_encoder); + + ViEInputManagerScoped is(*(shared_data_.input_manager())); + ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder); + if (provider) { + ViECapturer* capturer = is.Capture(provider->Id()); + if (capturer) { + capturer->SetCpuOveruseOptions(options); + return 0; + } + } + return -1; +} + int ViEBaseImpl::CpuOveruseMeasures(int video_channel, int* capture_jitter_ms, int* avg_encode_time_ms, diff --git a/webrtc/video_engine/vie_base_impl.h b/webrtc/video_engine/vie_base_impl.h index 04c1b40a10..52c888e3ba 100644 --- a/webrtc/video_engine/vie_base_impl.h +++ b/webrtc/video_engine/vie_base_impl.h @@ -33,6 +33,8 @@ class ViEBaseImpl virtual int SetVoiceEngine(VoiceEngine* voice_engine); virtual int RegisterCpuOveruseObserver(int channel, CpuOveruseObserver* observer); + virtual int SetCpuOveruseOptions(int channel, + const CpuOveruseOptions& options); virtual int CpuOveruseMeasures(int channel, int* capture_jitter_ms, int* avg_encode_time_ms, diff --git a/webrtc/video_engine/vie_capturer.cc b/webrtc/video_engine/vie_capturer.cc index 8b96277736..d8f81e3442 100644 --- a/webrtc/video_engine/vie_capturer.cc +++ b/webrtc/video_engine/vie_capturer.cc @@ -22,7 +22,6 @@ #include "webrtc/system_wrappers/interface/thread_wrapper.h" #include "webrtc/system_wrappers/interface/trace.h" #include "webrtc/system_wrappers/interface/trace_event.h" -#include "webrtc/video_engine/include/vie_base.h" #include "webrtc/video_engine/include/vie_image_process.h" #include "webrtc/video_engine/overuse_frame_detector.h" #include "webrtc/video_engine/vie_defines.h" @@ -59,9 +58,7 @@ ViECapturer::ViECapturer(int capture_id, denoising_enabled_(false), observer_cs_(CriticalSectionWrapper::CreateCriticalSection()), observer_(NULL), - overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock(), - kNormalUseStdDevMs, - kOveruseStdDevMs)) { + overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock())) { WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, capture_id), "ViECapturer::ViECapturer(capture_id: %d, engine_id: %d)", capture_id, engine_id); @@ -267,11 +264,15 @@ void ViECapturer::RegisterCpuOveruseObserver(CpuOveruseObserver* observer) { overuse_detector_->SetObserver(observer); } +void ViECapturer::SetCpuOveruseOptions(const CpuOveruseOptions& options) { + overuse_detector_->SetOptions(options); +} + void ViECapturer::CpuOveruseMeasures(int* capture_jitter_ms, int* avg_encode_time_ms, int* encode_usage_percent, int* capture_queue_delay_ms_per_s) const { - *capture_jitter_ms = overuse_detector_->last_capture_jitter_ms(); + *capture_jitter_ms = overuse_detector_->CaptureJitterMs(); *avg_encode_time_ms = overuse_detector_->AvgEncodeTimeMs(); *encode_usage_percent = overuse_detector_->EncodeUsagePercent(); *capture_queue_delay_ms_per_s = diff --git a/webrtc/video_engine/vie_capturer.h b/webrtc/video_engine/vie_capturer.h index 21644e20c6..37f203a8fa 100644 --- a/webrtc/video_engine/vie_capturer.h +++ b/webrtc/video_engine/vie_capturer.h @@ -22,6 +22,7 @@ #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/thread_annotations.h" #include "webrtc/typedefs.h" +#include "webrtc/video_engine/include/vie_base.h" #include "webrtc/video_engine/include/vie_capture.h" #include "webrtc/video_engine/vie_defines.h" #include "webrtc/video_engine/vie_frame_provider_base.h" @@ -106,6 +107,7 @@ class ViECapturer const char* CurrentDeviceName() const; void RegisterCpuOveruseObserver(CpuOveruseObserver* observer); + void SetCpuOveruseOptions(const CpuOveruseOptions& options); void CpuOveruseMeasures(int* capture_jitter_ms, int* avg_encode_time_ms,