diff options
author | asapersson@webrtc.org <asapersson@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2013-09-23 20:05:39 +0000 |
---|---|---|
committer | asapersson@webrtc.org <asapersson@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2013-09-23 20:05:39 +0000 |
commit | ae14504dd56981e01bad96c86cca729ec31e6596 (patch) | |
tree | f95dc9cdb325f549cd474068ff68dbafdcbe815f | |
parent | a6665e70dd52036515e14bfc77078007a941a84c (diff) | |
download | webrtc-ae14504dd56981e01bad96c86cca729ec31e6596.tar.gz |
- 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
-rw-r--r-- | video_engine/overuse_frame_detector.cc | 140 | ||||
-rw-r--r-- | video_engine/overuse_frame_detector.h | 49 | ||||
-rw-r--r-- | video_engine/overuse_frame_detector_unittest.cc | 16 | ||||
-rw-r--r-- | video_engine/vie_capturer.cc | 7 |
4 files changed, 141 insertions, 71 deletions
diff --git a/video_engine/overuse_frame_detector.cc b/video_engine/overuse_frame_detector.cc index b8c1a0d5..96cea176 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,61 +22,91 @@ namespace webrtc { -Statistics::Statistics() { Reset(); } +// TODO(mflodman) Test different values for all of these to trigger correctly, +// avoid fluctuations etc. +namespace { +const int64_t kProcessIntervalMs = 5000; + +// 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. +const int kStandardRampUpDelayMs = 30 * 1000; +const int kMaxRampUpDelayMs = 120 * 1000; +// Expontential back-off factor, to prevent annoying up-down behaviour. +const double kRampUpBackoffFactor = 2.0; + +} // namespace + +Statistics::Statistics() : + sum_(0.0), + count_(0), + filtered_samples_(new VCMExpFilter(kWeightFactorMean)), + filtered_variance_(new VCMExpFilter(kWeightFactor)) { +} void Statistics::Reset() { - sum_ = sum_squared_ = 0.0; + sum_ = 0.0; count_ = 0; } -void Statistics::AddSample(double sample) { - sum_ += sample; - sum_squared_ += sample * sample; +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())); } -double Statistics::Mean() const { +float Statistics::InitialMean() 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(); +float Statistics::InitialVariance() const { + // Start in between the underuse and overuse threshold. + float average_stddev = (kNormalUseStdDevMs + kOveruseStdDevMs)/2.0f; + return average_stddev * average_stddev; } -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; +float Statistics::Mean() const { return filtered_samples_->Value(); } -// Limits on standard deviation for under/overuse. -const double kOveruseStdDevMs = 15.0; -const double kNormalUseStdDevMs = 10.0; +float Statistics::StdDev() const { + return sqrt(std::max(filtered_variance_->Value(), 0.0f)); +} -// Rampdown checks. -const int kConsecutiveChecksAboveThreshold = 2; +uint64_t Statistics::Count() const { return count_; } -// Delay between consecutive rampups. (Used for quick recovery.) -const int kQuickRampUpDelayMs = 10 * 1000; -// Delay between rampup attempts. Initially uses standard, scales up to max. -const int kStandardRampUpDelayMs = 30 * 1000; -const int kMaxRampUpDelayMs = 120 * 1000; -// 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) +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 @@ OveruseFrameDetector::OveruseFrameDetector(Clock* clock) 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 @@ void OveruseFrameDetector::SetObserver(CpuOveruseObserver* observer) { 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 @@ int32_t OveruseFrameDetector::Process() { 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 @@ int32_t OveruseFrameDetector::Process() { observer_->NormalUsage(); } - capture_deltas_.Reset(); - - return 0; -} - -bool OveruseFrameDetector::IsOverusing() { WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideo, @@ -169,10 +205,14 @@ bool OveruseFrameDetector::IsOverusing() { 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 @@ bool OveruseFrameDetector::IsUnderusing(int64_t time_now) { if (time_now < last_rampup_time_ + delay) return false; - return capture_deltas_.StdDev() < kNormalUseStdDevMs; + return capture_deltas_.StdDev() < normaluse_stddev_ms_; } } // namespace webrtc diff --git a/video_engine/overuse_frame_detector.h b/video_engine/overuse_frame_detector.h index 00d3b19b..4717a606 100644 --- a/video_engine/overuse_frame_detector.h +++ b/video_engine/overuse_frame_detector.h @@ -18,32 +18,50 @@ namespace webrtc { class Clock; -class CriticalSectionWrapper; class CpuOveruseObserver; - -// TODO(pbos): Move this somewhere appropriate +class CriticalSectionWrapper; +class VCMExpFilter; + +// Limits on standard deviation for under/overuse. +#ifdef WEBRTC_LINUX +const float kOveruseStdDevMs = 15.0f; +const float kNormalUseStdDevMs = 7.0f; +#elif WEBRTC_MAC +const float kOveruseStdDevMs = 22.0f; +const float kNormalUseStdDevMs = 12.0f; +#else +const float kOveruseStdDevMs = 17.0f; +const float kNormalUseStdDevMs = 10.0f; +#endif + +// TODO(pbos): Move this somewhere appropriate. class Statistics { public: Statistics(); - void AddSample(double sample); + void AddSample(float sample_ms); void Reset(); - double Mean() const; - double Variance() const; - double StdDev() const; - uint64_t Samples() const; + float Mean() const; + float StdDev() const; + uint64_t Count() const; private: - double sum_; - double sum_squared_; + float InitialMean() const; + float InitialVariance() const; + + float sum_; uint64_t count_; + scoped_ptr<VCMExpFilter> filtered_samples_; + scoped_ptr<VCMExpFilter> filtered_variance_; }; // Use to detect system overuse based on jitter in incoming frames. class OveruseFrameDetector : public Module { public: - explicit OveruseFrameDetector(Clock* clock); + explicit OveruseFrameDetector(Clock* clock, + float normaluse_stddev_ms, + float overuse_stddev_ms); ~OveruseFrameDetector(); // Registers an observer receiving overuse and underuse callbacks. Set @@ -51,7 +69,7 @@ class OveruseFrameDetector : public Module { void SetObserver(CpuOveruseObserver* observer); // Called for each captured frame. - void FrameCaptured(); + void FrameCaptured(int width, int height); // Implements Module. virtual int32_t TimeUntilNextProcess() OVERRIDE; @@ -64,6 +82,10 @@ class OveruseFrameDetector : public Module { // Protecting all members. scoped_ptr<CriticalSectionWrapper> crit_; + // Limits on standard deviation for under/overuse. + const float normaluse_stddev_ms_; + const float overuse_stddev_ms_; + // Observer getting overuse reports. CpuOveruseObserver* observer_; @@ -80,6 +102,9 @@ class OveruseFrameDetector : public Module { bool in_quick_rampup_; int current_rampup_delay_ms_; + // Number of pixels of last captured frame. + int num_pixels_; + DISALLOW_COPY_AND_ASSIGN(OveruseFrameDetector); }; diff --git a/video_engine/overuse_frame_detector_unittest.cc b/video_engine/overuse_frame_detector_unittest.cc index 616b13dc..d1995692 100644 --- a/video_engine/overuse_frame_detector_unittest.cc +++ b/video_engine/overuse_frame_detector_unittest.cc @@ -32,14 +32,16 @@ class OveruseFrameDetectorTest : public ::testing::Test { virtual void SetUp() { clock_.reset(new SimulatedClock(1234)); observer_.reset(new MockCpuOveruseObserver()); - overuse_detector_.reset(new OveruseFrameDetector(clock_.get())); + overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), + 10.0f, + 15.0f)); overuse_detector_->SetObserver(observer_.get()); } void InsertFramesWithInterval(size_t num_frames, int interval_ms) { while (num_frames-- > 0) { clock_->AdvanceTimeMilliseconds(interval_ms); - overuse_detector_->FrameCaptured(); + overuse_detector_->FrameCaptured(640, 480); } } @@ -48,12 +50,12 @@ class OveruseFrameDetectorTest : public ::testing::Test { EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); - InsertFramesWithInterval(30, regular_frame_interval_ms); - InsertFramesWithInterval(30, 1000); + InsertFramesWithInterval(50, regular_frame_interval_ms); + InsertFramesWithInterval(50, 110); overuse_detector_->Process(); - InsertFramesWithInterval(30, regular_frame_interval_ms); - InsertFramesWithInterval(30, 1000); + InsertFramesWithInterval(50, regular_frame_interval_ms); + InsertFramesWithInterval(50, 110); overuse_detector_->Process(); } @@ -62,7 +64,7 @@ class OveruseFrameDetectorTest : public ::testing::Test { EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); - InsertFramesWithInterval(300, regular_frame_interval_ms); + InsertFramesWithInterval(900, regular_frame_interval_ms); overuse_detector_->Process(); } diff --git a/video_engine/vie_capturer.cc b/video_engine/vie_capturer.cc index 1e49f4eb..dd0f3177 100644 --- a/video_engine/vie_capturer.cc +++ b/video_engine/vie_capturer.cc @@ -59,7 +59,9 @@ ViECapturer::ViECapturer(int capture_id, denoising_enabled_(false), observer_cs_(CriticalSectionWrapper::CreateCriticalSection()), observer_(NULL), - overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock())) { + overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock(), + kNormalUseStdDevMs, + kOveruseStdDevMs)) { WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, capture_id), "ViECapturer::ViECapturer(capture_id: %d, engine_id: %d)", capture_id, engine_id); @@ -350,7 +352,8 @@ void ViECapturer::OnIncomingCapturedFrame(const int32_t capture_id, captured_frame_.SwapFrame(&video_frame); capture_event_.Set(); - overuse_detector_->FrameCaptured(); + overuse_detector_->FrameCaptured(captured_frame_.width(), + captured_frame_.height()); return; } |