Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(970)

Unified Diff: media/capture/video_capture_oracle_unittest.cc

Issue 1199593005: Automatic resolution throttling for screen capture pipeline. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@resolution_chooser_ITEM13
Patch Set: Move all end_t assignments out of for-loop init. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/capture/video_capture_oracle.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/capture/video_capture_oracle_unittest.cc
diff --git a/media/capture/video_capture_oracle_unittest.cc b/media/capture/video_capture_oracle_unittest.cc
index f343c879085034b945619e7cdb11bb63eef4efeb..ab43871566b72369cf400629a76ac526795aeb56 100644
--- a/media/capture/video_capture_oracle_unittest.cc
+++ b/media/capture/video_capture_oracle_unittest.cc
@@ -15,17 +15,26 @@ base::TimeTicks InitialTestTimeTicks() {
return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
}
+base::TimeDelta Get30HzPeriod() {
+ return base::TimeDelta::FromSeconds(1) / 30;
+}
+
+gfx::Size Get720pSize() {
+ return gfx::Size(1280, 720);
+}
+
} // namespace
// Tests that VideoCaptureOracle filters out events whose timestamps are
// decreasing.
TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
- const base::TimeDelta min_capture_period =
- base::TimeDelta::FromSeconds(1) / 30;
- const gfx::Rect damage_rect(0, 0, 1280, 720);
- const base::TimeDelta event_increment = min_capture_period * 2;
+ const gfx::Rect damage_rect(Get720pSize());
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
- VideoCaptureOracle oracle(min_capture_period);
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION,
+ false);
base::TimeTicks t = InitialTestTimeTicks();
for (int i = 0; i < 10; ++i) {
@@ -56,12 +65,13 @@ TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
// successfully captured frames are delivered in order. Otherwise, downstream
// consumers could be tripped-up by out-of-order frames or frame timestamps.
TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
- const base::TimeDelta min_capture_period =
- base::TimeDelta::FromSeconds(1) / 30;
- const gfx::Rect damage_rect(0, 0, 1280, 720);
- const base::TimeDelta event_increment = min_capture_period * 2;
+ const gfx::Rect damage_rect(Get720pSize());
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
- VideoCaptureOracle oracle(min_capture_period);
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION,
+ false);
// Most basic scenario: Frames delivered one at a time, with no additional
// captures in-between deliveries.
@@ -73,7 +83,7 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
damage_rect, t));
- last_frame_number = oracle.RecordCapture();
+ last_frame_number = oracle.RecordCapture(0.0);
ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, true, &ignored));
}
@@ -85,7 +95,7 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
damage_rect, t));
- last_frame_number = oracle.RecordCapture();
+ last_frame_number = oracle.RecordCapture(0.0);
}
for (int j = num_in_flight - 1; j >= 0; --j) {
ASSERT_TRUE(
@@ -102,7 +112,7 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
damage_rect, t));
- last_frame_number = oracle.RecordCapture();
+ last_frame_number = oracle.RecordCapture(0.0);
}
ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, true, &ignored));
for (int j = 1; j < num_in_flight; ++j) {
@@ -120,7 +130,7 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
damage_rect, t));
- last_frame_number = oracle.RecordCapture();
+ last_frame_number = oracle.RecordCapture(0.0);
}
// Report the last frame as an out of order failure.
ASSERT_FALSE(oracle.CompleteCapture(last_frame_number, false, &ignored));
@@ -135,12 +145,13 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
// Tests that VideoCaptureOracle transitions between using its two samplers in a
// way that does not introduce severe jank, pauses, etc.
TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
- const base::TimeDelta min_capture_period =
- base::TimeDelta::FromSeconds(1) / 30;
- const gfx::Rect animation_damage_rect(0, 0, 1280, 720);
- const base::TimeDelta event_increment = min_capture_period * 2;
+ const gfx::Rect animation_damage_rect(Get720pSize());
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
- VideoCaptureOracle oracle(min_capture_period);
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION,
+ false);
// Run sequences of animation events and non-animation events through the
// oracle. As the oracle transitions between each sampler, make sure the
@@ -173,7 +184,7 @@ TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
}
ASSERT_LT(base::TimeDelta(), oracle.estimated_frame_duration());
- const int frame_number = oracle.RecordCapture();
+ const int frame_number = oracle.RecordCapture(0.0);
base::TimeTicks frame_timestamp;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &frame_timestamp));
@@ -196,14 +207,15 @@ TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
// Tests that VideoCaptureOracle prevents timer polling from initiating
// simultaneous captures.
TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
- const base::TimeDelta min_capture_period =
- base::TimeDelta::FromSeconds(1) / 30;
const base::TimeDelta vsync_interval =
base::TimeDelta::FromSeconds(1) / 60;
const base::TimeDelta timer_interval = base::TimeDelta::FromMilliseconds(
VideoCaptureOracle::kMinTimerPollPeriodMillis);
- VideoCaptureOracle oracle(min_capture_period);
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION,
+ false);
// Have the oracle observe some compositor events. Simulate that each capture
// completes successfully.
@@ -215,7 +227,7 @@ TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
if (oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t)) {
ASSERT_TRUE(
- oracle.CompleteCapture(oracle.RecordCapture(), true, &ignored));
+ oracle.CompleteCapture(oracle.RecordCapture(0.0), true, &ignored));
did_complete_a_capture = true;
}
}
@@ -231,7 +243,7 @@ TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
break;
}
}
- int frame_number = oracle.RecordCapture();
+ int frame_number = oracle.RecordCapture(0.0);
// Stop providing the compositor events and start providing timer polling
// events. No overdue samplings should be recommended because of the
@@ -252,7 +264,7 @@ TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
if (oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kTimerPoll, gfx::Rect(), t)) {
ASSERT_TRUE(
- oracle.CompleteCapture(oracle.RecordCapture(), true, &ignored));
+ oracle.CompleteCapture(oracle.RecordCapture(0.0), true, &ignored));
did_complete_a_capture = true;
}
}
@@ -267,7 +279,7 @@ TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
break;
}
}
- frame_number = oracle.RecordCapture();
+ frame_number = oracle.RecordCapture(0.0);
// Confirm that the oracle does not recommend sampling until the outstanding
// timer-based capture completes.
@@ -287,4 +299,227 @@ TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) {
}
}
+// Tests that VideoCaptureOracle does not rapidly change proposed capture sizes,
+// to allow both the source content and the rest of the end-to-end system to
+// stabilize.
+TEST(VideoCaptureOracleTest, DoesNotRapidlyChangeCaptureSize) {
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT,
+ true);
+
+ // Run 30 seconds of frame captures without any source size changes.
+ base::TimeTicks t = InitialTestTimeTicks();
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
+ base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(30);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
+ ASSERT_EQ(Get720pSize(), oracle.capture_size());
+ base::TimeTicks ignored;
+ ASSERT_TRUE(oracle.CompleteCapture(
+ oracle.RecordCapture(0.0), true, &ignored));
+ }
+
+ // Now run 30 seconds of frame captures with lots of random source size
+ // changes. Check that there was no more than one size change per second.
+ gfx::Size source_size = oracle.capture_size();
+ base::TimeTicks time_of_last_size_change = InitialTestTimeTicks();
+ gfx::Size last_capture_size = oracle.capture_size();
+ end_t = t + base::TimeDelta::FromSeconds(30);
+ for (; t < end_t; t += event_increment) {
+ // Change the source size every frame to a random non-empty size.
+ const gfx::Size last_source_size = source_size;
+ source_size.SetSize(
+ ((last_source_size.width() * 11 + 12345) % 1280) + 1,
+ ((last_source_size.height() * 11 + 12345) % 720) + 1);
+ ASSERT_NE(last_source_size, source_size);
+ oracle.SetSourceSize(source_size);
+
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
+
+ if (oracle.capture_size() != last_capture_size) {
+ ASSERT_GE(t - time_of_last_size_change, base::TimeDelta::FromSeconds(1));
+ time_of_last_size_change = t;
+ last_capture_size = oracle.capture_size();
+ }
+
+ base::TimeTicks ignored;
+ ASSERT_TRUE(oracle.CompleteCapture(
+ oracle.RecordCapture(0.0), true, &ignored));
+ }
+}
+
+namespace {
+
+// Tests that VideoCaptureOracle can auto-throttle by stepping the capture size
+// up or down. When |is_content_animating| is false, there is more
+// aggressiveness expected in the timing of stepping upwards. If
+// |with_consumer_feedback| is false, only buffer pool utilization varies and no
+// consumer feedback is provided. If |with_consumer_feedback| is true, the
+// buffer pool utilization is held constant at 25%, and the consumer utilization
+// feedback varies.
+void RunAutoThrottleTest(bool is_content_animating,
+ bool with_consumer_feedback) {
+ SCOPED_TRACE(::testing::Message() << "RunAutoThrottleTest("
+ << "(is_content_animating=" << is_content_animating
+ << ", with_consumer_feedback=" << with_consumer_feedback << ")");
+
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT,
+ true);
+
+ // Run 10 seconds of frame captures with 90% utilization expect no capture
+ // size changes.
+ base::TimeTicks t = InitialTestTimeTicks();
+ base::TimeTicks time_of_last_size_change = t;
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
+ base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(),
+ t));
+ ASSERT_EQ(Get720pSize(), oracle.capture_size());
+ const double utilization = 0.9;
+ const int frame_number =
+ oracle.RecordCapture(with_consumer_feedback ? 0.25 : utilization);
+ base::TimeTicks ignored;
+ ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
+ if (with_consumer_feedback)
+ oracle.RecordConsumerFeedback(frame_number, utilization);
+ }
+
+ // Cause two downward steppings in resolution. First, indicate overload
+ // until the resolution steps down. Then, indicate a 90% utilization and
+ // expect the resolution to remain constant. Repeat.
+ for (int i = 0; i < 2; ++i) {
+ const gfx::Size starting_size = oracle.capture_size();
+ SCOPED_TRACE(::testing::Message()
+ << "Stepping down from " << starting_size.ToString()
+ << ", i=" << i);
+
+ gfx::Size stepped_down_size;
+ end_t = t + base::TimeDelta::FromSeconds(10);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(),
+ t));
+
+ if (stepped_down_size.IsEmpty()) {
+ if (oracle.capture_size() != starting_size) {
+ time_of_last_size_change = t;
+ stepped_down_size = oracle.capture_size();
+ ASSERT_GT(starting_size.width(), stepped_down_size.width());
+ ASSERT_GT(starting_size.height(), stepped_down_size.height());
+ }
+ } else {
+ ASSERT_EQ(stepped_down_size, oracle.capture_size());
+ }
+
+ const double utilization = stepped_down_size.IsEmpty() ? 1.5 : 0.9;
+ const int frame_number =
+ oracle.RecordCapture(with_consumer_feedback ? 0.25 : utilization);
+ base::TimeTicks ignored;
+ ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
+ if (with_consumer_feedback)
+ oracle.RecordConsumerFeedback(frame_number, utilization);
+ }
+ }
+
+ // Now, cause two upward steppings in resolution. First, indicate
+ // under-utilization until the resolution steps up. Then, indicate a 90%
+ // utilization and expect the resolution to remain constant. Repeat.
+ for (int i = 0; i < 2; ++i) {
+ const gfx::Size starting_size = oracle.capture_size();
+ SCOPED_TRACE(::testing::Message()
+ << "Stepping up from " << starting_size.ToString()
+ << ", i=" << i);
+
+ gfx::Size stepped_up_size;
+ end_t = t + base::TimeDelta::FromSeconds(is_content_animating ? 90 : 10);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(),
+ t));
+
+ if (stepped_up_size.IsEmpty()) {
+ if (oracle.capture_size() != starting_size) {
+ // When content is animating, a much longer amount of time must pass
+ // before the capture size will step up.
+ ASSERT_LT(
+ base::TimeDelta::FromSeconds(is_content_animating ? 15 : 1),
+ t - time_of_last_size_change);
+ time_of_last_size_change = t;
+ stepped_up_size = oracle.capture_size();
+ ASSERT_LT(starting_size.width(), stepped_up_size.width());
+ ASSERT_LT(starting_size.height(), stepped_up_size.height());
+ }
+ } else {
+ ASSERT_EQ(stepped_up_size, oracle.capture_size());
+ }
+
+ const double utilization = stepped_up_size.IsEmpty() ? 0.0 : 0.9;
+ const int frame_number =
+ oracle.RecordCapture(with_consumer_feedback ? 0.25 : utilization);
+ base::TimeTicks ignored;
+ ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
+ if (with_consumer_feedback)
+ oracle.RecordConsumerFeedback(frame_number, utilization);
+ }
+ }
+}
+
+} // namespace
+
+// Tests that VideoCaptureOracle can auto-throttle by stepping the capture size
+// up or down, using utilization feedback signals from either the buffer pool or
+// the consumer, and with slightly different behavior depending on whether
+// content is animating.
+TEST(VideoCaptureOracleTest, AutoThrottlesBasedOnUtilizationFeedback) {
+ RunAutoThrottleTest(false, false);
+ RunAutoThrottleTest(false, true);
+ RunAutoThrottleTest(true, false);
+ RunAutoThrottleTest(true, true);
+}
+
+// Tests that VideoCaptureOracle does not change the capture size if
+// auto-throttling is enabled when using a fixed resolution policy.
+TEST(VideoCaptureOracleTest, DoesNotAutoThrottleWhenResolutionIsFixed) {
+ VideoCaptureOracle oracle(Get30HzPeriod(),
+ Get720pSize(),
+ media::RESOLUTION_POLICY_FIXED_RESOLUTION,
+ true);
+
+ // Run 10 seconds of frame captures with 90% utilization expect no capture
+ // size changes.
+ base::TimeTicks t = InitialTestTimeTicks();
+ const base::TimeDelta event_increment = Get30HzPeriod() * 2;
+ base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
+ ASSERT_EQ(Get720pSize(), oracle.capture_size());
+ base::TimeTicks ignored;
+ ASSERT_TRUE(
+ oracle.CompleteCapture(oracle.RecordCapture(0.9), true, &ignored));
+ }
+
+ // Now run 10 seconds with overload indicated. Still, expect no capture size
+ // changes.
+ end_t = t + base::TimeDelta::FromSeconds(10);
+ for (; t < end_t; t += event_increment) {
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
+ ASSERT_EQ(Get720pSize(), oracle.capture_size());
+ base::TimeTicks ignored;
+ ASSERT_TRUE(
+ oracle.CompleteCapture(oracle.RecordCapture(2.0), true, &ignored));
+ }
+}
+
} // namespace media
« no previous file with comments | « media/capture/video_capture_oracle.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698