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 <algorithm>
14 #include <limits>
15 #include <utility>
16 
17 #include "rtc_base/logging.h"
18 #include "rtc_base/numerics/safe_conversions.h"
19 #include "rtc_base/strings/string_builder.h"
20 
21 namespace webrtc {
22 
23 namespace {
24 
WantsToString(const rtc::VideoSinkWants & wants)25 std::string WantsToString(const rtc::VideoSinkWants& wants) {
26   rtc::StringBuilder ss;
27 
28   ss << "max_fps=" << wants.max_framerate_fps
29      << " max_pixel_count=" << wants.max_pixel_count << " target_pixel_count="
30      << (wants.target_pixel_count.has_value()
31              ? std::to_string(wants.target_pixel_count.value())
32              : "null");
33 
34   return ss.Release();
35 }
36 
37 }  // namespace
38 
VideoSourceSinkController(rtc::VideoSinkInterface<VideoFrame> * sink,rtc::VideoSourceInterface<VideoFrame> * source)39 VideoSourceSinkController::VideoSourceSinkController(
40     rtc::VideoSinkInterface<VideoFrame>* sink,
41     rtc::VideoSourceInterface<VideoFrame>* source)
42     : sink_(sink), source_(source) {
43   RTC_DCHECK(sink_);
44 }
45 
~VideoSourceSinkController()46 VideoSourceSinkController::~VideoSourceSinkController() {
47   RTC_DCHECK_RUN_ON(&sequence_checker_);
48 }
49 
SetSource(rtc::VideoSourceInterface<VideoFrame> * source)50 void VideoSourceSinkController::SetSource(
51     rtc::VideoSourceInterface<VideoFrame>* source) {
52   RTC_DCHECK_RUN_ON(&sequence_checker_);
53 
54   rtc::VideoSourceInterface<VideoFrame>* old_source = source_;
55   source_ = source;
56 
57   if (old_source != source && old_source)
58     old_source->RemoveSink(sink_);
59 
60   if (!source)
61     return;
62 
63   source->AddOrUpdateSink(sink_, CurrentSettingsToSinkWants());
64 }
65 
HasSource() const66 bool VideoSourceSinkController::HasSource() const {
67   RTC_DCHECK_RUN_ON(&sequence_checker_);
68   return source_ != nullptr;
69 }
70 
PushSourceSinkSettings()71 void VideoSourceSinkController::PushSourceSinkSettings() {
72   RTC_DCHECK_RUN_ON(&sequence_checker_);
73   if (!source_)
74     return;
75   rtc::VideoSinkWants wants = CurrentSettingsToSinkWants();
76   RTC_LOG(INFO) << "Pushing SourceSink restrictions: " << WantsToString(wants);
77   source_->AddOrUpdateSink(sink_, wants);
78 }
79 
restrictions() const80 VideoSourceRestrictions VideoSourceSinkController::restrictions() const {
81   RTC_DCHECK_RUN_ON(&sequence_checker_);
82   return restrictions_;
83 }
84 
pixels_per_frame_upper_limit() const85 absl::optional<size_t> VideoSourceSinkController::pixels_per_frame_upper_limit()
86     const {
87   RTC_DCHECK_RUN_ON(&sequence_checker_);
88   return pixels_per_frame_upper_limit_;
89 }
90 
frame_rate_upper_limit() const91 absl::optional<double> VideoSourceSinkController::frame_rate_upper_limit()
92     const {
93   RTC_DCHECK_RUN_ON(&sequence_checker_);
94   return frame_rate_upper_limit_;
95 }
96 
rotation_applied() const97 bool VideoSourceSinkController::rotation_applied() const {
98   RTC_DCHECK_RUN_ON(&sequence_checker_);
99   return rotation_applied_;
100 }
101 
resolution_alignment() const102 int VideoSourceSinkController::resolution_alignment() const {
103   RTC_DCHECK_RUN_ON(&sequence_checker_);
104   return resolution_alignment_;
105 }
106 
SetRestrictions(VideoSourceRestrictions restrictions)107 void VideoSourceSinkController::SetRestrictions(
108     VideoSourceRestrictions restrictions) {
109   RTC_DCHECK_RUN_ON(&sequence_checker_);
110   restrictions_ = std::move(restrictions);
111 }
112 
SetPixelsPerFrameUpperLimit(absl::optional<size_t> pixels_per_frame_upper_limit)113 void VideoSourceSinkController::SetPixelsPerFrameUpperLimit(
114     absl::optional<size_t> pixels_per_frame_upper_limit) {
115   RTC_DCHECK_RUN_ON(&sequence_checker_);
116   pixels_per_frame_upper_limit_ = std::move(pixels_per_frame_upper_limit);
117 }
118 
SetFrameRateUpperLimit(absl::optional<double> frame_rate_upper_limit)119 void VideoSourceSinkController::SetFrameRateUpperLimit(
120     absl::optional<double> frame_rate_upper_limit) {
121   RTC_DCHECK_RUN_ON(&sequence_checker_);
122   frame_rate_upper_limit_ = std::move(frame_rate_upper_limit);
123 }
124 
SetRotationApplied(bool rotation_applied)125 void VideoSourceSinkController::SetRotationApplied(bool rotation_applied) {
126   RTC_DCHECK_RUN_ON(&sequence_checker_);
127   rotation_applied_ = rotation_applied;
128 }
129 
SetResolutionAlignment(int resolution_alignment)130 void VideoSourceSinkController::SetResolutionAlignment(
131     int resolution_alignment) {
132   RTC_DCHECK_RUN_ON(&sequence_checker_);
133   resolution_alignment_ = resolution_alignment;
134 }
135 
136 // RTC_EXCLUSIVE_LOCKS_REQUIRED(sequence_checker_)
CurrentSettingsToSinkWants() const137 rtc::VideoSinkWants VideoSourceSinkController::CurrentSettingsToSinkWants()
138     const {
139   rtc::VideoSinkWants wants;
140   wants.rotation_applied = rotation_applied_;
141   // |wants.black_frames| is not used, it always has its default value false.
142   wants.max_pixel_count =
143       rtc::dchecked_cast<int>(restrictions_.max_pixels_per_frame().value_or(
144           std::numeric_limits<int>::max()));
145   wants.target_pixel_count =
146       restrictions_.target_pixels_per_frame().has_value()
147           ? absl::optional<int>(rtc::dchecked_cast<int>(
148                 restrictions_.target_pixels_per_frame().value()))
149           : absl::nullopt;
150   wants.max_framerate_fps =
151       restrictions_.max_frame_rate().has_value()
152           ? static_cast<int>(restrictions_.max_frame_rate().value())
153           : std::numeric_limits<int>::max();
154   wants.resolution_alignment = resolution_alignment_;
155   wants.max_pixel_count =
156       std::min(wants.max_pixel_count,
157                rtc::dchecked_cast<int>(pixels_per_frame_upper_limit_.value_or(
158                    std::numeric_limits<int>::max())));
159   wants.max_framerate_fps =
160       std::min(wants.max_framerate_fps,
161                frame_rate_upper_limit_.has_value()
162                    ? static_cast<int>(frame_rate_upper_limit_.value())
163                    : std::numeric_limits<int>::max());
164   return wants;
165 }
166 
167 }  // namespace webrtc
168