blob: fb48a7e3f62b6c0115375c26f870d7b4f24392a1 [file] [log] [blame]
Evan Shrubsole6cd6d8e2022-02-11 14:30:261/*
2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "video/decode_synchronizer.h"
12
13#include <stddef.h>
14
15#include <memory>
16#include <utility>
17
Markus Handellbe400e42022-11-08 11:14:2318#include "absl/functional/any_invocable.h"
Evan Shrubsole6cd6d8e2022-02-11 14:30:2619#include "api/metronome/test/fake_metronome.h"
20#include "api/units/time_delta.h"
21#include "test/gmock.h"
22#include "test/gtest.h"
Evan Shrubsole6cd6d8e2022-02-11 14:30:2623#include "test/time_controller/simulated_time_controller.h"
24#include "video/frame_decode_scheduler.h"
25#include "video/frame_decode_timing.h"
26
27using ::testing::_;
28using ::testing::Eq;
Markus Handellbe400e42022-11-08 11:14:2329using ::testing::Invoke;
Markus Handellaee5b172023-04-28 09:16:3030using ::testing::Mock;
31using ::testing::MockFunction;
Markus Handellbe400e42022-11-08 11:14:2332using ::testing::Return;
Evan Shrubsole6cd6d8e2022-02-11 14:30:2633
34namespace webrtc {
35
Markus Handellbe400e42022-11-08 11:14:2336class MockMetronome : public Metronome {
37 public:
38 MOCK_METHOD(void,
39 RequestCallOnNextTick,
40 (absl::AnyInvocable<void() &&> callback),
41 (override));
42 MOCK_METHOD(TimeDelta, TickPeriod, (), (const override));
43};
44
Evan Shrubsole6cd6d8e2022-02-11 14:30:2645class DecodeSynchronizerTest : public ::testing::Test {
46 public:
47 static constexpr TimeDelta kTickPeriod = TimeDelta::Millis(33);
48
49 DecodeSynchronizerTest()
50 : time_controller_(Timestamp::Millis(1337)),
51 clock_(time_controller_.GetClock()),
52 metronome_(kTickPeriod),
Evan Shrubsole7cbd8de2022-08-16 08:08:5353 decode_synchronizer_(clock_,
54 &metronome_,
55 time_controller_.GetMainThread()) {}
Evan Shrubsole6cd6d8e2022-02-11 14:30:2656
57 protected:
58 GlobalSimulatedTimeController time_controller_;
59 Clock* clock_;
Evan Shrubsole6cd6d8e2022-02-11 14:30:2660 test::ForcedTickMetronome metronome_;
61 DecodeSynchronizer decode_synchronizer_;
62};
63
64TEST_F(DecodeSynchronizerTest, AllFramesReadyBeforeNextTickDecoded) {
Markus Handellaee5b172023-04-28 09:16:3065 MockFunction<void(uint32_t, Timestamp)> mock_callback1;
Evan Shrubsole6cd6d8e2022-02-11 14:30:2666 auto scheduler1 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
67
Markus Handellaee5b172023-04-28 09:16:3068 MockFunction<void(unsigned int, Timestamp)> mock_callback2;
Evan Shrubsole6cd6d8e2022-02-11 14:30:2669 auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
70
71 {
72 uint32_t frame_rtp = 90000;
73 FrameDecodeTiming::FrameSchedule frame_sched{
74 .latest_decode_time =
75 clock_->CurrentTime() + kTickPeriod - TimeDelta::Millis(3),
76 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
77 scheduler1->ScheduleFrame(frame_rtp, frame_sched,
78 mock_callback1.AsStdFunction());
79 EXPECT_CALL(mock_callback1,
80 Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
81 }
82 {
83 uint32_t frame_rtp = 123456;
84 FrameDecodeTiming::FrameSchedule frame_sched{
85 .latest_decode_time =
86 clock_->CurrentTime() + kTickPeriod - TimeDelta::Millis(2),
87 .render_time = clock_->CurrentTime() + TimeDelta::Millis(70)};
88 scheduler2->ScheduleFrame(frame_rtp, frame_sched,
89 mock_callback2.AsStdFunction());
90 EXPECT_CALL(mock_callback2,
91 Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
92 }
93 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:5394 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:2695
96 // Cleanup
97 scheduler1->Stop();
98 scheduler2->Stop();
99}
100
101TEST_F(DecodeSynchronizerTest, FramesNotDecodedIfDecodeTimeIsInNextInterval) {
Markus Handellaee5b172023-04-28 09:16:30102 MockFunction<void(unsigned int, Timestamp)> mock_callback;
Evan Shrubsole6cd6d8e2022-02-11 14:30:26103 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
104
105 uint32_t frame_rtp = 90000;
106 FrameDecodeTiming::FrameSchedule frame_sched{
107 .latest_decode_time =
108 clock_->CurrentTime() + kTickPeriod + TimeDelta::Millis(10),
109 .render_time =
110 clock_->CurrentTime() + kTickPeriod + TimeDelta::Millis(30)};
111 scheduler->ScheduleFrame(frame_rtp, frame_sched,
112 mock_callback.AsStdFunction());
113
114 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53115 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26116 // No decodes should have happened in this tick.
117 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
118
119 // Decode should happen on next tick.
120 EXPECT_CALL(mock_callback, Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
121 time_controller_.AdvanceTime(kTickPeriod);
122 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53123 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26124
125 // Cleanup
126 scheduler->Stop();
127}
128
129TEST_F(DecodeSynchronizerTest, FrameDecodedOnce) {
Markus Handellaee5b172023-04-28 09:16:30130 MockFunction<void(unsigned int, Timestamp)> mock_callback;
Evan Shrubsole6cd6d8e2022-02-11 14:30:26131 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
132
133 uint32_t frame_rtp = 90000;
134 FrameDecodeTiming::FrameSchedule frame_sched{
135 .latest_decode_time = clock_->CurrentTime() + TimeDelta::Millis(30),
136 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
137 scheduler->ScheduleFrame(frame_rtp, frame_sched,
138 mock_callback.AsStdFunction());
139 EXPECT_CALL(mock_callback, Call(_, _)).Times(1);
140 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53141 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26142 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
143
144 // Trigger tick again. No frame should be decoded now.
145 time_controller_.AdvanceTime(kTickPeriod);
146 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53147 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26148
149 // Cleanup
150 scheduler->Stop();
151}
152
153TEST_F(DecodeSynchronizerTest, FrameWithDecodeTimeInPastDecodedImmediately) {
Markus Handellaee5b172023-04-28 09:16:30154 MockFunction<void(unsigned int, Timestamp)> mock_callback;
Evan Shrubsole6cd6d8e2022-02-11 14:30:26155 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
156
157 uint32_t frame_rtp = 90000;
158 FrameDecodeTiming::FrameSchedule frame_sched{
159 .latest_decode_time = clock_->CurrentTime() - TimeDelta::Millis(5),
160 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
161 EXPECT_CALL(mock_callback, Call(Eq(90000u), _)).Times(1);
162 scheduler->ScheduleFrame(frame_rtp, frame_sched,
163 mock_callback.AsStdFunction());
164 // Verify the callback was invoked already.
165 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
166
167 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53168 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26169
170 // Cleanup
171 scheduler->Stop();
172}
173
174TEST_F(DecodeSynchronizerTest,
175 FrameWithDecodeTimeFarBeforeNextTickDecodedImmediately) {
Markus Handellaee5b172023-04-28 09:16:30176 MockFunction<void(unsigned int, Timestamp)> mock_callback;
Evan Shrubsole6cd6d8e2022-02-11 14:30:26177 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
178
179 // Frame which would be behind by more than kMaxAllowedFrameDelay after
180 // the next tick.
181 FrameDecodeTiming::FrameSchedule frame_sched{
182 .latest_decode_time = clock_->CurrentTime() + kTickPeriod -
183 FrameDecodeTiming::kMaxAllowedFrameDelay -
184 TimeDelta::Millis(1),
185 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
186 EXPECT_CALL(mock_callback, Call(Eq(90000u), _)).Times(1);
187 scheduler->ScheduleFrame(90000, frame_sched, mock_callback.AsStdFunction());
188 // Verify the callback was invoked already.
189 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
190
191 time_controller_.AdvanceTime(kTickPeriod);
192 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53193 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26194
195 // A frame that would be behind by exactly kMaxAllowedFrameDelay after next
196 // tick should decode at the next tick.
197 FrameDecodeTiming::FrameSchedule queued_frame{
198 .latest_decode_time = clock_->CurrentTime() + kTickPeriod -
199 FrameDecodeTiming::kMaxAllowedFrameDelay,
200 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
201 scheduler->ScheduleFrame(180000, queued_frame, mock_callback.AsStdFunction());
202 // Verify the callback was invoked already.
203 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
204
205 EXPECT_CALL(mock_callback, Call(Eq(180000u), _)).Times(1);
206 time_controller_.AdvanceTime(kTickPeriod);
207 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53208 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26209
210 // Cleanup
211 scheduler->Stop();
212}
213
214TEST_F(DecodeSynchronizerTest, FramesNotReleasedAfterStop) {
Markus Handellaee5b172023-04-28 09:16:30215 MockFunction<void(unsigned int, Timestamp)> mock_callback;
Evan Shrubsole6cd6d8e2022-02-11 14:30:26216 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
217
218 uint32_t frame_rtp = 90000;
219 FrameDecodeTiming::FrameSchedule frame_sched{
220 .latest_decode_time = clock_->CurrentTime() + TimeDelta::Millis(30),
221 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
222 scheduler->ScheduleFrame(frame_rtp, frame_sched,
223 mock_callback.AsStdFunction());
224 // Cleanup
225 scheduler->Stop();
226
227 // No callback should occur on this tick since Stop() was called before.
228 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53229 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 14:30:26230}
231
Markus Handellbe400e42022-11-08 11:14:23232TEST(DecodeSynchronizerStandaloneTest,
233 MetronomeNotListenedWhenNoStreamsAreActive) {
234 GlobalSimulatedTimeController time_controller(Timestamp::Millis(4711));
235 Clock* clock(time_controller.GetClock());
236 MockMetronome metronome;
237 ON_CALL(metronome, TickPeriod).WillByDefault(Return(TimeDelta::Seconds(1)));
238 DecodeSynchronizer decode_synchronizer_(clock, &metronome,
239 time_controller.GetMainThread());
240 absl::AnyInvocable<void() &&> callback;
241 EXPECT_CALL(metronome, RequestCallOnNextTick)
242 .WillOnce(Invoke([&callback](absl::AnyInvocable<void() &&> cb) {
243 callback = std::move(cb);
244 }));
Evan Shrubsole6cd6d8e2022-02-11 14:30:26245 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
Evan Shrubsole6cd6d8e2022-02-11 14:30:26246 auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
Evan Shrubsole6cd6d8e2022-02-11 14:30:26247 scheduler->Stop();
Evan Shrubsole6cd6d8e2022-02-11 14:30:26248 scheduler2->Stop();
Markus Handellbe400e42022-11-08 11:14:23249 time_controller.AdvanceTime(TimeDelta::Seconds(1));
250 ASSERT_TRUE(callback);
251 (std::move)(callback)();
Evan Shrubsole6cd6d8e2022-02-11 14:30:26252}
253
Markus Handellaee5b172023-04-28 09:16:30254TEST(DecodeSynchronizerStandaloneTest,
255 RegistersCallbackOnceDuringRepeatedRegistrations) {
256 GlobalSimulatedTimeController time_controller(Timestamp::Millis(4711));
257 Clock* clock(time_controller.GetClock());
258 MockMetronome metronome;
259 ON_CALL(metronome, TickPeriod).WillByDefault(Return(TimeDelta::Seconds(1)));
260 DecodeSynchronizer decode_synchronizer_(clock, &metronome,
261 time_controller.GetMainThread());
262 // Expect at most 1 call to register a callback.
263 EXPECT_CALL(metronome, RequestCallOnNextTick);
264 auto scheduler1 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
265 scheduler1->Stop();
266 auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
267 Mock::VerifyAndClearExpectations(&metronome);
268 scheduler2->Stop();
269}
270
Evan Shrubsole6cd6d8e2022-02-11 14:30:26271} // namespace webrtc