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