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 constexpr int kIntUnconstrained = std::numeric_limits<int>::max();
28
29 class MockVideoSinkWithVideoFrame : public rtc::VideoSinkInterface<VideoFrame> {
30 public:
~MockVideoSinkWithVideoFrame()31 ~MockVideoSinkWithVideoFrame() override {}
32
33 MOCK_METHOD(void, OnFrame, (const VideoFrame& frame), (override));
34 MOCK_METHOD(void, OnDiscardedFrame, (), (override));
35 };
36
37 class MockVideoSourceWithVideoFrame
38 : public rtc::VideoSourceInterface<VideoFrame> {
39 public:
~MockVideoSourceWithVideoFrame()40 ~MockVideoSourceWithVideoFrame() override {}
41
42 MOCK_METHOD(void,
43 AddOrUpdateSink,
44 (rtc::VideoSinkInterface<VideoFrame>*,
45 const rtc::VideoSinkWants&),
46 (override));
47 MOCK_METHOD(void,
48 RemoveSink,
49 (rtc::VideoSinkInterface<VideoFrame>*),
50 (override));
51 };
52
53 } // namespace
54
TEST(VideoSourceSinkControllerTest,UnconstrainedByDefault)55 TEST(VideoSourceSinkControllerTest, UnconstrainedByDefault) {
56 MockVideoSinkWithVideoFrame sink;
57 MockVideoSourceWithVideoFrame source;
58 VideoSourceSinkController controller(&sink, &source);
59 EXPECT_EQ(controller.restrictions(), VideoSourceRestrictions());
60 EXPECT_FALSE(controller.pixels_per_frame_upper_limit().has_value());
61 EXPECT_FALSE(controller.frame_rate_upper_limit().has_value());
62 EXPECT_FALSE(controller.rotation_applied());
63 EXPECT_EQ(controller.resolution_alignment(), 1);
64
65 EXPECT_CALL(source, AddOrUpdateSink(_, _))
66 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
67 const rtc::VideoSinkWants& wants) {
68 EXPECT_FALSE(wants.rotation_applied);
69 EXPECT_EQ(wants.max_pixel_count, kIntUnconstrained);
70 EXPECT_EQ(wants.target_pixel_count, absl::nullopt);
71 EXPECT_EQ(wants.max_framerate_fps, kIntUnconstrained);
72 EXPECT_EQ(wants.resolution_alignment, 1);
73 });
74 controller.PushSourceSinkSettings();
75 }
76
TEST(VideoSourceSinkControllerTest,VideoRestrictionsToSinkWants)77 TEST(VideoSourceSinkControllerTest, VideoRestrictionsToSinkWants) {
78 MockVideoSinkWithVideoFrame sink;
79 MockVideoSourceWithVideoFrame source;
80 VideoSourceSinkController controller(&sink, &source);
81
82 VideoSourceRestrictions restrictions = controller.restrictions();
83 // max_pixels_per_frame() maps to |max_pixel_count|.
84 restrictions.set_max_pixels_per_frame(42u);
85 // target_pixels_per_frame() maps to |target_pixel_count|.
86 restrictions.set_target_pixels_per_frame(200u);
87 // max_frame_rate() maps to |max_framerate_fps|.
88 restrictions.set_max_frame_rate(30.0);
89 controller.SetRestrictions(restrictions);
90 EXPECT_CALL(source, AddOrUpdateSink(_, _))
91 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
92 const rtc::VideoSinkWants& wants) {
93 EXPECT_EQ(wants.max_pixel_count, 42);
94 EXPECT_EQ(wants.target_pixel_count, 200);
95 EXPECT_EQ(wants.max_framerate_fps, 30);
96 });
97 controller.PushSourceSinkSettings();
98
99 // pixels_per_frame_upper_limit() caps |max_pixel_count|.
100 controller.SetPixelsPerFrameUpperLimit(24);
101 // frame_rate_upper_limit() caps |max_framerate_fps|.
102 controller.SetFrameRateUpperLimit(10.0);
103
104 EXPECT_CALL(source, AddOrUpdateSink(_, _))
105 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
106 const rtc::VideoSinkWants& wants) {
107 EXPECT_EQ(wants.max_pixel_count, 24);
108 EXPECT_EQ(wants.max_framerate_fps, 10);
109 });
110 controller.PushSourceSinkSettings();
111 }
112
TEST(VideoSourceSinkControllerTest,RotationApplied)113 TEST(VideoSourceSinkControllerTest, RotationApplied) {
114 MockVideoSinkWithVideoFrame sink;
115 MockVideoSourceWithVideoFrame source;
116 VideoSourceSinkController controller(&sink, &source);
117 controller.SetRotationApplied(true);
118 EXPECT_TRUE(controller.rotation_applied());
119
120 EXPECT_CALL(source, AddOrUpdateSink(_, _))
121 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
122 const rtc::VideoSinkWants& wants) {
123 EXPECT_TRUE(wants.rotation_applied);
124 });
125 controller.PushSourceSinkSettings();
126 }
127
TEST(VideoSourceSinkControllerTest,ResolutionAlignment)128 TEST(VideoSourceSinkControllerTest, ResolutionAlignment) {
129 MockVideoSinkWithVideoFrame sink;
130 MockVideoSourceWithVideoFrame source;
131 VideoSourceSinkController controller(&sink, &source);
132 controller.SetResolutionAlignment(13);
133 EXPECT_EQ(controller.resolution_alignment(), 13);
134
135 EXPECT_CALL(source, AddOrUpdateSink(_, _))
136 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
137 const rtc::VideoSinkWants& wants) {
138 EXPECT_EQ(wants.resolution_alignment, 13);
139 });
140 controller.PushSourceSinkSettings();
141 }
142
TEST(VideoSourceSinkControllerTest,PushSourceSinkSettingsWithoutSourceDoesNotCrash)143 TEST(VideoSourceSinkControllerTest,
144 PushSourceSinkSettingsWithoutSourceDoesNotCrash) {
145 MockVideoSinkWithVideoFrame sink;
146 VideoSourceSinkController controller(&sink, nullptr);
147 controller.PushSourceSinkSettings();
148 }
149
150 } // namespace webrtc
151