| 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
|
|
|