Reset estimate if no frame has been seen for a certain time (to avoid large jitter if stop sending).
Add delay before start processing after a reset.

BUG=1577
R=mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/8699006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5561 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/video_engine/overuse_frame_detector.cc b/webrtc/video_engine/overuse_frame_detector.cc
index a5e2d6f..21aa769 100644
--- a/webrtc/video_engine/overuse_frame_detector.cc
+++ b/webrtc/video_engine/overuse_frame_detector.cc
@@ -29,11 +29,16 @@
 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 = 15;
+const size_t kMinFrameSampleCount = 120;
 
 // Weight factor to apply to the standard deviation.
 const float kWeightFactor = 0.997f;
@@ -238,9 +243,11 @@
     : 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()),
+      num_process_times_(0),
       last_capture_time_(0),
       last_overuse_time_(0),
       checks_above_threshold_(0),
@@ -288,26 +295,34 @@
   return next_process_time_ - clock_->TimeInMilliseconds();
 }
 
+bool OveruseFrameDetector::DetectFrameTimeout(int64_t now) const {
+  if (last_capture_time_ == 0) {
+    return false;
+  }
+  return (now - last_capture_time_) > kFrameTimeoutIntervalMs;
+}
+
 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_) {
+  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;
   }
 
-  int64_t time = clock_->TimeInMilliseconds();
   if (last_capture_time_ != 0) {
-    capture_deltas_.AddSample(time - last_capture_time_);
-    encode_usage_->AddSample(time - last_capture_time_);
+    capture_deltas_.AddSample(now - last_capture_time_);
+    encode_usage_->AddSample(now - last_capture_time_);
   }
-  last_capture_time_ = time;
+  last_capture_time_ = now;
 
-  capture_queue_delay_->FrameCaptured(time);
+  capture_queue_delay_->FrameCaptured(now);
 }
 
 void OveruseFrameDetector::FrameProcessingStarted() {
@@ -342,6 +357,7 @@
 
   int64_t diff_ms = now - next_process_time_ + kProcessIntervalMs;
   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)
@@ -349,6 +365,10 @@
 
   capture_queue_delay_->CalculateDelayChange(diff_ms);
 
+  if (num_process_times_ <= min_process_count_before_reporting_) {
+    return 0;
+  }
+
   if (IsOverusing()) {
     // 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
diff --git a/webrtc/video_engine/overuse_frame_detector.h b/webrtc/video_engine/overuse_frame_detector.h
index 5dbb48a..c9f691c 100644
--- a/webrtc/video_engine/overuse_frame_detector.h
+++ b/webrtc/video_engine/overuse_frame_detector.h
@@ -14,6 +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"
 
 namespace webrtc {
 
@@ -104,6 +105,19 @@
   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;
@@ -111,6 +125,8 @@
   bool IsOverusing();
   bool IsUnderusing(int64_t time_now);
 
+  bool DetectFrameTimeout(int64_t now) const;
+
   // Protecting all members.
   scoped_ptr<CriticalSectionWrapper> crit_;
 
@@ -118,11 +134,14 @@
   const float normaluse_stddev_ms_;
   const float overuse_stddev_ms_;
 
+  int64_t min_process_count_before_reporting_;
+
   // Observer getting overuse reports.
   CpuOveruseObserver* observer_;
 
   Clock* clock_;
   int64_t next_process_time_;
+  int64_t num_process_times_;
 
   Statistics capture_deltas_;
   int64_t last_capture_time_;
diff --git a/webrtc/video_engine/overuse_frame_detector_unittest.cc b/webrtc/video_engine/overuse_frame_detector_unittest.cc
index f974f28..8d45fdb 100644
--- a/webrtc/video_engine/overuse_frame_detector_unittest.cc
+++ b/webrtc/video_engine/overuse_frame_detector_unittest.cc
@@ -50,11 +50,11 @@
 
     EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
 
-    InsertFramesWithInterval(50, regular_frame_interval_ms);
+    InsertFramesWithInterval(200, regular_frame_interval_ms);
     InsertFramesWithInterval(50, 110);
     overuse_detector_->Process();
 
-    InsertFramesWithInterval(50, regular_frame_interval_ms);
+    InsertFramesWithInterval(200, regular_frame_interval_ms);
     InsertFramesWithInterval(50, 110);
     overuse_detector_->Process();
   }
@@ -74,21 +74,35 @@
 };
 
 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
+  overuse_detector_->set_min_process_count_before_reporting(0);
   TriggerOveruse();
 }
 
 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
+  overuse_detector_->set_min_process_count_before_reporting(0);
   TriggerOveruse();
   TriggerNormalUsage();
 }
 
 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
+  overuse_detector_->set_min_process_count_before_reporting(0);
   TriggerOveruse();
   TriggerOveruse();
   TriggerNormalUsage();
 }
 
+TEST_F(OveruseFrameDetectorTest, TriggerNormalUsageWithMinProcessCount) {
+  overuse_detector_->set_min_process_count_before_reporting(1);
+  InsertFramesWithInterval(900, 33);
+  overuse_detector_->Process();
+  EXPECT_EQ(-1, overuse_detector_->last_capture_jitter_ms());
+  clock_->AdvanceTimeMilliseconds(5000);
+  overuse_detector_->Process();
+  EXPECT_GT(overuse_detector_->last_capture_jitter_ms(), 0);
+}
+
 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)
@@ -96,6 +110,7 @@
 }
 
 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);