Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/media/video_capture_oracle.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "base/time/time.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace content {
     12 namespace {
     13 
     14 void SteadyStateSampleAndAdvance(base::TimeDelta vsync,
     15                                  SmoothEventSampler* sampler, base::Time* t) {
     16   ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
     17   ASSERT_TRUE(sampler->HasUnrecordedEvent());
     18   sampler->RecordSample();
     19   ASSERT_FALSE(sampler->HasUnrecordedEvent());
     20   ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
     21   *t += vsync;
     22   ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
     23 }
     24 
     25 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
     26                                    SmoothEventSampler* sampler, base::Time* t) {
     27   ASSERT_FALSE(sampler->AddEventAndConsiderSampling(*t));
     28   ASSERT_TRUE(sampler->HasUnrecordedEvent());
     29   ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
     30   *t += vsync;
     31   ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
     32 }
     33 
     34 void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
     35                                   int redundant_capture_goal,
     36                                   SmoothEventSampler* sampler, base::Time* t) {
     37   // Before any events have been considered, we're overdue for sampling.
     38   ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t));
     39 
     40   // Consider the first event.  We want to sample that.
     41   ASSERT_FALSE(sampler->HasUnrecordedEvent());
     42   ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
     43   ASSERT_TRUE(sampler->HasUnrecordedEvent());
     44   sampler->RecordSample();
     45   ASSERT_FALSE(sampler->HasUnrecordedEvent());
     46 
     47   // After more than one capture period has passed without considering an event,
     48   // we should repeatedly be overdue for sampling.  However, once the redundant
     49   // capture goal is achieved, we should no longer be overdue for sampling.
     50   *t += capture_period * 4;
     51   for (int i = 0; i < redundant_capture_goal; i++) {
     52     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
     53     ASSERT_FALSE(sampler->HasUnrecordedEvent());
     54     ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t))
     55         << "Should sample until redundant capture goal is hit";
     56     sampler->RecordSample();
     57     *t += capture_period;  // Timer fires once every capture period.
     58   }
     59   ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t))
     60       << "Should not be overdue once redundant capture goal achieved.";
     61 }
     62 
     63 // 60Hz sampled at 30Hz should produce 30Hz.  In addition, this test contains
     64 // much more comprehensive before/after/edge-case scenarios than the others.
     65 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
     66   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
     67   const int redundant_capture_goal = 200;
     68   const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
     69 
     70   SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
     71   base::Time t;
     72   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
     73 
     74   TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
     75                                &sampler, &t);
     76 
     77   // Steady state, we should capture every other vsync, indefinitely.
     78   for (int i = 0; i < 100; i++) {
     79     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
     80     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
     81     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
     82   }
     83 
     84   // Now pretend we're limited by backpressure in the pipeline. In this scenario
     85   // case we are adding events but not sampling them.
     86   for (int i = 0; i < 20; i++) {
     87     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
     88     ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
     89     ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
     90     ASSERT_TRUE(sampler.HasUnrecordedEvent());
     91     t += vsync;
     92   }
     93 
     94   // Now suppose we can sample again. We should be back in the steady state,
     95   // but at a different phase.
     96   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
     97   for (int i = 0; i < 100; i++) {
     98     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
     99     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    100     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    101   }
    102 }
    103 
    104 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped.
    105 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
    106   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
    107   const int redundant_capture_goal = 2;
    108   const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
    109 
    110   SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
    111   base::Time t;
    112   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    113 
    114   TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
    115                                &sampler, &t);
    116 
    117   // Steady state, we should capture 1st, 2nd and 4th frames out of every five
    118   // frames, indefinitely.
    119   for (int i = 0; i < 100; i++) {
    120     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    121     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    122     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    123     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    124     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    125     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    126   }
    127 
    128   // Now pretend we're limited by backpressure in the pipeline. In this scenario
    129   // case we are adding events but not sampling them.
    130   for (int i = 0; i < 12; i++) {
    131     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    132     ASSERT_EQ(i >= 5, sampler.IsOverdueForSamplingAt(t));
    133     ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    134     t += vsync;
    135   }
    136 
    137   // Now suppose we can sample again. We should be back in the steady state
    138   // again.
    139   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
    140   for (int i = 0; i < 100; i++) {
    141     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    142     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    143     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    144     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    145     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    146     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    147   }
    148 }
    149 
    150 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped.
    151 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
    152   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
    153   const int redundant_capture_goal = 32;
    154   const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
    155 
    156   SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
    157   base::Time t;
    158   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    159 
    160   TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
    161                                &sampler, &t);
    162 
    163   // Steady state, we should capture 1st and 3rd frames out of every five
    164   // frames, indefinitely.
    165   SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    166   SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    167   for (int i = 0; i < 100; i++) {
    168     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    169     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    170     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    171     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    172     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    173     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    174   }
    175 
    176   // Now pretend we're limited by backpressure in the pipeline. In this scenario
    177   // case we are adding events but not sampling them.
    178   for (int i = 0; i < 20; i++) {
    179     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    180     ASSERT_EQ(i >= 8, sampler.IsOverdueForSamplingAt(t));
    181     ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    182     t += vsync;
    183   }
    184 
    185   // Now suppose we can sample again. We capture the next frame, and not the one
    186   // after that, and then we're back in the steady state again.
    187   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
    188   SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    189   SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    190   for (int i = 0; i < 100; i++) {
    191     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    192     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    193     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    194     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    195     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    196     SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
    197   }
    198 }
    199 
    200 // 30Hz sampled at 30Hz should produce 30Hz.
    201 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
    202   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
    203   const int redundant_capture_goal = 1;
    204   const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
    205 
    206   SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
    207   base::Time t;
    208   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    209 
    210   TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
    211                                &sampler, &t);
    212 
    213   // Steady state, we should capture every vsync, indefinitely.
    214   for (int i = 0; i < 200; i++) {
    215     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    216     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    217   }
    218 
    219   // Now pretend we're limited by backpressure in the pipeline. In this scenario
    220   // case we are adding events but not sampling them.
    221   for (int i = 0; i < 7; i++) {
    222     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    223     ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
    224     ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    225     t += vsync;
    226   }
    227 
    228   // Now suppose we can sample again. We should be back in the steady state.
    229   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
    230   for (int i = 0; i < 100; i++) {
    231     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    232     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    233   }
    234 }
    235 
    236 // 24Hz sampled at 30Hz should produce 24Hz.
    237 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
    238   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
    239   const int redundant_capture_goal = 333;
    240   const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
    241 
    242   SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
    243   base::Time t;
    244   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    245 
    246   TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
    247                                &sampler, &t);
    248 
    249   // Steady state, we should capture every vsync, indefinitely.
    250   for (int i = 0; i < 200; i++) {
    251     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    252     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    253   }
    254 
    255   // Now pretend we're limited by backpressure in the pipeline. In this scenario
    256   // case we are adding events but not sampling them.
    257   for (int i = 0; i < 7; i++) {
    258     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    259     ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
    260     ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    261     t += vsync;
    262   }
    263 
    264   // Now suppose we can sample again. We should be back in the steady state.
    265   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
    266   for (int i = 0; i < 100; i++) {
    267     SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
    268     SteadyStateSampleAndAdvance(vsync, &sampler, &t);
    269   }
    270 }
    271 
    272 TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
    273   const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
    274   const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
    275 
    276   SmoothEventSampler sampler(capture_period, true, 1);
    277   base::Time t;
    278   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    279 
    280   ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    281   sampler.RecordSample();
    282   ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t))
    283       << "Sampled last event; should not be dirty.";
    284   t += overdue_period;
    285 
    286   // Now simulate 2 events with the same clock value.
    287   ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
    288   sampler.RecordSample();
    289   ASSERT_FALSE(sampler.AddEventAndConsiderSampling(t))
    290       << "Two events at same time -- expected second not to be sampled.";
    291   ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period))
    292       << "Second event should dirty the capture state.";
    293   sampler.RecordSample();
    294   ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period));
    295 }
    296 
    297 TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
    298   const base::TimeDelta timer_interval = base::TimeDelta::FromSeconds(1) / 30;
    299 
    300   SmoothEventSampler should_not_poll(timer_interval, true, 1);
    301   SmoothEventSampler should_poll(timer_interval, false, 1);
    302   base::Time t;
    303   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    304 
    305   // Do one round of the "happy case" where an event was received and
    306   // RecordSample() was called by the client.
    307   ASSERT_TRUE(should_not_poll.AddEventAndConsiderSampling(t));
    308   ASSERT_TRUE(should_poll.AddEventAndConsiderSampling(t));
    309   should_not_poll.RecordSample();
    310   should_poll.RecordSample();
    311 
    312   // One time period ahead, neither sampler says we're overdue.
    313   for (int i = 0; i < 3; i++) {
    314     t += timer_interval;
    315     ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
    316         << "Sampled last event; should not be dirty.";
    317     ASSERT_FALSE(should_poll.IsOverdueForSamplingAt(t))
    318         << "Dirty interval has not elapsed yet.";
    319   }
    320 
    321   // Next time period ahead, both samplers say we're overdue.  The non-polling
    322   // sampler is returning true here because it has been configured to allow one
    323   // redundant capture.
    324   t += timer_interval;
    325   ASSERT_TRUE(should_not_poll.IsOverdueForSamplingAt(t))
    326       << "Sampled last event; is dirty one time only to meet redundancy goal.";
    327   ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
    328       << "If updates are unreliable, must fall back to polling when idle.";
    329   should_not_poll.RecordSample();
    330   should_poll.RecordSample();
    331 
    332   // Forever more, the non-polling sampler returns false while the polling one
    333   // returns true.
    334   for (int i = 0; i < 100; ++i) {
    335     t += timer_interval;
    336     ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
    337         << "Sampled last event; should not be dirty.";
    338     ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
    339         << "If updates are unreliable, must fall back to polling when idle.";
    340     should_poll.RecordSample();
    341   }
    342   t += timer_interval / 3;
    343   ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
    344       << "Sampled last event; should not be dirty.";
    345   ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
    346       << "If updates are unreliable, must fall back to polling when idle.";
    347   should_poll.RecordSample();
    348 }
    349 
    350 struct DataPoint {
    351   bool should_capture;
    352   double increment_ms;
    353 };
    354 
    355 void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
    356                                     size_t num_data_points,
    357                                     SmoothEventSampler* sampler) {
    358   base::Time t;
    359   ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
    360   for (size_t i = 0; i < num_data_points; ++i) {
    361     t += base::TimeDelta::FromMicroseconds(
    362         static_cast<int64>(data_points[i].increment_ms * 1000));
    363     ASSERT_EQ(data_points[i].should_capture,
    364               sampler->AddEventAndConsiderSampling(t))
    365         << "at data_points[" << i << ']';
    366     if (data_points[i].should_capture)
    367       sampler->RecordSample();
    368   }
    369 }
    370 
    371 TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) {
    372   // Actual capturing of timing data: Initial instability as a 24 FPS video was
    373   // started from a still screen, then clearly followed by steady-state.
    374   static const DataPoint data_points[] = {
    375     { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 },
    376     { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 },
    377     { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 },
    378     { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 },
    379     { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 },
    380     { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 },
    381     { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 },
    382     { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 },
    383     { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 },
    384     { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 },
    385     { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 },
    386     { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 },
    387     { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 },
    388     { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 },
    389     { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 },
    390     { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
    391     { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
    392     { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }
    393   };
    394 
    395   SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
    396   ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
    397 }
    398 
    399 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) {
    400   // Actual capturing of timing data: Initial instability as a 30 FPS video was
    401   // started from a still screen, then followed by steady-state.  Drawing
    402   // framerate from the video rendering was a bit volatile, but averaged 30 FPS.
    403   static const DataPoint data_points[] = {
    404     { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 },
    405     { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 },
    406     { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 },
    407     { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 },
    408     { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 },
    409     { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 },
    410     { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 },
    411     { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 },
    412     { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 },
    413     { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 },
    414     { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 },
    415     { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 },
    416     { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 },
    417     { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 },
    418     { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
    419     { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 },
    420     { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
    421     { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
    422     { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 },
    423     { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 },
    424     { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
    425     { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 },
    426     { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 },
    427     { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 },
    428     { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }
    429   };
    430 
    431   SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
    432   ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
    433 }
    434 
    435 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
    436   // Actual capturing of timing data: WebGL Acquarium demo
    437   // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran
    438   // between 55-60 FPS in the steady-state.
    439   static const DataPoint data_points[] = {
    440     { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 },
    441     { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 },
    442     { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 },
    443     { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 },
    444     { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 },
    445     { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
    446     { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
    447     { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
    448     { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
    449     { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
    450     { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
    451     { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 },
    452     { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 },
    453     { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
    454     { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
    455     { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 },
    456     { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
    457     { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
    458     { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
    459     { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
    460     { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 },
    461     { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 },
    462     { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
    463     { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 },
    464     { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 },
    465     { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 },
    466     { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 },
    467     { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
    468     { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 },
    469     { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 },
    470     { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 }
    471   };
    472 
    473   SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
    474   ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
    475 }
    476 
    477 }  // namespace
    478 }  // namespace content
    479