blob: 61cfafd45c41c71941964cd2882ef7294be4d819 [file] [log] [blame]
Henrik Boströmce0ea492020-01-13 11:27:18 +01001/*
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
21using testing::_;
22
23namespace webrtc {
24
25namespace {
26
27constexpr int kIntUnconstrained = std::numeric_limits<int>::max();
28
29class MockVideoSinkWithVideoFrame : public rtc::VideoSinkInterface<VideoFrame> {
30 public:
31 ~MockVideoSinkWithVideoFrame() override {}
32
33 MOCK_METHOD1(OnFrame, void(const VideoFrame& frame));
34 MOCK_METHOD0(OnDiscardedFrame, void());
35};
36
37class MockVideoSourceWithVideoFrame
38 : public rtc::VideoSourceInterface<VideoFrame> {
39 public:
40 ~MockVideoSourceWithVideoFrame() override {}
41
42 MOCK_METHOD2(AddOrUpdateSink,
43 void(rtc::VideoSinkInterface<VideoFrame>*,
44 const rtc::VideoSinkWants&));
45 MOCK_METHOD1(RemoveSink, void(rtc::VideoSinkInterface<VideoFrame>*));
46};
47
48} // namespace
49
50TEST(VideoSourceSinkControllerTest, UnconstrainedByDefault) {
51 MockVideoSinkWithVideoFrame sink;
52 MockVideoSourceWithVideoFrame source;
53 VideoSourceSinkController controller(&sink, &source);
54 EXPECT_EQ(controller.restrictions(), VideoSourceRestrictions());
55 EXPECT_FALSE(controller.pixels_per_frame_upper_limit().has_value());
56 EXPECT_FALSE(controller.frame_rate_upper_limit().has_value());
57 EXPECT_FALSE(controller.rotation_applied());
58 EXPECT_EQ(controller.resolution_alignment(), 1);
59
60 EXPECT_CALL(source, AddOrUpdateSink(_, _))
61 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
62 const rtc::VideoSinkWants& wants) {
63 EXPECT_FALSE(wants.rotation_applied);
64 EXPECT_EQ(wants.max_pixel_count, kIntUnconstrained);
65 EXPECT_EQ(wants.target_pixel_count, absl::nullopt);
66 EXPECT_EQ(wants.max_framerate_fps, kIntUnconstrained);
67 EXPECT_EQ(wants.resolution_alignment, 1);
68 });
69 controller.PushSourceSinkSettings();
70}
71
72TEST(VideoSourceSinkControllerTest, VideoRestrictionsToSinkWants) {
73 MockVideoSinkWithVideoFrame sink;
74 MockVideoSourceWithVideoFrame source;
75 VideoSourceSinkController controller(&sink, &source);
76
77 // Balanced degradation preference gives us what we ask for.
78 EXPECT_CALL(source, AddOrUpdateSink(_, _)).Times(1);
79 controller.SetSource(&source, DegradationPreference::BALANCED);
80
81 VideoSourceRestrictions restrictions = controller.restrictions();
82 // max_pixels_per_frame() maps to |max_pixel_count|.
83 restrictions.set_max_pixels_per_frame(42u);
84 // target_pixels_per_frame() maps to |target_pixel_count|.
85 restrictions.set_target_pixels_per_frame(200u);
86 // max_frame_rate() maps to |max_framerate_fps|.
87 restrictions.set_max_frame_rate(30.0);
88 controller.SetRestrictions(restrictions);
89 EXPECT_CALL(source, AddOrUpdateSink(_, _))
90 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
91 const rtc::VideoSinkWants& wants) {
92 EXPECT_EQ(wants.max_pixel_count, 42);
93 EXPECT_EQ(wants.target_pixel_count, 200);
94 EXPECT_EQ(wants.max_framerate_fps, 30);
95 });
96 controller.PushSourceSinkSettings();
97
98 // Disabled degradation preference makes the "wants" unconstrained despite our
99 // restrictions.
100 EXPECT_CALL(source, AddOrUpdateSink(_, _)).Times(1);
101 controller.SetSource(&source, DegradationPreference::DISABLED);
102 EXPECT_CALL(source, AddOrUpdateSink(_, _))
103 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
104 const rtc::VideoSinkWants& wants) {
105 EXPECT_EQ(wants.max_pixel_count, kIntUnconstrained);
106 EXPECT_FALSE(wants.target_pixel_count.has_value());
107 EXPECT_EQ(wants.max_framerate_fps, kIntUnconstrained);
108 });
109 controller.PushSourceSinkSettings();
110
111 // pixels_per_frame_upper_limit() caps |max_pixel_count| regardless of
112 // degradation preferences.
113 controller.SetPixelsPerFrameUpperLimit(24);
114 // frame_rate_upper_limit() caps |max_framerate_fps| regardless of degradation
115 // preferences.
116 controller.SetFrameRateUpperLimit(10.0);
117
118 EXPECT_CALL(source, AddOrUpdateSink(_, _))
119 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
120 const rtc::VideoSinkWants& wants) {
121 EXPECT_EQ(wants.max_pixel_count, 24);
122 EXPECT_EQ(wants.max_framerate_fps, 10);
123 });
124 controller.PushSourceSinkSettings();
125}
126
127TEST(VideoSourceSinkControllerTest, RotationApplied) {
128 MockVideoSinkWithVideoFrame sink;
129 MockVideoSourceWithVideoFrame source;
130 VideoSourceSinkController controller(&sink, &source);
131 controller.SetRotationApplied(true);
132 EXPECT_TRUE(controller.rotation_applied());
133
134 EXPECT_CALL(source, AddOrUpdateSink(_, _))
135 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
136 const rtc::VideoSinkWants& wants) {
137 EXPECT_TRUE(wants.rotation_applied);
138 });
139 controller.PushSourceSinkSettings();
140}
141
142TEST(VideoSourceSinkControllerTest, ResolutionAlignment) {
143 MockVideoSinkWithVideoFrame sink;
144 MockVideoSourceWithVideoFrame source;
145 VideoSourceSinkController controller(&sink, &source);
146 controller.SetResolutionAlignment(13);
147 EXPECT_EQ(controller.resolution_alignment(), 13);
148
149 EXPECT_CALL(source, AddOrUpdateSink(_, _))
150 .WillOnce([](rtc::VideoSinkInterface<VideoFrame>* sink,
151 const rtc::VideoSinkWants& wants) {
152 EXPECT_EQ(wants.resolution_alignment, 13);
153 });
154 controller.PushSourceSinkSettings();
155}
156
157TEST(VideoSourceSinkControllerTest,
158 PushSourceSinkSettingsWithoutSourceDoesNotCrash) {
159 MockVideoSinkWithVideoFrame sink;
160 VideoSourceSinkController controller(&sink, nullptr);
161 controller.PushSourceSinkSettings();
162}
163
164} // namespace webrtc