Add configuration for ability to use the encode usage measure for triggering overuse/underuse.
BUG=1577
R=mflodman@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/10509004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5767 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/video_engine/include/vie_base.h b/webrtc/video_engine/include/vie_base.h
index 64c53ec..a08cbac 100644
--- a/webrtc/video_engine/include/vie_base.h
+++ b/webrtc/video_engine/include/vie_base.h
@@ -66,6 +66,9 @@
: enable_capture_jitter_method(true),
low_capture_jitter_threshold_ms(kNormalUseStdDevMs),
high_capture_jitter_threshold_ms(kOveruseStdDevMs),
+ enable_encode_usage_method(false),
+ low_encode_usage_threshold_percent(60),
+ high_encode_usage_threshold_percent(90),
frame_timeout_interval_ms(1500),
min_frame_samples(120),
min_process_count(3),
@@ -75,6 +78,10 @@
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.
+ // Method based on encode time of frames.
+ bool enable_encode_usage_method;
+ int low_encode_usage_threshold_percent; // Threshold for triggering underuse.
+ int high_encode_usage_threshold_percent; // Threshold for triggering overuse.
// General settings.
int frame_timeout_interval_ms; // The maximum allowed interval between two
// frames before resetting estimations.
@@ -90,6 +97,11 @@
low_capture_jitter_threshold_ms == o.low_capture_jitter_threshold_ms &&
high_capture_jitter_threshold_ms ==
o.high_capture_jitter_threshold_ms &&
+ enable_encode_usage_method == o.enable_encode_usage_method &&
+ low_encode_usage_threshold_percent ==
+ o.low_encode_usage_threshold_percent &&
+ high_encode_usage_threshold_percent ==
+ o.high_encode_usage_threshold_percent &&
frame_timeout_interval_ms == o.frame_timeout_interval_ms &&
min_frame_samples == o.min_frame_samples &&
min_process_count == o.min_process_count &&
diff --git a/webrtc/video_engine/overuse_frame_detector.cc b/webrtc/video_engine/overuse_frame_detector.cc
index bc283e2..bfecbb5 100644
--- a/webrtc/video_engine/overuse_frame_detector.cc
+++ b/webrtc/video_engine/overuse_frame_detector.cc
@@ -140,13 +140,27 @@
EncodeUsage()
: kWeightFactorFrameDiff(0.998f),
kWeightFactorEncodeTime(0.995f),
+ kInitialSampleDiffMs(50.0f),
+ kMaxSampleDiffMs(66.0f),
+ count_(0),
filtered_encode_time_ms_(new VCMExpFilter(kWeightFactorEncodeTime)),
filtered_frame_diff_ms_(new VCMExpFilter(kWeightFactorFrameDiff)) {
- filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
- filtered_frame_diff_ms_->Apply(1.0f, kSampleDiffMs);
+ Reset();
}
~EncodeUsage() {}
+ void SetOptions(const CpuOveruseOptions& options) {
+ options_ = options;
+ }
+
+ void Reset() {
+ count_ = 0;
+ filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff);
+ filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs);
+ filtered_encode_time_ms_->Reset(kWeightFactorEncodeTime);
+ filtered_encode_time_ms_->Apply(1.0f, InitialEncodeTimeMs());
+ }
+
void AddSample(float sample_ms) {
float exp = sample_ms / kSampleDiffMs;
exp = std::min(exp, kMaxExp);
@@ -154,21 +168,40 @@
}
void AddEncodeSample(float encode_time_ms, int64_t diff_last_sample_ms) {
+ ++count_;
float exp = diff_last_sample_ms / kSampleDiffMs;
exp = std::min(exp, kMaxExp);
filtered_encode_time_ms_->Apply(exp, encode_time_ms);
}
int UsageInPercent() const {
+ if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
+ return static_cast<int>(InitialUsageInPercent() + 0.5f);
+ }
float frame_diff_ms = std::max(filtered_frame_diff_ms_->Value(), 1.0f);
+ frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
float encode_usage_percent =
100.0f * filtered_encode_time_ms_->Value() / frame_diff_ms;
return static_cast<int>(encode_usage_percent + 0.5);
}
+ float InitialUsageInPercent() const {
+ // Start in between the underuse and overuse threshold.
+ return (options_.low_encode_usage_threshold_percent +
+ options_.high_encode_usage_threshold_percent) / 2.0f;
+ }
+
+ float InitialEncodeTimeMs() const {
+ return InitialUsageInPercent() * kInitialSampleDiffMs / 100;
+ }
+
private:
const float kWeightFactorFrameDiff;
const float kWeightFactorEncodeTime;
+ const float kInitialSampleDiffMs;
+ const float kMaxSampleDiffMs;
+ uint64_t count_;
+ CpuOveruseOptions options_;
scoped_ptr<VCMExpFilter> filtered_encode_time_ms_;
scoped_ptr<VCMExpFilter> filtered_frame_diff_ms_;
};
@@ -265,6 +298,7 @@
}
options_ = options;
capture_deltas_.SetOptions(options);
+ encode_usage_->SetOptions(options);
ResetAll(num_pixels_);
}
@@ -315,6 +349,7 @@
void OveruseFrameDetector::ResetAll(int num_pixels) {
num_pixels_ = num_pixels;
capture_deltas_.Reset();
+ encode_usage_->Reset();
capture_queue_delay_->ClearFrames();
last_capture_time_ = 0;
num_process_times_ = 0;
@@ -420,8 +455,15 @@
}
bool OveruseFrameDetector::IsOverusing() {
- bool overusing = options_.enable_capture_jitter_method &&
- (capture_deltas_.StdDev() >= options_.high_capture_jitter_threshold_ms);
+ bool overusing = false;
+ if (options_.enable_capture_jitter_method) {
+ overusing = capture_deltas_.StdDev() >=
+ options_.high_capture_jitter_threshold_ms;
+ } else if (options_.enable_encode_usage_method) {
+ overusing = encode_usage_->UsageInPercent() >=
+ options_.high_encode_usage_threshold_percent;
+ }
+
if (overusing) {
++checks_above_threshold_;
} else {
@@ -435,8 +477,14 @@
if (time_now < last_rampup_time_ + delay)
return false;
- bool underusing = options_.enable_capture_jitter_method &&
- (capture_deltas_.StdDev() < options_.low_capture_jitter_threshold_ms);
+ bool underusing = false;
+ if (options_.enable_capture_jitter_method) {
+ underusing = capture_deltas_.StdDev() <
+ options_.low_capture_jitter_threshold_ms;
+ } else if (options_.enable_encode_usage_method) {
+ underusing = encode_usage_->UsageInPercent() <
+ options_.low_encode_usage_threshold_percent;
+ }
return underusing;
}
} // namespace webrtc
diff --git a/webrtc/video_engine/overuse_frame_detector_unittest.cc b/webrtc/video_engine/overuse_frame_detector_unittest.cc
index 5d9cedb..a760fbf 100644
--- a/webrtc/video_engine/overuse_frame_detector_unittest.cc
+++ b/webrtc/video_engine/overuse_frame_detector_unittest.cc
@@ -66,6 +66,11 @@
options_.high_capture_jitter_threshold_ms) / 2.0f) + 0.5;
}
+ int InitialEncodeUsage() {
+ return ((options_.low_encode_usage_threshold_percent +
+ options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
+ }
+
void InsertFramesWithInterval(
size_t num_frames, int interval_ms, int width, int height) {
while (num_frames-- > 0) {
@@ -74,6 +79,16 @@
}
}
+ void InsertAndEncodeFramesWithInterval(
+ int num_frames, int interval_ms, int width, int height, int encode_ms) {
+ while (num_frames-- > 0) {
+ overuse_detector_->FrameCaptured(width, height);
+ clock_->AdvanceTimeMilliseconds(encode_ms);
+ overuse_detector_->FrameEncoded(encode_ms);
+ clock_->AdvanceTimeMilliseconds(interval_ms - encode_ms);
+ }
+ }
+
void TriggerOveruse(int num_times) {
for (int i = 0; i < num_times; ++i) {
InsertFramesWithInterval(200, kFrameInterval33ms, kWidth, kHeight);
@@ -87,6 +102,22 @@
overuse_detector_->Process();
}
+ void TriggerOveruseWithEncodeUsage(int num_times) {
+ const int kEncodeTimeMs = 32;
+ for (int i = 0; i < num_times; ++i) {
+ InsertAndEncodeFramesWithInterval(
+ 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
+ overuse_detector_->Process();
+ }
+ }
+
+ void TriggerNormalUsageWithEncodeUsage() {
+ const int kEncodeTimeMs = 5;
+ InsertAndEncodeFramesWithInterval(
+ 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
+ overuse_detector_->Process();
+ }
+
CpuOveruseOptions options_;
scoped_ptr<SimulatedClock> clock_;
scoped_ptr<MockCpuOveruseObserver> observer_;
@@ -266,13 +297,42 @@
EXPECT_EQ(2, overuse_detector_->AvgEncodeTimeMs());
}
+TEST_F(OveruseFrameDetectorTest, InitialEncodeUsage) {
+ EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
+}
+
TEST_F(OveruseFrameDetectorTest, EncodedUsage) {
- for (int i = 0; i < 30; i++) {
- overuse_detector_->FrameCaptured(kWidth, kHeight);
- clock_->AdvanceTimeMilliseconds(5);
- overuse_detector_->FrameEncoded(5);
- clock_->AdvanceTimeMilliseconds(33-5);
- }
+ const int kEncodeTimeMs = 5;
+ InsertAndEncodeFramesWithInterval(
+ 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
EXPECT_EQ(15, overuse_detector_->EncodeUsagePercent());
}
+
+TEST_F(OveruseFrameDetectorTest, EncodeUsageResetAfterChangingThreshold) {
+ EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
+ options_.high_encode_usage_threshold_percent = 100;
+ overuse_detector_->SetOptions(options_);
+ EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
+ options_.low_encode_usage_threshold_percent = 20;
+ overuse_detector_->SetOptions(options_);
+ EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
+}
+
+TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithEncodeUsage) {
+ options_.enable_capture_jitter_method = false;
+ options_.enable_encode_usage_method = true;
+ overuse_detector_->SetOptions(options_);
+ EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
+ TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count);
+}
+
+TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithEncodeUsage) {
+ options_.enable_capture_jitter_method = false;
+ options_.enable_encode_usage_method = true;
+ overuse_detector_->SetOptions(options_);
+ EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
+ TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count);
+ EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
+ TriggerNormalUsageWithEncodeUsage();
+}
} // namespace webrtc