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:
@ -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
|
||||
|
||||
Reference in New Issue
Block a user