xref: /aosp_15_r20/external/webrtc/call/adaptation/video_stream_adapter.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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