1 /*
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/frame_decode_timing.h"
12
13 #include <stdint.h>
14
15 #include "absl/types/optional.h"
16 #include "api/units/time_delta.h"
17 #include "modules/video_coding/timing/timing.h"
18 #include "rtc_base/containers/flat_map.h"
19 #include "test/gmock.h"
20 #include "test/gtest.h"
21 #include "test/scoped_key_value_config.h"
22 #include "video/video_receive_stream2.h"
23
24 namespace webrtc {
25
26 using ::testing::AllOf;
27 using ::testing::Eq;
28 using ::testing::Field;
29 using ::testing::Optional;
30
31 namespace {
32
33 class FakeVCMTiming : public webrtc::VCMTiming {
34 public:
FakeVCMTiming(Clock * clock,const FieldTrialsView & field_trials)35 explicit FakeVCMTiming(Clock* clock, const FieldTrialsView& field_trials)
36 : webrtc::VCMTiming(clock, field_trials) {}
37
RenderTime(uint32_t frame_timestamp,Timestamp now) const38 Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const override {
39 RTC_DCHECK(render_time_map_.contains(frame_timestamp));
40 auto it = render_time_map_.find(frame_timestamp);
41 return it->second;
42 }
43
MaxWaitingTime(Timestamp render_time,Timestamp now,bool too_many_frames_queued) const44 TimeDelta MaxWaitingTime(Timestamp render_time,
45 Timestamp now,
46 bool too_many_frames_queued) const override {
47 RTC_DCHECK(wait_time_map_.contains(render_time));
48 auto it = wait_time_map_.find(render_time);
49 return it->second;
50 }
51
SetTimes(uint32_t frame_timestamp,Timestamp render_time,TimeDelta max_decode_wait)52 void SetTimes(uint32_t frame_timestamp,
53 Timestamp render_time,
54 TimeDelta max_decode_wait) {
55 render_time_map_.insert_or_assign(frame_timestamp, render_time);
56 wait_time_map_.insert_or_assign(render_time, max_decode_wait);
57 }
58
59 protected:
60 flat_map<uint32_t, Timestamp> render_time_map_;
61 flat_map<Timestamp, TimeDelta> wait_time_map_;
62 };
63 } // namespace
64
65 class FrameDecodeTimingTest : public ::testing::Test {
66 public:
FrameDecodeTimingTest()67 FrameDecodeTimingTest()
68 : clock_(Timestamp::Millis(1000)),
69 timing_(&clock_, field_trials_),
70 frame_decode_scheduler_(&clock_, &timing_) {}
71
72 protected:
73 test::ScopedKeyValueConfig field_trials_;
74 SimulatedClock clock_;
75 FakeVCMTiming timing_;
76 FrameDecodeTiming frame_decode_scheduler_;
77 };
78
TEST_F(FrameDecodeTimingTest,ReturnsWaitTimesWhenValid)79 TEST_F(FrameDecodeTimingTest, ReturnsWaitTimesWhenValid) {
80 const TimeDelta decode_delay = TimeDelta::Millis(42);
81 const Timestamp render_time = clock_.CurrentTime() + TimeDelta::Millis(60);
82 timing_.SetTimes(90000, render_time, decode_delay);
83
84 EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated(
85 90000, 180000, kMaxWaitForFrame, false),
86 Optional(AllOf(
87 Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time,
88 Eq(clock_.CurrentTime() + decode_delay)),
89 Field(&FrameDecodeTiming::FrameSchedule::render_time,
90 Eq(render_time)))));
91 }
92
TEST_F(FrameDecodeTimingTest,FastForwardsFrameTooFarInThePast)93 TEST_F(FrameDecodeTimingTest, FastForwardsFrameTooFarInThePast) {
94 const TimeDelta decode_delay =
95 -FrameDecodeTiming::kMaxAllowedFrameDelay - TimeDelta::Millis(1);
96 const Timestamp render_time = clock_.CurrentTime();
97 timing_.SetTimes(90000, render_time, decode_delay);
98
99 EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated(
100 90000, 180000, kMaxWaitForFrame, false),
101 Eq(absl::nullopt));
102 }
103
TEST_F(FrameDecodeTimingTest,NoFastForwardIfOnlyFrameToDecode)104 TEST_F(FrameDecodeTimingTest, NoFastForwardIfOnlyFrameToDecode) {
105 const TimeDelta decode_delay =
106 -FrameDecodeTiming::kMaxAllowedFrameDelay - TimeDelta::Millis(1);
107 const Timestamp render_time = clock_.CurrentTime();
108 timing_.SetTimes(90000, render_time, decode_delay);
109
110 // Negative `decode_delay` means that `latest_decode_time` is now.
111 EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated(
112 90000, 90000, kMaxWaitForFrame, false),
113 Optional(AllOf(
114 Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time,
115 Eq(clock_.CurrentTime())),
116 Field(&FrameDecodeTiming::FrameSchedule::render_time,
117 Eq(render_time)))));
118 }
119
TEST_F(FrameDecodeTimingTest,MaxWaitCapped)120 TEST_F(FrameDecodeTimingTest, MaxWaitCapped) {
121 TimeDelta frame_delay = TimeDelta::Millis(30);
122 const TimeDelta decode_delay = TimeDelta::Seconds(3);
123 const Timestamp render_time = clock_.CurrentTime() + TimeDelta::Seconds(3);
124 timing_.SetTimes(90000, render_time, decode_delay);
125 timing_.SetTimes(180000, render_time + frame_delay,
126 decode_delay + frame_delay);
127
128 EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated(
129 90000, 270000, kMaxWaitForFrame, false),
130 Optional(AllOf(
131 Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time,
132 Eq(clock_.CurrentTime() + kMaxWaitForFrame)),
133 Field(&FrameDecodeTiming::FrameSchedule::render_time,
134 Eq(render_time)))));
135
136 // Test cap keyframe.
137 clock_.AdvanceTime(frame_delay);
138 EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated(
139 180000, 270000, kMaxWaitForKeyFrame, false),
140 Optional(AllOf(
141 Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time,
142 Eq(clock_.CurrentTime() + kMaxWaitForKeyFrame)),
143 Field(&FrameDecodeTiming::FrameSchedule::render_time,
144 Eq(render_time + frame_delay)))));
145 }
146
147 } // namespace webrtc
148