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
3 // found in the LICENSE file.
5 #include "media/capture/video_capture_oracle.h"
7 #include "base/strings/stringprintf.h"
8 #include "testing/gtest/include/gtest/gtest.h"
14 base::TimeTicks
InitialTestTimeTicks() {
15 return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
20 // Tests that VideoCaptureOracle filters out events whose timestamps are
22 TEST(VideoCaptureOracleTest
, EnforcesEventTimeMonotonicity
) {
23 const base::TimeDelta min_capture_period
=
24 base::TimeDelta::FromSeconds(1) / 30;
25 const gfx::Rect
damage_rect(0, 0, 1280, 720);
26 const base::TimeDelta event_increment
= min_capture_period
* 2;
28 VideoCaptureOracle
oracle(min_capture_period
);
30 base::TimeTicks t
= InitialTestTimeTicks();
31 for (int i
= 0; i
< 10; ++i
) {
33 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
34 VideoCaptureOracle::kCompositorUpdate
,
38 base::TimeTicks furthest_event_time
= t
;
39 for (int i
= 0; i
< 10; ++i
) {
41 ASSERT_FALSE(oracle
.ObserveEventAndDecideCapture(
42 VideoCaptureOracle::kCompositorUpdate
,
46 t
= furthest_event_time
;
47 for (int i
= 0; i
< 10; ++i
) {
49 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
50 VideoCaptureOracle::kCompositorUpdate
,
55 // Tests that VideoCaptureOracle is enforcing the requirement that
56 // successfully captured frames are delivered in order. Otherwise, downstream
57 // consumers could be tripped-up by out-of-order frames or frame timestamps.
58 TEST(VideoCaptureOracleTest
, EnforcesFramesDeliveredInOrder
) {
59 const base::TimeDelta min_capture_period
=
60 base::TimeDelta::FromSeconds(1) / 30;
61 const gfx::Rect
damage_rect(0, 0, 1280, 720);
62 const base::TimeDelta event_increment
= min_capture_period
* 2;
64 VideoCaptureOracle
oracle(min_capture_period
);
66 // Most basic scenario: Frames delivered one at a time, with no additional
67 // captures in-between deliveries.
68 base::TimeTicks t
= InitialTestTimeTicks();
69 int last_frame_number
;
70 base::TimeTicks ignored
;
71 for (int i
= 0; i
< 10; ++i
) {
73 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
74 VideoCaptureOracle::kCompositorUpdate
,
76 last_frame_number
= oracle
.RecordCapture();
77 ASSERT_TRUE(oracle
.CompleteCapture(last_frame_number
, true, &ignored
));
80 // Basic pipelined scenario: More than one frame in-flight at delivery points.
81 for (int i
= 0; i
< 50; ++i
) {
82 const int num_in_flight
= 1 + i
% 3;
83 for (int j
= 0; j
< num_in_flight
; ++j
) {
85 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
86 VideoCaptureOracle::kCompositorUpdate
,
88 last_frame_number
= oracle
.RecordCapture();
90 for (int j
= num_in_flight
- 1; j
>= 0; --j
) {
92 oracle
.CompleteCapture(last_frame_number
- j
, true, &ignored
));
96 // Pipelined scenario with successful out-of-order delivery attempts
98 for (int i
= 0; i
< 50; ++i
) {
99 const int num_in_flight
= 1 + i
% 3;
100 for (int j
= 0; j
< num_in_flight
; ++j
) {
101 t
+= event_increment
;
102 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
103 VideoCaptureOracle::kCompositorUpdate
,
105 last_frame_number
= oracle
.RecordCapture();
107 ASSERT_TRUE(oracle
.CompleteCapture(last_frame_number
, true, &ignored
));
108 for (int j
= 1; j
< num_in_flight
; ++j
) {
110 oracle
.CompleteCapture(last_frame_number
- j
, true, &ignored
));
114 // Pipelined scenario with successful delivery attempts accepted after an
115 // unsuccessful out of order delivery attempt.
116 for (int i
= 0; i
< 50; ++i
) {
117 const int num_in_flight
= 1 + i
% 3;
118 for (int j
= 0; j
< num_in_flight
; ++j
) {
119 t
+= event_increment
;
120 ASSERT_TRUE(oracle
.ObserveEventAndDecideCapture(
121 VideoCaptureOracle::kCompositorUpdate
,
123 last_frame_number
= oracle
.RecordCapture();
125 // Report the last frame as an out of order failure.
126 ASSERT_FALSE(oracle
.CompleteCapture(last_frame_number
, false, &ignored
));
127 for (int j
= 1; j
< num_in_flight
- 1; ++j
) {
129 oracle
.CompleteCapture(last_frame_number
- j
, true, &ignored
));
135 // Tests that VideoCaptureOracle transitions between using its two samplers in a
136 // way that does not introduce severe jank, pauses, etc.
137 TEST(VideoCaptureOracleTest
, TransitionsSmoothlyBetweenSamplers
) {
138 const base::TimeDelta min_capture_period
=
139 base::TimeDelta::FromSeconds(1) / 30;
140 const gfx::Rect
animation_damage_rect(0, 0, 1280, 720);
141 const base::TimeDelta event_increment
= min_capture_period
* 2;
143 VideoCaptureOracle
oracle(min_capture_period
);
145 // Run sequences of animation events and non-animation events through the
146 // oracle. As the oracle transitions between each sampler, make sure the
147 // frame timestamps won't trip-up downstream consumers.
148 base::TimeTicks t
= InitialTestTimeTicks();
149 base::TimeTicks last_frame_timestamp
;
150 for (int i
= 0; i
< 1000; ++i
) {
151 t
+= event_increment
;
153 // For every 100 events, provide 50 that will cause the
154 // AnimatedContentSampler to lock-in, followed by 50 that will cause it to
155 // lock-out (i.e., the oracle will use the SmoothEventSampler instead).
156 const bool provide_animated_content_event
=
157 (i
% 100) >= 25 && (i
% 100) < 75;
159 // Only the few events that trigger the lock-out transition should be
160 // dropped, because the AnimatedContentSampler doesn't yet realize the
161 // animation ended. Otherwise, the oracle should always decide to sample
162 // because one of its samplers says to.
163 const bool require_oracle_says_sample
= (i
% 100) < 75 || (i
% 100) >= 78;
164 const bool oracle_says_sample
= oracle
.ObserveEventAndDecideCapture(
165 VideoCaptureOracle::kCompositorUpdate
,
166 provide_animated_content_event
? animation_damage_rect
: gfx::Rect(),
168 if (require_oracle_says_sample
)
169 ASSERT_TRUE(oracle_says_sample
);
170 if (!oracle_says_sample
) {
171 ASSERT_EQ(base::TimeDelta(), oracle
.estimated_frame_duration());
174 ASSERT_LT(base::TimeDelta(), oracle
.estimated_frame_duration());
176 const int frame_number
= oracle
.RecordCapture();
178 base::TimeTicks frame_timestamp
;
179 ASSERT_TRUE(oracle
.CompleteCapture(frame_number
, true, &frame_timestamp
));
180 ASSERT_FALSE(frame_timestamp
.is_null());
181 if (!last_frame_timestamp
.is_null()) {
182 const base::TimeDelta delta
= frame_timestamp
- last_frame_timestamp
;
183 EXPECT_LE(event_increment
.InMicroseconds(), delta
.InMicroseconds());
184 // Right after the AnimatedContentSampler lock-out transition, there were
185 // a few frames dropped, so allow a gap in the timestamps. Otherwise, the
186 // delta between frame timestamps should never be more than 2X the
187 // |event_increment|.
188 const base::TimeDelta max_acceptable_delta
= (i
% 100) == 78 ?
189 event_increment
* 5 : event_increment
* 2;
190 EXPECT_GE(max_acceptable_delta
.InMicroseconds(), delta
.InMicroseconds());
192 last_frame_timestamp
= frame_timestamp
;
196 // Tests that VideoCaptureOracle prevents timer polling from initiating
197 // simultaneous captures.
198 TEST(VideoCaptureOracleTest
, SamplesOnlyOneOverdueFrameAtATime
) {
199 const base::TimeDelta min_capture_period
=
200 base::TimeDelta::FromSeconds(1) / 30;
201 const base::TimeDelta vsync_interval
=
202 base::TimeDelta::FromSeconds(1) / 60;
203 const base::TimeDelta timer_interval
= base::TimeDelta::FromMilliseconds(
204 VideoCaptureOracle::kMinTimerPollPeriodMillis
);
206 VideoCaptureOracle
oracle(min_capture_period
);
208 // Have the oracle observe some compositor events. Simulate that each capture
209 // completes successfully.
210 base::TimeTicks t
= InitialTestTimeTicks();
211 base::TimeTicks ignored
;
212 bool did_complete_a_capture
= false;
213 for (int i
= 0; i
< 10; ++i
) {
215 if (oracle
.ObserveEventAndDecideCapture(
216 VideoCaptureOracle::kCompositorUpdate
, gfx::Rect(), t
)) {
218 oracle
.CompleteCapture(oracle
.RecordCapture(), true, &ignored
));
219 did_complete_a_capture
= true;
222 ASSERT_TRUE(did_complete_a_capture
);
224 // Start one more compositor-based capture, but do not notify of completion
226 for (int i
= 0; i
<= 10; ++i
) {
227 ASSERT_GT(10, i
) << "BUG: Seems like it'll never happen!";
229 if (oracle
.ObserveEventAndDecideCapture(
230 VideoCaptureOracle::kCompositorUpdate
, gfx::Rect(), t
)) {
234 int frame_number
= oracle
.RecordCapture();
236 // Stop providing the compositor events and start providing timer polling
237 // events. No overdue samplings should be recommended because of the
238 // not-yet-complete compositor-based capture.
239 for (int i
= 0; i
< 10; ++i
) {
241 ASSERT_FALSE(oracle
.ObserveEventAndDecideCapture(
242 VideoCaptureOracle::kTimerPoll
, gfx::Rect(), t
));
245 // Now, complete the oustanding compositor-based capture and continue
246 // providing timer polling events. The oracle should start recommending
248 ASSERT_TRUE(oracle
.CompleteCapture(frame_number
, true, &ignored
));
249 did_complete_a_capture
= false;
250 for (int i
= 0; i
< 10; ++i
) {
252 if (oracle
.ObserveEventAndDecideCapture(
253 VideoCaptureOracle::kTimerPoll
, gfx::Rect(), t
)) {
255 oracle
.CompleteCapture(oracle
.RecordCapture(), true, &ignored
));
256 did_complete_a_capture
= true;
259 ASSERT_TRUE(did_complete_a_capture
);
261 // Start one more timer-based capture, but do not notify of completion yet.
262 for (int i
= 0; i
<= 10; ++i
) {
263 ASSERT_GT(10, i
) << "BUG: Seems like it'll never happen!";
265 if (oracle
.ObserveEventAndDecideCapture(
266 VideoCaptureOracle::kTimerPoll
, gfx::Rect(), t
)) {
270 frame_number
= oracle
.RecordCapture();
272 // Confirm that the oracle does not recommend sampling until the outstanding
273 // timer-based capture completes.
274 for (int i
= 0; i
< 10; ++i
) {
276 ASSERT_FALSE(oracle
.ObserveEventAndDecideCapture(
277 VideoCaptureOracle::kTimerPoll
, gfx::Rect(), t
));
279 ASSERT_TRUE(oracle
.CompleteCapture(frame_number
, true, &ignored
));
280 for (int i
= 0; i
<= 10; ++i
) {
281 ASSERT_GT(10, i
) << "BUG: Seems like it'll never happen!";
283 if (oracle
.ObserveEventAndDecideCapture(
284 VideoCaptureOracle::kTimerPoll
, gfx::Rect(), t
)) {