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 #ifndef CALL_ADAPTATION_VIDEO_STREAM_ADAPTER_H_ 12 #define CALL_ADAPTATION_VIDEO_STREAM_ADAPTER_H_ 13 14 #include <memory> 15 #include <utility> 16 #include <vector> 17 18 #include "absl/types/optional.h" 19 #include "absl/types/variant.h" 20 #include "api/adaptation/resource.h" 21 #include "api/field_trials_view.h" 22 #include "api/rtp_parameters.h" 23 #include "api/video/video_adaptation_counters.h" 24 #include "call/adaptation/adaptation_constraint.h" 25 #include "call/adaptation/degradation_preference_provider.h" 26 #include "call/adaptation/video_source_restrictions.h" 27 #include "call/adaptation/video_stream_input_state.h" 28 #include "call/adaptation/video_stream_input_state_provider.h" 29 #include "modules/video_coding/utility/quality_scaler.h" 30 #include "rtc_base/experiments/balanced_degradation_settings.h" 31 #include "rtc_base/system/no_unique_address.h" 32 #include "rtc_base/thread_annotations.h" 33 #include "video/video_stream_encoder_observer.h" 34 35 namespace webrtc { 36 37 // The listener is responsible for carrying out the reconfiguration of the video 38 // source such that the VideoSourceRestrictions are fulfilled. 39 class VideoSourceRestrictionsListener { 40 public: 41 virtual ~VideoSourceRestrictionsListener(); 42 43 // The `restrictions` are filtered by degradation preference but not the 44 // `adaptation_counters`, which are currently only reported for legacy stats 45 // calculation purposes. 46 virtual void OnVideoSourceRestrictionsUpdated( 47 VideoSourceRestrictions restrictions, 48 const VideoAdaptationCounters& adaptation_counters, 49 rtc::scoped_refptr<Resource> reason, 50 const VideoSourceRestrictions& unfiltered_restrictions) = 0; 51 }; 52 53 class VideoStreamAdapter; 54 55 extern const int kMinFrameRateFps; 56 57 VideoSourceRestrictions FilterRestrictionsByDegradationPreference( 58 VideoSourceRestrictions source_restrictions, 59 DegradationPreference degradation_preference); 60 61 int GetLowerResolutionThan(int pixel_count); 62 int GetHigherResolutionThan(int pixel_count); 63 64 // Either represents the next VideoSourceRestrictions the VideoStreamAdapter 65 // will take, or provides a Status code indicating the reason for not adapting 66 // if the adaptation is not valid. 67 class Adaptation final { 68 public: 69 enum class Status { 70 // Applying this adaptation will have an effect. All other Status codes 71 // indicate that adaptation is not possible and why. 72 kValid, 73 // Cannot adapt. The minimum or maximum adaptation has already been reached. 74 // There are no more steps to take. 75 kLimitReached, 76 // Cannot adapt. The resolution or frame rate requested by a recent 77 // adaptation has not yet been reflected in the input resolution or frame 78 // rate; adaptation is refused to avoid "double-adapting". 79 kAwaitingPreviousAdaptation, 80 // Not enough input. 81 kInsufficientInput, 82 // Adaptation disabled via degradation preference. 83 kAdaptationDisabled, 84 // Adaptation up was rejected by a VideoAdaptationConstraint. 85 kRejectedByConstraint, 86 }; 87 88 static const char* StatusToString(Status status); 89 90 Status status() const; 91 const VideoStreamInputState& input_state() const; 92 const VideoSourceRestrictions& restrictions() const; 93 const VideoAdaptationCounters& counters() const; 94 95 private: 96 friend class VideoStreamAdapter; 97 98 // Constructs with a valid adaptation. Status is kValid. 99 Adaptation(int validation_id, 100 VideoSourceRestrictions restrictions, 101 VideoAdaptationCounters counters, 102 VideoStreamInputState input_state); 103 // Constructor when adaptation is not valid. Status MUST NOT be kValid. 104 Adaptation(int validation_id, Status invalid_status); 105 106 // An Adaptation can become invalidated if the state of VideoStreamAdapter is 107 // modified before the Adaptation is applied. To guard against this, this ID 108 // has to match VideoStreamAdapter::adaptation_validation_id_ when applied. 109 // TODO(https://crbug.com/webrtc/11700): Remove the validation_id_. 110 const int validation_id_; 111 const Status status_; 112 // Input state when adaptation was made. 113 const VideoStreamInputState input_state_; 114 const VideoSourceRestrictions restrictions_; 115 const VideoAdaptationCounters counters_; 116 }; 117 118 // Owns the VideoSourceRestriction for a single stream and is responsible for 119 // adapting it up or down when told to do so. This class serves the following 120 // purposes: 121 // 1. Keep track of a stream's restrictions. 122 // 2. Provide valid ways to adapt up or down the stream's restrictions. 123 // 3. Modify the stream's restrictions in one of the valid ways. 124 class VideoStreamAdapter { 125 public: 126 VideoStreamAdapter(VideoStreamInputStateProvider* input_state_provider, 127 VideoStreamEncoderObserver* encoder_stats_observer, 128 const FieldTrialsView& field_trials); 129 ~VideoStreamAdapter(); 130 131 VideoSourceRestrictions source_restrictions() const; 132 const VideoAdaptationCounters& adaptation_counters() const; 133 void ClearRestrictions(); 134 135 void AddRestrictionsListener( 136 VideoSourceRestrictionsListener* restrictions_listener); 137 void RemoveRestrictionsListener( 138 VideoSourceRestrictionsListener* restrictions_listener); 139 void AddAdaptationConstraint(AdaptationConstraint* adaptation_constraint); 140 void RemoveAdaptationConstraint(AdaptationConstraint* adaptation_constraint); 141 142 // TODO(hbos): Setting the degradation preference should not clear 143 // restrictions! This is not defined in the spec and is unexpected, there is a 144 // tiny risk that people would discover and rely on this behavior. 145 void SetDegradationPreference(DegradationPreference degradation_preference); 146 147 // Returns an adaptation that we are guaranteed to be able to apply, or a 148 // status code indicating the reason why we cannot adapt. 149 Adaptation GetAdaptationUp(); 150 Adaptation GetAdaptationDown(); 151 Adaptation GetAdaptationTo(const VideoAdaptationCounters& counters, 152 const VideoSourceRestrictions& restrictions); 153 // Tries to adapt the resolution one step. This is used for initial frame 154 // dropping. Does nothing if the degradation preference is not BALANCED or 155 // MAINTAIN_FRAMERATE. In the case of BALANCED, it will try twice to reduce 156 // the resolution. If it fails twice it gives up. 157 Adaptation GetAdaptDownResolution(); 158 159 // Updates source_restrictions() the Adaptation. 160 void ApplyAdaptation(const Adaptation& adaptation, 161 rtc::scoped_refptr<Resource> resource); 162 163 struct RestrictionsWithCounters { 164 VideoSourceRestrictions restrictions; 165 VideoAdaptationCounters counters; 166 }; 167 168 static absl::optional<uint32_t> GetSingleActiveLayerPixels( 169 const VideoCodec& codec); 170 171 private: 172 void BroadcastVideoRestrictionsUpdate( 173 const VideoStreamInputState& input_state, 174 const rtc::scoped_refptr<Resource>& resource); 175 176 bool HasSufficientInputForAdaptation(const VideoStreamInputState& input_state) 177 const RTC_RUN_ON(&sequence_checker_); 178 179 using RestrictionsOrState = 180 absl::variant<RestrictionsWithCounters, Adaptation::Status>; 181 RestrictionsOrState GetAdaptationUpStep( 182 const VideoStreamInputState& input_state) const 183 RTC_RUN_ON(&sequence_checker_); 184 RestrictionsOrState GetAdaptationDownStep( 185 const VideoStreamInputState& input_state, 186 const RestrictionsWithCounters& current_restrictions) const 187 RTC_RUN_ON(&sequence_checker_); 188 RestrictionsOrState GetAdaptDownResolutionStepForBalanced( 189 const VideoStreamInputState& input_state) const 190 RTC_RUN_ON(&sequence_checker_); 191 RestrictionsOrState AdaptIfFpsDiffInsufficient( 192 const VideoStreamInputState& input_state, 193 const RestrictionsWithCounters& restrictions) const 194 RTC_RUN_ON(&sequence_checker_); 195 196 Adaptation GetAdaptationUp(const VideoStreamInputState& input_state) const 197 RTC_RUN_ON(&sequence_checker_); 198 Adaptation GetAdaptationDown(const VideoStreamInputState& input_state) const 199 RTC_RUN_ON(&sequence_checker_); 200 201 static RestrictionsOrState DecreaseResolution( 202 const VideoStreamInputState& input_state, 203 const RestrictionsWithCounters& current_restrictions); 204 static RestrictionsOrState IncreaseResolution( 205 const VideoStreamInputState& input_state, 206 const RestrictionsWithCounters& current_restrictions); 207 // Framerate methods are member functions because they need internal state 208 // if the degradation preference is BALANCED. 209 RestrictionsOrState DecreaseFramerate( 210 const VideoStreamInputState& input_state, 211 const RestrictionsWithCounters& current_restrictions) const 212 RTC_RUN_ON(&sequence_checker_); 213 RestrictionsOrState IncreaseFramerate( 214 const VideoStreamInputState& input_state, 215 const RestrictionsWithCounters& current_restrictions) const 216 RTC_RUN_ON(&sequence_checker_); 217 218 struct RestrictionsOrStateVisitor; 219 Adaptation RestrictionsOrStateToAdaptation( 220 RestrictionsOrState step_or_state, 221 const VideoStreamInputState& input_state) const 222 RTC_RUN_ON(&sequence_checker_); 223 224 RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_ 225 RTC_GUARDED_BY(&sequence_checker_); 226 // Gets the input state which is the basis of all adaptations. 227 // Thread safe. 228 VideoStreamInputStateProvider* input_state_provider_; 229 // Used to signal when min pixel limit has been reached. 230 VideoStreamEncoderObserver* const encoder_stats_observer_; 231 // Decides the next adaptation target in DegradationPreference::BALANCED. 232 const BalancedDegradationSettings balanced_settings_; 233 // To guard against applying adaptations that have become invalidated, an 234 // Adaptation that is applied has to have a matching validation ID. 235 int adaptation_validation_id_ RTC_GUARDED_BY(&sequence_checker_); 236 // When deciding the next target up or down, different strategies are used 237 // depending on the DegradationPreference. 238 // https://w3c.github.io/mst-content-hint/#dom-rtcdegradationpreference 239 DegradationPreference degradation_preference_ 240 RTC_GUARDED_BY(&sequence_checker_); 241 // Used to avoid adapting twice. Stores the resolution at the time of the last 242 // adaptation. 243 // TODO(hbos): Can we implement a more general "cooldown" mechanism of 244 // resources intead? If we already have adapted it seems like we should wait 245 // a while before adapting again, so that we are not acting on usage 246 // measurements that are made obsolete/unreliable by an "ongoing" adaptation. 247 struct AwaitingFrameSizeChange { 248 AwaitingFrameSizeChange(bool pixels_increased, int frame_size); 249 const bool pixels_increased; 250 const int frame_size_pixels; 251 }; 252 absl::optional<AwaitingFrameSizeChange> awaiting_frame_size_change_ 253 RTC_GUARDED_BY(&sequence_checker_); 254 // The previous restrictions value. Starts as unrestricted. 255 VideoSourceRestrictions last_video_source_restrictions_ 256 RTC_GUARDED_BY(&sequence_checker_); 257 VideoSourceRestrictions last_filtered_restrictions_ 258 RTC_GUARDED_BY(&sequence_checker_); 259 260 std::vector<VideoSourceRestrictionsListener*> restrictions_listeners_ 261 RTC_GUARDED_BY(&sequence_checker_); 262 std::vector<AdaptationConstraint*> adaptation_constraints_ 263 RTC_GUARDED_BY(&sequence_checker_); 264 265 RestrictionsWithCounters current_restrictions_ 266 RTC_GUARDED_BY(&sequence_checker_); 267 }; 268 269 } // namespace webrtc 270 271 #endif // CALL_ADAPTATION_VIDEO_STREAM_ADAPTER_H_ 272