1 /*
2 * Copyright 2020 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/video_source_sink_controller.h"
12
13 #include <limits>
14
15 #include "api/video/video_frame.h"
16 #include "api/video/video_source_interface.h"
17 #include "call/adaptation/video_source_restrictions.h"
18 #include "test/gmock.h"
19 #include "test/gtest.h"
20
21 using testing::_;
22
23 namespace webrtc {
24
25 namespace {
26
27 using FrameSize = rtc::VideoSinkWants::FrameSize;
28 constexpr int kIntUnconstrained = std::numeric_limits<int>::max();
29
30 class MockVideoSinkWithVideoFrame : public rtc::VideoSinkInterface<VideoFrame> {
31 public:
~MockVideoSinkWithVideoFrame()32 ~MockVideoSinkWithVideoFrame() override {}
33
34 MOCK_METHOD(void, OnFrame, (const VideoFrame& frame), (override));
35 MOCK_METHOD(void, OnDiscardedFrame, (), (override));
36 };
37
38 class MockVideoSourceWithVideoFrame
39 : public rtc::VideoSourceInterface<VideoFrame> {
40 public:
~MockVideoSourceWithVideoFrame()41 ~MockVideoSourceWithVideoFrame() override {}
42
43 MOCK_METHOD(void,
44 AddOrUpdateSink,
45 (rtc::VideoSinkInterface<VideoFrame>*,
46 const rtc::VideoSinkWants&),
47 (override));
48 MOCK_METHOD(void,
49 RemoveSink,
50 (rtc::VideoSinkInterface<VideoFrame>*),
51 (override));
52 MOCK_METHOD(void, RequestRefreshFrame, (), (override));
53 };
54
55 } // namespace
56
TEST(VideoSourceSinkControllerTest,UnconstrainedByDefault)57 TEST(VideoSourceSinkControllerTest, UnconstrainedByDefault) {
58 MockVideoSinkWithVideoFrame sink;
59 MockVideoSourceWithVideoFrame source;
60 VideoSourceSinkController controller(&sink, &source);
61 EXPECT_EQ(controller.restrictions(), VideoSourceRestrictions());
62 EXPECT_FALSE(controller.pixels_per_frame_upper_limit().has_value());
63 EXPECT_FALSE(controller.frame_rate_upper_limit().has_value());
64 EXPECT_FALSE(controller.rotation_applied());
65 EXPECT_FALSE(controller.requested_resolution().has_value());
66 EXPECT_EQ(controller.resolution_alignment(), 1);
67
68 EXPECT_CALL(source, AddOrUpdateSink(_, _))
69 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
70 const rtc::VideoSinkWants& wants) {
71 EXPECT_FALSE(wants.rotation_applied);
72 EXPECT_EQ(wants.max_pixel_count, kIntUnconstrained);
73 EXPECT_EQ(wants.target_pixel_count, absl::nullopt);
74 EXPECT_EQ(wants.max_framerate_fps, kIntUnconstrained);
75 EXPECT_EQ(wants.resolution_alignment, 1);
76 EXPECT_FALSE(wants.requested_resolution.has_value());
77 });
78 controller.PushSourceSinkSettings();
79 }
80
TEST(VideoSourceSinkControllerTest,VideoRestrictionsToSinkWants)81 TEST(VideoSourceSinkControllerTest, VideoRestrictionsToSinkWants) {
82 MockVideoSinkWithVideoFrame sink;
83 MockVideoSourceWithVideoFrame source;
84 VideoSourceSinkController controller(&sink, &source);
85
86 VideoSourceRestrictions restrictions = controller.restrictions();
87 // max_pixels_per_frame() maps to `max_pixel_count`.
88 restrictions.set_max_pixels_per_frame(42u);
89 // target_pixels_per_frame() maps to `target_pixel_count`.
90 restrictions.set_target_pixels_per_frame(200u);
91 // max_frame_rate() maps to `max_framerate_fps`.
92 restrictions.set_max_frame_rate(30.0);
93 controller.SetRestrictions(restrictions);
94 EXPECT_CALL(source, AddOrUpdateSink(_, _))
95 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
96 const rtc::VideoSinkWants& wants) {
97 EXPECT_EQ(wants.max_pixel_count, 42);
98 EXPECT_EQ(wants.target_pixel_count, 200);
99 EXPECT_EQ(wants.max_framerate_fps, 30);
100 });
101 controller.PushSourceSinkSettings();
102
103 // pixels_per_frame_upper_limit() caps `max_pixel_count`.
104 controller.SetPixelsPerFrameUpperLimit(24);
105 // frame_rate_upper_limit() caps `max_framerate_fps`.
106 controller.SetFrameRateUpperLimit(10.0);
107
108 EXPECT_CALL(source, AddOrUpdateSink(_, _))
109 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
110 const rtc::VideoSinkWants& wants) {
111 EXPECT_EQ(wants.max_pixel_count, 24);
112 EXPECT_EQ(wants.max_framerate_fps, 10);
113 });
114 controller.PushSourceSinkSettings();
115 }
116
TEST(VideoSourceSinkControllerTest,RotationApplied)117 TEST(VideoSourceSinkControllerTest, RotationApplied) {
118 MockVideoSinkWithVideoFrame sink;
119 MockVideoSourceWithVideoFrame source;
120 VideoSourceSinkController controller(&sink, &source);
121 controller.SetRotationApplied(true);
122 EXPECT_TRUE(controller.rotation_applied());
123
124 EXPECT_CALL(source, AddOrUpdateSink(_, _))
125 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
126 const rtc::VideoSinkWants& wants) {
127 EXPECT_TRUE(wants.rotation_applied);
128 });
129 controller.PushSourceSinkSettings();
130 }
131
TEST(VideoSourceSinkControllerTest,ResolutionAlignment)132 TEST(VideoSourceSinkControllerTest, ResolutionAlignment) {
133 MockVideoSinkWithVideoFrame sink;
134 MockVideoSourceWithVideoFrame source;
135 VideoSourceSinkController controller(&sink, &source);
136 controller.SetResolutionAlignment(13);
137 EXPECT_EQ(controller.resolution_alignment(), 13);
138
139 EXPECT_CALL(source, AddOrUpdateSink(_, _))
140 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
141 const rtc::VideoSinkWants& wants) {
142 EXPECT_EQ(wants.resolution_alignment, 13);
143 });
144 controller.PushSourceSinkSettings();
145 }
146
TEST(VideoSourceSinkControllerTest,PushSourceSinkSettingsWithoutSourceDoesNotCrash)147 TEST(VideoSourceSinkControllerTest,
148 PushSourceSinkSettingsWithoutSourceDoesNotCrash) {
149 MockVideoSinkWithVideoFrame sink;
150 VideoSourceSinkController controller(&sink, nullptr);
151 controller.PushSourceSinkSettings();
152 }
153
TEST(VideoSourceSinkControllerTest,RequestsRefreshFrameWithSource)154 TEST(VideoSourceSinkControllerTest, RequestsRefreshFrameWithSource) {
155 MockVideoSinkWithVideoFrame sink;
156 MockVideoSourceWithVideoFrame source;
157 VideoSourceSinkController controller(&sink, &source);
158 EXPECT_CALL(source, RequestRefreshFrame);
159 controller.RequestRefreshFrame();
160 }
161
TEST(VideoSourceSinkControllerTest,RequestsRefreshFrameWithoutSourceDoesNotCrash)162 TEST(VideoSourceSinkControllerTest,
163 RequestsRefreshFrameWithoutSourceDoesNotCrash) {
164 MockVideoSinkWithVideoFrame sink;
165 VideoSourceSinkController controller(&sink, nullptr);
166 controller.RequestRefreshFrame();
167 }
168
TEST(VideoSourceSinkControllerTest,RequestedResolutionPropagatesToWants)169 TEST(VideoSourceSinkControllerTest, RequestedResolutionPropagatesToWants) {
170 MockVideoSinkWithVideoFrame sink;
171 MockVideoSourceWithVideoFrame source;
172 VideoSourceSinkController controller(&sink, &source);
173 controller.SetRequestedResolution(FrameSize(640, 360));
174 EXPECT_TRUE(controller.requested_resolution().has_value());
175
176 EXPECT_CALL(source, AddOrUpdateSink(_, _))
177 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
178 const rtc::VideoSinkWants& wants) {
179 EXPECT_EQ(*wants.requested_resolution, FrameSize(640, 360));
180 });
181 controller.PushSourceSinkSettings();
182 }
183
TEST(VideoSourceSinkControllerTest,ActivePropagatesToWants)184 TEST(VideoSourceSinkControllerTest, ActivePropagatesToWants) {
185 MockVideoSinkWithVideoFrame sink;
186 MockVideoSourceWithVideoFrame source;
187 VideoSourceSinkController controller(&sink, &source);
188 controller.SetActive(true);
189 EXPECT_TRUE(controller.active());
190
191 EXPECT_CALL(source, AddOrUpdateSink(_, _))
192 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
193 const rtc::VideoSinkWants& wants) {
194 EXPECT_TRUE(wants.is_active);
195 });
196 controller.PushSourceSinkSettings();
197 }
198
199 } // namespace webrtc
200