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