- Reset capture deltas at resolution change.
- Applied smoothing of capture jitter.
- Adjusted thresholds.
R=stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2070005
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4817 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/video_engine/overuse_frame_detector.cc b/video_engine/overuse_frame_detector.cc
index b8c1a0d..96cea17 100644
--- a/video_engine/overuse_frame_detector.cc
+++ b/video_engine/overuse_frame_detector.cc
@@ -10,9 +10,11 @@
#include "webrtc/video_engine/overuse_frame_detector.h"
+#include <algorithm>
#include <assert.h>
#include <math.h>
+#include "webrtc/modules/video_coding/utility/include/exp_filter.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
@@ -20,47 +22,23 @@
namespace webrtc {
-Statistics::Statistics() { Reset(); }
-
-void Statistics::Reset() {
- sum_ = sum_squared_ = 0.0;
- count_ = 0;
-}
-
-void Statistics::AddSample(double sample) {
- sum_ += sample;
- sum_squared_ += sample * sample;
- ++count_;
-}
-
-double Statistics::Mean() const {
- if (count_ == 0)
- return 0.0;
- return sum_ / count_;
-}
-
-double Statistics::Variance() const {
- if (count_ == 0)
- return 0.0;
- return sum_squared_ / count_ - Mean() * Mean();
-}
-
-double Statistics::StdDev() const { return sqrt(Variance()); }
-
-uint64_t Statistics::Samples() const { return count_; }
-
// TODO(mflodman) Test different values for all of these to trigger correctly,
// avoid fluctuations etc.
namespace {
const int64_t kProcessIntervalMs = 5000;
-// Limits on standard deviation for under/overuse.
-const double kOveruseStdDevMs = 15.0;
-const double kNormalUseStdDevMs = 10.0;
-
-// Rampdown checks.
+// Consecutive checks above threshold to trigger overuse.
const int kConsecutiveChecksAboveThreshold = 2;
+// Minimum samples required to perform a check.
+const size_t kMinFrameSampleCount = 15;
+
+// 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;
+
// Delay between consecutive rampups. (Used for quick recovery.)
const int kQuickRampUpDelayMs = 10 * 1000;
// Delay between rampup attempts. Initially uses standard, scales up to max.
@@ -69,12 +47,66 @@
// Expontential back-off factor, to prevent annoying up-down behaviour.
const double kRampUpBackoffFactor = 2.0;
-// Minimum samples required to perform a check.
-const size_t kMinFrameSampleCount = 30;
} // namespace
-OveruseFrameDetector::OveruseFrameDetector(Clock* clock)
+Statistics::Statistics() :
+ sum_(0.0),
+ count_(0),
+ filtered_samples_(new VCMExpFilter(kWeightFactorMean)),
+ filtered_variance_(new VCMExpFilter(kWeightFactor)) {
+}
+
+void Statistics::Reset() {
+ sum_ = 0.0;
+ count_ = 0;
+}
+
+void Statistics::AddSample(float sample_ms) {
+ sum_ += sample_ms;
+ ++count_;
+
+ if (count_ < kMinFrameSampleCount) {
+ // Initialize filtered samples.
+ filtered_samples_->Reset(kWeightFactorMean);
+ filtered_samples_->Apply(1.0f, InitialMean());
+ filtered_variance_->Reset(kWeightFactor);
+ filtered_variance_->Apply(1.0f, InitialVariance());
+ return;
+ }
+
+ float exp = sample_ms/33.0f;
+ exp = std::min(exp, 7.0f);
+ filtered_samples_->Apply(exp, sample_ms);
+ filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->Value()) *
+ (sample_ms - filtered_samples_->Value()));
+}
+
+float Statistics::InitialMean() const {
+ if (count_ == 0)
+ return 0.0;
+ return sum_ / count_;
+}
+
+float Statistics::InitialVariance() const {
+ // Start in between the underuse and overuse threshold.
+ float average_stddev = (kNormalUseStdDevMs + kOveruseStdDevMs)/2.0f;
+ return average_stddev * average_stddev;
+}
+
+float Statistics::Mean() const { return filtered_samples_->Value(); }
+
+float Statistics::StdDev() const {
+ return sqrt(std::max(filtered_variance_->Value(), 0.0f));
+}
+
+uint64_t Statistics::Count() const { return count_; }
+
+OveruseFrameDetector::OveruseFrameDetector(Clock* clock,
+ float normaluse_stddev_ms,
+ float overuse_stddev_ms)
: crit_(CriticalSectionWrapper::CreateCriticalSection()),
+ normaluse_stddev_ms_(normaluse_stddev_ms),
+ overuse_stddev_ms_(overuse_stddev_ms),
observer_(NULL),
clock_(clock),
next_process_time_(clock_->TimeInMilliseconds()),
@@ -83,7 +115,8 @@
checks_above_threshold_(0),
last_rampup_time_(0),
in_quick_rampup_(false),
- current_rampup_delay_ms_(kStandardRampUpDelayMs) {}
+ current_rampup_delay_ms_(kStandardRampUpDelayMs),
+ num_pixels_(0) {}
OveruseFrameDetector::~OveruseFrameDetector() {
}
@@ -93,8 +126,17 @@
observer_ = observer;
}
-void OveruseFrameDetector::FrameCaptured() {
+void OveruseFrameDetector::FrameCaptured(int width, int height) {
CriticalSectionScoped cs(crit_.get());
+
+ int num_pixels = width * height;
+ if (num_pixels != num_pixels_) {
+ // Frame size changed, reset statistics.
+ num_pixels_ = num_pixels;
+ capture_deltas_.Reset();
+ last_capture_time_ = 0;
+ }
+
int64_t time = clock_->TimeInMilliseconds();
if (last_capture_time_ != 0) {
capture_deltas_.AddSample(time - last_capture_time_);
@@ -118,8 +160,8 @@
next_process_time_ = now + kProcessIntervalMs;
- // Don't trigger overuse unless we've seen any frames
- if (capture_deltas_.Samples() < kMinFrameSampleCount)
+ // Don't trigger overuse unless we've seen a certain number of frames.
+ if (capture_deltas_.Count() < kMinFrameSampleCount)
return 0;
if (IsOverusing()) {
@@ -153,12 +195,6 @@
observer_->NormalUsage();
}
- capture_deltas_.Reset();
-
- return 0;
-}
-
-bool OveruseFrameDetector::IsOverusing() {
WEBRTC_TRACE(
webrtc::kTraceInfo,
webrtc::kTraceVideo,
@@ -169,10 +205,14 @@
capture_deltas_.Mean(),
capture_deltas_.StdDev(),
in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_,
- kOveruseStdDevMs,
- kNormalUseStdDevMs);
+ overuse_stddev_ms_,
+ normaluse_stddev_ms_);
- if (capture_deltas_.StdDev() >= kOveruseStdDevMs) {
+ return 0;
+}
+
+bool OveruseFrameDetector::IsOverusing() {
+ if (capture_deltas_.StdDev() >= overuse_stddev_ms_) {
++checks_above_threshold_;
} else {
checks_above_threshold_ = 0;
@@ -186,6 +226,6 @@
if (time_now < last_rampup_time_ + delay)
return false;
- return capture_deltas_.StdDev() < kNormalUseStdDevMs;
+ return capture_deltas_.StdDev() < normaluse_stddev_ms_;
}
} // namespace webrtc