Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1772)

Side by Side Diff: content/browser/media/capture/animated_content_sampler_unittest.cc

Issue 1109603003: Clean-up: Break sampler classes into their own files. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/media/capture/video_capture_oracle.h" 5 #include "content/browser/media/capture/animated_content_sampler.h"
6 6
7 #include <cstdlib> 7 #include <cstdlib>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/time/time.h" 13 #include "base/time/time.h"
14 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gfx/geometry/rect.h" 15 #include "ui/gfx/geometry/rect.h"
16 16
17 namespace content { 17 namespace content {
18
18 namespace { 19 namespace {
19 20
20 bool AddEventAndConsiderSampling(SmoothEventSampler* sampler,
21 base::TimeTicks event_time) {
22 sampler->ConsiderPresentationEvent(event_time);
23 return sampler->ShouldSample();
24 }
25
26 void SteadyStateSampleAndAdvance(base::TimeDelta vsync,
27 SmoothEventSampler* sampler,
28 base::TimeTicks* t) {
29 ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
30 ASSERT_TRUE(sampler->HasUnrecordedEvent());
31 sampler->RecordSample();
32 ASSERT_FALSE(sampler->HasUnrecordedEvent());
33 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
34 *t += vsync;
35 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
36 }
37
38 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
39 SmoothEventSampler* sampler,
40 base::TimeTicks* t) {
41 ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t));
42 ASSERT_TRUE(sampler->HasUnrecordedEvent());
43 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
44 *t += vsync;
45 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
46 }
47
48 base::TimeTicks InitialTestTimeTicks() { 21 base::TimeTicks InitialTestTimeTicks() {
49 return base::TimeTicks() + base::TimeDelta::FromSeconds(1); 22 return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
50 } 23 }
51 24
52 void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
53 int redundant_capture_goal,
54 SmoothEventSampler* sampler,
55 base::TimeTicks* t) {
56 // Before any events have been considered, we're overdue for sampling.
57 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t));
58
59 // Consider the first event. We want to sample that.
60 ASSERT_FALSE(sampler->HasUnrecordedEvent());
61 ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
62 ASSERT_TRUE(sampler->HasUnrecordedEvent());
63 sampler->RecordSample();
64 ASSERT_FALSE(sampler->HasUnrecordedEvent());
65
66 // After more than 250 ms has passed without considering an event, we should
67 // repeatedly be overdue for sampling. However, once the redundant capture
68 // goal is achieved, we should no longer be overdue for sampling.
69 *t += base::TimeDelta::FromMilliseconds(250);
70 for (int i = 0; i < redundant_capture_goal; i++) {
71 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
72 ASSERT_FALSE(sampler->HasUnrecordedEvent());
73 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t))
74 << "Should sample until redundant capture goal is hit";
75 sampler->RecordSample();
76 *t += capture_period; // Timer fires once every capture period.
77 }
78 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t))
79 << "Should not be overdue once redundant capture goal achieved.";
80 }
81
82 } // namespace 25 } // namespace
83 26
84 // 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains
85 // much more comprehensive before/after/edge-case scenarios than the others.
86 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
87 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
88 const int redundant_capture_goal = 200;
89 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
90
91 SmoothEventSampler sampler(capture_period, redundant_capture_goal);
92 base::TimeTicks t = InitialTestTimeTicks();
93
94 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
95 &sampler, &t);
96
97 // Steady state, we should capture every other vsync, indefinitely.
98 for (int i = 0; i < 100; i++) {
99 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
100 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
101 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
102 }
103
104 // Now pretend we're limited by backpressure in the pipeline. In this scenario
105 // case we are adding events but not sampling them.
106 for (int i = 0; i < 20; i++) {
107 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
108 ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t));
109 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
110 ASSERT_TRUE(sampler.HasUnrecordedEvent());
111 t += vsync;
112 }
113
114 // Now suppose we can sample again. We should be back in the steady state,
115 // but at a different phase.
116 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
117 for (int i = 0; i < 100; i++) {
118 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
119 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
120 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
121 }
122 }
123
124 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped.
125 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
126 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
127 const int redundant_capture_goal = 2;
128 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
129
130 SmoothEventSampler sampler(capture_period, redundant_capture_goal);
131 base::TimeTicks t = InitialTestTimeTicks();
132
133 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
134 &sampler, &t);
135
136 // Steady state, we should capture 1st, 2nd and 4th frames out of every five
137 // frames, indefinitely.
138 for (int i = 0; i < 100; i++) {
139 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
140 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
141 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
142 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
143 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
144 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
145 }
146
147 // Now pretend we're limited by backpressure in the pipeline. In this scenario
148 // case we are adding events but not sampling them.
149 for (int i = 0; i < 20; i++) {
150 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
151 ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t));
152 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
153 t += vsync;
154 }
155
156 // Now suppose we can sample again. We should be back in the steady state
157 // again.
158 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
159 for (int i = 0; i < 100; i++) {
160 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
161 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
162 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
163 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
164 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
165 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
166 }
167 }
168
169 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped.
170 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
171 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
172 const int redundant_capture_goal = 32;
173 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
174
175 SmoothEventSampler sampler(capture_period, redundant_capture_goal);
176 base::TimeTicks t = InitialTestTimeTicks();
177
178 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
179 &sampler, &t);
180
181 // Steady state, we should capture 1st and 3rd frames out of every five
182 // frames, indefinitely.
183 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
184 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
185 for (int i = 0; i < 100; i++) {
186 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
187 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
188 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
189 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
190 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
191 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
192 }
193
194 // Now pretend we're limited by backpressure in the pipeline. In this scenario
195 // case we are adding events but not sampling them.
196 for (int i = 0; i < 20; i++) {
197 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
198 ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t));
199 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
200 t += vsync;
201 }
202
203 // Now suppose we can sample again. We capture the next frame, and not the one
204 // after that, and then we're back in the steady state again.
205 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
206 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
207 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
208 for (int i = 0; i < 100; i++) {
209 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
210 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
211 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
212 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
213 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
214 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
215 }
216 }
217
218 // 30Hz sampled at 30Hz should produce 30Hz.
219 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
220 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
221 const int redundant_capture_goal = 1;
222 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
223
224 SmoothEventSampler sampler(capture_period, redundant_capture_goal);
225 base::TimeTicks t = InitialTestTimeTicks();
226
227 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
228 &sampler, &t);
229
230 // Steady state, we should capture every vsync, indefinitely.
231 for (int i = 0; i < 200; i++) {
232 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
233 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
234 }
235
236 // Now pretend we're limited by backpressure in the pipeline. In this scenario
237 // case we are adding events but not sampling them.
238 for (int i = 0; i < 10; i++) {
239 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
240 ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
241 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
242 t += vsync;
243 }
244
245 // Now suppose we can sample again. We should be back in the steady state.
246 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
247 for (int i = 0; i < 100; i++) {
248 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
249 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
250 }
251 }
252
253 // 24Hz sampled at 30Hz should produce 24Hz.
254 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
255 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
256 const int redundant_capture_goal = 333;
257 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
258
259 SmoothEventSampler sampler(capture_period, redundant_capture_goal);
260 base::TimeTicks t = InitialTestTimeTicks();
261
262 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
263 &sampler, &t);
264
265 // Steady state, we should capture every vsync, indefinitely.
266 for (int i = 0; i < 200; i++) {
267 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
268 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
269 }
270
271 // Now pretend we're limited by backpressure in the pipeline. In this scenario
272 // case we are adding events but not sampling them.
273 for (int i = 0; i < 10; i++) {
274 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
275 ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t));
276 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
277 t += vsync;
278 }
279
280 // Now suppose we can sample again. We should be back in the steady state.
281 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
282 for (int i = 0; i < 100; i++) {
283 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
284 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
285 }
286 }
287
288 TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
289 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
290 const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
291
292 SmoothEventSampler sampler(capture_period, 1);
293 base::TimeTicks t = InitialTestTimeTicks();
294
295 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
296 sampler.RecordSample();
297 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t))
298 << "Sampled last event; should not be dirty.";
299 t += overdue_period;
300
301 // Now simulate 2 events with the same clock value.
302 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
303 sampler.RecordSample();
304 ASSERT_FALSE(AddEventAndConsiderSampling(&sampler, t))
305 << "Two events at same time -- expected second not to be sampled.";
306 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period))
307 << "Second event should dirty the capture state.";
308 sampler.RecordSample();
309 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period));
310 }
311
312 namespace {
313
314 struct DataPoint {
315 bool should_capture;
316 double increment_ms;
317 };
318
319 void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
320 size_t num_data_points,
321 SmoothEventSampler* sampler) {
322 base::TimeTicks t = InitialTestTimeTicks();
323 for (size_t i = 0; i < num_data_points; ++i) {
324 t += base::TimeDelta::FromMicroseconds(
325 static_cast<int64>(data_points[i].increment_ms * 1000));
326 ASSERT_EQ(data_points[i].should_capture,
327 AddEventAndConsiderSampling(sampler, t))
328 << "at data_points[" << i << ']';
329 if (data_points[i].should_capture)
330 sampler->RecordSample();
331 }
332 }
333
334 } // namespace
335
336 TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) {
337 // Actual capturing of timing data: Initial instability as a 24 FPS video was
338 // started from a still screen, then clearly followed by steady-state.
339 static const DataPoint data_points[] = {
340 { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 },
341 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 },
342 { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 },
343 { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 },
344 { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 },
345 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 },
346 { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 },
347 { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 },
348 { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 },
349 { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 },
350 { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 },
351 { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 },
352 { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 },
353 { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 },
354 { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 },
355 { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
356 { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
357 { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }
358 };
359
360 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
361 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
362 }
363
364 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) {
365 // Actual capturing of timing data: Initial instability as a 30 FPS video was
366 // started from a still screen, then followed by steady-state. Drawing
367 // framerate from the video rendering was a bit volatile, but averaged 30 FPS.
368 static const DataPoint data_points[] = {
369 { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 },
370 { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 },
371 { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 },
372 { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 },
373 { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 },
374 { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 },
375 { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 },
376 { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 },
377 { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 },
378 { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 },
379 { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 },
380 { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 },
381 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 },
382 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 },
383 { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
384 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 },
385 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
386 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
387 { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 },
388 { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 },
389 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
390 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 },
391 { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 },
392 { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 },
393 { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }
394 };
395
396 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
397 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
398 }
399
400 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
401 // Actual capturing of timing data: WebGL Acquarium demo
402 // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran
403 // between 55-60 FPS in the steady-state.
404 static const DataPoint data_points[] = {
405 { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 },
406 { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 },
407 { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 },
408 { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 },
409 { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 },
410 { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
411 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
412 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
413 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
414 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
415 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
416 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 },
417 { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 },
418 { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
419 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
420 { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 },
421 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
422 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
423 { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
424 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
425 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 },
426 { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 },
427 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
428 { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 },
429 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 },
430 { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 },
431 { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 },
432 { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
433 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 },
434 { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 },
435 { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 }
436 };
437
438 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3);
439 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
440 }
441
442 class AnimatedContentSamplerTest : public ::testing::Test { 27 class AnimatedContentSamplerTest : public ::testing::Test {
443 public: 28 public:
444 AnimatedContentSamplerTest() {} 29 AnimatedContentSamplerTest() {}
445 ~AnimatedContentSamplerTest() override {} 30 ~AnimatedContentSamplerTest() override {}
446 31
447 void SetUp() override { 32 void SetUp() override {
448 const base::TimeDelta since_epoch = 33 const base::TimeDelta since_epoch =
449 InitialTestTimeTicks() - base::TimeTicks::UnixEpoch(); 34 InitialTestTimeTicks() - base::TimeTicks::UnixEpoch();
450 rand_seed_ = abs(static_cast<int>(since_epoch.InMicroseconds())); 35 rand_seed_ = abs(static_cast<int>(since_epoch.InMicroseconds()));
451 sampler_.reset(new AnimatedContentSampler(GetMinCapturePeriod())); 36 sampler_.reset(new AnimatedContentSampler(GetMinCapturePeriod()));
(...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(20)), 631 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(20)),
1047 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(23)), 632 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(23)),
1048 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(26)), 633 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(26)),
1049 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(27)), 634 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(27)),
1050 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(28)), 635 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(28)),
1051 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(29)), 636 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(29)),
1052 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(31)), 637 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(31)),
1053 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(32)), 638 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(32)),
1054 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(33)))); 639 Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(33))));
1055 640
1056 // Tests that VideoCaptureOracle filters out events whose timestamps are
1057 // decreasing.
1058 TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
1059 const base::TimeDelta min_capture_period =
1060 base::TimeDelta::FromSeconds(1) / 30;
1061 const gfx::Rect damage_rect(0, 0, 1280, 720);
1062 const base::TimeDelta event_increment = min_capture_period * 2;
1063
1064 VideoCaptureOracle oracle(min_capture_period);
1065
1066 base::TimeTicks t = InitialTestTimeTicks();
1067 for (int i = 0; i < 10; ++i) {
1068 t += event_increment;
1069 ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
1070 VideoCaptureOracle::kCompositorUpdate,
1071 damage_rect, t));
1072 }
1073
1074 base::TimeTicks furthest_event_time = t;
1075 for (int i = 0; i < 10; ++i) {
1076 t -= event_increment;
1077 ASSERT_FALSE(oracle.ObserveEventAndDecideCapture(
1078 VideoCaptureOracle::kCompositorUpdate,
1079 damage_rect, t));
1080 }
1081
1082 t = furthest_event_time;
1083 for (int i = 0; i < 10; ++i) {
1084 t += event_increment;
1085 ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
1086 VideoCaptureOracle::kCompositorUpdate,
1087 damage_rect, t));
1088 }
1089 }
1090
1091 // Tests that VideoCaptureOracle is enforcing the requirement that captured
1092 // frames are delivered in order. Otherwise, downstream consumers could be
1093 // tripped-up by out-of-order frames or frame timestamps.
1094 TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
1095 const base::TimeDelta min_capture_period =
1096 base::TimeDelta::FromSeconds(1) / 30;
1097 const gfx::Rect damage_rect(0, 0, 1280, 720);
1098 const base::TimeDelta event_increment = min_capture_period * 2;
1099
1100 VideoCaptureOracle oracle(min_capture_period);
1101
1102 // Most basic scenario: Frames delivered one at a time, with no additional
1103 // captures in-between deliveries.
1104 base::TimeTicks t = InitialTestTimeTicks();
1105 int last_frame_number;
1106 base::TimeTicks ignored;
1107 for (int i = 0; i < 10; ++i) {
1108 t += event_increment;
1109 ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
1110 VideoCaptureOracle::kCompositorUpdate,
1111 damage_rect, t));
1112 last_frame_number = oracle.RecordCapture();
1113 ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &ignored));
1114 }
1115
1116 // Basic pipelined scenario: More than one frame in-flight at delivery points.
1117 for (int i = 0; i < 50; ++i) {
1118 const int num_in_flight = 1 + i % 3;
1119 for (int j = 0; j < num_in_flight; ++j) {
1120 t += event_increment;
1121 ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
1122 VideoCaptureOracle::kCompositorUpdate,
1123 damage_rect, t));
1124 last_frame_number = oracle.RecordCapture();
1125 }
1126 for (int j = num_in_flight - 1; j >= 0; --j) {
1127 ASSERT_TRUE(oracle.CompleteCapture(last_frame_number - j, &ignored));
1128 }
1129 }
1130
1131 // Pipelined scenario with out-of-order delivery attempts rejected.
1132 for (int i = 0; i < 50; ++i) {
1133 const int num_in_flight = 1 + i % 3;
1134 for (int j = 0; j < num_in_flight; ++j) {
1135 t += event_increment;
1136 ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
1137 VideoCaptureOracle::kCompositorUpdate,
1138 damage_rect, t));
1139 last_frame_number = oracle.RecordCapture();
1140 }
1141 ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &ignored));
1142 for (int j = 1; j < num_in_flight; ++j) {
1143 ASSERT_FALSE(oracle.CompleteCapture(last_frame_number - j, &ignored));
1144 }
1145 }
1146 }
1147
1148 // Tests that VideoCaptureOracle transitions between using its two samplers in a
1149 // way that does not introduce severe jank, pauses, etc.
1150 TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
1151 const base::TimeDelta min_capture_period =
1152 base::TimeDelta::FromSeconds(1) / 30;
1153 const gfx::Rect animation_damage_rect(0, 0, 1280, 720);
1154 const base::TimeDelta event_increment = min_capture_period * 2;
1155
1156 VideoCaptureOracle oracle(min_capture_period);
1157
1158 // Run sequences of animation events and non-animation events through the
1159 // oracle. As the oracle transitions between each sampler, make sure the
1160 // frame timestamps won't trip-up downstream consumers.
1161 base::TimeTicks t = InitialTestTimeTicks();
1162 base::TimeTicks last_frame_timestamp;
1163 for (int i = 0; i < 1000; ++i) {
1164 t += event_increment;
1165
1166 // For every 100 events, provide 50 that will cause the
1167 // AnimatedContentSampler to lock-in, followed by 50 that will cause it to
1168 // lock-out (i.e., the oracle will use the SmoothEventSampler instead).
1169 const bool provide_animated_content_event =
1170 (i % 100) >= 25 && (i % 100) < 75;
1171
1172 // Only the few events that trigger the lock-out transition should be
1173 // dropped, because the AnimatedContentSampler doesn't yet realize the
1174 // animation ended. Otherwise, the oracle should always decide to sample
1175 // because one of its samplers says to.
1176 const bool require_oracle_says_sample = (i % 100) < 75 || (i % 100) >= 78;
1177 const bool oracle_says_sample = oracle.ObserveEventAndDecideCapture(
1178 VideoCaptureOracle::kCompositorUpdate,
1179 provide_animated_content_event ? animation_damage_rect : gfx::Rect(),
1180 t);
1181 if (require_oracle_says_sample)
1182 ASSERT_TRUE(oracle_says_sample);
1183 if (!oracle_says_sample)
1184 continue;
1185
1186 const int frame_number = oracle.RecordCapture();
1187
1188 base::TimeTicks frame_timestamp;
1189 ASSERT_TRUE(oracle.CompleteCapture(frame_number, &frame_timestamp));
1190 ASSERT_FALSE(frame_timestamp.is_null());
1191 if (!last_frame_timestamp.is_null()) {
1192 const base::TimeDelta delta = frame_timestamp - last_frame_timestamp;
1193 EXPECT_LE(event_increment.InMicroseconds(), delta.InMicroseconds());
1194 // Right after the AnimatedContentSampler lock-out transition, there were
1195 // a few frames dropped, so allow a gap in the timestamps. Otherwise, the
1196 // delta between frame timestamps should never be more than 2X the
1197 // |event_increment|.
1198 const base::TimeDelta max_acceptable_delta = (i % 100) == 78 ?
1199 event_increment * 5 : event_increment * 2;
1200 EXPECT_GE(max_acceptable_delta.InMicroseconds(), delta.InMicroseconds());
1201 }
1202 last_frame_timestamp = frame_timestamp;
1203 }
1204 }
1205
1206 } // namespace content 641 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/capture/animated_content_sampler.cc ('k') | content/browser/media/capture/smooth_event_sampler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698