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