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
diff --git a/webrtc/video_engine/include/vie_base.h b/webrtc/video_engine/include/vie_base.h
index cd5f385..64c53ec 100644
--- a/webrtc/video_engine/include/vie_base.h
+++ b/webrtc/video_engine/include/vie_base.h
@@ -43,6 +43,59 @@
   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 @@
   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 21aa769..bc283e2 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 {
 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 @@
     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<uint32_t>(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::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 @@
   scoped_ptr<VCMExpFilter> 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 @@
       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 @@
   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<int>(capture_deltas_.StdDev() + 0.5);
+}
+
 int OveruseFrameDetector::AvgEncodeTimeMs() const {
   CriticalSectionScoped cs(crit_.get());
   return encode_time_->filtered_encode_time_ms();
@@ -295,25 +298,34 @@
   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 @@
   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 @@
   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 @@
       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<int>(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 @@
   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 c87fe36..92a2d14 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 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 @@
 
   void AddSample(float sample_ms);
   void Reset();
+  void SetOptions(const CpuOveruseOptions& options);
 
   float Mean() const;
   float StdDev() const;
@@ -59,6 +42,7 @@
 
   float sum_;
   uint64_t count_;
+  CpuOveruseOptions options_;
   scoped_ptr<VCMExpFilter> filtered_samples_;
   scoped_ptr<VCMExpFilter> filtered_variance_;
 };
@@ -66,15 +50,16 @@
 // 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 @@
   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 @@
   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 @@
   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<CriticalSectionWrapper> 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 @@
   // Number of pixels of last captured frame.
   int num_pixels_;
 
-  int last_capture_jitter_ms_;
-
   int64_t last_encode_sample_ms_;
   scoped_ptr<EncodeTimeAvg> encode_time_;
   scoped_ptr<EncodeUsage> encode_usage_;
diff --git a/webrtc/video_engine/overuse_frame_detector_unittest.cc b/webrtc/video_engine/overuse_frame_detector_unittest.cc
index 8d45fdb..5d9cedb 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 @@
   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<SimulatedClock> clock_;
   scoped_ptr<MockCpuOveruseObserver> observer_;
   scoped_ptr<OveruseFrameDetector> 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, 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, 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, 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 0b2f007..0d60221 100644
--- a/webrtc/video_engine/vie_base_impl.cc
+++ b/webrtc/video_engine/vie_base_impl.cc
@@ -118,6 +118,35 @@
   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 04c1b40..52c888e3 100644
--- a/webrtc/video_engine/vie_base_impl.h
+++ b/webrtc/video_engine/vie_base_impl.h
@@ -33,6 +33,8 @@
   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 8b96277..d8f81e3 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 @@
       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 @@
   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 21644e2..37f203a 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 @@
   const char* CurrentDeviceName() const;
 
   void RegisterCpuOveruseObserver(CpuOveruseObserver* observer);
+  void SetCpuOveruseOptions(const CpuOveruseOptions& options);
 
   void CpuOveruseMeasures(int* capture_jitter_ms,
                           int* avg_encode_time_ms,