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