diff options
Diffstat (limited to 'chromium/media/capture/content/video_capture_oracle_unittest.cc')
-rw-r--r-- | chromium/media/capture/content/video_capture_oracle_unittest.cc | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/chromium/media/capture/content/video_capture_oracle_unittest.cc b/chromium/media/capture/content/video_capture_oracle_unittest.cc new file mode 100644 index 00000000000..64fff4fb4d0 --- /dev/null +++ b/chromium/media/capture/content/video_capture_oracle_unittest.cc @@ -0,0 +1,619 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/capture/content/video_capture_oracle.h" + +#include "base/strings/stringprintf.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace { + +base::TimeTicks InitialTestTimeTicks() { + return base::TimeTicks() + base::TimeDelta::FromSeconds(1); +} + +base::TimeDelta Get30HzPeriod() { + return base::TimeDelta::FromSeconds(1) / 30; +} + +gfx::Size Get1080pSize() { + return gfx::Size(1920, 1080); +} + +gfx::Size Get720pSize() { + return gfx::Size(1280, 720); +} + +gfx::Size Get360pSize() { + return gfx::Size(640, 360); +} + +} // namespace + +// Tests that VideoCaptureOracle filters out events whose timestamps are +// decreasing. +TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) { + const gfx::Rect damage_rect(Get720pSize()); + const base::TimeDelta event_increment = Get30HzPeriod() * 2; + + VideoCaptureOracle oracle(Get30HzPeriod(), Get720pSize(), + media::RESOLUTION_POLICY_FIXED_RESOLUTION, false); + + base::TimeTicks t = InitialTestTimeTicks(); + for (int i = 0; i < 10; ++i) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + } + + base::TimeTicks furthest_event_time = t; + for (int i = 0; i < 10; ++i) { + t -= event_increment; + ASSERT_FALSE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + } + + t = furthest_event_time; + for (int i = 0; i < 10; ++i) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + } +} + +// Tests that VideoCaptureOracle is enforcing the requirement that +// 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 gfx::Rect damage_rect(Get720pSize()); + const base::TimeDelta event_increment = Get30HzPeriod() * 2; + + 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. + base::TimeTicks t = InitialTestTimeTicks(); + int last_frame_number; + base::TimeTicks ignored; + for (int i = 0; i < 10; ++i) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + last_frame_number = oracle.RecordCapture(0.0); + ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, true, &ignored)); + } + + // Basic pipelined scenario: More than one frame in-flight at delivery points. + for (int i = 0; i < 50; ++i) { + const int num_in_flight = 1 + i % 3; + for (int j = 0; j < num_in_flight; ++j) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + last_frame_number = oracle.RecordCapture(0.0); + } + for (int j = num_in_flight - 1; j >= 0; --j) { + ASSERT_TRUE( + oracle.CompleteCapture(last_frame_number - j, true, &ignored)); + } + } + + // Pipelined scenario with successful out-of-order delivery attempts + // rejected. + for (int i = 0; i < 50; ++i) { + const int num_in_flight = 1 + i % 3; + for (int j = 0; j < num_in_flight; ++j) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + 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) { + ASSERT_FALSE( + oracle.CompleteCapture(last_frame_number - j, true, &ignored)); + } + } + + // Pipelined scenario with successful delivery attempts accepted after an + // unsuccessful out of order delivery attempt. + for (int i = 0; i < 50; ++i) { + const int num_in_flight = 1 + i % 3; + for (int j = 0; j < num_in_flight; ++j) { + t += event_increment; + ASSERT_TRUE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, damage_rect, t)); + 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)); + for (int j = 1; j < num_in_flight - 1; ++j) { + ASSERT_TRUE( + oracle.CompleteCapture(last_frame_number - j, true, &ignored)); + } + } +} + +// Tests that VideoCaptureOracle transitions between using its two samplers in a +// way that does not introduce severe jank, pauses, etc. +TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) { + const gfx::Rect animation_damage_rect(Get720pSize()); + const base::TimeDelta event_increment = Get30HzPeriod() * 2; + + 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 + // frame timestamps won't trip-up downstream consumers. + base::TimeTicks t = InitialTestTimeTicks(); + base::TimeTicks last_frame_timestamp; + for (int i = 0; i < 1000; ++i) { + t += event_increment; + + // For every 100 events, provide 50 that will cause the + // AnimatedContentSampler to lock-in, followed by 50 that will cause it to + // lock-out (i.e., the oracle will use the SmoothEventSampler instead). + const bool provide_animated_content_event = + (i % 100) >= 25 && (i % 100) < 75; + + // Only the few events that trigger the lock-out transition should be + // dropped, because the AnimatedContentSampler doesn't yet realize the + // animation ended. Otherwise, the oracle should always decide to sample + // because one of its samplers says to. + const bool require_oracle_says_sample = (i % 100) < 75 || (i % 100) >= 78; + const bool oracle_says_sample = oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, + provide_animated_content_event ? animation_damage_rect : gfx::Rect(), + t); + if (require_oracle_says_sample) + ASSERT_TRUE(oracle_says_sample); + if (!oracle_says_sample) { + ASSERT_EQ(base::TimeDelta(), oracle.estimated_frame_duration()); + continue; + } + ASSERT_LT(base::TimeDelta(), oracle.estimated_frame_duration()); + + const int frame_number = oracle.RecordCapture(0.0); + + base::TimeTicks frame_timestamp; + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &frame_timestamp)); + ASSERT_FALSE(frame_timestamp.is_null()); + if (!last_frame_timestamp.is_null()) { + const base::TimeDelta delta = frame_timestamp - last_frame_timestamp; + EXPECT_LE(event_increment.InMicroseconds(), delta.InMicroseconds()); + // Right after the AnimatedContentSampler lock-out transition, there were + // a few frames dropped, so allow a gap in the timestamps. Otherwise, the + // delta between frame timestamps should never be more than 2X the + // |event_increment|. + const base::TimeDelta max_acceptable_delta = + (i % 100) == 78 ? event_increment * 5 : event_increment * 2; + EXPECT_GE(max_acceptable_delta.InMicroseconds(), delta.InMicroseconds()); + } + last_frame_timestamp = frame_timestamp; + } +} + +// Tests that VideoCaptureOracle prevents timer polling from initiating +// simultaneous captures. +TEST(VideoCaptureOracleTest, SamplesOnlyOneOverdueFrameAtATime) { + const base::TimeDelta vsync_interval = base::TimeDelta::FromSeconds(1) / 60; + const base::TimeDelta timer_interval = base::TimeDelta::FromMilliseconds( + VideoCaptureOracle::kMinTimerPollPeriodMillis); + + VideoCaptureOracle oracle(Get30HzPeriod(), Get720pSize(), + media::RESOLUTION_POLICY_FIXED_RESOLUTION, false); + + // Have the oracle observe some compositor events. Simulate that each capture + // completes successfully. + base::TimeTicks t = InitialTestTimeTicks(); + base::TimeTicks ignored; + bool did_complete_a_capture = false; + for (int i = 0; i < 10; ++i) { + t += vsync_interval; + if (oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t)) { + ASSERT_TRUE( + oracle.CompleteCapture(oracle.RecordCapture(0.0), true, &ignored)); + did_complete_a_capture = true; + } + } + ASSERT_TRUE(did_complete_a_capture); + + // Start one more compositor-based capture, but do not notify of completion + // yet. + for (int i = 0; i <= 10; ++i) { + ASSERT_GT(10, i) << "BUG: Seems like it'll never happen!"; + t += vsync_interval; + if (oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t)) { + break; + } + } + 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 + // not-yet-complete compositor-based capture. + for (int i = 0; i < 10; ++i) { + t += timer_interval; + ASSERT_FALSE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kTimerPoll, gfx::Rect(), t)); + } + + // Now, complete the oustanding compositor-based capture and continue + // providing timer polling events. The oracle should start recommending + // sampling again. + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + did_complete_a_capture = false; + for (int i = 0; i < 10; ++i) { + t += timer_interval; + if (oracle.ObserveEventAndDecideCapture(VideoCaptureOracle::kTimerPoll, + gfx::Rect(), t)) { + ASSERT_TRUE( + oracle.CompleteCapture(oracle.RecordCapture(0.0), true, &ignored)); + did_complete_a_capture = true; + } + } + ASSERT_TRUE(did_complete_a_capture); + + // Start one more timer-based capture, but do not notify of completion yet. + for (int i = 0; i <= 10; ++i) { + ASSERT_GT(10, i) << "BUG: Seems like it'll never happen!"; + t += timer_interval; + if (oracle.ObserveEventAndDecideCapture(VideoCaptureOracle::kTimerPoll, + gfx::Rect(), t)) { + break; + } + } + frame_number = oracle.RecordCapture(0.0); + + // Confirm that the oracle does not recommend sampling until the outstanding + // timer-based capture completes. + for (int i = 0; i < 10; ++i) { + t += timer_interval; + ASSERT_FALSE(oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kTimerPoll, gfx::Rect(), t)); + } + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + for (int i = 0; i <= 10; ++i) { + ASSERT_GT(10, i) << "BUG: Seems like it'll never happen!"; + t += timer_interval; + if (oracle.ObserveEventAndDecideCapture(VideoCaptureOracle::kTimerPoll, + gfx::Rect(), t)) { + break; + } + } +} + +// 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, while content is animating, VideoCaptureOracle can make frequent +// capture size increases only just after the source size has changed. +// Otherwise, capture size increases should only be made cautiously, after a +// long "proving period of under-utilization" has elapsed. +TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) { + VideoCaptureOracle oracle(Get30HzPeriod(), Get720pSize(), + media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT, true); + + // Start out the source size at 360p, so there is room to grow to the 720p + // maximum. + oracle.SetSourceSize(Get360pSize()); + + // Run 10 seconds of frame captures with under-utilization to represent a + // machine that can do more, but won't because the source size is small. + 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) { + if (!oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get360pSize()), + t)) { + continue; + } + ASSERT_EQ(Get360pSize(), oracle.capture_size()); + const int frame_number = oracle.RecordCapture(0.25); + base::TimeTicks ignored; + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + } + + // Now, set the source size to 720p, continuing to report under-utilization, + // and expect the capture size increases to reach a full 720p within 15 + // seconds. + oracle.SetSourceSize(Get720pSize()); + gfx::Size last_capture_size = oracle.capture_size(); + end_t = t + base::TimeDelta::FromSeconds(15); + for (; t < end_t; t += event_increment) { + if (!oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get720pSize()), + t)) { + continue; + } + ASSERT_LE(last_capture_size.width(), oracle.capture_size().width()); + ASSERT_LE(last_capture_size.height(), oracle.capture_size().height()); + last_capture_size = oracle.capture_size(); + const int frame_number = oracle.RecordCapture(0.25); + base::TimeTicks ignored; + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + } + ASSERT_EQ(Get720pSize(), oracle.capture_size()); + + // Now, change the source size again, but report over-utilization so the + // capture size will decrease. Once it decreases one step, report 90% + // utilization to achieve a steady-state. + oracle.SetSourceSize(Get1080pSize()); + gfx::Size stepped_down_size; + end_t = t + base::TimeDelta::FromSeconds(10); + for (; t < end_t; t += event_increment) { + if (!oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get1080pSize()), + t)) { + continue; + } + + if (stepped_down_size.IsEmpty()) { + if (oracle.capture_size() != Get720pSize()) { + stepped_down_size = oracle.capture_size(); + ASSERT_GT(Get720pSize().width(), stepped_down_size.width()); + ASSERT_GT(Get720pSize().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(utilization); + base::TimeTicks ignored; + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + } + ASSERT_FALSE(stepped_down_size.IsEmpty()); + + // Now, if we report under-utilization again (without any source size change), + // there should be a long "proving period" before there is any increase in + // capture size made by the oracle. + const base::TimeTicks proving_period_end_time = + t + base::TimeDelta::FromSeconds(15); + gfx::Size stepped_up_size; + end_t = t + base::TimeDelta::FromSeconds(60); + for (; t < end_t; t += event_increment) { + if (!oracle.ObserveEventAndDecideCapture( + VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get1080pSize()), + t)) { + continue; + } + + if (stepped_up_size.IsEmpty()) { + if (oracle.capture_size() != stepped_down_size) { + ASSERT_LT(proving_period_end_time, t); + stepped_up_size = oracle.capture_size(); + ASSERT_LT(stepped_down_size.width(), stepped_up_size.width()); + ASSERT_LT(stepped_down_size.height(), stepped_up_size.height()); + } + } else { + ASSERT_EQ(stepped_up_size, oracle.capture_size()); + } + + const double utilization = stepped_up_size.IsEmpty() ? 0.25 : 0.9; + const int frame_number = oracle.RecordCapture(utilization); + base::TimeTicks ignored; + ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored)); + } + ASSERT_FALSE(stepped_up_size.IsEmpty()); +} + +// 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 |