Index: content/browser/media/capture/animated_content_sampler_unittest.cc |
diff --git a/content/browser/media/capture/video_capture_oracle_unittest.cc b/content/browser/media/capture/animated_content_sampler_unittest.cc |
similarity index 49% |
copy from content/browser/media/capture/video_capture_oracle_unittest.cc |
copy to content/browser/media/capture/animated_content_sampler_unittest.cc |
index 630e081bec37ec043b76a3d4783ab967aa7f4d43..a1017370ce892d4e6ef72159d676b055b0770132 100644 |
--- a/content/browser/media/capture/video_capture_oracle_unittest.cc |
+++ b/content/browser/media/capture/animated_content_sampler_unittest.cc |
@@ -1,444 +1,29 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// 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 "content/browser/media/capture/video_capture_oracle.h" |
+#include "content/browser/media/capture/animated_content_sampler.h" |
#include <cstdlib> |
#include <utility> |
#include <vector> |
#include "base/logging.h" |
-#include "base/strings/stringprintf.h" |
+#include "base/memory/scoped_ptr.h" |
#include "base/time/time.h" |
#include "testing/gtest/include/gtest/gtest.h" |
#include "ui/gfx/geometry/rect.h" |
namespace content { |
-namespace { |
- |
-bool AddEventAndConsiderSampling(SmoothEventSampler* sampler, |
- base::TimeTicks event_time) { |
- sampler->ConsiderPresentationEvent(event_time); |
- return sampler->ShouldSample(); |
-} |
-void SteadyStateSampleAndAdvance(base::TimeDelta vsync, |
- SmoothEventSampler* sampler, |
- base::TimeTicks* t) { |
- ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t)); |
- ASSERT_TRUE(sampler->HasUnrecordedEvent()); |
- sampler->RecordSample(); |
- ASSERT_FALSE(sampler->HasUnrecordedEvent()); |
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); |
- *t += vsync; |
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); |
-} |
- |
-void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync, |
- SmoothEventSampler* sampler, |
- base::TimeTicks* t) { |
- ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t)); |
- ASSERT_TRUE(sampler->HasUnrecordedEvent()); |
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); |
- *t += vsync; |
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); |
-} |
+namespace { |
base::TimeTicks InitialTestTimeTicks() { |
return base::TimeTicks() + base::TimeDelta::FromSeconds(1); |
} |
-void TestRedundantCaptureStrategy(base::TimeDelta capture_period, |
- int redundant_capture_goal, |
- SmoothEventSampler* sampler, |
- base::TimeTicks* t) { |
- // Before any events have been considered, we're overdue for sampling. |
- ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)); |
- |
- // Consider the first event. We want to sample that. |
- ASSERT_FALSE(sampler->HasUnrecordedEvent()); |
- ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t)); |
- ASSERT_TRUE(sampler->HasUnrecordedEvent()); |
- sampler->RecordSample(); |
- ASSERT_FALSE(sampler->HasUnrecordedEvent()); |
- |
- // After more than 250 ms has passed without considering an event, we should |
- // repeatedly be overdue for sampling. However, once the redundant capture |
- // goal is achieved, we should no longer be overdue for sampling. |
- *t += base::TimeDelta::FromMilliseconds(250); |
- for (int i = 0; i < redundant_capture_goal; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_FALSE(sampler->HasUnrecordedEvent()); |
- ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)) |
- << "Should sample until redundant capture goal is hit"; |
- sampler->RecordSample(); |
- *t += capture_period; // Timer fires once every capture period. |
- } |
- ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)) |
- << "Should not be overdue once redundant capture goal achieved."; |
-} |
- |
} // namespace |
-// 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains |
-// much more comprehensive before/after/edge-case scenarios than the others. |
-TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const int redundant_capture_goal = 200; |
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; |
- |
- SmoothEventSampler sampler(capture_period, redundant_capture_goal); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, |
- &sampler, &t); |
- |
- // Steady state, we should capture every other vsync, indefinitely. |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
- |
- // Now pretend we're limited by backpressure in the pipeline. In this scenario |
- // case we are adding events but not sampling them. |
- for (int i = 0; i < 20; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t)); |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- ASSERT_TRUE(sampler.HasUnrecordedEvent()); |
- t += vsync; |
- } |
- |
- // Now suppose we can sample again. We should be back in the steady state, |
- // but at a different phase. |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
-} |
- |
-// 50Hz sampled at 30Hz should produce a sequence where some frames are skipped. |
-TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const int redundant_capture_goal = 2; |
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50; |
- |
- SmoothEventSampler sampler(capture_period, redundant_capture_goal); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, |
- &sampler, &t); |
- |
- // Steady state, we should capture 1st, 2nd and 4th frames out of every five |
- // frames, indefinitely. |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
- |
- // Now pretend we're limited by backpressure in the pipeline. In this scenario |
- // case we are adding events but not sampling them. |
- for (int i = 0; i < 20; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t)); |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- t += vsync; |
- } |
- |
- // Now suppose we can sample again. We should be back in the steady state |
- // again. |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
-} |
- |
-// 75Hz sampled at 30Hz should produce a sequence where some frames are skipped. |
-TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const int redundant_capture_goal = 32; |
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75; |
- |
- SmoothEventSampler sampler(capture_period, redundant_capture_goal); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, |
- &sampler, &t); |
- |
- // Steady state, we should capture 1st and 3rd frames out of every five |
- // frames, indefinitely. |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
- |
- // Now pretend we're limited by backpressure in the pipeline. In this scenario |
- // case we are adding events but not sampling them. |
- for (int i = 0; i < 20; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t)); |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- t += vsync; |
- } |
- |
- // Now suppose we can sample again. We capture the next frame, and not the one |
- // after that, and then we're back in the steady state again. |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
- } |
-} |
- |
-// 30Hz sampled at 30Hz should produce 30Hz. |
-TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const int redundant_capture_goal = 1; |
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30; |
- |
- SmoothEventSampler sampler(capture_period, redundant_capture_goal); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, |
- &sampler, &t); |
- |
- // Steady state, we should capture every vsync, indefinitely. |
- for (int i = 0; i < 200; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- } |
- |
- // Now pretend we're limited by backpressure in the pipeline. In this scenario |
- // case we are adding events but not sampling them. |
- for (int i = 0; i < 10; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t)); |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- t += vsync; |
- } |
- |
- // Now suppose we can sample again. We should be back in the steady state. |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- } |
-} |
- |
-// 24Hz sampled at 30Hz should produce 24Hz. |
-TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const int redundant_capture_goal = 333; |
- const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24; |
- |
- SmoothEventSampler sampler(capture_period, redundant_capture_goal); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, |
- &sampler, &t); |
- |
- // Steady state, we should capture every vsync, indefinitely. |
- for (int i = 0; i < 200; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- } |
- |
- // Now pretend we're limited by backpressure in the pipeline. In this scenario |
- // case we are adding events but not sampling them. |
- for (int i = 0; i < 10; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t)); |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- t += vsync; |
- } |
- |
- // Now suppose we can sample again. We should be back in the steady state. |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); |
- for (int i = 0; i < 100; i++) { |
- SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
- SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
- } |
-} |
- |
-TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) { |
- const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
- const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1); |
- |
- SmoothEventSampler sampler(capture_period, 1); |
- base::TimeTicks t = InitialTestTimeTicks(); |
- |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- sampler.RecordSample(); |
- ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t)) |
- << "Sampled last event; should not be dirty."; |
- t += overdue_period; |
- |
- // Now simulate 2 events with the same clock value. |
- ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
- sampler.RecordSample(); |
- ASSERT_FALSE(AddEventAndConsiderSampling(&sampler, t)) |
- << "Two events at same time -- expected second not to be sampled."; |
- ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period)) |
- << "Second event should dirty the capture state."; |
- sampler.RecordSample(); |
- ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period)); |
-} |
- |
-namespace { |
- |
-struct DataPoint { |
- bool should_capture; |
- double increment_ms; |
-}; |
- |
-void ReplayCheckingSamplerDecisions(const DataPoint* data_points, |
- size_t num_data_points, |
- SmoothEventSampler* sampler) { |
- base::TimeTicks t = InitialTestTimeTicks(); |
- for (size_t i = 0; i < num_data_points; ++i) { |
- t += base::TimeDelta::FromMicroseconds( |
- static_cast<int64>(data_points[i].increment_ms * 1000)); |
- ASSERT_EQ(data_points[i].should_capture, |
- AddEventAndConsiderSampling(sampler, t)) |
- << "at data_points[" << i << ']'; |
- if (data_points[i].should_capture) |
- sampler->RecordSample(); |
- } |
-} |
- |
-} // namespace |
- |
-TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) { |
- // Actual capturing of timing data: Initial instability as a 24 FPS video was |
- // started from a still screen, then clearly followed by steady-state. |
- static const DataPoint data_points[] = { |
- { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 }, |
- { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 }, |
- { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 }, |
- { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 }, |
- { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 }, |
- { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 }, |
- { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 }, |
- { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 }, |
- { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 }, |
- { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 }, |
- { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 }, |
- { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 }, |
- { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 }, |
- { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 }, |
- { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 }, |
- { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 }, |
- { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 } |
- }; |
- |
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); |
- ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
-} |
- |
-TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) { |
- // Actual capturing of timing data: Initial instability as a 30 FPS video was |
- // started from a still screen, then followed by steady-state. Drawing |
- // framerate from the video rendering was a bit volatile, but averaged 30 FPS. |
- static const DataPoint data_points[] = { |
- { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 }, |
- { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, |
- { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, |
- { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 }, |
- { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 }, |
- { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 }, |
- { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 }, |
- { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 }, |
- { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 }, |
- { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 }, |
- { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 }, |
- { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 }, |
- { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, |
- { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 }, |
- { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 }, |
- { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 }, |
- { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 }, |
- { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 }, |
- { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 }, |
- { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 } |
- }; |
- |
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); |
- ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
-} |
- |
-TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) { |
- // Actual capturing of timing data: WebGL Acquarium demo |
- // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran |
- // between 55-60 FPS in the steady-state. |
- static const DataPoint data_points[] = { |
- { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 }, |
- { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 }, |
- { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 }, |
- { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 }, |
- { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 }, |
- { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, |
- { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 }, |
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 }, |
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 }, |
- { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 }, |
- { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 }, |
- { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 }, |
- { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 }, |
- { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 }, |
- { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, |
- { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, |
- { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 }, |
- { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 }, |
- { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 }, |
- { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 }, |
- { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 }, |
- { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 }, |
- { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 }, |
- { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 }, |
- { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 }, |
- { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }, |
- { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 } |
- }; |
- |
- SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); |
- ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
-} |
- |
class AnimatedContentSamplerTest : public ::testing::Test { |
public: |
AnimatedContentSamplerTest() {} |
@@ -1053,154 +638,4 @@ INSTANTIATE_TEST_CASE_P( |
Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(32)), |
Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(33)))); |
-// 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; |
- |
- VideoCaptureOracle oracle(min_capture_period); |
- |
- 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 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; |
- |
- VideoCaptureOracle oracle(min_capture_period); |
- |
- // 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(); |
- ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &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(); |
- } |
- for (int j = num_in_flight - 1; j >= 0; --j) { |
- ASSERT_TRUE(oracle.CompleteCapture(last_frame_number - j, &ignored)); |
- } |
- } |
- |
- // Pipelined scenario with 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(); |
- } |
- ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &ignored)); |
- for (int j = 1; j < num_in_flight; ++j) { |
- ASSERT_FALSE(oracle.CompleteCapture(last_frame_number - j, &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 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; |
- |
- VideoCaptureOracle oracle(min_capture_period); |
- |
- // 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) |
- continue; |
- |
- const int frame_number = oracle.RecordCapture(); |
- |
- base::TimeTicks frame_timestamp; |
- ASSERT_TRUE(oracle.CompleteCapture(frame_number, &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; |
- } |
-} |
- |
} // namespace content |