Overuse detection based on capture-input jitter.

This is believed to be more reliable in real-world cases. The camera seems to fall behind sooner than the encoder starts taking too long time encoding, so this is believed to be an earlier trigger.

BUG=2325
R=asapersson@webrtc.org, mflodman@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4648 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org
2013-08-30 17:16:32 +00:00
parent 0b960cf7a1
commit a957570d62
4 changed files with 184 additions and 339 deletions

View File

@ -16,17 +16,8 @@
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/overuse_frame_detector.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Return;
namespace webrtc {
const int kProcessIntervalMs = 2000;
const int kOveruseHistoryMs = 5000;
const int kMinCallbackDeltaMs = 30000;
const int64_t kMinValidHistoryMs = kOveruseHistoryMs / 2;
class MockCpuOveruseObserver : public CpuOveruseObserver {
public:
MockCpuOveruseObserver() {}
@ -45,29 +36,34 @@ class OveruseFrameDetectorTest : public ::testing::Test {
overuse_detector_->SetObserver(observer_.get());
}
void CaptureAndEncodeFrames(int num_frames, int64_t frame_interval_ms,
int encode_time_ms, size_t width, size_t height) {
for (int frame = 0; frame < num_frames; ++frame) {
void InsertFramesWithInterval(size_t num_frames, int interval_ms) {
while (num_frames-- > 0) {
clock_->AdvanceTimeMilliseconds(interval_ms);
overuse_detector_->FrameCaptured();
overuse_detector_->FrameEncoded(encode_time_ms, width, height);
clock_->AdvanceTimeMilliseconds(frame_interval_ms);
}
}
void CaptureAndEncodeWithOveruse(int overuse_time_ms,
int64_t frame_interval_ms,
int64_t encode_time_ms, size_t width,
size_t height) {
// 'encodes_before_dropping' is derived from 'kMinEncodeRatio' in
// 'overuse_frame_detector.h'.
const int encodes_before_dropping = 14;
for (int time_ms = 0; time_ms < overuse_time_ms;
time_ms += frame_interval_ms * (1 + encodes_before_dropping)) {
CaptureAndEncodeFrames(encodes_before_dropping, frame_interval_ms,
encode_time_ms, width, height);
overuse_detector_->FrameCaptured();
clock_->AdvanceTimeMilliseconds(frame_interval_ms);
}
void TriggerOveruse() {
int regular_frame_interval_ms = 33;
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
InsertFramesWithInterval(30, regular_frame_interval_ms);
InsertFramesWithInterval(30, 1000);
overuse_detector_->Process();
InsertFramesWithInterval(30, regular_frame_interval_ms);
InsertFramesWithInterval(30, 1000);
overuse_detector_->Process();
}
void TriggerNormalUsage() {
int regular_frame_interval_ms = 33;
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
InsertFramesWithInterval(300, regular_frame_interval_ms);
overuse_detector_->Process();
}
scoped_ptr<SimulatedClock> clock_;
@ -76,140 +72,25 @@ class OveruseFrameDetectorTest : public ::testing::Test {
};
TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
EXPECT_EQ(overuse_detector_->TimeUntilNextProcess(), kProcessIntervalMs);
// Enough history to trigger an overuse, but life is good so far.
int frame_interval_ms = 33;
int num_frames = kMinValidHistoryMs / frame_interval_ms + 1;
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 2, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
overuse_detector_->Process();
// Trigger an overuse.
CaptureAndEncodeWithOveruse(kOveruseHistoryMs, frame_interval_ms, 2, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
TriggerOveruse();
}
TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
overuse_detector_->set_underuse_encode_timing_enabled(true);
// Start with triggering an overuse.
// A new resolution will trigger a reset, so add one frame to get going.
int frame_interval_ms = 33;
CaptureAndEncodeWithOveruse(kMinValidHistoryMs, frame_interval_ms, 2, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
// Make everything good again, but don't advance time long enough to trigger
// an underuse.
int num_frames = kOveruseHistoryMs / frame_interval_ms;
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 1, 1, 1);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
overuse_detector_->Process();
// Advance time long enough to trigger an increase callback.
num_frames = (kMinCallbackDeltaMs - kOveruseHistoryMs + 1) /
(frame_interval_ms - 0.5f);
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 1, 1, 1);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(1);
overuse_detector_->Process();
TriggerOveruse();
TriggerNormalUsage();
}
TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
overuse_detector_->set_underuse_encode_timing_enabled(true);
// Start with triggering an overuse.
int frame_interval_ms = 33;
CaptureAndEncodeWithOveruse(kMinValidHistoryMs, frame_interval_ms, 16, 4, 4);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
TriggerOveruse();
TriggerOveruse();
TriggerNormalUsage();
}
CaptureAndEncodeWithOveruse(kOveruseHistoryMs, frame_interval_ms, 4, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
// Let life be good again and wait for an underuse callback.
int num_frames = kMinCallbackDeltaMs / (frame_interval_ms - 0.5f);
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 1, 1, 1);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(1);
overuse_detector_->Process();
// And one more.
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 4, 2, 2);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(1);
overuse_detector_->Process();
// But no more since we're at the max resolution.
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 4, 4, 4);
TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
overuse_detector_->Process();
for(size_t i = 0; i < 64; ++i)
TriggerOveruse();
}
TEST_F(OveruseFrameDetectorTest, OveruseAndNoRecovery) {
overuse_detector_->set_underuse_encode_timing_enabled(true);
// Start with triggering an overuse.
int frame_interval_ms = 33;
CaptureAndEncodeWithOveruse(kMinValidHistoryMs, frame_interval_ms, 4, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
// Everything is fine, but we haven't waited long enough to trigger an
// increase callback.
CaptureAndEncodeFrames(30, 33, 3, 1, 1);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
overuse_detector_->Process();
// Advance time enough to trigger an increase callback, but encode time
// shouldn't have decreased enough to try an increase.
int num_frames = kMinCallbackDeltaMs / (frame_interval_ms - 0.5f);
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 3, 1, 1);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
overuse_detector_->Process();
}
TEST_F(OveruseFrameDetectorTest, NoEncodeTimeForUnderuse) {
overuse_detector_->set_underuse_encode_timing_enabled(false);
// Start with triggering an overuse.
int frame_interval_ms = 33;
CaptureAndEncodeWithOveruse(kMinValidHistoryMs, frame_interval_ms, 4, 2, 2);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
// Everything is fine, but we haven't waited long enough to trigger an
// increase callback.
int num_frames = 1000 / (frame_interval_ms - 0.5f);
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 3, 1, 1);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
overuse_detector_->Process();
// Advance time enough to allow underuse, but keep encode time too high to
// trigger an underuse if accounted for, see 'OveruseAndNoRecovery' test case.
num_frames = kMinCallbackDeltaMs / (frame_interval_ms - 0.5f);
CaptureAndEncodeFrames(num_frames, frame_interval_ms, 3, 1, 1);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(1);
overuse_detector_->Process();
}
TEST_F(OveruseFrameDetectorTest, ResolutionChange) {
overuse_detector_->set_underuse_encode_timing_enabled(true);
int frame_interval_ms = 33;
CaptureAndEncodeWithOveruse(kMinValidHistoryMs / 2, frame_interval_ms, 3, 1,
1);
// Keep overusing, but with a new resolution.
CaptureAndEncodeWithOveruse(kMinValidHistoryMs - frame_interval_ms,
frame_interval_ms, 4, 2, 2);
// Enough samples and time to trigger an overuse, but resolution reset should
// prevent this.
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
overuse_detector_->Process();
// Fill the history.
CaptureAndEncodeFrames(2, kOveruseHistoryMs / 2, 3, 1, 1);
// Capture a frame without finish encoding to trigger an overuse.
overuse_detector_->FrameCaptured();
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
overuse_detector_->Process();
}
} // namespace webrtc