xref: /aosp_15_r20/external/webrtc/video/video_stream_encoder.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "video/video_stream_encoder.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <array>
15*d9f75844SAndroid Build Coastguard Worker #include <limits>
16*d9f75844SAndroid Build Coastguard Worker #include <memory>
17*d9f75844SAndroid Build Coastguard Worker #include <numeric>
18*d9f75844SAndroid Build Coastguard Worker #include <utility>
19*d9f75844SAndroid Build Coastguard Worker 
20*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
21*d9f75844SAndroid Build Coastguard Worker #include "absl/cleanup/cleanup.h"
22*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/field_trials_view.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
25*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/task_queue_base.h"
26*d9f75844SAndroid Build Coastguard Worker #include "api/video/encoded_image.h"
27*d9f75844SAndroid Build Coastguard Worker #include "api/video/i420_buffer.h"
28*d9f75844SAndroid Build Coastguard Worker #include "api/video/render_resolution.h"
29*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_adaptation_reason.h"
30*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_bitrate_allocator_factory.h"
31*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_codec_constants.h"
32*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_layers_allocation.h"
33*d9f75844SAndroid Build Coastguard Worker #include "api/video_codecs/sdp_video_format.h"
34*d9f75844SAndroid Build Coastguard Worker #include "api/video_codecs/video_encoder.h"
35*d9f75844SAndroid Build Coastguard Worker #include "call/adaptation/resource_adaptation_processor.h"
36*d9f75844SAndroid Build Coastguard Worker #include "call/adaptation/video_source_restrictions.h"
37*d9f75844SAndroid Build Coastguard Worker #include "call/adaptation/video_stream_adapter.h"
38*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_channel.h"
39*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/include/video_codec_initializer.h"
40*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/svc/svc_rate_allocator.h"
41*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/utility/vp8_constants.h"
42*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/arraysize.h"
43*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
44*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/event.h"
45*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/alr_experiment.h"
46*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/encoder_info_settings.h"
47*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/rate_control_settings.h"
48*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
49*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
50*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/no_unique_address.h"
51*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread_annotations.h"
52*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
53*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/metrics.h"
54*d9f75844SAndroid Build Coastguard Worker #include "video/adaptation/video_stream_encoder_resource_manager.h"
55*d9f75844SAndroid Build Coastguard Worker #include "video/alignment_adjuster.h"
56*d9f75844SAndroid Build Coastguard Worker #include "video/config/encoder_stream_factory.h"
57*d9f75844SAndroid Build Coastguard Worker #include "video/frame_cadence_adapter.h"
58*d9f75844SAndroid Build Coastguard Worker 
59*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
60*d9f75844SAndroid Build Coastguard Worker 
61*d9f75844SAndroid Build Coastguard Worker namespace {
62*d9f75844SAndroid Build Coastguard Worker 
63*d9f75844SAndroid Build Coastguard Worker // Time interval for logging frame counts.
64*d9f75844SAndroid Build Coastguard Worker const int64_t kFrameLogIntervalMs = 60000;
65*d9f75844SAndroid Build Coastguard Worker 
66*d9f75844SAndroid Build Coastguard Worker // Time to keep a single cached pending frame in paused state.
67*d9f75844SAndroid Build Coastguard Worker const int64_t kPendingFrameTimeoutMs = 1000;
68*d9f75844SAndroid Build Coastguard Worker 
69*d9f75844SAndroid Build Coastguard Worker constexpr char kFrameDropperFieldTrial[] = "WebRTC-FrameDropper";
70*d9f75844SAndroid Build Coastguard Worker 
71*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/13572): Remove this kill switch after deploying the
72*d9f75844SAndroid Build Coastguard Worker // feature.
73*d9f75844SAndroid Build Coastguard Worker constexpr char kSwitchEncoderOnInitializationFailuresFieldTrial[] =
74*d9f75844SAndroid Build Coastguard Worker     "WebRTC-SwitchEncoderOnInitializationFailures";
75*d9f75844SAndroid Build Coastguard Worker 
76*d9f75844SAndroid Build Coastguard Worker const size_t kDefaultPayloadSize = 1440;
77*d9f75844SAndroid Build Coastguard Worker 
78*d9f75844SAndroid Build Coastguard Worker const int64_t kParameterUpdateIntervalMs = 1000;
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker // Animation is capped to 720p.
81*d9f75844SAndroid Build Coastguard Worker constexpr int kMaxAnimationPixels = 1280 * 720;
82*d9f75844SAndroid Build Coastguard Worker 
83*d9f75844SAndroid Build Coastguard Worker constexpr int kDefaultMinScreenSharebps = 1200000;
84*d9f75844SAndroid Build Coastguard Worker 
RequiresEncoderReset(const VideoCodec & prev_send_codec,const VideoCodec & new_send_codec,bool was_encode_called_since_last_initialization)85*d9f75844SAndroid Build Coastguard Worker bool RequiresEncoderReset(const VideoCodec& prev_send_codec,
86*d9f75844SAndroid Build Coastguard Worker                           const VideoCodec& new_send_codec,
87*d9f75844SAndroid Build Coastguard Worker                           bool was_encode_called_since_last_initialization) {
88*d9f75844SAndroid Build Coastguard Worker   // Does not check max/minBitrate or maxFramerate.
89*d9f75844SAndroid Build Coastguard Worker   if (new_send_codec.codecType != prev_send_codec.codecType ||
90*d9f75844SAndroid Build Coastguard Worker       new_send_codec.width != prev_send_codec.width ||
91*d9f75844SAndroid Build Coastguard Worker       new_send_codec.height != prev_send_codec.height ||
92*d9f75844SAndroid Build Coastguard Worker       new_send_codec.qpMax != prev_send_codec.qpMax ||
93*d9f75844SAndroid Build Coastguard Worker       new_send_codec.numberOfSimulcastStreams !=
94*d9f75844SAndroid Build Coastguard Worker           prev_send_codec.numberOfSimulcastStreams ||
95*d9f75844SAndroid Build Coastguard Worker       new_send_codec.mode != prev_send_codec.mode ||
96*d9f75844SAndroid Build Coastguard Worker       new_send_codec.GetFrameDropEnabled() !=
97*d9f75844SAndroid Build Coastguard Worker           prev_send_codec.GetFrameDropEnabled()) {
98*d9f75844SAndroid Build Coastguard Worker     return true;
99*d9f75844SAndroid Build Coastguard Worker   }
100*d9f75844SAndroid Build Coastguard Worker 
101*d9f75844SAndroid Build Coastguard Worker   if (!was_encode_called_since_last_initialization &&
102*d9f75844SAndroid Build Coastguard Worker       (new_send_codec.startBitrate != prev_send_codec.startBitrate)) {
103*d9f75844SAndroid Build Coastguard Worker     // If start bitrate has changed reconfigure encoder only if encoding had not
104*d9f75844SAndroid Build Coastguard Worker     // yet started.
105*d9f75844SAndroid Build Coastguard Worker     return true;
106*d9f75844SAndroid Build Coastguard Worker   }
107*d9f75844SAndroid Build Coastguard Worker 
108*d9f75844SAndroid Build Coastguard Worker   switch (new_send_codec.codecType) {
109*d9f75844SAndroid Build Coastguard Worker     case kVideoCodecVP8:
110*d9f75844SAndroid Build Coastguard Worker       if (new_send_codec.VP8() != prev_send_codec.VP8()) {
111*d9f75844SAndroid Build Coastguard Worker         return true;
112*d9f75844SAndroid Build Coastguard Worker       }
113*d9f75844SAndroid Build Coastguard Worker       break;
114*d9f75844SAndroid Build Coastguard Worker 
115*d9f75844SAndroid Build Coastguard Worker     case kVideoCodecVP9:
116*d9f75844SAndroid Build Coastguard Worker       if (new_send_codec.VP9() != prev_send_codec.VP9()) {
117*d9f75844SAndroid Build Coastguard Worker         return true;
118*d9f75844SAndroid Build Coastguard Worker       }
119*d9f75844SAndroid Build Coastguard Worker       break;
120*d9f75844SAndroid Build Coastguard Worker 
121*d9f75844SAndroid Build Coastguard Worker     case kVideoCodecH264:
122*d9f75844SAndroid Build Coastguard Worker       if (new_send_codec.H264() != prev_send_codec.H264()) {
123*d9f75844SAndroid Build Coastguard Worker         return true;
124*d9f75844SAndroid Build Coastguard Worker       }
125*d9f75844SAndroid Build Coastguard Worker       break;
126*d9f75844SAndroid Build Coastguard Worker 
127*d9f75844SAndroid Build Coastguard Worker     default:
128*d9f75844SAndroid Build Coastguard Worker       break;
129*d9f75844SAndroid Build Coastguard Worker   }
130*d9f75844SAndroid Build Coastguard Worker 
131*d9f75844SAndroid Build Coastguard Worker   for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
132*d9f75844SAndroid Build Coastguard Worker     if (!new_send_codec.simulcastStream[i].active) {
133*d9f75844SAndroid Build Coastguard Worker       // No need to reset when stream is inactive.
134*d9f75844SAndroid Build Coastguard Worker       continue;
135*d9f75844SAndroid Build Coastguard Worker     }
136*d9f75844SAndroid Build Coastguard Worker 
137*d9f75844SAndroid Build Coastguard Worker     if (!prev_send_codec.simulcastStream[i].active ||
138*d9f75844SAndroid Build Coastguard Worker         new_send_codec.simulcastStream[i].width !=
139*d9f75844SAndroid Build Coastguard Worker             prev_send_codec.simulcastStream[i].width ||
140*d9f75844SAndroid Build Coastguard Worker         new_send_codec.simulcastStream[i].height !=
141*d9f75844SAndroid Build Coastguard Worker             prev_send_codec.simulcastStream[i].height ||
142*d9f75844SAndroid Build Coastguard Worker         new_send_codec.simulcastStream[i].numberOfTemporalLayers !=
143*d9f75844SAndroid Build Coastguard Worker             prev_send_codec.simulcastStream[i].numberOfTemporalLayers ||
144*d9f75844SAndroid Build Coastguard Worker         new_send_codec.simulcastStream[i].qpMax !=
145*d9f75844SAndroid Build Coastguard Worker             prev_send_codec.simulcastStream[i].qpMax) {
146*d9f75844SAndroid Build Coastguard Worker       return true;
147*d9f75844SAndroid Build Coastguard Worker     }
148*d9f75844SAndroid Build Coastguard Worker   }
149*d9f75844SAndroid Build Coastguard Worker 
150*d9f75844SAndroid Build Coastguard Worker   if (new_send_codec.codecType == kVideoCodecVP9) {
151*d9f75844SAndroid Build Coastguard Worker     size_t num_spatial_layers = new_send_codec.VP9().numberOfSpatialLayers;
152*d9f75844SAndroid Build Coastguard Worker     for (unsigned char i = 0; i < num_spatial_layers; ++i) {
153*d9f75844SAndroid Build Coastguard Worker       if (new_send_codec.spatialLayers[i].width !=
154*d9f75844SAndroid Build Coastguard Worker               prev_send_codec.spatialLayers[i].width ||
155*d9f75844SAndroid Build Coastguard Worker           new_send_codec.spatialLayers[i].height !=
156*d9f75844SAndroid Build Coastguard Worker               prev_send_codec.spatialLayers[i].height ||
157*d9f75844SAndroid Build Coastguard Worker           new_send_codec.spatialLayers[i].numberOfTemporalLayers !=
158*d9f75844SAndroid Build Coastguard Worker               prev_send_codec.spatialLayers[i].numberOfTemporalLayers ||
159*d9f75844SAndroid Build Coastguard Worker           new_send_codec.spatialLayers[i].qpMax !=
160*d9f75844SAndroid Build Coastguard Worker               prev_send_codec.spatialLayers[i].qpMax) {
161*d9f75844SAndroid Build Coastguard Worker         return true;
162*d9f75844SAndroid Build Coastguard Worker       }
163*d9f75844SAndroid Build Coastguard Worker     }
164*d9f75844SAndroid Build Coastguard Worker   }
165*d9f75844SAndroid Build Coastguard Worker 
166*d9f75844SAndroid Build Coastguard Worker   if (new_send_codec.GetScalabilityMode() !=
167*d9f75844SAndroid Build Coastguard Worker       prev_send_codec.GetScalabilityMode()) {
168*d9f75844SAndroid Build Coastguard Worker     return true;
169*d9f75844SAndroid Build Coastguard Worker   }
170*d9f75844SAndroid Build Coastguard Worker 
171*d9f75844SAndroid Build Coastguard Worker   return false;
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker 
GetExperimentGroups()174*d9f75844SAndroid Build Coastguard Worker std::array<uint8_t, 2> GetExperimentGroups() {
175*d9f75844SAndroid Build Coastguard Worker   std::array<uint8_t, 2> experiment_groups;
176*d9f75844SAndroid Build Coastguard Worker   absl::optional<AlrExperimentSettings> experiment_settings =
177*d9f75844SAndroid Build Coastguard Worker       AlrExperimentSettings::CreateFromFieldTrial(
178*d9f75844SAndroid Build Coastguard Worker           AlrExperimentSettings::kStrictPacingAndProbingExperimentName);
179*d9f75844SAndroid Build Coastguard Worker   if (experiment_settings) {
180*d9f75844SAndroid Build Coastguard Worker     experiment_groups[0] = experiment_settings->group_id + 1;
181*d9f75844SAndroid Build Coastguard Worker   } else {
182*d9f75844SAndroid Build Coastguard Worker     experiment_groups[0] = 0;
183*d9f75844SAndroid Build Coastguard Worker   }
184*d9f75844SAndroid Build Coastguard Worker   experiment_settings = AlrExperimentSettings::CreateFromFieldTrial(
185*d9f75844SAndroid Build Coastguard Worker       AlrExperimentSettings::kScreenshareProbingBweExperimentName);
186*d9f75844SAndroid Build Coastguard Worker   if (experiment_settings) {
187*d9f75844SAndroid Build Coastguard Worker     experiment_groups[1] = experiment_settings->group_id + 1;
188*d9f75844SAndroid Build Coastguard Worker   } else {
189*d9f75844SAndroid Build Coastguard Worker     experiment_groups[1] = 0;
190*d9f75844SAndroid Build Coastguard Worker   }
191*d9f75844SAndroid Build Coastguard Worker   return experiment_groups;
192*d9f75844SAndroid Build Coastguard Worker }
193*d9f75844SAndroid Build Coastguard Worker 
194*d9f75844SAndroid Build Coastguard Worker // Limit allocation across TLs in bitrate allocation according to number of TLs
195*d9f75844SAndroid Build Coastguard Worker // in EncoderInfo.
UpdateAllocationFromEncoderInfo(const VideoBitrateAllocation & allocation,const VideoEncoder::EncoderInfo & encoder_info)196*d9f75844SAndroid Build Coastguard Worker VideoBitrateAllocation UpdateAllocationFromEncoderInfo(
197*d9f75844SAndroid Build Coastguard Worker     const VideoBitrateAllocation& allocation,
198*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::EncoderInfo& encoder_info) {
199*d9f75844SAndroid Build Coastguard Worker   if (allocation.get_sum_bps() == 0) {
200*d9f75844SAndroid Build Coastguard Worker     return allocation;
201*d9f75844SAndroid Build Coastguard Worker   }
202*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation new_allocation;
203*d9f75844SAndroid Build Coastguard Worker   for (int si = 0; si < kMaxSpatialLayers; ++si) {
204*d9f75844SAndroid Build Coastguard Worker     if (encoder_info.fps_allocation[si].size() == 1 &&
205*d9f75844SAndroid Build Coastguard Worker         allocation.IsSpatialLayerUsed(si)) {
206*d9f75844SAndroid Build Coastguard Worker       // One TL is signalled to be used by the encoder. Do not distribute
207*d9f75844SAndroid Build Coastguard Worker       // bitrate allocation across TLs (use sum at ti:0).
208*d9f75844SAndroid Build Coastguard Worker       new_allocation.SetBitrate(si, 0, allocation.GetSpatialLayerSum(si));
209*d9f75844SAndroid Build Coastguard Worker     } else {
210*d9f75844SAndroid Build Coastguard Worker       for (int ti = 0; ti < kMaxTemporalStreams; ++ti) {
211*d9f75844SAndroid Build Coastguard Worker         if (allocation.HasBitrate(si, ti))
212*d9f75844SAndroid Build Coastguard Worker           new_allocation.SetBitrate(si, ti, allocation.GetBitrate(si, ti));
213*d9f75844SAndroid Build Coastguard Worker       }
214*d9f75844SAndroid Build Coastguard Worker     }
215*d9f75844SAndroid Build Coastguard Worker   }
216*d9f75844SAndroid Build Coastguard Worker   new_allocation.set_bw_limited(allocation.is_bw_limited());
217*d9f75844SAndroid Build Coastguard Worker   return new_allocation;
218*d9f75844SAndroid Build Coastguard Worker }
219*d9f75844SAndroid Build Coastguard Worker 
220*d9f75844SAndroid Build Coastguard Worker // Converts a VideoBitrateAllocation that contains allocated bitrate per layer,
221*d9f75844SAndroid Build Coastguard Worker // and an EncoderInfo that contains information about the actual encoder
222*d9f75844SAndroid Build Coastguard Worker // structure used by a codec. Stream structures can be Ksvc, Full SVC, Simulcast
223*d9f75844SAndroid Build Coastguard Worker // etc.
CreateVideoLayersAllocation(const VideoCodec & encoder_config,const VideoEncoder::RateControlParameters & current_rate,const VideoEncoder::EncoderInfo & encoder_info)224*d9f75844SAndroid Build Coastguard Worker VideoLayersAllocation CreateVideoLayersAllocation(
225*d9f75844SAndroid Build Coastguard Worker     const VideoCodec& encoder_config,
226*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::RateControlParameters& current_rate,
227*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::EncoderInfo& encoder_info) {
228*d9f75844SAndroid Build Coastguard Worker   const VideoBitrateAllocation& target_bitrate = current_rate.target_bitrate;
229*d9f75844SAndroid Build Coastguard Worker   VideoLayersAllocation layers_allocation;
230*d9f75844SAndroid Build Coastguard Worker   if (target_bitrate.get_sum_bps() == 0) {
231*d9f75844SAndroid Build Coastguard Worker     return layers_allocation;
232*d9f75844SAndroid Build Coastguard Worker   }
233*d9f75844SAndroid Build Coastguard Worker 
234*d9f75844SAndroid Build Coastguard Worker   if (encoder_config.numberOfSimulcastStreams > 1) {
235*d9f75844SAndroid Build Coastguard Worker     layers_allocation.resolution_and_frame_rate_is_valid = true;
236*d9f75844SAndroid Build Coastguard Worker     for (int si = 0; si < encoder_config.numberOfSimulcastStreams; ++si) {
237*d9f75844SAndroid Build Coastguard Worker       if (!target_bitrate.IsSpatialLayerUsed(si) ||
238*d9f75844SAndroid Build Coastguard Worker           target_bitrate.GetSpatialLayerSum(si) == 0) {
239*d9f75844SAndroid Build Coastguard Worker         continue;
240*d9f75844SAndroid Build Coastguard Worker       }
241*d9f75844SAndroid Build Coastguard Worker       layers_allocation.active_spatial_layers.emplace_back();
242*d9f75844SAndroid Build Coastguard Worker       VideoLayersAllocation::SpatialLayer& spatial_layer =
243*d9f75844SAndroid Build Coastguard Worker           layers_allocation.active_spatial_layers.back();
244*d9f75844SAndroid Build Coastguard Worker       spatial_layer.width = encoder_config.simulcastStream[si].width;
245*d9f75844SAndroid Build Coastguard Worker       spatial_layer.height = encoder_config.simulcastStream[si].height;
246*d9f75844SAndroid Build Coastguard Worker       spatial_layer.rtp_stream_index = si;
247*d9f75844SAndroid Build Coastguard Worker       spatial_layer.spatial_id = 0;
248*d9f75844SAndroid Build Coastguard Worker       auto frame_rate_fraction =
249*d9f75844SAndroid Build Coastguard Worker           VideoEncoder::EncoderInfo::kMaxFramerateFraction;
250*d9f75844SAndroid Build Coastguard Worker       if (encoder_info.fps_allocation[si].size() == 1) {
251*d9f75844SAndroid Build Coastguard Worker         // One TL is signalled to be used by the encoder. Do not distribute
252*d9f75844SAndroid Build Coastguard Worker         // bitrate allocation across TLs (use sum at tl:0).
253*d9f75844SAndroid Build Coastguard Worker         spatial_layer.target_bitrate_per_temporal_layer.push_back(
254*d9f75844SAndroid Build Coastguard Worker             DataRate::BitsPerSec(target_bitrate.GetSpatialLayerSum(si)));
255*d9f75844SAndroid Build Coastguard Worker         frame_rate_fraction = encoder_info.fps_allocation[si][0];
256*d9f75844SAndroid Build Coastguard Worker       } else {  // Temporal layers are supported.
257*d9f75844SAndroid Build Coastguard Worker         uint32_t temporal_layer_bitrate_bps = 0;
258*d9f75844SAndroid Build Coastguard Worker         for (size_t ti = 0;
259*d9f75844SAndroid Build Coastguard Worker              ti < encoder_config.simulcastStream[si].numberOfTemporalLayers;
260*d9f75844SAndroid Build Coastguard Worker              ++ti) {
261*d9f75844SAndroid Build Coastguard Worker           if (!target_bitrate.HasBitrate(si, ti)) {
262*d9f75844SAndroid Build Coastguard Worker             break;
263*d9f75844SAndroid Build Coastguard Worker           }
264*d9f75844SAndroid Build Coastguard Worker           if (ti < encoder_info.fps_allocation[si].size()) {
265*d9f75844SAndroid Build Coastguard Worker             // Use frame rate of the top used temporal layer.
266*d9f75844SAndroid Build Coastguard Worker             frame_rate_fraction = encoder_info.fps_allocation[si][ti];
267*d9f75844SAndroid Build Coastguard Worker           }
268*d9f75844SAndroid Build Coastguard Worker           temporal_layer_bitrate_bps += target_bitrate.GetBitrate(si, ti);
269*d9f75844SAndroid Build Coastguard Worker           spatial_layer.target_bitrate_per_temporal_layer.push_back(
270*d9f75844SAndroid Build Coastguard Worker               DataRate::BitsPerSec(temporal_layer_bitrate_bps));
271*d9f75844SAndroid Build Coastguard Worker         }
272*d9f75844SAndroid Build Coastguard Worker       }
273*d9f75844SAndroid Build Coastguard Worker       // Encoder may drop frames internally if `maxFramerate` is set.
274*d9f75844SAndroid Build Coastguard Worker       spatial_layer.frame_rate_fps = std::min<uint8_t>(
275*d9f75844SAndroid Build Coastguard Worker           encoder_config.simulcastStream[si].maxFramerate,
276*d9f75844SAndroid Build Coastguard Worker           rtc::saturated_cast<uint8_t>(
277*d9f75844SAndroid Build Coastguard Worker               (current_rate.framerate_fps * frame_rate_fraction) /
278*d9f75844SAndroid Build Coastguard Worker               VideoEncoder::EncoderInfo::kMaxFramerateFraction));
279*d9f75844SAndroid Build Coastguard Worker     }
280*d9f75844SAndroid Build Coastguard Worker   } else if (encoder_config.numberOfSimulcastStreams == 1) {
281*d9f75844SAndroid Build Coastguard Worker     // TODO(bugs.webrtc.org/12000): Implement support for AV1 with
282*d9f75844SAndroid Build Coastguard Worker     // scalability.
283*d9f75844SAndroid Build Coastguard Worker     const bool higher_spatial_depend_on_lower =
284*d9f75844SAndroid Build Coastguard Worker         encoder_config.codecType == kVideoCodecVP9 &&
285*d9f75844SAndroid Build Coastguard Worker         encoder_config.VP9().interLayerPred == InterLayerPredMode::kOn;
286*d9f75844SAndroid Build Coastguard Worker     layers_allocation.resolution_and_frame_rate_is_valid = true;
287*d9f75844SAndroid Build Coastguard Worker 
288*d9f75844SAndroid Build Coastguard Worker     std::vector<DataRate> aggregated_spatial_bitrate(
289*d9f75844SAndroid Build Coastguard Worker         webrtc::kMaxTemporalStreams, DataRate::Zero());
290*d9f75844SAndroid Build Coastguard Worker     for (int si = 0; si < webrtc::kMaxSpatialLayers; ++si) {
291*d9f75844SAndroid Build Coastguard Worker       layers_allocation.resolution_and_frame_rate_is_valid = true;
292*d9f75844SAndroid Build Coastguard Worker       if (!target_bitrate.IsSpatialLayerUsed(si) ||
293*d9f75844SAndroid Build Coastguard Worker           target_bitrate.GetSpatialLayerSum(si) == 0) {
294*d9f75844SAndroid Build Coastguard Worker         break;
295*d9f75844SAndroid Build Coastguard Worker       }
296*d9f75844SAndroid Build Coastguard Worker       layers_allocation.active_spatial_layers.emplace_back();
297*d9f75844SAndroid Build Coastguard Worker       VideoLayersAllocation::SpatialLayer& spatial_layer =
298*d9f75844SAndroid Build Coastguard Worker           layers_allocation.active_spatial_layers.back();
299*d9f75844SAndroid Build Coastguard Worker       spatial_layer.width = encoder_config.spatialLayers[si].width;
300*d9f75844SAndroid Build Coastguard Worker       spatial_layer.height = encoder_config.spatialLayers[si].height;
301*d9f75844SAndroid Build Coastguard Worker       spatial_layer.rtp_stream_index = 0;
302*d9f75844SAndroid Build Coastguard Worker       spatial_layer.spatial_id = si;
303*d9f75844SAndroid Build Coastguard Worker       auto frame_rate_fraction =
304*d9f75844SAndroid Build Coastguard Worker           VideoEncoder::EncoderInfo::kMaxFramerateFraction;
305*d9f75844SAndroid Build Coastguard Worker       if (encoder_info.fps_allocation[si].size() == 1) {
306*d9f75844SAndroid Build Coastguard Worker         // One TL is signalled to be used by the encoder. Do not distribute
307*d9f75844SAndroid Build Coastguard Worker         // bitrate allocation across TLs (use sum at tl:0).
308*d9f75844SAndroid Build Coastguard Worker         DataRate aggregated_temporal_bitrate =
309*d9f75844SAndroid Build Coastguard Worker             DataRate::BitsPerSec(target_bitrate.GetSpatialLayerSum(si));
310*d9f75844SAndroid Build Coastguard Worker         aggregated_spatial_bitrate[0] += aggregated_temporal_bitrate;
311*d9f75844SAndroid Build Coastguard Worker         if (higher_spatial_depend_on_lower) {
312*d9f75844SAndroid Build Coastguard Worker           spatial_layer.target_bitrate_per_temporal_layer.push_back(
313*d9f75844SAndroid Build Coastguard Worker               aggregated_spatial_bitrate[0]);
314*d9f75844SAndroid Build Coastguard Worker         } else {
315*d9f75844SAndroid Build Coastguard Worker           spatial_layer.target_bitrate_per_temporal_layer.push_back(
316*d9f75844SAndroid Build Coastguard Worker               aggregated_temporal_bitrate);
317*d9f75844SAndroid Build Coastguard Worker         }
318*d9f75844SAndroid Build Coastguard Worker         frame_rate_fraction = encoder_info.fps_allocation[si][0];
319*d9f75844SAndroid Build Coastguard Worker       } else {  // Temporal layers are supported.
320*d9f75844SAndroid Build Coastguard Worker         DataRate aggregated_temporal_bitrate = DataRate::Zero();
321*d9f75844SAndroid Build Coastguard Worker         for (size_t ti = 0;
322*d9f75844SAndroid Build Coastguard Worker              ti < encoder_config.spatialLayers[si].numberOfTemporalLayers;
323*d9f75844SAndroid Build Coastguard Worker              ++ti) {
324*d9f75844SAndroid Build Coastguard Worker           if (!target_bitrate.HasBitrate(si, ti)) {
325*d9f75844SAndroid Build Coastguard Worker             break;
326*d9f75844SAndroid Build Coastguard Worker           }
327*d9f75844SAndroid Build Coastguard Worker           if (ti < encoder_info.fps_allocation[si].size()) {
328*d9f75844SAndroid Build Coastguard Worker             // Use frame rate of the top used temporal layer.
329*d9f75844SAndroid Build Coastguard Worker             frame_rate_fraction = encoder_info.fps_allocation[si][ti];
330*d9f75844SAndroid Build Coastguard Worker           }
331*d9f75844SAndroid Build Coastguard Worker           aggregated_temporal_bitrate +=
332*d9f75844SAndroid Build Coastguard Worker               DataRate::BitsPerSec(target_bitrate.GetBitrate(si, ti));
333*d9f75844SAndroid Build Coastguard Worker           if (higher_spatial_depend_on_lower) {
334*d9f75844SAndroid Build Coastguard Worker             spatial_layer.target_bitrate_per_temporal_layer.push_back(
335*d9f75844SAndroid Build Coastguard Worker                 aggregated_temporal_bitrate + aggregated_spatial_bitrate[ti]);
336*d9f75844SAndroid Build Coastguard Worker             aggregated_spatial_bitrate[ti] += aggregated_temporal_bitrate;
337*d9f75844SAndroid Build Coastguard Worker           } else {
338*d9f75844SAndroid Build Coastguard Worker             spatial_layer.target_bitrate_per_temporal_layer.push_back(
339*d9f75844SAndroid Build Coastguard Worker                 aggregated_temporal_bitrate);
340*d9f75844SAndroid Build Coastguard Worker           }
341*d9f75844SAndroid Build Coastguard Worker         }
342*d9f75844SAndroid Build Coastguard Worker       }
343*d9f75844SAndroid Build Coastguard Worker       // Encoder may drop frames internally if `maxFramerate` is set.
344*d9f75844SAndroid Build Coastguard Worker       spatial_layer.frame_rate_fps = std::min<uint8_t>(
345*d9f75844SAndroid Build Coastguard Worker           encoder_config.spatialLayers[si].maxFramerate,
346*d9f75844SAndroid Build Coastguard Worker           rtc::saturated_cast<uint8_t>(
347*d9f75844SAndroid Build Coastguard Worker               (current_rate.framerate_fps * frame_rate_fraction) /
348*d9f75844SAndroid Build Coastguard Worker               VideoEncoder::EncoderInfo::kMaxFramerateFraction));
349*d9f75844SAndroid Build Coastguard Worker     }
350*d9f75844SAndroid Build Coastguard Worker   }
351*d9f75844SAndroid Build Coastguard Worker 
352*d9f75844SAndroid Build Coastguard Worker   return layers_allocation;
353*d9f75844SAndroid Build Coastguard Worker }
354*d9f75844SAndroid Build Coastguard Worker 
GetEncoderInfoWithBitrateLimitUpdate(const VideoEncoder::EncoderInfo & info,const VideoEncoderConfig & encoder_config,bool default_limits_allowed)355*d9f75844SAndroid Build Coastguard Worker VideoEncoder::EncoderInfo GetEncoderInfoWithBitrateLimitUpdate(
356*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::EncoderInfo& info,
357*d9f75844SAndroid Build Coastguard Worker     const VideoEncoderConfig& encoder_config,
358*d9f75844SAndroid Build Coastguard Worker     bool default_limits_allowed) {
359*d9f75844SAndroid Build Coastguard Worker   if (!default_limits_allowed || !info.resolution_bitrate_limits.empty() ||
360*d9f75844SAndroid Build Coastguard Worker       encoder_config.simulcast_layers.size() <= 1) {
361*d9f75844SAndroid Build Coastguard Worker     return info;
362*d9f75844SAndroid Build Coastguard Worker   }
363*d9f75844SAndroid Build Coastguard Worker   // Bitrate limits are not configured and more than one layer is used, use
364*d9f75844SAndroid Build Coastguard Worker   // the default limits (bitrate limits are not used for simulcast).
365*d9f75844SAndroid Build Coastguard Worker   VideoEncoder::EncoderInfo new_info = info;
366*d9f75844SAndroid Build Coastguard Worker   new_info.resolution_bitrate_limits =
367*d9f75844SAndroid Build Coastguard Worker       EncoderInfoSettings::GetDefaultSinglecastBitrateLimits(
368*d9f75844SAndroid Build Coastguard Worker           encoder_config.codec_type);
369*d9f75844SAndroid Build Coastguard Worker   return new_info;
370*d9f75844SAndroid Build Coastguard Worker }
371*d9f75844SAndroid Build Coastguard Worker 
NumActiveStreams(const std::vector<VideoStream> & streams)372*d9f75844SAndroid Build Coastguard Worker int NumActiveStreams(const std::vector<VideoStream>& streams) {
373*d9f75844SAndroid Build Coastguard Worker   int num_active = 0;
374*d9f75844SAndroid Build Coastguard Worker   for (const auto& stream : streams) {
375*d9f75844SAndroid Build Coastguard Worker     if (stream.active)
376*d9f75844SAndroid Build Coastguard Worker       ++num_active;
377*d9f75844SAndroid Build Coastguard Worker   }
378*d9f75844SAndroid Build Coastguard Worker   return num_active;
379*d9f75844SAndroid Build Coastguard Worker }
380*d9f75844SAndroid Build Coastguard Worker 
ApplyVp9BitrateLimits(const VideoEncoder::EncoderInfo & encoder_info,const VideoEncoderConfig & encoder_config,VideoCodec * codec)381*d9f75844SAndroid Build Coastguard Worker void ApplyVp9BitrateLimits(const VideoEncoder::EncoderInfo& encoder_info,
382*d9f75844SAndroid Build Coastguard Worker                            const VideoEncoderConfig& encoder_config,
383*d9f75844SAndroid Build Coastguard Worker                            VideoCodec* codec) {
384*d9f75844SAndroid Build Coastguard Worker   if (codec->codecType != VideoCodecType::kVideoCodecVP9 ||
385*d9f75844SAndroid Build Coastguard Worker       encoder_config.simulcast_layers.size() <= 1 ||
386*d9f75844SAndroid Build Coastguard Worker       VideoStreamEncoderResourceManager::IsSimulcastOrMultipleSpatialLayers(
387*d9f75844SAndroid Build Coastguard Worker           encoder_config)) {
388*d9f75844SAndroid Build Coastguard Worker     // Resolution bitrate limits usage is restricted to singlecast.
389*d9f75844SAndroid Build Coastguard Worker     return;
390*d9f75844SAndroid Build Coastguard Worker   }
391*d9f75844SAndroid Build Coastguard Worker 
392*d9f75844SAndroid Build Coastguard Worker   // Get bitrate limits for active stream.
393*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> pixels =
394*d9f75844SAndroid Build Coastguard Worker       VideoStreamAdapter::GetSingleActiveLayerPixels(*codec);
395*d9f75844SAndroid Build Coastguard Worker   if (!pixels.has_value()) {
396*d9f75844SAndroid Build Coastguard Worker     return;
397*d9f75844SAndroid Build Coastguard Worker   }
398*d9f75844SAndroid Build Coastguard Worker   absl::optional<VideoEncoder::ResolutionBitrateLimits> bitrate_limits =
399*d9f75844SAndroid Build Coastguard Worker       encoder_info.GetEncoderBitrateLimitsForResolution(*pixels);
400*d9f75844SAndroid Build Coastguard Worker   if (!bitrate_limits.has_value()) {
401*d9f75844SAndroid Build Coastguard Worker     return;
402*d9f75844SAndroid Build Coastguard Worker   }
403*d9f75844SAndroid Build Coastguard Worker 
404*d9f75844SAndroid Build Coastguard Worker   // Index for the active stream.
405*d9f75844SAndroid Build Coastguard Worker   absl::optional<size_t> index;
406*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) {
407*d9f75844SAndroid Build Coastguard Worker     if (encoder_config.simulcast_layers[i].active)
408*d9f75844SAndroid Build Coastguard Worker       index = i;
409*d9f75844SAndroid Build Coastguard Worker   }
410*d9f75844SAndroid Build Coastguard Worker   if (!index.has_value()) {
411*d9f75844SAndroid Build Coastguard Worker     return;
412*d9f75844SAndroid Build Coastguard Worker   }
413*d9f75844SAndroid Build Coastguard Worker 
414*d9f75844SAndroid Build Coastguard Worker   int min_bitrate_bps;
415*d9f75844SAndroid Build Coastguard Worker   if (encoder_config.simulcast_layers[*index].min_bitrate_bps <= 0) {
416*d9f75844SAndroid Build Coastguard Worker     min_bitrate_bps = bitrate_limits->min_bitrate_bps;
417*d9f75844SAndroid Build Coastguard Worker   } else {
418*d9f75844SAndroid Build Coastguard Worker     min_bitrate_bps =
419*d9f75844SAndroid Build Coastguard Worker         std::max(bitrate_limits->min_bitrate_bps,
420*d9f75844SAndroid Build Coastguard Worker                  encoder_config.simulcast_layers[*index].min_bitrate_bps);
421*d9f75844SAndroid Build Coastguard Worker   }
422*d9f75844SAndroid Build Coastguard Worker   int max_bitrate_bps;
423*d9f75844SAndroid Build Coastguard Worker   if (encoder_config.simulcast_layers[*index].max_bitrate_bps <= 0) {
424*d9f75844SAndroid Build Coastguard Worker     max_bitrate_bps = bitrate_limits->max_bitrate_bps;
425*d9f75844SAndroid Build Coastguard Worker   } else {
426*d9f75844SAndroid Build Coastguard Worker     max_bitrate_bps =
427*d9f75844SAndroid Build Coastguard Worker         std::min(bitrate_limits->max_bitrate_bps,
428*d9f75844SAndroid Build Coastguard Worker                  encoder_config.simulcast_layers[*index].max_bitrate_bps);
429*d9f75844SAndroid Build Coastguard Worker   }
430*d9f75844SAndroid Build Coastguard Worker   if (min_bitrate_bps >= max_bitrate_bps) {
431*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Bitrate limits not used, min_bitrate_bps "
432*d9f75844SAndroid Build Coastguard Worker                         << min_bitrate_bps << " >= max_bitrate_bps "
433*d9f75844SAndroid Build Coastguard Worker                         << max_bitrate_bps;
434*d9f75844SAndroid Build Coastguard Worker     return;
435*d9f75844SAndroid Build Coastguard Worker   }
436*d9f75844SAndroid Build Coastguard Worker 
437*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < codec->VP9()->numberOfSpatialLayers; ++i) {
438*d9f75844SAndroid Build Coastguard Worker     if (codec->spatialLayers[i].active) {
439*d9f75844SAndroid Build Coastguard Worker       codec->spatialLayers[i].minBitrate = min_bitrate_bps / 1000;
440*d9f75844SAndroid Build Coastguard Worker       codec->spatialLayers[i].maxBitrate = max_bitrate_bps / 1000;
441*d9f75844SAndroid Build Coastguard Worker       codec->spatialLayers[i].targetBitrate =
442*d9f75844SAndroid Build Coastguard Worker           std::min(codec->spatialLayers[i].targetBitrate,
443*d9f75844SAndroid Build Coastguard Worker                    codec->spatialLayers[i].maxBitrate);
444*d9f75844SAndroid Build Coastguard Worker       break;
445*d9f75844SAndroid Build Coastguard Worker     }
446*d9f75844SAndroid Build Coastguard Worker   }
447*d9f75844SAndroid Build Coastguard Worker }
448*d9f75844SAndroid Build Coastguard Worker 
ApplyEncoderBitrateLimitsIfSingleActiveStream(const VideoEncoder::EncoderInfo & encoder_info,const std::vector<VideoStream> & encoder_config_layers,std::vector<VideoStream> * streams)449*d9f75844SAndroid Build Coastguard Worker void ApplyEncoderBitrateLimitsIfSingleActiveStream(
450*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::EncoderInfo& encoder_info,
451*d9f75844SAndroid Build Coastguard Worker     const std::vector<VideoStream>& encoder_config_layers,
452*d9f75844SAndroid Build Coastguard Worker     std::vector<VideoStream>* streams) {
453*d9f75844SAndroid Build Coastguard Worker   // Apply limits if simulcast with one active stream (expect lowest).
454*d9f75844SAndroid Build Coastguard Worker   bool single_active_stream =
455*d9f75844SAndroid Build Coastguard Worker       streams->size() > 1 && NumActiveStreams(*streams) == 1 &&
456*d9f75844SAndroid Build Coastguard Worker       !streams->front().active && NumActiveStreams(encoder_config_layers) == 1;
457*d9f75844SAndroid Build Coastguard Worker   if (!single_active_stream) {
458*d9f75844SAndroid Build Coastguard Worker     return;
459*d9f75844SAndroid Build Coastguard Worker   }
460*d9f75844SAndroid Build Coastguard Worker 
461*d9f75844SAndroid Build Coastguard Worker   // Index for the active stream.
462*d9f75844SAndroid Build Coastguard Worker   size_t index = 0;
463*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < encoder_config_layers.size(); ++i) {
464*d9f75844SAndroid Build Coastguard Worker     if (encoder_config_layers[i].active)
465*d9f75844SAndroid Build Coastguard Worker       index = i;
466*d9f75844SAndroid Build Coastguard Worker   }
467*d9f75844SAndroid Build Coastguard Worker   if (streams->size() < (index + 1) || !(*streams)[index].active) {
468*d9f75844SAndroid Build Coastguard Worker     return;
469*d9f75844SAndroid Build Coastguard Worker   }
470*d9f75844SAndroid Build Coastguard Worker 
471*d9f75844SAndroid Build Coastguard Worker   // Get bitrate limits for active stream.
472*d9f75844SAndroid Build Coastguard Worker   absl::optional<VideoEncoder::ResolutionBitrateLimits> encoder_bitrate_limits =
473*d9f75844SAndroid Build Coastguard Worker       encoder_info.GetEncoderBitrateLimitsForResolution(
474*d9f75844SAndroid Build Coastguard Worker           (*streams)[index].width * (*streams)[index].height);
475*d9f75844SAndroid Build Coastguard Worker   if (!encoder_bitrate_limits) {
476*d9f75844SAndroid Build Coastguard Worker     return;
477*d9f75844SAndroid Build Coastguard Worker   }
478*d9f75844SAndroid Build Coastguard Worker 
479*d9f75844SAndroid Build Coastguard Worker   // If bitrate limits are set by RtpEncodingParameters, use intersection.
480*d9f75844SAndroid Build Coastguard Worker   int min_bitrate_bps;
481*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_layers[index].min_bitrate_bps <= 0) {
482*d9f75844SAndroid Build Coastguard Worker     min_bitrate_bps = encoder_bitrate_limits->min_bitrate_bps;
483*d9f75844SAndroid Build Coastguard Worker   } else {
484*d9f75844SAndroid Build Coastguard Worker     min_bitrate_bps = std::max(encoder_bitrate_limits->min_bitrate_bps,
485*d9f75844SAndroid Build Coastguard Worker                                (*streams)[index].min_bitrate_bps);
486*d9f75844SAndroid Build Coastguard Worker   }
487*d9f75844SAndroid Build Coastguard Worker   int max_bitrate_bps;
488*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_layers[index].max_bitrate_bps <= 0) {
489*d9f75844SAndroid Build Coastguard Worker     max_bitrate_bps = encoder_bitrate_limits->max_bitrate_bps;
490*d9f75844SAndroid Build Coastguard Worker   } else {
491*d9f75844SAndroid Build Coastguard Worker     max_bitrate_bps = std::min(encoder_bitrate_limits->max_bitrate_bps,
492*d9f75844SAndroid Build Coastguard Worker                                (*streams)[index].max_bitrate_bps);
493*d9f75844SAndroid Build Coastguard Worker   }
494*d9f75844SAndroid Build Coastguard Worker   if (min_bitrate_bps >= max_bitrate_bps) {
495*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Encoder bitrate limits"
496*d9f75844SAndroid Build Coastguard Worker                         << " (min=" << encoder_bitrate_limits->min_bitrate_bps
497*d9f75844SAndroid Build Coastguard Worker                         << ", max=" << encoder_bitrate_limits->max_bitrate_bps
498*d9f75844SAndroid Build Coastguard Worker                         << ") do not intersect with stream limits"
499*d9f75844SAndroid Build Coastguard Worker                         << " (min=" << (*streams)[index].min_bitrate_bps
500*d9f75844SAndroid Build Coastguard Worker                         << ", max=" << (*streams)[index].max_bitrate_bps
501*d9f75844SAndroid Build Coastguard Worker                         << "). Encoder bitrate limits not used.";
502*d9f75844SAndroid Build Coastguard Worker     return;
503*d9f75844SAndroid Build Coastguard Worker   }
504*d9f75844SAndroid Build Coastguard Worker 
505*d9f75844SAndroid Build Coastguard Worker   (*streams)[index].min_bitrate_bps = min_bitrate_bps;
506*d9f75844SAndroid Build Coastguard Worker   (*streams)[index].max_bitrate_bps = max_bitrate_bps;
507*d9f75844SAndroid Build Coastguard Worker   (*streams)[index].target_bitrate_bps =
508*d9f75844SAndroid Build Coastguard Worker       std::min((*streams)[index].target_bitrate_bps,
509*d9f75844SAndroid Build Coastguard Worker                encoder_bitrate_limits->max_bitrate_bps);
510*d9f75844SAndroid Build Coastguard Worker }
511*d9f75844SAndroid Build Coastguard Worker 
ParseVp9LowTierCoreCountThreshold(const FieldTrialsView & trials)512*d9f75844SAndroid Build Coastguard Worker absl::optional<int> ParseVp9LowTierCoreCountThreshold(
513*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView& trials) {
514*d9f75844SAndroid Build Coastguard Worker   FieldTrialFlag disable_low_tier("Disabled");
515*d9f75844SAndroid Build Coastguard Worker   FieldTrialParameter<int> max_core_count("max_core_count", 2);
516*d9f75844SAndroid Build Coastguard Worker   ParseFieldTrial({&disable_low_tier, &max_core_count},
517*d9f75844SAndroid Build Coastguard Worker                   trials.Lookup("WebRTC-VP9-LowTierOptimizations"));
518*d9f75844SAndroid Build Coastguard Worker   if (disable_low_tier.Get()) {
519*d9f75844SAndroid Build Coastguard Worker     return absl::nullopt;
520*d9f75844SAndroid Build Coastguard Worker   }
521*d9f75844SAndroid Build Coastguard Worker   return max_core_count.Get();
522*d9f75844SAndroid Build Coastguard Worker }
523*d9f75844SAndroid Build Coastguard Worker 
MergeRestrictions(const std::vector<absl::optional<VideoSourceRestrictions>> & list)524*d9f75844SAndroid Build Coastguard Worker absl::optional<VideoSourceRestrictions> MergeRestrictions(
525*d9f75844SAndroid Build Coastguard Worker     const std::vector<absl::optional<VideoSourceRestrictions>>& list) {
526*d9f75844SAndroid Build Coastguard Worker   absl::optional<VideoSourceRestrictions> return_value;
527*d9f75844SAndroid Build Coastguard Worker   for (const auto& res : list) {
528*d9f75844SAndroid Build Coastguard Worker     if (!res) {
529*d9f75844SAndroid Build Coastguard Worker       continue;
530*d9f75844SAndroid Build Coastguard Worker     }
531*d9f75844SAndroid Build Coastguard Worker     if (!return_value) {
532*d9f75844SAndroid Build Coastguard Worker       return_value = *res;
533*d9f75844SAndroid Build Coastguard Worker       continue;
534*d9f75844SAndroid Build Coastguard Worker     }
535*d9f75844SAndroid Build Coastguard Worker     return_value->UpdateMin(*res);
536*d9f75844SAndroid Build Coastguard Worker   }
537*d9f75844SAndroid Build Coastguard Worker   return return_value;
538*d9f75844SAndroid Build Coastguard Worker }
539*d9f75844SAndroid Build Coastguard Worker 
540*d9f75844SAndroid Build Coastguard Worker }  //  namespace
541*d9f75844SAndroid Build Coastguard Worker 
EncoderRateSettings()542*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::EncoderRateSettings::EncoderRateSettings()
543*d9f75844SAndroid Build Coastguard Worker     : rate_control(),
544*d9f75844SAndroid Build Coastguard Worker       encoder_target(DataRate::Zero()),
545*d9f75844SAndroid Build Coastguard Worker       stable_encoder_target(DataRate::Zero()) {}
546*d9f75844SAndroid Build Coastguard Worker 
EncoderRateSettings(const VideoBitrateAllocation & bitrate,double framerate_fps,DataRate bandwidth_allocation,DataRate encoder_target,DataRate stable_encoder_target)547*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::EncoderRateSettings::EncoderRateSettings(
548*d9f75844SAndroid Build Coastguard Worker     const VideoBitrateAllocation& bitrate,
549*d9f75844SAndroid Build Coastguard Worker     double framerate_fps,
550*d9f75844SAndroid Build Coastguard Worker     DataRate bandwidth_allocation,
551*d9f75844SAndroid Build Coastguard Worker     DataRate encoder_target,
552*d9f75844SAndroid Build Coastguard Worker     DataRate stable_encoder_target)
553*d9f75844SAndroid Build Coastguard Worker     : rate_control(bitrate, framerate_fps, bandwidth_allocation),
554*d9f75844SAndroid Build Coastguard Worker       encoder_target(encoder_target),
555*d9f75844SAndroid Build Coastguard Worker       stable_encoder_target(stable_encoder_target) {}
556*d9f75844SAndroid Build Coastguard Worker 
operator ==(const EncoderRateSettings & rhs) const557*d9f75844SAndroid Build Coastguard Worker bool VideoStreamEncoder::EncoderRateSettings::operator==(
558*d9f75844SAndroid Build Coastguard Worker     const EncoderRateSettings& rhs) const {
559*d9f75844SAndroid Build Coastguard Worker   return rate_control == rhs.rate_control &&
560*d9f75844SAndroid Build Coastguard Worker          encoder_target == rhs.encoder_target &&
561*d9f75844SAndroid Build Coastguard Worker          stable_encoder_target == rhs.stable_encoder_target;
562*d9f75844SAndroid Build Coastguard Worker }
563*d9f75844SAndroid Build Coastguard Worker 
operator !=(const EncoderRateSettings & rhs) const564*d9f75844SAndroid Build Coastguard Worker bool VideoStreamEncoder::EncoderRateSettings::operator!=(
565*d9f75844SAndroid Build Coastguard Worker     const EncoderRateSettings& rhs) const {
566*d9f75844SAndroid Build Coastguard Worker   return !(*this == rhs);
567*d9f75844SAndroid Build Coastguard Worker }
568*d9f75844SAndroid Build Coastguard Worker 
569*d9f75844SAndroid Build Coastguard Worker class VideoStreamEncoder::DegradationPreferenceManager
570*d9f75844SAndroid Build Coastguard Worker     : public DegradationPreferenceProvider {
571*d9f75844SAndroid Build Coastguard Worker  public:
DegradationPreferenceManager(VideoStreamAdapter * video_stream_adapter)572*d9f75844SAndroid Build Coastguard Worker   explicit DegradationPreferenceManager(
573*d9f75844SAndroid Build Coastguard Worker       VideoStreamAdapter* video_stream_adapter)
574*d9f75844SAndroid Build Coastguard Worker       : degradation_preference_(DegradationPreference::DISABLED),
575*d9f75844SAndroid Build Coastguard Worker         is_screenshare_(false),
576*d9f75844SAndroid Build Coastguard Worker         effective_degradation_preference_(DegradationPreference::DISABLED),
577*d9f75844SAndroid Build Coastguard Worker         video_stream_adapter_(video_stream_adapter) {
578*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(video_stream_adapter_);
579*d9f75844SAndroid Build Coastguard Worker     sequence_checker_.Detach();
580*d9f75844SAndroid Build Coastguard Worker   }
581*d9f75844SAndroid Build Coastguard Worker 
582*d9f75844SAndroid Build Coastguard Worker   ~DegradationPreferenceManager() override = default;
583*d9f75844SAndroid Build Coastguard Worker 
degradation_preference() const584*d9f75844SAndroid Build Coastguard Worker   DegradationPreference degradation_preference() const override {
585*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&sequence_checker_);
586*d9f75844SAndroid Build Coastguard Worker     return effective_degradation_preference_;
587*d9f75844SAndroid Build Coastguard Worker   }
588*d9f75844SAndroid Build Coastguard Worker 
SetDegradationPreference(DegradationPreference degradation_preference)589*d9f75844SAndroid Build Coastguard Worker   void SetDegradationPreference(DegradationPreference degradation_preference) {
590*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&sequence_checker_);
591*d9f75844SAndroid Build Coastguard Worker     degradation_preference_ = degradation_preference;
592*d9f75844SAndroid Build Coastguard Worker     MaybeUpdateEffectiveDegradationPreference();
593*d9f75844SAndroid Build Coastguard Worker   }
594*d9f75844SAndroid Build Coastguard Worker 
SetIsScreenshare(bool is_screenshare)595*d9f75844SAndroid Build Coastguard Worker   void SetIsScreenshare(bool is_screenshare) {
596*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&sequence_checker_);
597*d9f75844SAndroid Build Coastguard Worker     is_screenshare_ = is_screenshare;
598*d9f75844SAndroid Build Coastguard Worker     MaybeUpdateEffectiveDegradationPreference();
599*d9f75844SAndroid Build Coastguard Worker   }
600*d9f75844SAndroid Build Coastguard Worker 
601*d9f75844SAndroid Build Coastguard Worker  private:
MaybeUpdateEffectiveDegradationPreference()602*d9f75844SAndroid Build Coastguard Worker   void MaybeUpdateEffectiveDegradationPreference()
603*d9f75844SAndroid Build Coastguard Worker       RTC_RUN_ON(&sequence_checker_) {
604*d9f75844SAndroid Build Coastguard Worker     DegradationPreference effective_degradation_preference =
605*d9f75844SAndroid Build Coastguard Worker         (is_screenshare_ &&
606*d9f75844SAndroid Build Coastguard Worker          degradation_preference_ == DegradationPreference::BALANCED)
607*d9f75844SAndroid Build Coastguard Worker             ? DegradationPreference::MAINTAIN_RESOLUTION
608*d9f75844SAndroid Build Coastguard Worker             : degradation_preference_;
609*d9f75844SAndroid Build Coastguard Worker 
610*d9f75844SAndroid Build Coastguard Worker     if (effective_degradation_preference != effective_degradation_preference_) {
611*d9f75844SAndroid Build Coastguard Worker       effective_degradation_preference_ = effective_degradation_preference;
612*d9f75844SAndroid Build Coastguard Worker       video_stream_adapter_->SetDegradationPreference(
613*d9f75844SAndroid Build Coastguard Worker           effective_degradation_preference);
614*d9f75844SAndroid Build Coastguard Worker     }
615*d9f75844SAndroid Build Coastguard Worker   }
616*d9f75844SAndroid Build Coastguard Worker 
617*d9f75844SAndroid Build Coastguard Worker   RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_;
618*d9f75844SAndroid Build Coastguard Worker   DegradationPreference degradation_preference_
619*d9f75844SAndroid Build Coastguard Worker       RTC_GUARDED_BY(&sequence_checker_);
620*d9f75844SAndroid Build Coastguard Worker   bool is_screenshare_ RTC_GUARDED_BY(&sequence_checker_);
621*d9f75844SAndroid Build Coastguard Worker   DegradationPreference effective_degradation_preference_
622*d9f75844SAndroid Build Coastguard Worker       RTC_GUARDED_BY(&sequence_checker_);
623*d9f75844SAndroid Build Coastguard Worker   VideoStreamAdapter* video_stream_adapter_ RTC_GUARDED_BY(&sequence_checker_);
624*d9f75844SAndroid Build Coastguard Worker };
625*d9f75844SAndroid Build Coastguard Worker 
VideoStreamEncoder(Clock * clock,uint32_t number_of_cores,VideoStreamEncoderObserver * encoder_stats_observer,const VideoStreamEncoderSettings & settings,std::unique_ptr<OveruseFrameDetector> overuse_detector,std::unique_ptr<FrameCadenceAdapterInterface> frame_cadence_adapter,std::unique_ptr<webrtc::TaskQueueBase,webrtc::TaskQueueDeleter> encoder_queue,BitrateAllocationCallbackType allocation_cb_type,const FieldTrialsView & field_trials,webrtc::VideoEncoderFactory::EncoderSelectorInterface * encoder_selector)626*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::VideoStreamEncoder(
627*d9f75844SAndroid Build Coastguard Worker     Clock* clock,
628*d9f75844SAndroid Build Coastguard Worker     uint32_t number_of_cores,
629*d9f75844SAndroid Build Coastguard Worker     VideoStreamEncoderObserver* encoder_stats_observer,
630*d9f75844SAndroid Build Coastguard Worker     const VideoStreamEncoderSettings& settings,
631*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<OveruseFrameDetector> overuse_detector,
632*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<FrameCadenceAdapterInterface> frame_cadence_adapter,
633*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>
634*d9f75844SAndroid Build Coastguard Worker         encoder_queue,
635*d9f75844SAndroid Build Coastguard Worker     BitrateAllocationCallbackType allocation_cb_type,
636*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView& field_trials,
637*d9f75844SAndroid Build Coastguard Worker     webrtc::VideoEncoderFactory::EncoderSelectorInterface* encoder_selector)
638*d9f75844SAndroid Build Coastguard Worker     : field_trials_(field_trials),
639*d9f75844SAndroid Build Coastguard Worker       worker_queue_(TaskQueueBase::Current()),
640*d9f75844SAndroid Build Coastguard Worker       number_of_cores_(number_of_cores),
641*d9f75844SAndroid Build Coastguard Worker       sink_(nullptr),
642*d9f75844SAndroid Build Coastguard Worker       settings_(settings),
643*d9f75844SAndroid Build Coastguard Worker       allocation_cb_type_(allocation_cb_type),
644*d9f75844SAndroid Build Coastguard Worker       rate_control_settings_(RateControlSettings::ParseFromFieldTrials()),
645*d9f75844SAndroid Build Coastguard Worker       encoder_selector_from_constructor_(encoder_selector),
646*d9f75844SAndroid Build Coastguard Worker       encoder_selector_from_factory_(
647*d9f75844SAndroid Build Coastguard Worker           encoder_selector_from_constructor_
648*d9f75844SAndroid Build Coastguard Worker               ? nullptr
649*d9f75844SAndroid Build Coastguard Worker               : settings.encoder_factory->GetEncoderSelector()),
650*d9f75844SAndroid Build Coastguard Worker       encoder_selector_(encoder_selector_from_constructor_
651*d9f75844SAndroid Build Coastguard Worker                             ? encoder_selector_from_constructor_
652*d9f75844SAndroid Build Coastguard Worker                             : encoder_selector_from_factory_.get()),
653*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_(encoder_stats_observer),
654*d9f75844SAndroid Build Coastguard Worker       cadence_callback_(*this),
655*d9f75844SAndroid Build Coastguard Worker       frame_cadence_adapter_(std::move(frame_cadence_adapter)),
656*d9f75844SAndroid Build Coastguard Worker       encoder_initialized_(false),
657*d9f75844SAndroid Build Coastguard Worker       max_framerate_(-1),
658*d9f75844SAndroid Build Coastguard Worker       pending_encoder_reconfiguration_(false),
659*d9f75844SAndroid Build Coastguard Worker       pending_encoder_creation_(false),
660*d9f75844SAndroid Build Coastguard Worker       crop_width_(0),
661*d9f75844SAndroid Build Coastguard Worker       crop_height_(0),
662*d9f75844SAndroid Build Coastguard Worker       encoder_target_bitrate_bps_(absl::nullopt),
663*d9f75844SAndroid Build Coastguard Worker       max_data_payload_length_(0),
664*d9f75844SAndroid Build Coastguard Worker       encoder_paused_and_dropped_frame_(false),
665*d9f75844SAndroid Build Coastguard Worker       was_encode_called_since_last_initialization_(false),
666*d9f75844SAndroid Build Coastguard Worker       encoder_failed_(false),
667*d9f75844SAndroid Build Coastguard Worker       clock_(clock),
668*d9f75844SAndroid Build Coastguard Worker       last_captured_timestamp_(0),
669*d9f75844SAndroid Build Coastguard Worker       delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
670*d9f75844SAndroid Build Coastguard Worker                              clock_->TimeInMilliseconds()),
671*d9f75844SAndroid Build Coastguard Worker       last_frame_log_ms_(clock_->TimeInMilliseconds()),
672*d9f75844SAndroid Build Coastguard Worker       captured_frame_count_(0),
673*d9f75844SAndroid Build Coastguard Worker       dropped_frame_cwnd_pushback_count_(0),
674*d9f75844SAndroid Build Coastguard Worker       dropped_frame_encoder_block_count_(0),
675*d9f75844SAndroid Build Coastguard Worker       pending_frame_post_time_us_(0),
676*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_{0, 0, 0, 0},
677*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_is_valid_(true),
678*d9f75844SAndroid Build Coastguard Worker       animation_start_time_(Timestamp::PlusInfinity()),
679*d9f75844SAndroid Build Coastguard Worker       cap_resolution_due_to_video_content_(false),
680*d9f75844SAndroid Build Coastguard Worker       expect_resize_state_(ExpectResizeState::kNoResize),
681*d9f75844SAndroid Build Coastguard Worker       fec_controller_override_(nullptr),
682*d9f75844SAndroid Build Coastguard Worker       force_disable_frame_dropper_(false),
683*d9f75844SAndroid Build Coastguard Worker       pending_frame_drops_(0),
684*d9f75844SAndroid Build Coastguard Worker       cwnd_frame_counter_(0),
685*d9f75844SAndroid Build Coastguard Worker       next_frame_types_(1, VideoFrameType::kVideoFrameDelta),
686*d9f75844SAndroid Build Coastguard Worker       frame_encode_metadata_writer_(this),
687*d9f75844SAndroid Build Coastguard Worker       experiment_groups_(GetExperimentGroups()),
688*d9f75844SAndroid Build Coastguard Worker       automatic_animation_detection_experiment_(
689*d9f75844SAndroid Build Coastguard Worker           ParseAutomatincAnimationDetectionFieldTrial()),
690*d9f75844SAndroid Build Coastguard Worker       input_state_provider_(encoder_stats_observer),
691*d9f75844SAndroid Build Coastguard Worker       video_stream_adapter_(
692*d9f75844SAndroid Build Coastguard Worker           std::make_unique<VideoStreamAdapter>(&input_state_provider_,
693*d9f75844SAndroid Build Coastguard Worker                                                encoder_stats_observer,
694*d9f75844SAndroid Build Coastguard Worker                                                field_trials)),
695*d9f75844SAndroid Build Coastguard Worker       degradation_preference_manager_(
696*d9f75844SAndroid Build Coastguard Worker           std::make_unique<DegradationPreferenceManager>(
697*d9f75844SAndroid Build Coastguard Worker               video_stream_adapter_.get())),
698*d9f75844SAndroid Build Coastguard Worker       adaptation_constraints_(),
699*d9f75844SAndroid Build Coastguard Worker       stream_resource_manager_(&input_state_provider_,
700*d9f75844SAndroid Build Coastguard Worker                                encoder_stats_observer,
701*d9f75844SAndroid Build Coastguard Worker                                clock_,
702*d9f75844SAndroid Build Coastguard Worker                                settings_.experiment_cpu_load_estimator,
703*d9f75844SAndroid Build Coastguard Worker                                std::move(overuse_detector),
704*d9f75844SAndroid Build Coastguard Worker                                degradation_preference_manager_.get(),
705*d9f75844SAndroid Build Coastguard Worker                                field_trials),
706*d9f75844SAndroid Build Coastguard Worker       video_source_sink_controller_(/*sink=*/frame_cadence_adapter_.get(),
707*d9f75844SAndroid Build Coastguard Worker                                     /*source=*/nullptr),
708*d9f75844SAndroid Build Coastguard Worker       default_limits_allowed_(
709*d9f75844SAndroid Build Coastguard Worker           !field_trials.IsEnabled("WebRTC-DefaultBitrateLimitsKillSwitch")),
710*d9f75844SAndroid Build Coastguard Worker       qp_parsing_allowed_(
711*d9f75844SAndroid Build Coastguard Worker           !field_trials.IsEnabled("WebRTC-QpParsingKillSwitch")),
712*d9f75844SAndroid Build Coastguard Worker       switch_encoder_on_init_failures_(!field_trials.IsDisabled(
713*d9f75844SAndroid Build Coastguard Worker           kSwitchEncoderOnInitializationFailuresFieldTrial)),
714*d9f75844SAndroid Build Coastguard Worker       vp9_low_tier_core_threshold_(
715*d9f75844SAndroid Build Coastguard Worker           ParseVp9LowTierCoreCountThreshold(field_trials)),
716*d9f75844SAndroid Build Coastguard Worker       encoder_queue_(std::move(encoder_queue)) {
717*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "VideoStreamEncoder::VideoStreamEncoder");
718*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
719*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(encoder_stats_observer);
720*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(number_of_cores, 1);
721*d9f75844SAndroid Build Coastguard Worker 
722*d9f75844SAndroid Build Coastguard Worker   frame_cadence_adapter_->Initialize(&cadence_callback_);
723*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.Initialize(encoder_queue_.Get());
724*d9f75844SAndroid Build Coastguard Worker 
__anon52fa13d80202null725*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this] {
726*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
727*d9f75844SAndroid Build Coastguard Worker 
728*d9f75844SAndroid Build Coastguard Worker     resource_adaptation_processor_ =
729*d9f75844SAndroid Build Coastguard Worker         std::make_unique<ResourceAdaptationProcessor>(
730*d9f75844SAndroid Build Coastguard Worker             video_stream_adapter_.get());
731*d9f75844SAndroid Build Coastguard Worker 
732*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.SetAdaptationProcessor(
733*d9f75844SAndroid Build Coastguard Worker         resource_adaptation_processor_.get(), video_stream_adapter_.get());
734*d9f75844SAndroid Build Coastguard Worker     resource_adaptation_processor_->AddResourceLimitationsListener(
735*d9f75844SAndroid Build Coastguard Worker         &stream_resource_manager_);
736*d9f75844SAndroid Build Coastguard Worker     video_stream_adapter_->AddRestrictionsListener(&stream_resource_manager_);
737*d9f75844SAndroid Build Coastguard Worker     video_stream_adapter_->AddRestrictionsListener(this);
738*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.MaybeInitializePixelLimitResource();
739*d9f75844SAndroid Build Coastguard Worker 
740*d9f75844SAndroid Build Coastguard Worker     // Add the stream resource manager's resources to the processor.
741*d9f75844SAndroid Build Coastguard Worker     adaptation_constraints_ = stream_resource_manager_.AdaptationConstraints();
742*d9f75844SAndroid Build Coastguard Worker     for (auto* constraint : adaptation_constraints_) {
743*d9f75844SAndroid Build Coastguard Worker       video_stream_adapter_->AddAdaptationConstraint(constraint);
744*d9f75844SAndroid Build Coastguard Worker     }
745*d9f75844SAndroid Build Coastguard Worker   });
746*d9f75844SAndroid Build Coastguard Worker }
747*d9f75844SAndroid Build Coastguard Worker 
~VideoStreamEncoder()748*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::~VideoStreamEncoder() {
749*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
750*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!video_source_sink_controller_.HasSource())
751*d9f75844SAndroid Build Coastguard Worker       << "Must call ::Stop() before destruction.";
752*d9f75844SAndroid Build Coastguard Worker }
753*d9f75844SAndroid Build Coastguard Worker 
Stop()754*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::Stop() {
755*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
756*d9f75844SAndroid Build Coastguard Worker   video_source_sink_controller_.SetSource(nullptr);
757*d9f75844SAndroid Build Coastguard Worker 
758*d9f75844SAndroid Build Coastguard Worker   rtc::Event shutdown_event;
759*d9f75844SAndroid Build Coastguard Worker   absl::Cleanup shutdown = [&shutdown_event] { shutdown_event.Set(); };
760*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask(
761*d9f75844SAndroid Build Coastguard Worker       [this, shutdown = std::move(shutdown)] {
762*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK_RUN_ON(&encoder_queue_);
763*d9f75844SAndroid Build Coastguard Worker         if (resource_adaptation_processor_) {
764*d9f75844SAndroid Build Coastguard Worker           stream_resource_manager_.StopManagedResources();
765*d9f75844SAndroid Build Coastguard Worker           for (auto* constraint : adaptation_constraints_) {
766*d9f75844SAndroid Build Coastguard Worker             video_stream_adapter_->RemoveAdaptationConstraint(constraint);
767*d9f75844SAndroid Build Coastguard Worker           }
768*d9f75844SAndroid Build Coastguard Worker           for (auto& resource : additional_resources_) {
769*d9f75844SAndroid Build Coastguard Worker             stream_resource_manager_.RemoveResource(resource);
770*d9f75844SAndroid Build Coastguard Worker           }
771*d9f75844SAndroid Build Coastguard Worker           additional_resources_.clear();
772*d9f75844SAndroid Build Coastguard Worker           video_stream_adapter_->RemoveRestrictionsListener(this);
773*d9f75844SAndroid Build Coastguard Worker           video_stream_adapter_->RemoveRestrictionsListener(
774*d9f75844SAndroid Build Coastguard Worker               &stream_resource_manager_);
775*d9f75844SAndroid Build Coastguard Worker           resource_adaptation_processor_->RemoveResourceLimitationsListener(
776*d9f75844SAndroid Build Coastguard Worker               &stream_resource_manager_);
777*d9f75844SAndroid Build Coastguard Worker           stream_resource_manager_.SetAdaptationProcessor(nullptr, nullptr);
778*d9f75844SAndroid Build Coastguard Worker           resource_adaptation_processor_.reset();
779*d9f75844SAndroid Build Coastguard Worker         }
780*d9f75844SAndroid Build Coastguard Worker         rate_allocator_ = nullptr;
781*d9f75844SAndroid Build Coastguard Worker         ReleaseEncoder();
782*d9f75844SAndroid Build Coastguard Worker         encoder_ = nullptr;
783*d9f75844SAndroid Build Coastguard Worker         frame_cadence_adapter_ = nullptr;
784*d9f75844SAndroid Build Coastguard Worker       });
785*d9f75844SAndroid Build Coastguard Worker   shutdown_event.Wait(rtc::Event::kForever);
786*d9f75844SAndroid Build Coastguard Worker }
787*d9f75844SAndroid Build Coastguard Worker 
SetFecControllerOverride(FecControllerOverride * fec_controller_override)788*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SetFecControllerOverride(
789*d9f75844SAndroid Build Coastguard Worker     FecControllerOverride* fec_controller_override) {
790*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, fec_controller_override] {
791*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
792*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(!fec_controller_override_);
793*d9f75844SAndroid Build Coastguard Worker     fec_controller_override_ = fec_controller_override;
794*d9f75844SAndroid Build Coastguard Worker     if (encoder_) {
795*d9f75844SAndroid Build Coastguard Worker       encoder_->SetFecControllerOverride(fec_controller_override_);
796*d9f75844SAndroid Build Coastguard Worker     }
797*d9f75844SAndroid Build Coastguard Worker   });
798*d9f75844SAndroid Build Coastguard Worker }
799*d9f75844SAndroid Build Coastguard Worker 
AddAdaptationResource(rtc::scoped_refptr<Resource> resource)800*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::AddAdaptationResource(
801*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<Resource> resource) {
802*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
803*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "VideoStreamEncoder::AddAdaptationResource");
804*d9f75844SAndroid Build Coastguard Worker   // Map any externally added resources as kCpu for the sake of stats reporting.
805*d9f75844SAndroid Build Coastguard Worker   // TODO(hbos): Make the manager map any unknown resources to kCpu and get rid
806*d9f75844SAndroid Build Coastguard Worker   // of this MapResourceToReason() call.
807*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT_ASYNC_BEGIN0(
808*d9f75844SAndroid Build Coastguard Worker       "webrtc", "VideoStreamEncoder::AddAdaptationResource(latency)", this);
809*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, resource = std::move(resource)] {
810*d9f75844SAndroid Build Coastguard Worker     TRACE_EVENT_ASYNC_END0(
811*d9f75844SAndroid Build Coastguard Worker         "webrtc", "VideoStreamEncoder::AddAdaptationResource(latency)", this);
812*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
813*d9f75844SAndroid Build Coastguard Worker     additional_resources_.push_back(resource);
814*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.AddResource(resource, VideoAdaptationReason::kCpu);
815*d9f75844SAndroid Build Coastguard Worker   });
816*d9f75844SAndroid Build Coastguard Worker }
817*d9f75844SAndroid Build Coastguard Worker 
818*d9f75844SAndroid Build Coastguard Worker std::vector<rtc::scoped_refptr<Resource>>
GetAdaptationResources()819*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::GetAdaptationResources() {
820*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
821*d9f75844SAndroid Build Coastguard Worker   // In practice, this method is only called by tests to verify operations that
822*d9f75844SAndroid Build Coastguard Worker   // run on the encoder queue. So rather than force PostTask() operations to
823*d9f75844SAndroid Build Coastguard Worker   // be accompanied by an event and a `Wait()`, we'll use PostTask + Wait()
824*d9f75844SAndroid Build Coastguard Worker   // here.
825*d9f75844SAndroid Build Coastguard Worker   rtc::Event event;
826*d9f75844SAndroid Build Coastguard Worker   std::vector<rtc::scoped_refptr<Resource>> resources;
827*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([&] {
828*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
829*d9f75844SAndroid Build Coastguard Worker     resources = resource_adaptation_processor_->GetResources();
830*d9f75844SAndroid Build Coastguard Worker     event.Set();
831*d9f75844SAndroid Build Coastguard Worker   });
832*d9f75844SAndroid Build Coastguard Worker   event.Wait(rtc::Event::kForever);
833*d9f75844SAndroid Build Coastguard Worker   return resources;
834*d9f75844SAndroid Build Coastguard Worker }
835*d9f75844SAndroid Build Coastguard Worker 
SetSource(rtc::VideoSourceInterface<VideoFrame> * source,const DegradationPreference & degradation_preference)836*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SetSource(
837*d9f75844SAndroid Build Coastguard Worker     rtc::VideoSourceInterface<VideoFrame>* source,
838*d9f75844SAndroid Build Coastguard Worker     const DegradationPreference& degradation_preference) {
839*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
840*d9f75844SAndroid Build Coastguard Worker   video_source_sink_controller_.SetSource(source);
841*d9f75844SAndroid Build Coastguard Worker   input_state_provider_.OnHasInputChanged(source);
842*d9f75844SAndroid Build Coastguard Worker 
843*d9f75844SAndroid Build Coastguard Worker   // This may trigger reconfiguring the QualityScaler on the encoder queue.
844*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, degradation_preference] {
845*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
846*d9f75844SAndroid Build Coastguard Worker     degradation_preference_manager_->SetDegradationPreference(
847*d9f75844SAndroid Build Coastguard Worker         degradation_preference);
848*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.SetDegradationPreferences(degradation_preference);
849*d9f75844SAndroid Build Coastguard Worker     if (encoder_) {
850*d9f75844SAndroid Build Coastguard Worker       stream_resource_manager_.ConfigureQualityScaler(
851*d9f75844SAndroid Build Coastguard Worker           encoder_->GetEncoderInfo());
852*d9f75844SAndroid Build Coastguard Worker       stream_resource_manager_.ConfigureBandwidthQualityScaler(
853*d9f75844SAndroid Build Coastguard Worker           encoder_->GetEncoderInfo());
854*d9f75844SAndroid Build Coastguard Worker     }
855*d9f75844SAndroid Build Coastguard Worker   });
856*d9f75844SAndroid Build Coastguard Worker }
857*d9f75844SAndroid Build Coastguard Worker 
SetSink(EncoderSink * sink,bool rotation_applied)858*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
859*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
860*d9f75844SAndroid Build Coastguard Worker   video_source_sink_controller_.SetRotationApplied(rotation_applied);
861*d9f75844SAndroid Build Coastguard Worker   video_source_sink_controller_.PushSourceSinkSettings();
862*d9f75844SAndroid Build Coastguard Worker 
863*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, sink] {
864*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
865*d9f75844SAndroid Build Coastguard Worker     sink_ = sink;
866*d9f75844SAndroid Build Coastguard Worker   });
867*d9f75844SAndroid Build Coastguard Worker }
868*d9f75844SAndroid Build Coastguard Worker 
SetStartBitrate(int start_bitrate_bps)869*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
870*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, start_bitrate_bps] {
871*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
872*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "SetStartBitrate " << start_bitrate_bps;
873*d9f75844SAndroid Build Coastguard Worker     encoder_target_bitrate_bps_ =
874*d9f75844SAndroid Build Coastguard Worker         start_bitrate_bps != 0 ? absl::optional<uint32_t>(start_bitrate_bps)
875*d9f75844SAndroid Build Coastguard Worker                                : absl::nullopt;
876*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.SetStartBitrate(
877*d9f75844SAndroid Build Coastguard Worker         DataRate::BitsPerSec(start_bitrate_bps));
878*d9f75844SAndroid Build Coastguard Worker   });
879*d9f75844SAndroid Build Coastguard Worker }
880*d9f75844SAndroid Build Coastguard Worker 
ConfigureEncoder(VideoEncoderConfig config,size_t max_data_payload_length)881*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
882*d9f75844SAndroid Build Coastguard Worker                                           size_t max_data_payload_length) {
883*d9f75844SAndroid Build Coastguard Worker   ConfigureEncoder(std::move(config), max_data_payload_length, nullptr);
884*d9f75844SAndroid Build Coastguard Worker }
885*d9f75844SAndroid Build Coastguard Worker 
ConfigureEncoder(VideoEncoderConfig config,size_t max_data_payload_length,SetParametersCallback callback)886*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
887*d9f75844SAndroid Build Coastguard Worker                                           size_t max_data_payload_length,
888*d9f75844SAndroid Build Coastguard Worker                                           SetParametersCallback callback) {
889*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(worker_queue_);
890*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask(
891*d9f75844SAndroid Build Coastguard Worker       [this, config = std::move(config), max_data_payload_length,
892*d9f75844SAndroid Build Coastguard Worker        callback = std::move(callback)]() mutable {
893*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK_RUN_ON(&encoder_queue_);
894*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK(sink_);
895*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_INFO) << "ConfigureEncoder requested.";
896*d9f75844SAndroid Build Coastguard Worker 
897*d9f75844SAndroid Build Coastguard Worker         // Set up the frame cadence adapter according to if we're going to do
898*d9f75844SAndroid Build Coastguard Worker         // screencast. The final number of spatial layers is based on info
899*d9f75844SAndroid Build Coastguard Worker         // in `send_codec_`, which is computed based on incoming frame
900*d9f75844SAndroid Build Coastguard Worker         // dimensions which can only be determined later.
901*d9f75844SAndroid Build Coastguard Worker         //
902*d9f75844SAndroid Build Coastguard Worker         // Note: zero-hertz mode isn't enabled by this alone. Constraints also
903*d9f75844SAndroid Build Coastguard Worker         // have to be set up with min_fps = 0 and max_fps > 0.
904*d9f75844SAndroid Build Coastguard Worker         if (config.content_type == VideoEncoderConfig::ContentType::kScreen) {
905*d9f75844SAndroid Build Coastguard Worker           frame_cadence_adapter_->SetZeroHertzModeEnabled(
906*d9f75844SAndroid Build Coastguard Worker               FrameCadenceAdapterInterface::ZeroHertzModeParams{});
907*d9f75844SAndroid Build Coastguard Worker         } else {
908*d9f75844SAndroid Build Coastguard Worker           frame_cadence_adapter_->SetZeroHertzModeEnabled(absl::nullopt);
909*d9f75844SAndroid Build Coastguard Worker         }
910*d9f75844SAndroid Build Coastguard Worker 
911*d9f75844SAndroid Build Coastguard Worker         pending_encoder_creation_ =
912*d9f75844SAndroid Build Coastguard Worker             (!encoder_ || encoder_config_.video_format != config.video_format ||
913*d9f75844SAndroid Build Coastguard Worker              max_data_payload_length_ != max_data_payload_length);
914*d9f75844SAndroid Build Coastguard Worker         encoder_config_ = std::move(config);
915*d9f75844SAndroid Build Coastguard Worker         max_data_payload_length_ = max_data_payload_length;
916*d9f75844SAndroid Build Coastguard Worker         pending_encoder_reconfiguration_ = true;
917*d9f75844SAndroid Build Coastguard Worker 
918*d9f75844SAndroid Build Coastguard Worker         // Reconfigure the encoder now if the frame resolution is known.
919*d9f75844SAndroid Build Coastguard Worker         // Otherwise, the reconfiguration is deferred until the next frame to
920*d9f75844SAndroid Build Coastguard Worker         // minimize the number of reconfigurations. The codec configuration
921*d9f75844SAndroid Build Coastguard Worker         // depends on incoming video frame size.
922*d9f75844SAndroid Build Coastguard Worker         if (last_frame_info_) {
923*d9f75844SAndroid Build Coastguard Worker           if (callback) {
924*d9f75844SAndroid Build Coastguard Worker             encoder_configuration_callbacks_.push_back(std::move(callback));
925*d9f75844SAndroid Build Coastguard Worker           }
926*d9f75844SAndroid Build Coastguard Worker 
927*d9f75844SAndroid Build Coastguard Worker           ReconfigureEncoder();
928*d9f75844SAndroid Build Coastguard Worker         } else {
929*d9f75844SAndroid Build Coastguard Worker           webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
930*d9f75844SAndroid Build Coastguard Worker         }
931*d9f75844SAndroid Build Coastguard Worker       });
932*d9f75844SAndroid Build Coastguard Worker }
933*d9f75844SAndroid Build Coastguard Worker 
934*d9f75844SAndroid Build Coastguard Worker // We should reduce the number of 'full' ReconfigureEncoder(). If only need
935*d9f75844SAndroid Build Coastguard Worker // subset of it at runtime, consider handle it in
936*d9f75844SAndroid Build Coastguard Worker // VideoStreamEncoder::EncodeVideoFrame() when encoder_info_ != info.
ReconfigureEncoder()937*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::ReconfigureEncoder() {
938*d9f75844SAndroid Build Coastguard Worker   // Running on the encoder queue.
939*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(pending_encoder_reconfiguration_);
940*d9f75844SAndroid Build Coastguard Worker 
941*d9f75844SAndroid Build Coastguard Worker   bool encoder_reset_required = false;
942*d9f75844SAndroid Build Coastguard Worker   if (pending_encoder_creation_) {
943*d9f75844SAndroid Build Coastguard Worker     // Destroy existing encoder instance before creating a new one. Otherwise
944*d9f75844SAndroid Build Coastguard Worker     // attempt to create another instance will fail if encoder factory
945*d9f75844SAndroid Build Coastguard Worker     // supports only single instance of encoder of given type.
946*d9f75844SAndroid Build Coastguard Worker     encoder_.reset();
947*d9f75844SAndroid Build Coastguard Worker 
948*d9f75844SAndroid Build Coastguard Worker     encoder_ = settings_.encoder_factory->CreateVideoEncoder(
949*d9f75844SAndroid Build Coastguard Worker         encoder_config_.video_format);
950*d9f75844SAndroid Build Coastguard Worker     if (!encoder_) {
951*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "CreateVideoEncoder failed, failing encoder format: "
952*d9f75844SAndroid Build Coastguard Worker                         << encoder_config_.video_format.ToString();
953*d9f75844SAndroid Build Coastguard Worker       RequestEncoderSwitch();
954*d9f75844SAndroid Build Coastguard Worker       return;
955*d9f75844SAndroid Build Coastguard Worker     }
956*d9f75844SAndroid Build Coastguard Worker 
957*d9f75844SAndroid Build Coastguard Worker     if (encoder_selector_) {
958*d9f75844SAndroid Build Coastguard Worker       encoder_selector_->OnCurrentEncoder(encoder_config_.video_format);
959*d9f75844SAndroid Build Coastguard Worker     }
960*d9f75844SAndroid Build Coastguard Worker 
961*d9f75844SAndroid Build Coastguard Worker     encoder_->SetFecControllerOverride(fec_controller_override_);
962*d9f75844SAndroid Build Coastguard Worker 
963*d9f75844SAndroid Build Coastguard Worker     encoder_reset_required = true;
964*d9f75844SAndroid Build Coastguard Worker   }
965*d9f75844SAndroid Build Coastguard Worker 
966*d9f75844SAndroid Build Coastguard Worker   // TODO(webrtc:14451) : Move AlignmentAdjuster into EncoderStreamFactory
967*d9f75844SAndroid Build Coastguard Worker   // Possibly adjusts scale_resolution_down_by in `encoder_config_` to limit the
968*d9f75844SAndroid Build Coastguard Worker   // alignment value.
969*d9f75844SAndroid Build Coastguard Worker   AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
970*d9f75844SAndroid Build Coastguard Worker       encoder_->GetEncoderInfo(), &encoder_config_, absl::nullopt);
971*d9f75844SAndroid Build Coastguard Worker 
972*d9f75844SAndroid Build Coastguard Worker   std::vector<VideoStream> streams;
973*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_.video_stream_factory) {
974*d9f75844SAndroid Build Coastguard Worker     // Note: only tests set their own EncoderStreamFactory...
975*d9f75844SAndroid Build Coastguard Worker     streams = encoder_config_.video_stream_factory->CreateEncoderStreams(
976*d9f75844SAndroid Build Coastguard Worker         last_frame_info_->width, last_frame_info_->height, encoder_config_);
977*d9f75844SAndroid Build Coastguard Worker   } else {
978*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<VideoEncoderConfig::VideoStreamFactoryInterface>
979*d9f75844SAndroid Build Coastguard Worker         factory = rtc::make_ref_counted<cricket::EncoderStreamFactory>(
980*d9f75844SAndroid Build Coastguard Worker             encoder_config_.video_format.name, encoder_config_.max_qp,
981*d9f75844SAndroid Build Coastguard Worker             encoder_config_.content_type ==
982*d9f75844SAndroid Build Coastguard Worker                 webrtc::VideoEncoderConfig::ContentType::kScreen,
983*d9f75844SAndroid Build Coastguard Worker             encoder_config_.legacy_conference_mode, encoder_->GetEncoderInfo(),
984*d9f75844SAndroid Build Coastguard Worker             MergeRestrictions({latest_restrictions_, animate_restrictions_}),
985*d9f75844SAndroid Build Coastguard Worker             &field_trials_);
986*d9f75844SAndroid Build Coastguard Worker 
987*d9f75844SAndroid Build Coastguard Worker     streams = factory->CreateEncoderStreams(
988*d9f75844SAndroid Build Coastguard Worker         last_frame_info_->width, last_frame_info_->height, encoder_config_);
989*d9f75844SAndroid Build Coastguard Worker   }
990*d9f75844SAndroid Build Coastguard Worker 
991*d9f75844SAndroid Build Coastguard Worker   // TODO(webrtc:14451) : Move AlignmentAdjuster into EncoderStreamFactory
992*d9f75844SAndroid Build Coastguard Worker   // Get alignment when actual number of layers are known.
993*d9f75844SAndroid Build Coastguard Worker   int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
994*d9f75844SAndroid Build Coastguard Worker       encoder_->GetEncoderInfo(), &encoder_config_, streams.size());
995*d9f75844SAndroid Build Coastguard Worker 
996*d9f75844SAndroid Build Coastguard Worker   // Check that the higher layers do not try to set number of temporal layers
997*d9f75844SAndroid Build Coastguard Worker   // to less than 1.
998*d9f75844SAndroid Build Coastguard Worker   // TODO(brandtr): Get rid of the wrapping optional as it serves no purpose
999*d9f75844SAndroid Build Coastguard Worker   // at this layer.
1000*d9f75844SAndroid Build Coastguard Worker #if RTC_DCHECK_IS_ON
1001*d9f75844SAndroid Build Coastguard Worker   for (const auto& stream : streams) {
1002*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GE(stream.num_temporal_layers.value_or(1), 1);
1003*d9f75844SAndroid Build Coastguard Worker   }
1004*d9f75844SAndroid Build Coastguard Worker #endif
1005*d9f75844SAndroid Build Coastguard Worker 
1006*d9f75844SAndroid Build Coastguard Worker   // TODO(ilnik): If configured resolution is significantly less than provided,
1007*d9f75844SAndroid Build Coastguard Worker   // e.g. because there are not enough SSRCs for all simulcast streams,
1008*d9f75844SAndroid Build Coastguard Worker   // signal new resolutions via SinkWants to video source.
1009*d9f75844SAndroid Build Coastguard Worker 
1010*d9f75844SAndroid Build Coastguard Worker   // Stream dimensions may be not equal to given because of a simulcast
1011*d9f75844SAndroid Build Coastguard Worker   // restrictions.
1012*d9f75844SAndroid Build Coastguard Worker   auto highest_stream = absl::c_max_element(
1013*d9f75844SAndroid Build Coastguard Worker       streams, [](const webrtc::VideoStream& a, const webrtc::VideoStream& b) {
1014*d9f75844SAndroid Build Coastguard Worker         return std::tie(a.width, a.height) < std::tie(b.width, b.height);
1015*d9f75844SAndroid Build Coastguard Worker       });
1016*d9f75844SAndroid Build Coastguard Worker   int highest_stream_width = static_cast<int>(highest_stream->width);
1017*d9f75844SAndroid Build Coastguard Worker   int highest_stream_height = static_cast<int>(highest_stream->height);
1018*d9f75844SAndroid Build Coastguard Worker   // Dimension may be reduced to be, e.g. divisible by 4.
1019*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(last_frame_info_->width, highest_stream_width);
1020*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(last_frame_info_->height, highest_stream_height);
1021*d9f75844SAndroid Build Coastguard Worker   crop_width_ = last_frame_info_->width - highest_stream_width;
1022*d9f75844SAndroid Build Coastguard Worker   crop_height_ = last_frame_info_->height - highest_stream_height;
1023*d9f75844SAndroid Build Coastguard Worker 
1024*d9f75844SAndroid Build Coastguard Worker   if (!encoder_->GetEncoderInfo().is_qp_trusted.value_or(true)) {
1025*d9f75844SAndroid Build Coastguard Worker     // when qp is not trusted, we priorities to using the
1026*d9f75844SAndroid Build Coastguard Worker     // |resolution_bitrate_limits| provided by the decoder.
1027*d9f75844SAndroid Build Coastguard Worker     const std::vector<VideoEncoder::ResolutionBitrateLimits>& bitrate_limits =
1028*d9f75844SAndroid Build Coastguard Worker         encoder_->GetEncoderInfo().resolution_bitrate_limits.empty()
1029*d9f75844SAndroid Build Coastguard Worker             ? EncoderInfoSettings::
1030*d9f75844SAndroid Build Coastguard Worker                   GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted()
1031*d9f75844SAndroid Build Coastguard Worker             : encoder_->GetEncoderInfo().resolution_bitrate_limits;
1032*d9f75844SAndroid Build Coastguard Worker 
1033*d9f75844SAndroid Build Coastguard Worker     // For BandwidthQualityScaler, its implement based on a certain pixel_count
1034*d9f75844SAndroid Build Coastguard Worker     // correspond a certain bps interval. In fact, WebRTC default max_bps is
1035*d9f75844SAndroid Build Coastguard Worker     // 2500Kbps when width * height > 960 * 540. For example, we assume:
1036*d9f75844SAndroid Build Coastguard Worker     // 1.the camera support 1080p.
1037*d9f75844SAndroid Build Coastguard Worker     // 2.ResolutionBitrateLimits set 720p bps interval is [1500Kbps,2000Kbps].
1038*d9f75844SAndroid Build Coastguard Worker     // 3.ResolutionBitrateLimits set 1080p bps interval is [2000Kbps,2500Kbps].
1039*d9f75844SAndroid Build Coastguard Worker     // We will never be stable at 720p due to actual encoding bps of 720p and
1040*d9f75844SAndroid Build Coastguard Worker     // 1080p are both 2500Kbps. So it is necessary to do a linear interpolation
1041*d9f75844SAndroid Build Coastguard Worker     // to get a certain bitrate for certain pixel_count. It also doesn't work
1042*d9f75844SAndroid Build Coastguard Worker     // for 960*540 and 640*520, we will nerver be stable at 640*520 due to their
1043*d9f75844SAndroid Build Coastguard Worker     // |target_bitrate_bps| are both 2000Kbps.
1044*d9f75844SAndroid Build Coastguard Worker     absl::optional<VideoEncoder::ResolutionBitrateLimits>
1045*d9f75844SAndroid Build Coastguard Worker         qp_untrusted_bitrate_limit = EncoderInfoSettings::
1046*d9f75844SAndroid Build Coastguard Worker             GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
1047*d9f75844SAndroid Build Coastguard Worker                 last_frame_info_->width * last_frame_info_->height,
1048*d9f75844SAndroid Build Coastguard Worker                 bitrate_limits);
1049*d9f75844SAndroid Build Coastguard Worker 
1050*d9f75844SAndroid Build Coastguard Worker     if (qp_untrusted_bitrate_limit) {
1051*d9f75844SAndroid Build Coastguard Worker       // bandwidth_quality_scaler is only used for singlecast.
1052*d9f75844SAndroid Build Coastguard Worker       if (streams.size() == 1 && encoder_config_.simulcast_layers.size() == 1) {
1053*d9f75844SAndroid Build Coastguard Worker         streams.back().min_bitrate_bps =
1054*d9f75844SAndroid Build Coastguard Worker             qp_untrusted_bitrate_limit->min_bitrate_bps;
1055*d9f75844SAndroid Build Coastguard Worker         streams.back().max_bitrate_bps =
1056*d9f75844SAndroid Build Coastguard Worker             qp_untrusted_bitrate_limit->max_bitrate_bps;
1057*d9f75844SAndroid Build Coastguard Worker         // If it is screen share mode, the minimum value of max_bitrate should
1058*d9f75844SAndroid Build Coastguard Worker         // be greater than/equal to 1200kbps.
1059*d9f75844SAndroid Build Coastguard Worker         if (encoder_config_.content_type ==
1060*d9f75844SAndroid Build Coastguard Worker             VideoEncoderConfig::ContentType::kScreen) {
1061*d9f75844SAndroid Build Coastguard Worker           streams.back().max_bitrate_bps = std::max(
1062*d9f75844SAndroid Build Coastguard Worker               streams.back().max_bitrate_bps, kDefaultMinScreenSharebps);
1063*d9f75844SAndroid Build Coastguard Worker         }
1064*d9f75844SAndroid Build Coastguard Worker         streams.back().target_bitrate_bps =
1065*d9f75844SAndroid Build Coastguard Worker             qp_untrusted_bitrate_limit->max_bitrate_bps;
1066*d9f75844SAndroid Build Coastguard Worker       }
1067*d9f75844SAndroid Build Coastguard Worker     }
1068*d9f75844SAndroid Build Coastguard Worker   } else {
1069*d9f75844SAndroid Build Coastguard Worker     absl::optional<VideoEncoder::ResolutionBitrateLimits>
1070*d9f75844SAndroid Build Coastguard Worker         encoder_bitrate_limits =
1071*d9f75844SAndroid Build Coastguard Worker             encoder_->GetEncoderInfo().GetEncoderBitrateLimitsForResolution(
1072*d9f75844SAndroid Build Coastguard Worker                 last_frame_info_->width * last_frame_info_->height);
1073*d9f75844SAndroid Build Coastguard Worker 
1074*d9f75844SAndroid Build Coastguard Worker     if (encoder_bitrate_limits) {
1075*d9f75844SAndroid Build Coastguard Worker       if (streams.size() == 1 && encoder_config_.simulcast_layers.size() == 1) {
1076*d9f75844SAndroid Build Coastguard Worker         // Bitrate limits can be set by app (in SDP or RtpEncodingParameters)
1077*d9f75844SAndroid Build Coastguard Worker         // or/and can be provided by encoder. In presence of both set of
1078*d9f75844SAndroid Build Coastguard Worker         // limits, the final set is derived as their intersection.
1079*d9f75844SAndroid Build Coastguard Worker         int min_bitrate_bps;
1080*d9f75844SAndroid Build Coastguard Worker         if (encoder_config_.simulcast_layers.empty() ||
1081*d9f75844SAndroid Build Coastguard Worker             encoder_config_.simulcast_layers[0].min_bitrate_bps <= 0) {
1082*d9f75844SAndroid Build Coastguard Worker           min_bitrate_bps = encoder_bitrate_limits->min_bitrate_bps;
1083*d9f75844SAndroid Build Coastguard Worker         } else {
1084*d9f75844SAndroid Build Coastguard Worker           min_bitrate_bps = std::max(encoder_bitrate_limits->min_bitrate_bps,
1085*d9f75844SAndroid Build Coastguard Worker                                      streams.back().min_bitrate_bps);
1086*d9f75844SAndroid Build Coastguard Worker         }
1087*d9f75844SAndroid Build Coastguard Worker 
1088*d9f75844SAndroid Build Coastguard Worker         int max_bitrate_bps;
1089*d9f75844SAndroid Build Coastguard Worker         // We don't check encoder_config_.simulcast_layers[0].max_bitrate_bps
1090*d9f75844SAndroid Build Coastguard Worker         // here since encoder_config_.max_bitrate_bps is derived from it (as
1091*d9f75844SAndroid Build Coastguard Worker         // well as from other inputs).
1092*d9f75844SAndroid Build Coastguard Worker         if (encoder_config_.max_bitrate_bps <= 0) {
1093*d9f75844SAndroid Build Coastguard Worker           max_bitrate_bps = encoder_bitrate_limits->max_bitrate_bps;
1094*d9f75844SAndroid Build Coastguard Worker         } else {
1095*d9f75844SAndroid Build Coastguard Worker           max_bitrate_bps = std::min(encoder_bitrate_limits->max_bitrate_bps,
1096*d9f75844SAndroid Build Coastguard Worker                                      streams.back().max_bitrate_bps);
1097*d9f75844SAndroid Build Coastguard Worker         }
1098*d9f75844SAndroid Build Coastguard Worker 
1099*d9f75844SAndroid Build Coastguard Worker         if (min_bitrate_bps < max_bitrate_bps) {
1100*d9f75844SAndroid Build Coastguard Worker           streams.back().min_bitrate_bps = min_bitrate_bps;
1101*d9f75844SAndroid Build Coastguard Worker           streams.back().max_bitrate_bps = max_bitrate_bps;
1102*d9f75844SAndroid Build Coastguard Worker           streams.back().target_bitrate_bps =
1103*d9f75844SAndroid Build Coastguard Worker               std::min(streams.back().target_bitrate_bps,
1104*d9f75844SAndroid Build Coastguard Worker                        encoder_bitrate_limits->max_bitrate_bps);
1105*d9f75844SAndroid Build Coastguard Worker         } else {
1106*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING)
1107*d9f75844SAndroid Build Coastguard Worker               << "Bitrate limits provided by encoder"
1108*d9f75844SAndroid Build Coastguard Worker               << " (min=" << encoder_bitrate_limits->min_bitrate_bps
1109*d9f75844SAndroid Build Coastguard Worker               << ", max=" << encoder_bitrate_limits->max_bitrate_bps
1110*d9f75844SAndroid Build Coastguard Worker               << ") do not intersect with limits set by app"
1111*d9f75844SAndroid Build Coastguard Worker               << " (min=" << streams.back().min_bitrate_bps
1112*d9f75844SAndroid Build Coastguard Worker               << ", max=" << encoder_config_.max_bitrate_bps
1113*d9f75844SAndroid Build Coastguard Worker               << "). The app bitrate limits will be used.";
1114*d9f75844SAndroid Build Coastguard Worker         }
1115*d9f75844SAndroid Build Coastguard Worker       }
1116*d9f75844SAndroid Build Coastguard Worker     }
1117*d9f75844SAndroid Build Coastguard Worker   }
1118*d9f75844SAndroid Build Coastguard Worker 
1119*d9f75844SAndroid Build Coastguard Worker   ApplyEncoderBitrateLimitsIfSingleActiveStream(
1120*d9f75844SAndroid Build Coastguard Worker       GetEncoderInfoWithBitrateLimitUpdate(
1121*d9f75844SAndroid Build Coastguard Worker           encoder_->GetEncoderInfo(), encoder_config_, default_limits_allowed_),
1122*d9f75844SAndroid Build Coastguard Worker       encoder_config_.simulcast_layers, &streams);
1123*d9f75844SAndroid Build Coastguard Worker 
1124*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1125*d9f75844SAndroid Build Coastguard Worker   if (!VideoCodecInitializer::SetupCodec(encoder_config_, streams, &codec)) {
1126*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to create encoder configuration.";
1127*d9f75844SAndroid Build Coastguard Worker   }
1128*d9f75844SAndroid Build Coastguard Worker 
1129*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_.codec_type == kVideoCodecVP9) {
1130*d9f75844SAndroid Build Coastguard Worker     // Spatial layers configuration might impose some parity restrictions,
1131*d9f75844SAndroid Build Coastguard Worker     // thus some cropping might be needed.
1132*d9f75844SAndroid Build Coastguard Worker     crop_width_ = last_frame_info_->width - codec.width;
1133*d9f75844SAndroid Build Coastguard Worker     crop_height_ = last_frame_info_->height - codec.height;
1134*d9f75844SAndroid Build Coastguard Worker     ApplyVp9BitrateLimits(GetEncoderInfoWithBitrateLimitUpdate(
1135*d9f75844SAndroid Build Coastguard Worker                               encoder_->GetEncoderInfo(), encoder_config_,
1136*d9f75844SAndroid Build Coastguard Worker                               default_limits_allowed_),
1137*d9f75844SAndroid Build Coastguard Worker                           encoder_config_, &codec);
1138*d9f75844SAndroid Build Coastguard Worker   }
1139*d9f75844SAndroid Build Coastguard Worker 
1140*d9f75844SAndroid Build Coastguard Worker   char log_stream_buf[4 * 1024];
1141*d9f75844SAndroid Build Coastguard Worker   rtc::SimpleStringBuilder log_stream(log_stream_buf);
1142*d9f75844SAndroid Build Coastguard Worker   log_stream << "ReconfigureEncoder:\n";
1143*d9f75844SAndroid Build Coastguard Worker   log_stream << "Simulcast streams:\n";
1144*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < codec.numberOfSimulcastStreams; ++i) {
1145*d9f75844SAndroid Build Coastguard Worker     log_stream << i << ": " << codec.simulcastStream[i].width << "x"
1146*d9f75844SAndroid Build Coastguard Worker                << codec.simulcastStream[i].height
1147*d9f75844SAndroid Build Coastguard Worker                << " min_kbps: " << codec.simulcastStream[i].minBitrate
1148*d9f75844SAndroid Build Coastguard Worker                << " target_kbps: " << codec.simulcastStream[i].targetBitrate
1149*d9f75844SAndroid Build Coastguard Worker                << " max_kbps: " << codec.simulcastStream[i].maxBitrate
1150*d9f75844SAndroid Build Coastguard Worker                << " max_fps: " << codec.simulcastStream[i].maxFramerate
1151*d9f75844SAndroid Build Coastguard Worker                << " max_qp: " << codec.simulcastStream[i].qpMax
1152*d9f75844SAndroid Build Coastguard Worker                << " num_tl: " << codec.simulcastStream[i].numberOfTemporalLayers
1153*d9f75844SAndroid Build Coastguard Worker                << " active: "
1154*d9f75844SAndroid Build Coastguard Worker                << (codec.simulcastStream[i].active ? "true" : "false") << "\n";
1155*d9f75844SAndroid Build Coastguard Worker   }
1156*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_.codec_type == kVideoCodecVP9) {
1157*d9f75844SAndroid Build Coastguard Worker     size_t num_spatial_layers = codec.VP9()->numberOfSpatialLayers;
1158*d9f75844SAndroid Build Coastguard Worker     log_stream << "Spatial layers:\n";
1159*d9f75844SAndroid Build Coastguard Worker     for (size_t i = 0; i < num_spatial_layers; ++i) {
1160*d9f75844SAndroid Build Coastguard Worker       log_stream << i << ": " << codec.spatialLayers[i].width << "x"
1161*d9f75844SAndroid Build Coastguard Worker                  << codec.spatialLayers[i].height
1162*d9f75844SAndroid Build Coastguard Worker                  << " min_kbps: " << codec.spatialLayers[i].minBitrate
1163*d9f75844SAndroid Build Coastguard Worker                  << " target_kbps: " << codec.spatialLayers[i].targetBitrate
1164*d9f75844SAndroid Build Coastguard Worker                  << " max_kbps: " << codec.spatialLayers[i].maxBitrate
1165*d9f75844SAndroid Build Coastguard Worker                  << " max_fps: " << codec.spatialLayers[i].maxFramerate
1166*d9f75844SAndroid Build Coastguard Worker                  << " max_qp: " << codec.spatialLayers[i].qpMax
1167*d9f75844SAndroid Build Coastguard Worker                  << " num_tl: " << codec.spatialLayers[i].numberOfTemporalLayers
1168*d9f75844SAndroid Build Coastguard Worker                  << " active: "
1169*d9f75844SAndroid Build Coastguard Worker                  << (codec.spatialLayers[i].active ? "true" : "false") << "\n";
1170*d9f75844SAndroid Build Coastguard Worker     }
1171*d9f75844SAndroid Build Coastguard Worker   }
1172*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << log_stream.str();
1173*d9f75844SAndroid Build Coastguard Worker 
1174*d9f75844SAndroid Build Coastguard Worker   codec.startBitrate = std::max(encoder_target_bitrate_bps_.value_or(0) / 1000,
1175*d9f75844SAndroid Build Coastguard Worker                                 codec.minBitrate);
1176*d9f75844SAndroid Build Coastguard Worker   codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
1177*d9f75844SAndroid Build Coastguard Worker   codec.expect_encode_from_texture = last_frame_info_->is_texture;
1178*d9f75844SAndroid Build Coastguard Worker   // Make sure the start bit rate is sane...
1179*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LE(codec.startBitrate, 1000000);
1180*d9f75844SAndroid Build Coastguard Worker   max_framerate_ = codec.maxFramerate;
1181*d9f75844SAndroid Build Coastguard Worker 
1182*d9f75844SAndroid Build Coastguard Worker   // Inform source about max configured framerate,
1183*d9f75844SAndroid Build Coastguard Worker   // requested_resolution and which layers are active.
1184*d9f75844SAndroid Build Coastguard Worker   int max_framerate = 0;
1185*d9f75844SAndroid Build Coastguard Worker   // Is any layer active.
1186*d9f75844SAndroid Build Coastguard Worker   bool active = false;
1187*d9f75844SAndroid Build Coastguard Worker   // The max requested_resolution.
1188*d9f75844SAndroid Build Coastguard Worker   absl::optional<rtc::VideoSinkWants::FrameSize> requested_resolution;
1189*d9f75844SAndroid Build Coastguard Worker   for (const auto& stream : streams) {
1190*d9f75844SAndroid Build Coastguard Worker     max_framerate = std::max(stream.max_framerate, max_framerate);
1191*d9f75844SAndroid Build Coastguard Worker     active |= stream.active;
1192*d9f75844SAndroid Build Coastguard Worker     // Note: we propagate the highest requested_resolution regardless
1193*d9f75844SAndroid Build Coastguard Worker     // if layer is active or not.
1194*d9f75844SAndroid Build Coastguard Worker     if (stream.requested_resolution) {
1195*d9f75844SAndroid Build Coastguard Worker       if (!requested_resolution) {
1196*d9f75844SAndroid Build Coastguard Worker         requested_resolution.emplace(stream.requested_resolution->width,
1197*d9f75844SAndroid Build Coastguard Worker                                      stream.requested_resolution->height);
1198*d9f75844SAndroid Build Coastguard Worker       } else {
1199*d9f75844SAndroid Build Coastguard Worker         requested_resolution.emplace(
1200*d9f75844SAndroid Build Coastguard Worker             std::max(stream.requested_resolution->width,
1201*d9f75844SAndroid Build Coastguard Worker                      requested_resolution->width),
1202*d9f75844SAndroid Build Coastguard Worker             std::max(stream.requested_resolution->height,
1203*d9f75844SAndroid Build Coastguard Worker                      requested_resolution->height));
1204*d9f75844SAndroid Build Coastguard Worker       }
1205*d9f75844SAndroid Build Coastguard Worker     }
1206*d9f75844SAndroid Build Coastguard Worker   }
1207*d9f75844SAndroid Build Coastguard Worker 
1208*d9f75844SAndroid Build Coastguard Worker   // The resolutions that we're actually encoding with.
1209*d9f75844SAndroid Build Coastguard Worker   std::vector<rtc::VideoSinkWants::FrameSize> encoder_resolutions;
1210*d9f75844SAndroid Build Coastguard Worker   // TODO(hbos): For the case of SVC, also make use of `codec.spatialLayers`.
1211*d9f75844SAndroid Build Coastguard Worker   // For now, SVC layers are handled by the VP9 encoder.
1212*d9f75844SAndroid Build Coastguard Worker   for (const auto& simulcastStream : codec.simulcastStream) {
1213*d9f75844SAndroid Build Coastguard Worker     if (!simulcastStream.active)
1214*d9f75844SAndroid Build Coastguard Worker       continue;
1215*d9f75844SAndroid Build Coastguard Worker     encoder_resolutions.emplace_back(simulcastStream.width,
1216*d9f75844SAndroid Build Coastguard Worker                                      simulcastStream.height);
1217*d9f75844SAndroid Build Coastguard Worker   }
1218*d9f75844SAndroid Build Coastguard Worker 
1219*d9f75844SAndroid Build Coastguard Worker   worker_queue_->PostTask(SafeTask(
1220*d9f75844SAndroid Build Coastguard Worker       task_safety_.flag(),
1221*d9f75844SAndroid Build Coastguard Worker       [this, max_framerate, alignment,
1222*d9f75844SAndroid Build Coastguard Worker        encoder_resolutions = std::move(encoder_resolutions),
1223*d9f75844SAndroid Build Coastguard Worker        requested_resolution = std::move(requested_resolution), active]() {
1224*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK_RUN_ON(worker_queue_);
1225*d9f75844SAndroid Build Coastguard Worker         if (max_framerate !=
1226*d9f75844SAndroid Build Coastguard Worker                 video_source_sink_controller_.frame_rate_upper_limit() ||
1227*d9f75844SAndroid Build Coastguard Worker             alignment != video_source_sink_controller_.resolution_alignment() ||
1228*d9f75844SAndroid Build Coastguard Worker             encoder_resolutions !=
1229*d9f75844SAndroid Build Coastguard Worker                 video_source_sink_controller_.resolutions() ||
1230*d9f75844SAndroid Build Coastguard Worker             (video_source_sink_controller_.requested_resolution() !=
1231*d9f75844SAndroid Build Coastguard Worker              requested_resolution) ||
1232*d9f75844SAndroid Build Coastguard Worker             (video_source_sink_controller_.active() != active)) {
1233*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetFrameRateUpperLimit(max_framerate);
1234*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetResolutionAlignment(alignment);
1235*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetResolutions(
1236*d9f75844SAndroid Build Coastguard Worker               std::move(encoder_resolutions));
1237*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetRequestedResolution(
1238*d9f75844SAndroid Build Coastguard Worker               requested_resolution);
1239*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetActive(active);
1240*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.PushSourceSinkSettings();
1241*d9f75844SAndroid Build Coastguard Worker         }
1242*d9f75844SAndroid Build Coastguard Worker       }));
1243*d9f75844SAndroid Build Coastguard Worker 
1244*d9f75844SAndroid Build Coastguard Worker   rate_allocator_ =
1245*d9f75844SAndroid Build Coastguard Worker       settings_.bitrate_allocator_factory->CreateVideoBitrateAllocator(codec);
1246*d9f75844SAndroid Build Coastguard Worker   rate_allocator_->SetLegacyConferenceMode(
1247*d9f75844SAndroid Build Coastguard Worker       encoder_config_.legacy_conference_mode);
1248*d9f75844SAndroid Build Coastguard Worker 
1249*d9f75844SAndroid Build Coastguard Worker   // Reset (release existing encoder) if one exists and anything except
1250*d9f75844SAndroid Build Coastguard Worker   // start bitrate or max framerate has changed.
1251*d9f75844SAndroid Build Coastguard Worker   if (!encoder_reset_required) {
1252*d9f75844SAndroid Build Coastguard Worker     encoder_reset_required = RequiresEncoderReset(
1253*d9f75844SAndroid Build Coastguard Worker         send_codec_, codec, was_encode_called_since_last_initialization_);
1254*d9f75844SAndroid Build Coastguard Worker   }
1255*d9f75844SAndroid Build Coastguard Worker 
1256*d9f75844SAndroid Build Coastguard Worker   if (codec.codecType == VideoCodecType::kVideoCodecVP9 &&
1257*d9f75844SAndroid Build Coastguard Worker       number_of_cores_ <= vp9_low_tier_core_threshold_.value_or(0)) {
1258*d9f75844SAndroid Build Coastguard Worker     codec.SetVideoEncoderComplexity(VideoCodecComplexity::kComplexityLow);
1259*d9f75844SAndroid Build Coastguard Worker   }
1260*d9f75844SAndroid Build Coastguard Worker 
1261*d9f75844SAndroid Build Coastguard Worker   send_codec_ = codec;
1262*d9f75844SAndroid Build Coastguard Worker 
1263*d9f75844SAndroid Build Coastguard Worker   // Keep the same encoder, as long as the video_format is unchanged.
1264*d9f75844SAndroid Build Coastguard Worker   // Encoder creation block is split in two since EncoderInfo needed to start
1265*d9f75844SAndroid Build Coastguard Worker   // CPU adaptation with the correct settings should be polled after
1266*d9f75844SAndroid Build Coastguard Worker   // encoder_->InitEncode().
1267*d9f75844SAndroid Build Coastguard Worker   if (encoder_reset_required) {
1268*d9f75844SAndroid Build Coastguard Worker     ReleaseEncoder();
1269*d9f75844SAndroid Build Coastguard Worker     const size_t max_data_payload_length = max_data_payload_length_ > 0
1270*d9f75844SAndroid Build Coastguard Worker                                                ? max_data_payload_length_
1271*d9f75844SAndroid Build Coastguard Worker                                                : kDefaultPayloadSize;
1272*d9f75844SAndroid Build Coastguard Worker     if (encoder_->InitEncode(
1273*d9f75844SAndroid Build Coastguard Worker             &send_codec_,
1274*d9f75844SAndroid Build Coastguard Worker             VideoEncoder::Settings(settings_.capabilities, number_of_cores_,
1275*d9f75844SAndroid Build Coastguard Worker                                    max_data_payload_length)) != 0) {
1276*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
1277*d9f75844SAndroid Build Coastguard Worker                            "codec type: "
1278*d9f75844SAndroid Build Coastguard Worker                         << CodecTypeToPayloadString(send_codec_.codecType)
1279*d9f75844SAndroid Build Coastguard Worker                         << " (" << send_codec_.codecType << ")";
1280*d9f75844SAndroid Build Coastguard Worker       ReleaseEncoder();
1281*d9f75844SAndroid Build Coastguard Worker     } else {
1282*d9f75844SAndroid Build Coastguard Worker       encoder_initialized_ = true;
1283*d9f75844SAndroid Build Coastguard Worker       encoder_->RegisterEncodeCompleteCallback(this);
1284*d9f75844SAndroid Build Coastguard Worker       frame_encode_metadata_writer_.OnEncoderInit(send_codec_);
1285*d9f75844SAndroid Build Coastguard Worker       next_frame_types_.clear();
1286*d9f75844SAndroid Build Coastguard Worker       next_frame_types_.resize(
1287*d9f75844SAndroid Build Coastguard Worker           std::max(static_cast<int>(codec.numberOfSimulcastStreams), 1),
1288*d9f75844SAndroid Build Coastguard Worker           VideoFrameType::kVideoFrameKey);
1289*d9f75844SAndroid Build Coastguard Worker     }
1290*d9f75844SAndroid Build Coastguard Worker 
1291*d9f75844SAndroid Build Coastguard Worker     frame_encode_metadata_writer_.Reset();
1292*d9f75844SAndroid Build Coastguard Worker     last_encode_info_ms_ = absl::nullopt;
1293*d9f75844SAndroid Build Coastguard Worker     was_encode_called_since_last_initialization_ = false;
1294*d9f75844SAndroid Build Coastguard Worker   }
1295*d9f75844SAndroid Build Coastguard Worker 
1296*d9f75844SAndroid Build Coastguard Worker   // Inform dependents of updated encoder settings.
1297*d9f75844SAndroid Build Coastguard Worker   OnEncoderSettingsChanged();
1298*d9f75844SAndroid Build Coastguard Worker 
1299*d9f75844SAndroid Build Coastguard Worker   if (encoder_initialized_) {
1300*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_VERBOSE) << " max bitrate " << codec.maxBitrate
1301*d9f75844SAndroid Build Coastguard Worker                         << " start bitrate " << codec.startBitrate
1302*d9f75844SAndroid Build Coastguard Worker                         << " max frame rate " << codec.maxFramerate
1303*d9f75844SAndroid Build Coastguard Worker                         << " max payload size " << max_data_payload_length_;
1304*d9f75844SAndroid Build Coastguard Worker   } else {
1305*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to configure encoder.";
1306*d9f75844SAndroid Build Coastguard Worker     rate_allocator_ = nullptr;
1307*d9f75844SAndroid Build Coastguard Worker   }
1308*d9f75844SAndroid Build Coastguard Worker 
1309*d9f75844SAndroid Build Coastguard Worker   if (pending_encoder_creation_) {
1310*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.ConfigureEncodeUsageResource();
1311*d9f75844SAndroid Build Coastguard Worker     pending_encoder_creation_ = false;
1312*d9f75844SAndroid Build Coastguard Worker   }
1313*d9f75844SAndroid Build Coastguard Worker 
1314*d9f75844SAndroid Build Coastguard Worker   int num_layers;
1315*d9f75844SAndroid Build Coastguard Worker   if (codec.codecType == kVideoCodecVP8) {
1316*d9f75844SAndroid Build Coastguard Worker     num_layers = codec.VP8()->numberOfTemporalLayers;
1317*d9f75844SAndroid Build Coastguard Worker   } else if (codec.codecType == kVideoCodecVP9) {
1318*d9f75844SAndroid Build Coastguard Worker     num_layers = codec.VP9()->numberOfTemporalLayers;
1319*d9f75844SAndroid Build Coastguard Worker   } else if (codec.codecType == kVideoCodecH264) {
1320*d9f75844SAndroid Build Coastguard Worker     num_layers = codec.H264()->numberOfTemporalLayers;
1321*d9f75844SAndroid Build Coastguard Worker   } else if (codec.codecType == kVideoCodecGeneric &&
1322*d9f75844SAndroid Build Coastguard Worker              codec.numberOfSimulcastStreams > 0) {
1323*d9f75844SAndroid Build Coastguard Worker     // This is mainly for unit testing, disabling frame dropping.
1324*d9f75844SAndroid Build Coastguard Worker     // TODO(sprang): Add a better way to disable frame dropping.
1325*d9f75844SAndroid Build Coastguard Worker     num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
1326*d9f75844SAndroid Build Coastguard Worker   } else {
1327*d9f75844SAndroid Build Coastguard Worker     num_layers = 1;
1328*d9f75844SAndroid Build Coastguard Worker   }
1329*d9f75844SAndroid Build Coastguard Worker 
1330*d9f75844SAndroid Build Coastguard Worker   frame_dropper_.Reset();
1331*d9f75844SAndroid Build Coastguard Worker   frame_dropper_.SetRates(codec.startBitrate, max_framerate_);
1332*d9f75844SAndroid Build Coastguard Worker   // Force-disable frame dropper if either:
1333*d9f75844SAndroid Build Coastguard Worker   //  * We have screensharing with layers.
1334*d9f75844SAndroid Build Coastguard Worker   //  * "WebRTC-FrameDropper" field trial is "Disabled".
1335*d9f75844SAndroid Build Coastguard Worker   force_disable_frame_dropper_ =
1336*d9f75844SAndroid Build Coastguard Worker       field_trials_.IsDisabled(kFrameDropperFieldTrial) ||
1337*d9f75844SAndroid Build Coastguard Worker       (num_layers > 1 && codec.mode == VideoCodecMode::kScreensharing);
1338*d9f75844SAndroid Build Coastguard Worker 
1339*d9f75844SAndroid Build Coastguard Worker   VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
1340*d9f75844SAndroid Build Coastguard Worker   if (rate_control_settings_.UseEncoderBitrateAdjuster()) {
1341*d9f75844SAndroid Build Coastguard Worker     bitrate_adjuster_ = std::make_unique<EncoderBitrateAdjuster>(codec);
1342*d9f75844SAndroid Build Coastguard Worker     bitrate_adjuster_->OnEncoderInfo(info);
1343*d9f75844SAndroid Build Coastguard Worker   }
1344*d9f75844SAndroid Build Coastguard Worker 
1345*d9f75844SAndroid Build Coastguard Worker   if (rate_allocator_ && last_encoder_rate_settings_) {
1346*d9f75844SAndroid Build Coastguard Worker     // We have a new rate allocator instance and already configured target
1347*d9f75844SAndroid Build Coastguard Worker     // bitrate. Update the rate allocation and notify observers.
1348*d9f75844SAndroid Build Coastguard Worker     // We must invalidate the last_encoder_rate_settings_ to ensure
1349*d9f75844SAndroid Build Coastguard Worker     // the changes get propagated to all listeners.
1350*d9f75844SAndroid Build Coastguard Worker     EncoderRateSettings rate_settings = *last_encoder_rate_settings_;
1351*d9f75844SAndroid Build Coastguard Worker     last_encoder_rate_settings_.reset();
1352*d9f75844SAndroid Build Coastguard Worker     rate_settings.rate_control.framerate_fps = GetInputFramerateFps();
1353*d9f75844SAndroid Build Coastguard Worker 
1354*d9f75844SAndroid Build Coastguard Worker     SetEncoderRates(UpdateBitrateAllocation(rate_settings));
1355*d9f75844SAndroid Build Coastguard Worker   }
1356*d9f75844SAndroid Build Coastguard Worker 
1357*d9f75844SAndroid Build Coastguard Worker   encoder_stats_observer_->OnEncoderReconfigured(encoder_config_, streams);
1358*d9f75844SAndroid Build Coastguard Worker 
1359*d9f75844SAndroid Build Coastguard Worker   pending_encoder_reconfiguration_ = false;
1360*d9f75844SAndroid Build Coastguard Worker 
1361*d9f75844SAndroid Build Coastguard Worker   bool is_svc = false;
1362*d9f75844SAndroid Build Coastguard Worker   // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9
1363*d9f75844SAndroid Build Coastguard Worker   // and leave only one stream containing all necessary information.
1364*d9f75844SAndroid Build Coastguard Worker   if (encoder_config_.codec_type == kVideoCodecVP9) {
1365*d9f75844SAndroid Build Coastguard Worker     // Lower max bitrate to the level codec actually can produce.
1366*d9f75844SAndroid Build Coastguard Worker     streams[0].max_bitrate_bps =
1367*d9f75844SAndroid Build Coastguard Worker         std::min(streams[0].max_bitrate_bps,
1368*d9f75844SAndroid Build Coastguard Worker                  SvcRateAllocator::GetMaxBitrate(codec).bps<int>());
1369*d9f75844SAndroid Build Coastguard Worker     streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
1370*d9f75844SAndroid Build Coastguard Worker     // target_bitrate_bps specifies the maximum padding bitrate.
1371*d9f75844SAndroid Build Coastguard Worker     streams[0].target_bitrate_bps =
1372*d9f75844SAndroid Build Coastguard Worker         SvcRateAllocator::GetPaddingBitrate(codec).bps<int>();
1373*d9f75844SAndroid Build Coastguard Worker     streams[0].width = streams.back().width;
1374*d9f75844SAndroid Build Coastguard Worker     streams[0].height = streams.back().height;
1375*d9f75844SAndroid Build Coastguard Worker     is_svc = codec.VP9()->numberOfSpatialLayers > 1;
1376*d9f75844SAndroid Build Coastguard Worker     streams.resize(1);
1377*d9f75844SAndroid Build Coastguard Worker   }
1378*d9f75844SAndroid Build Coastguard Worker 
1379*d9f75844SAndroid Build Coastguard Worker   sink_->OnEncoderConfigurationChanged(
1380*d9f75844SAndroid Build Coastguard Worker       std::move(streams), is_svc, encoder_config_.content_type,
1381*d9f75844SAndroid Build Coastguard Worker       encoder_config_.min_transmit_bitrate_bps);
1382*d9f75844SAndroid Build Coastguard Worker 
1383*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.ConfigureQualityScaler(info);
1384*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.ConfigureBandwidthQualityScaler(info);
1385*d9f75844SAndroid Build Coastguard Worker 
1386*d9f75844SAndroid Build Coastguard Worker   webrtc::RTCError encoder_configuration_result = webrtc::RTCError::OK();
1387*d9f75844SAndroid Build Coastguard Worker 
1388*d9f75844SAndroid Build Coastguard Worker   if (!encoder_initialized_) {
1389*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to initialize "
1390*d9f75844SAndroid Build Coastguard Worker                         << CodecTypeToPayloadString(codec.codecType)
1391*d9f75844SAndroid Build Coastguard Worker                         << " encoder."
1392*d9f75844SAndroid Build Coastguard Worker                         << "switch_encoder_on_init_failures: "
1393*d9f75844SAndroid Build Coastguard Worker                         << switch_encoder_on_init_failures_;
1394*d9f75844SAndroid Build Coastguard Worker 
1395*d9f75844SAndroid Build Coastguard Worker     if (switch_encoder_on_init_failures_) {
1396*d9f75844SAndroid Build Coastguard Worker       RequestEncoderSwitch();
1397*d9f75844SAndroid Build Coastguard Worker     } else {
1398*d9f75844SAndroid Build Coastguard Worker       encoder_configuration_result =
1399*d9f75844SAndroid Build Coastguard Worker           webrtc::RTCError(RTCErrorType::UNSUPPORTED_OPERATION);
1400*d9f75844SAndroid Build Coastguard Worker     }
1401*d9f75844SAndroid Build Coastguard Worker   }
1402*d9f75844SAndroid Build Coastguard Worker 
1403*d9f75844SAndroid Build Coastguard Worker   if (!encoder_configuration_callbacks_.empty()) {
1404*d9f75844SAndroid Build Coastguard Worker     for (auto& callback : encoder_configuration_callbacks_) {
1405*d9f75844SAndroid Build Coastguard Worker       webrtc::InvokeSetParametersCallback(callback,
1406*d9f75844SAndroid Build Coastguard Worker                                           encoder_configuration_result);
1407*d9f75844SAndroid Build Coastguard Worker     }
1408*d9f75844SAndroid Build Coastguard Worker     encoder_configuration_callbacks_.clear();
1409*d9f75844SAndroid Build Coastguard Worker   }
1410*d9f75844SAndroid Build Coastguard Worker }
1411*d9f75844SAndroid Build Coastguard Worker 
RequestEncoderSwitch()1412*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::RequestEncoderSwitch() {
1413*d9f75844SAndroid Build Coastguard Worker   bool is_encoder_switching_supported =
1414*d9f75844SAndroid Build Coastguard Worker       settings_.encoder_switch_request_callback != nullptr;
1415*d9f75844SAndroid Build Coastguard Worker   bool is_encoder_selector_available = encoder_selector_ != nullptr;
1416*d9f75844SAndroid Build Coastguard Worker 
1417*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "RequestEncoderSwitch."
1418*d9f75844SAndroid Build Coastguard Worker                    << " is_encoder_selector_available: "
1419*d9f75844SAndroid Build Coastguard Worker                    << is_encoder_selector_available
1420*d9f75844SAndroid Build Coastguard Worker                    << " is_encoder_switching_supported: "
1421*d9f75844SAndroid Build Coastguard Worker                    << is_encoder_switching_supported;
1422*d9f75844SAndroid Build Coastguard Worker 
1423*d9f75844SAndroid Build Coastguard Worker   if (!is_encoder_switching_supported) {
1424*d9f75844SAndroid Build Coastguard Worker     return;
1425*d9f75844SAndroid Build Coastguard Worker   }
1426*d9f75844SAndroid Build Coastguard Worker 
1427*d9f75844SAndroid Build Coastguard Worker   // If encoder selector is available, switch to the encoder it prefers.
1428*d9f75844SAndroid Build Coastguard Worker   // Otherwise try switching to VP8 (default WebRTC codec).
1429*d9f75844SAndroid Build Coastguard Worker   absl::optional<SdpVideoFormat> preferred_fallback_encoder;
1430*d9f75844SAndroid Build Coastguard Worker   if (is_encoder_selector_available) {
1431*d9f75844SAndroid Build Coastguard Worker     preferred_fallback_encoder = encoder_selector_->OnEncoderBroken();
1432*d9f75844SAndroid Build Coastguard Worker   }
1433*d9f75844SAndroid Build Coastguard Worker 
1434*d9f75844SAndroid Build Coastguard Worker   if (!preferred_fallback_encoder) {
1435*d9f75844SAndroid Build Coastguard Worker     preferred_fallback_encoder =
1436*d9f75844SAndroid Build Coastguard Worker         SdpVideoFormat(CodecTypeToPayloadString(kVideoCodecVP8));
1437*d9f75844SAndroid Build Coastguard Worker   }
1438*d9f75844SAndroid Build Coastguard Worker 
1439*d9f75844SAndroid Build Coastguard Worker   settings_.encoder_switch_request_callback->RequestEncoderSwitch(
1440*d9f75844SAndroid Build Coastguard Worker       *preferred_fallback_encoder, /*allow_default_fallback=*/true);
1441*d9f75844SAndroid Build Coastguard Worker }
1442*d9f75844SAndroid Build Coastguard Worker 
OnEncoderSettingsChanged()1443*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnEncoderSettingsChanged() {
1444*d9f75844SAndroid Build Coastguard Worker   EncoderSettings encoder_settings(
1445*d9f75844SAndroid Build Coastguard Worker       GetEncoderInfoWithBitrateLimitUpdate(
1446*d9f75844SAndroid Build Coastguard Worker           encoder_->GetEncoderInfo(), encoder_config_, default_limits_allowed_),
1447*d9f75844SAndroid Build Coastguard Worker       encoder_config_.Copy(), send_codec_);
1448*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.SetEncoderSettings(encoder_settings);
1449*d9f75844SAndroid Build Coastguard Worker   input_state_provider_.OnEncoderSettingsChanged(encoder_settings);
1450*d9f75844SAndroid Build Coastguard Worker   bool is_screenshare = encoder_settings.encoder_config().content_type ==
1451*d9f75844SAndroid Build Coastguard Worker                         VideoEncoderConfig::ContentType::kScreen;
1452*d9f75844SAndroid Build Coastguard Worker   degradation_preference_manager_->SetIsScreenshare(is_screenshare);
1453*d9f75844SAndroid Build Coastguard Worker   if (is_screenshare) {
1454*d9f75844SAndroid Build Coastguard Worker     frame_cadence_adapter_->SetZeroHertzModeEnabled(
1455*d9f75844SAndroid Build Coastguard Worker         FrameCadenceAdapterInterface::ZeroHertzModeParams{
1456*d9f75844SAndroid Build Coastguard Worker             send_codec_.numberOfSimulcastStreams});
1457*d9f75844SAndroid Build Coastguard Worker   }
1458*d9f75844SAndroid Build Coastguard Worker }
1459*d9f75844SAndroid Build Coastguard Worker 
OnFrame(Timestamp post_time,int frames_scheduled_for_processing,const VideoFrame & video_frame)1460*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnFrame(Timestamp post_time,
1461*d9f75844SAndroid Build Coastguard Worker                                  int frames_scheduled_for_processing,
1462*d9f75844SAndroid Build Coastguard Worker                                  const VideoFrame& video_frame) {
1463*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1464*d9f75844SAndroid Build Coastguard Worker   VideoFrame incoming_frame = video_frame;
1465*d9f75844SAndroid Build Coastguard Worker 
1466*d9f75844SAndroid Build Coastguard Worker   // In some cases, e.g., when the frame from decoder is fed to encoder,
1467*d9f75844SAndroid Build Coastguard Worker   // the timestamp may be set to the future. As the encoding pipeline assumes
1468*d9f75844SAndroid Build Coastguard Worker   // capture time to be less than present time, we should reset the capture
1469*d9f75844SAndroid Build Coastguard Worker   // timestamps here. Otherwise there may be issues with RTP send stream.
1470*d9f75844SAndroid Build Coastguard Worker   if (incoming_frame.timestamp_us() > post_time.us())
1471*d9f75844SAndroid Build Coastguard Worker     incoming_frame.set_timestamp_us(post_time.us());
1472*d9f75844SAndroid Build Coastguard Worker 
1473*d9f75844SAndroid Build Coastguard Worker   // Capture time may come from clock with an offset and drift from clock_.
1474*d9f75844SAndroid Build Coastguard Worker   int64_t capture_ntp_time_ms;
1475*d9f75844SAndroid Build Coastguard Worker   if (video_frame.ntp_time_ms() > 0) {
1476*d9f75844SAndroid Build Coastguard Worker     capture_ntp_time_ms = video_frame.ntp_time_ms();
1477*d9f75844SAndroid Build Coastguard Worker   } else if (video_frame.render_time_ms() != 0) {
1478*d9f75844SAndroid Build Coastguard Worker     capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
1479*d9f75844SAndroid Build Coastguard Worker   } else {
1480*d9f75844SAndroid Build Coastguard Worker     capture_ntp_time_ms = post_time.ms() + delta_ntp_internal_ms_;
1481*d9f75844SAndroid Build Coastguard Worker   }
1482*d9f75844SAndroid Build Coastguard Worker   incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
1483*d9f75844SAndroid Build Coastguard Worker 
1484*d9f75844SAndroid Build Coastguard Worker   // Convert NTP time, in ms, to RTP timestamp.
1485*d9f75844SAndroid Build Coastguard Worker   const int kMsToRtpTimestamp = 90;
1486*d9f75844SAndroid Build Coastguard Worker   incoming_frame.set_timestamp(
1487*d9f75844SAndroid Build Coastguard Worker       kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
1488*d9f75844SAndroid Build Coastguard Worker 
1489*d9f75844SAndroid Build Coastguard Worker   if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
1490*d9f75844SAndroid Build Coastguard Worker     // We don't allow the same capture time for two frames, drop this one.
1491*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Same/old NTP timestamp ("
1492*d9f75844SAndroid Build Coastguard Worker                         << incoming_frame.ntp_time_ms()
1493*d9f75844SAndroid Build Coastguard Worker                         << " <= " << last_captured_timestamp_
1494*d9f75844SAndroid Build Coastguard Worker                         << ") for incoming frame. Dropping.";
1495*d9f75844SAndroid Build Coastguard Worker     encoder_queue_.PostTask([this, incoming_frame]() {
1496*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(&encoder_queue_);
1497*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_.Union(incoming_frame.update_rect());
1498*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_is_valid_ &= incoming_frame.has_update_rect();
1499*d9f75844SAndroid Build Coastguard Worker     });
1500*d9f75844SAndroid Build Coastguard Worker     return;
1501*d9f75844SAndroid Build Coastguard Worker   }
1502*d9f75844SAndroid Build Coastguard Worker 
1503*d9f75844SAndroid Build Coastguard Worker   bool log_stats = false;
1504*d9f75844SAndroid Build Coastguard Worker   if (post_time.ms() - last_frame_log_ms_ > kFrameLogIntervalMs) {
1505*d9f75844SAndroid Build Coastguard Worker     last_frame_log_ms_ = post_time.ms();
1506*d9f75844SAndroid Build Coastguard Worker     log_stats = true;
1507*d9f75844SAndroid Build Coastguard Worker   }
1508*d9f75844SAndroid Build Coastguard Worker 
1509*d9f75844SAndroid Build Coastguard Worker   last_captured_timestamp_ = incoming_frame.ntp_time_ms();
1510*d9f75844SAndroid Build Coastguard Worker 
1511*d9f75844SAndroid Build Coastguard Worker   encoder_stats_observer_->OnIncomingFrame(incoming_frame.width(),
1512*d9f75844SAndroid Build Coastguard Worker                                            incoming_frame.height());
1513*d9f75844SAndroid Build Coastguard Worker   ++captured_frame_count_;
1514*d9f75844SAndroid Build Coastguard Worker   CheckForAnimatedContent(incoming_frame, post_time.us());
1515*d9f75844SAndroid Build Coastguard Worker   bool cwnd_frame_drop =
1516*d9f75844SAndroid Build Coastguard Worker       cwnd_frame_drop_interval_ &&
1517*d9f75844SAndroid Build Coastguard Worker       (cwnd_frame_counter_++ % cwnd_frame_drop_interval_.value() == 0);
1518*d9f75844SAndroid Build Coastguard Worker   if (frames_scheduled_for_processing == 1 && !cwnd_frame_drop) {
1519*d9f75844SAndroid Build Coastguard Worker     MaybeEncodeVideoFrame(incoming_frame, post_time.us());
1520*d9f75844SAndroid Build Coastguard Worker   } else {
1521*d9f75844SAndroid Build Coastguard Worker     if (cwnd_frame_drop) {
1522*d9f75844SAndroid Build Coastguard Worker       // Frame drop by congestion window pushback. Do not encode this
1523*d9f75844SAndroid Build Coastguard Worker       // frame.
1524*d9f75844SAndroid Build Coastguard Worker       ++dropped_frame_cwnd_pushback_count_;
1525*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
1526*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kCongestionWindow);
1527*d9f75844SAndroid Build Coastguard Worker     } else {
1528*d9f75844SAndroid Build Coastguard Worker       // There is a newer frame in flight. Do not encode this frame.
1529*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_VERBOSE)
1530*d9f75844SAndroid Build Coastguard Worker           << "Incoming frame dropped due to that the encoder is blocked.";
1531*d9f75844SAndroid Build Coastguard Worker       ++dropped_frame_encoder_block_count_;
1532*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
1533*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1534*d9f75844SAndroid Build Coastguard Worker     }
1535*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.Union(incoming_frame.update_rect());
1536*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_is_valid_ &= incoming_frame.has_update_rect();
1537*d9f75844SAndroid Build Coastguard Worker   }
1538*d9f75844SAndroid Build Coastguard Worker   if (log_stats) {
1539*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Number of frames: captured " << captured_frame_count_
1540*d9f75844SAndroid Build Coastguard Worker                      << ", dropped (due to congestion window pushback) "
1541*d9f75844SAndroid Build Coastguard Worker                      << dropped_frame_cwnd_pushback_count_
1542*d9f75844SAndroid Build Coastguard Worker                      << ", dropped (due to encoder blocked) "
1543*d9f75844SAndroid Build Coastguard Worker                      << dropped_frame_encoder_block_count_ << ", interval_ms "
1544*d9f75844SAndroid Build Coastguard Worker                      << kFrameLogIntervalMs;
1545*d9f75844SAndroid Build Coastguard Worker     captured_frame_count_ = 0;
1546*d9f75844SAndroid Build Coastguard Worker     dropped_frame_cwnd_pushback_count_ = 0;
1547*d9f75844SAndroid Build Coastguard Worker     dropped_frame_encoder_block_count_ = 0;
1548*d9f75844SAndroid Build Coastguard Worker   }
1549*d9f75844SAndroid Build Coastguard Worker }
1550*d9f75844SAndroid Build Coastguard Worker 
OnDiscardedFrame()1551*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnDiscardedFrame() {
1552*d9f75844SAndroid Build Coastguard Worker   encoder_stats_observer_->OnFrameDropped(
1553*d9f75844SAndroid Build Coastguard Worker       VideoStreamEncoderObserver::DropReason::kSource);
1554*d9f75844SAndroid Build Coastguard Worker }
1555*d9f75844SAndroid Build Coastguard Worker 
EncoderPaused() const1556*d9f75844SAndroid Build Coastguard Worker bool VideoStreamEncoder::EncoderPaused() const {
1557*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1558*d9f75844SAndroid Build Coastguard Worker   // Pause video if paused by caller or as long as the network is down or the
1559*d9f75844SAndroid Build Coastguard Worker   // pacer queue has grown too large in buffered mode.
1560*d9f75844SAndroid Build Coastguard Worker   // If the pacer queue has grown too large or the network is down,
1561*d9f75844SAndroid Build Coastguard Worker   // `last_encoder_rate_settings_->encoder_target` will be 0.
1562*d9f75844SAndroid Build Coastguard Worker   return !last_encoder_rate_settings_ ||
1563*d9f75844SAndroid Build Coastguard Worker          last_encoder_rate_settings_->encoder_target == DataRate::Zero();
1564*d9f75844SAndroid Build Coastguard Worker }
1565*d9f75844SAndroid Build Coastguard Worker 
TraceFrameDropStart()1566*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::TraceFrameDropStart() {
1567*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1568*d9f75844SAndroid Build Coastguard Worker   // Start trace event only on the first frame after encoder is paused.
1569*d9f75844SAndroid Build Coastguard Worker   if (!encoder_paused_and_dropped_frame_) {
1570*d9f75844SAndroid Build Coastguard Worker     TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
1571*d9f75844SAndroid Build Coastguard Worker   }
1572*d9f75844SAndroid Build Coastguard Worker   encoder_paused_and_dropped_frame_ = true;
1573*d9f75844SAndroid Build Coastguard Worker }
1574*d9f75844SAndroid Build Coastguard Worker 
TraceFrameDropEnd()1575*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::TraceFrameDropEnd() {
1576*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1577*d9f75844SAndroid Build Coastguard Worker   // End trace event on first frame after encoder resumes, if frame was dropped.
1578*d9f75844SAndroid Build Coastguard Worker   if (encoder_paused_and_dropped_frame_) {
1579*d9f75844SAndroid Build Coastguard Worker     TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
1580*d9f75844SAndroid Build Coastguard Worker   }
1581*d9f75844SAndroid Build Coastguard Worker   encoder_paused_and_dropped_frame_ = false;
1582*d9f75844SAndroid Build Coastguard Worker }
1583*d9f75844SAndroid Build Coastguard Worker 
1584*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::EncoderRateSettings
UpdateBitrateAllocation(const EncoderRateSettings & rate_settings)1585*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::UpdateBitrateAllocation(
1586*d9f75844SAndroid Build Coastguard Worker     const EncoderRateSettings& rate_settings) {
1587*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation new_allocation;
1588*d9f75844SAndroid Build Coastguard Worker   // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
1589*d9f75844SAndroid Build Coastguard Worker   // might cap the bitrate to the min bitrate configured.
1590*d9f75844SAndroid Build Coastguard Worker   if (rate_allocator_ && rate_settings.encoder_target > DataRate::Zero()) {
1591*d9f75844SAndroid Build Coastguard Worker     new_allocation = rate_allocator_->Allocate(VideoBitrateAllocationParameters(
1592*d9f75844SAndroid Build Coastguard Worker         rate_settings.encoder_target, rate_settings.stable_encoder_target,
1593*d9f75844SAndroid Build Coastguard Worker         rate_settings.rate_control.framerate_fps));
1594*d9f75844SAndroid Build Coastguard Worker   }
1595*d9f75844SAndroid Build Coastguard Worker 
1596*d9f75844SAndroid Build Coastguard Worker   EncoderRateSettings new_rate_settings = rate_settings;
1597*d9f75844SAndroid Build Coastguard Worker   new_rate_settings.rate_control.target_bitrate = new_allocation;
1598*d9f75844SAndroid Build Coastguard Worker   new_rate_settings.rate_control.bitrate = new_allocation;
1599*d9f75844SAndroid Build Coastguard Worker   // VideoBitrateAllocator subclasses may allocate a bitrate higher than the
1600*d9f75844SAndroid Build Coastguard Worker   // target in order to sustain the min bitrate of the video codec. In this
1601*d9f75844SAndroid Build Coastguard Worker   // case, make sure the bandwidth allocation is at least equal the allocation
1602*d9f75844SAndroid Build Coastguard Worker   // as that is part of the document contract for that field.
1603*d9f75844SAndroid Build Coastguard Worker   new_rate_settings.rate_control.bandwidth_allocation =
1604*d9f75844SAndroid Build Coastguard Worker       std::max(new_rate_settings.rate_control.bandwidth_allocation,
1605*d9f75844SAndroid Build Coastguard Worker                DataRate::BitsPerSec(
1606*d9f75844SAndroid Build Coastguard Worker                    new_rate_settings.rate_control.bitrate.get_sum_bps()));
1607*d9f75844SAndroid Build Coastguard Worker 
1608*d9f75844SAndroid Build Coastguard Worker   if (bitrate_adjuster_) {
1609*d9f75844SAndroid Build Coastguard Worker     VideoBitrateAllocation adjusted_allocation =
1610*d9f75844SAndroid Build Coastguard Worker         bitrate_adjuster_->AdjustRateAllocation(new_rate_settings.rate_control);
1611*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_VERBOSE) << "Adjusting allocation, fps = "
1612*d9f75844SAndroid Build Coastguard Worker                         << rate_settings.rate_control.framerate_fps << ", from "
1613*d9f75844SAndroid Build Coastguard Worker                         << new_allocation.ToString() << ", to "
1614*d9f75844SAndroid Build Coastguard Worker                         << adjusted_allocation.ToString();
1615*d9f75844SAndroid Build Coastguard Worker     new_rate_settings.rate_control.bitrate = adjusted_allocation;
1616*d9f75844SAndroid Build Coastguard Worker   }
1617*d9f75844SAndroid Build Coastguard Worker 
1618*d9f75844SAndroid Build Coastguard Worker   return new_rate_settings;
1619*d9f75844SAndroid Build Coastguard Worker }
1620*d9f75844SAndroid Build Coastguard Worker 
GetInputFramerateFps()1621*d9f75844SAndroid Build Coastguard Worker uint32_t VideoStreamEncoder::GetInputFramerateFps() {
1622*d9f75844SAndroid Build Coastguard Worker   const uint32_t default_fps = max_framerate_ != -1 ? max_framerate_ : 30;
1623*d9f75844SAndroid Build Coastguard Worker 
1624*d9f75844SAndroid Build Coastguard Worker   // This method may be called after we cleared out the frame_cadence_adapter_
1625*d9f75844SAndroid Build Coastguard Worker   // reference in Stop(). In such a situation it's probably not important with a
1626*d9f75844SAndroid Build Coastguard Worker   // decent estimate.
1627*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> input_fps =
1628*d9f75844SAndroid Build Coastguard Worker       frame_cadence_adapter_ ? frame_cadence_adapter_->GetInputFrameRateFps()
1629*d9f75844SAndroid Build Coastguard Worker                              : absl::nullopt;
1630*d9f75844SAndroid Build Coastguard Worker   if (!input_fps || *input_fps == 0) {
1631*d9f75844SAndroid Build Coastguard Worker     return default_fps;
1632*d9f75844SAndroid Build Coastguard Worker   }
1633*d9f75844SAndroid Build Coastguard Worker   return *input_fps;
1634*d9f75844SAndroid Build Coastguard Worker }
1635*d9f75844SAndroid Build Coastguard Worker 
SetEncoderRates(const EncoderRateSettings & rate_settings)1636*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SetEncoderRates(
1637*d9f75844SAndroid Build Coastguard Worker     const EncoderRateSettings& rate_settings) {
1638*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(rate_settings.rate_control.framerate_fps, 0.0);
1639*d9f75844SAndroid Build Coastguard Worker   bool rate_control_changed =
1640*d9f75844SAndroid Build Coastguard Worker       (!last_encoder_rate_settings_.has_value() ||
1641*d9f75844SAndroid Build Coastguard Worker        last_encoder_rate_settings_->rate_control != rate_settings.rate_control);
1642*d9f75844SAndroid Build Coastguard Worker   // For layer allocation signal we care only about the target bitrate (not the
1643*d9f75844SAndroid Build Coastguard Worker   // adjusted one) and the target fps.
1644*d9f75844SAndroid Build Coastguard Worker   bool layer_allocation_changed =
1645*d9f75844SAndroid Build Coastguard Worker       !last_encoder_rate_settings_.has_value() ||
1646*d9f75844SAndroid Build Coastguard Worker       last_encoder_rate_settings_->rate_control.target_bitrate !=
1647*d9f75844SAndroid Build Coastguard Worker           rate_settings.rate_control.target_bitrate ||
1648*d9f75844SAndroid Build Coastguard Worker       last_encoder_rate_settings_->rate_control.framerate_fps !=
1649*d9f75844SAndroid Build Coastguard Worker           rate_settings.rate_control.framerate_fps;
1650*d9f75844SAndroid Build Coastguard Worker 
1651*d9f75844SAndroid Build Coastguard Worker   if (last_encoder_rate_settings_ != rate_settings) {
1652*d9f75844SAndroid Build Coastguard Worker     last_encoder_rate_settings_ = rate_settings;
1653*d9f75844SAndroid Build Coastguard Worker   }
1654*d9f75844SAndroid Build Coastguard Worker 
1655*d9f75844SAndroid Build Coastguard Worker   if (!encoder_)
1656*d9f75844SAndroid Build Coastguard Worker     return;
1657*d9f75844SAndroid Build Coastguard Worker 
1658*d9f75844SAndroid Build Coastguard Worker   // Make the cadence adapter know if streams were disabled.
1659*d9f75844SAndroid Build Coastguard Worker   for (int spatial_index = 0;
1660*d9f75844SAndroid Build Coastguard Worker        spatial_index != send_codec_.numberOfSimulcastStreams; ++spatial_index) {
1661*d9f75844SAndroid Build Coastguard Worker     frame_cadence_adapter_->UpdateLayerStatus(
1662*d9f75844SAndroid Build Coastguard Worker         spatial_index,
1663*d9f75844SAndroid Build Coastguard Worker         /*enabled=*/rate_settings.rate_control.target_bitrate
1664*d9f75844SAndroid Build Coastguard Worker                 .GetSpatialLayerSum(spatial_index) > 0);
1665*d9f75844SAndroid Build Coastguard Worker   }
1666*d9f75844SAndroid Build Coastguard Worker 
1667*d9f75844SAndroid Build Coastguard Worker   // `bitrate_allocation` is 0 it means that the network is down or the send
1668*d9f75844SAndroid Build Coastguard Worker   // pacer is full. We currently don't pass this on to the encoder since it is
1669*d9f75844SAndroid Build Coastguard Worker   // unclear how current encoder implementations behave when given a zero target
1670*d9f75844SAndroid Build Coastguard Worker   // bitrate.
1671*d9f75844SAndroid Build Coastguard Worker   // TODO(perkj): Make sure all known encoder implementations handle zero
1672*d9f75844SAndroid Build Coastguard Worker   // target bitrate and remove this check.
1673*d9f75844SAndroid Build Coastguard Worker   if (rate_settings.rate_control.bitrate.get_sum_bps() == 0)
1674*d9f75844SAndroid Build Coastguard Worker     return;
1675*d9f75844SAndroid Build Coastguard Worker 
1676*d9f75844SAndroid Build Coastguard Worker   if (rate_control_changed) {
1677*d9f75844SAndroid Build Coastguard Worker     encoder_->SetRates(rate_settings.rate_control);
1678*d9f75844SAndroid Build Coastguard Worker 
1679*d9f75844SAndroid Build Coastguard Worker     encoder_stats_observer_->OnBitrateAllocationUpdated(
1680*d9f75844SAndroid Build Coastguard Worker         send_codec_, rate_settings.rate_control.bitrate);
1681*d9f75844SAndroid Build Coastguard Worker     frame_encode_metadata_writer_.OnSetRates(
1682*d9f75844SAndroid Build Coastguard Worker         rate_settings.rate_control.bitrate,
1683*d9f75844SAndroid Build Coastguard Worker         static_cast<uint32_t>(rate_settings.rate_control.framerate_fps + 0.5));
1684*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.SetEncoderRates(rate_settings.rate_control);
1685*d9f75844SAndroid Build Coastguard Worker     if (layer_allocation_changed &&
1686*d9f75844SAndroid Build Coastguard Worker         allocation_cb_type_ ==
1687*d9f75844SAndroid Build Coastguard Worker             BitrateAllocationCallbackType::kVideoLayersAllocation) {
1688*d9f75844SAndroid Build Coastguard Worker       sink_->OnVideoLayersAllocationUpdated(CreateVideoLayersAllocation(
1689*d9f75844SAndroid Build Coastguard Worker           send_codec_, rate_settings.rate_control, encoder_->GetEncoderInfo()));
1690*d9f75844SAndroid Build Coastguard Worker     }
1691*d9f75844SAndroid Build Coastguard Worker   }
1692*d9f75844SAndroid Build Coastguard Worker   if ((allocation_cb_type_ ==
1693*d9f75844SAndroid Build Coastguard Worker        BitrateAllocationCallbackType::kVideoBitrateAllocation) ||
1694*d9f75844SAndroid Build Coastguard Worker       (encoder_config_.content_type ==
1695*d9f75844SAndroid Build Coastguard Worker            VideoEncoderConfig::ContentType::kScreen &&
1696*d9f75844SAndroid Build Coastguard Worker        allocation_cb_type_ == BitrateAllocationCallbackType::
1697*d9f75844SAndroid Build Coastguard Worker                                   kVideoBitrateAllocationWhenScreenSharing)) {
1698*d9f75844SAndroid Build Coastguard Worker     sink_->OnBitrateAllocationUpdated(
1699*d9f75844SAndroid Build Coastguard Worker         // Update allocation according to info from encoder. An encoder may
1700*d9f75844SAndroid Build Coastguard Worker         // choose to not use all layers due to for example HW.
1701*d9f75844SAndroid Build Coastguard Worker         UpdateAllocationFromEncoderInfo(
1702*d9f75844SAndroid Build Coastguard Worker             rate_settings.rate_control.target_bitrate,
1703*d9f75844SAndroid Build Coastguard Worker             encoder_->GetEncoderInfo()));
1704*d9f75844SAndroid Build Coastguard Worker   }
1705*d9f75844SAndroid Build Coastguard Worker }
1706*d9f75844SAndroid Build Coastguard Worker 
MaybeEncodeVideoFrame(const VideoFrame & video_frame,int64_t time_when_posted_us)1707*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::MaybeEncodeVideoFrame(const VideoFrame& video_frame,
1708*d9f75844SAndroid Build Coastguard Worker                                                int64_t time_when_posted_us) {
1709*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1710*d9f75844SAndroid Build Coastguard Worker   input_state_provider_.OnFrameSizeObserved(video_frame.size());
1711*d9f75844SAndroid Build Coastguard Worker 
1712*d9f75844SAndroid Build Coastguard Worker   if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
1713*d9f75844SAndroid Build Coastguard Worker       video_frame.height() != last_frame_info_->height ||
1714*d9f75844SAndroid Build Coastguard Worker       video_frame.is_texture() != last_frame_info_->is_texture) {
1715*d9f75844SAndroid Build Coastguard Worker     if ((!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
1716*d9f75844SAndroid Build Coastguard Worker          video_frame.height() != last_frame_info_->height) &&
1717*d9f75844SAndroid Build Coastguard Worker         settings_.encoder_switch_request_callback && encoder_selector_) {
1718*d9f75844SAndroid Build Coastguard Worker       if (auto encoder = encoder_selector_->OnResolutionChange(
1719*d9f75844SAndroid Build Coastguard Worker               {video_frame.width(), video_frame.height()})) {
1720*d9f75844SAndroid Build Coastguard Worker         settings_.encoder_switch_request_callback->RequestEncoderSwitch(
1721*d9f75844SAndroid Build Coastguard Worker             *encoder, /*allow_default_fallback=*/false);
1722*d9f75844SAndroid Build Coastguard Worker       }
1723*d9f75844SAndroid Build Coastguard Worker     }
1724*d9f75844SAndroid Build Coastguard Worker 
1725*d9f75844SAndroid Build Coastguard Worker     pending_encoder_reconfiguration_ = true;
1726*d9f75844SAndroid Build Coastguard Worker     last_frame_info_ = VideoFrameInfo(video_frame.width(), video_frame.height(),
1727*d9f75844SAndroid Build Coastguard Worker                                       video_frame.is_texture());
1728*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Video frame parameters changed: dimensions="
1729*d9f75844SAndroid Build Coastguard Worker                      << last_frame_info_->width << "x"
1730*d9f75844SAndroid Build Coastguard Worker                      << last_frame_info_->height
1731*d9f75844SAndroid Build Coastguard Worker                      << ", texture=" << last_frame_info_->is_texture << ".";
1732*d9f75844SAndroid Build Coastguard Worker     // Force full frame update, since resolution has changed.
1733*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_ =
1734*d9f75844SAndroid Build Coastguard Worker         VideoFrame::UpdateRect{0, 0, video_frame.width(), video_frame.height()};
1735*d9f75844SAndroid Build Coastguard Worker   }
1736*d9f75844SAndroid Build Coastguard Worker 
1737*d9f75844SAndroid Build Coastguard Worker   // We have to create the encoder before the frame drop logic,
1738*d9f75844SAndroid Build Coastguard Worker   // because the latter depends on encoder_->GetScalingSettings.
1739*d9f75844SAndroid Build Coastguard Worker   // According to the testcase
1740*d9f75844SAndroid Build Coastguard Worker   // InitialFrameDropOffWhenEncoderDisabledScaling, the return value
1741*d9f75844SAndroid Build Coastguard Worker   // from GetScalingSettings should enable or disable the frame drop.
1742*d9f75844SAndroid Build Coastguard Worker 
1743*d9f75844SAndroid Build Coastguard Worker   // Update input frame rate before we start using it. If we update it after
1744*d9f75844SAndroid Build Coastguard Worker   // any potential frame drop we are going to artificially increase frame sizes.
1745*d9f75844SAndroid Build Coastguard Worker   // Poll the rate before updating, otherwise we risk the rate being estimated
1746*d9f75844SAndroid Build Coastguard Worker   // a little too high at the start of the call when then window is small.
1747*d9f75844SAndroid Build Coastguard Worker   uint32_t framerate_fps = GetInputFramerateFps();
1748*d9f75844SAndroid Build Coastguard Worker   frame_cadence_adapter_->UpdateFrameRate();
1749*d9f75844SAndroid Build Coastguard Worker 
1750*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = clock_->TimeInMilliseconds();
1751*d9f75844SAndroid Build Coastguard Worker   if (pending_encoder_reconfiguration_) {
1752*d9f75844SAndroid Build Coastguard Worker     ReconfigureEncoder();
1753*d9f75844SAndroid Build Coastguard Worker     last_parameters_update_ms_.emplace(now_ms);
1754*d9f75844SAndroid Build Coastguard Worker   } else if (!last_parameters_update_ms_ ||
1755*d9f75844SAndroid Build Coastguard Worker              now_ms - *last_parameters_update_ms_ >=
1756*d9f75844SAndroid Build Coastguard Worker                  kParameterUpdateIntervalMs) {
1757*d9f75844SAndroid Build Coastguard Worker     if (last_encoder_rate_settings_) {
1758*d9f75844SAndroid Build Coastguard Worker       // Clone rate settings before update, so that SetEncoderRates() will
1759*d9f75844SAndroid Build Coastguard Worker       // actually detect the change between the input and
1760*d9f75844SAndroid Build Coastguard Worker       // `last_encoder_rate_setings_`, triggering the call to SetRate() on the
1761*d9f75844SAndroid Build Coastguard Worker       // encoder.
1762*d9f75844SAndroid Build Coastguard Worker       EncoderRateSettings new_rate_settings = *last_encoder_rate_settings_;
1763*d9f75844SAndroid Build Coastguard Worker       new_rate_settings.rate_control.framerate_fps =
1764*d9f75844SAndroid Build Coastguard Worker           static_cast<double>(framerate_fps);
1765*d9f75844SAndroid Build Coastguard Worker       SetEncoderRates(UpdateBitrateAllocation(new_rate_settings));
1766*d9f75844SAndroid Build Coastguard Worker     }
1767*d9f75844SAndroid Build Coastguard Worker     last_parameters_update_ms_.emplace(now_ms);
1768*d9f75844SAndroid Build Coastguard Worker   }
1769*d9f75844SAndroid Build Coastguard Worker 
1770*d9f75844SAndroid Build Coastguard Worker   // Because pending frame will be dropped in any case, we need to
1771*d9f75844SAndroid Build Coastguard Worker   // remember its updated region.
1772*d9f75844SAndroid Build Coastguard Worker   if (pending_frame_) {
1773*d9f75844SAndroid Build Coastguard Worker     encoder_stats_observer_->OnFrameDropped(
1774*d9f75844SAndroid Build Coastguard Worker         VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1775*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.Union(pending_frame_->update_rect());
1776*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_is_valid_ &= pending_frame_->has_update_rect();
1777*d9f75844SAndroid Build Coastguard Worker   }
1778*d9f75844SAndroid Build Coastguard Worker 
1779*d9f75844SAndroid Build Coastguard Worker   if (DropDueToSize(video_frame.size())) {
1780*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
1781*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.OnFrameDroppedDueToSize();
1782*d9f75844SAndroid Build Coastguard Worker     // Storing references to a native buffer risks blocking frame capture.
1783*d9f75844SAndroid Build Coastguard Worker     if (video_frame.video_frame_buffer()->type() !=
1784*d9f75844SAndroid Build Coastguard Worker         VideoFrameBuffer::Type::kNative) {
1785*d9f75844SAndroid Build Coastguard Worker       pending_frame_ = video_frame;
1786*d9f75844SAndroid Build Coastguard Worker       pending_frame_post_time_us_ = time_when_posted_us;
1787*d9f75844SAndroid Build Coastguard Worker     } else {
1788*d9f75844SAndroid Build Coastguard Worker       // Ensure that any previously stored frame is dropped.
1789*d9f75844SAndroid Build Coastguard Worker       pending_frame_.reset();
1790*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_.Union(video_frame.update_rect());
1791*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_is_valid_ &= video_frame.has_update_rect();
1792*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
1793*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1794*d9f75844SAndroid Build Coastguard Worker     }
1795*d9f75844SAndroid Build Coastguard Worker     return;
1796*d9f75844SAndroid Build Coastguard Worker   }
1797*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.OnMaybeEncodeFrame();
1798*d9f75844SAndroid Build Coastguard Worker 
1799*d9f75844SAndroid Build Coastguard Worker   if (EncoderPaused()) {
1800*d9f75844SAndroid Build Coastguard Worker     // Storing references to a native buffer risks blocking frame capture.
1801*d9f75844SAndroid Build Coastguard Worker     if (video_frame.video_frame_buffer()->type() !=
1802*d9f75844SAndroid Build Coastguard Worker         VideoFrameBuffer::Type::kNative) {
1803*d9f75844SAndroid Build Coastguard Worker       if (pending_frame_)
1804*d9f75844SAndroid Build Coastguard Worker         TraceFrameDropStart();
1805*d9f75844SAndroid Build Coastguard Worker       pending_frame_ = video_frame;
1806*d9f75844SAndroid Build Coastguard Worker       pending_frame_post_time_us_ = time_when_posted_us;
1807*d9f75844SAndroid Build Coastguard Worker     } else {
1808*d9f75844SAndroid Build Coastguard Worker       // Ensure that any previously stored frame is dropped.
1809*d9f75844SAndroid Build Coastguard Worker       pending_frame_.reset();
1810*d9f75844SAndroid Build Coastguard Worker       TraceFrameDropStart();
1811*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_.Union(video_frame.update_rect());
1812*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_is_valid_ &= video_frame.has_update_rect();
1813*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
1814*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1815*d9f75844SAndroid Build Coastguard Worker     }
1816*d9f75844SAndroid Build Coastguard Worker     return;
1817*d9f75844SAndroid Build Coastguard Worker   }
1818*d9f75844SAndroid Build Coastguard Worker 
1819*d9f75844SAndroid Build Coastguard Worker   pending_frame_.reset();
1820*d9f75844SAndroid Build Coastguard Worker 
1821*d9f75844SAndroid Build Coastguard Worker   frame_dropper_.Leak(framerate_fps);
1822*d9f75844SAndroid Build Coastguard Worker   // Frame dropping is enabled iff frame dropping is not force-disabled, and
1823*d9f75844SAndroid Build Coastguard Worker   // rate controller is not trusted.
1824*d9f75844SAndroid Build Coastguard Worker   const bool frame_dropping_enabled =
1825*d9f75844SAndroid Build Coastguard Worker       !force_disable_frame_dropper_ &&
1826*d9f75844SAndroid Build Coastguard Worker       !encoder_info_.has_trusted_rate_controller;
1827*d9f75844SAndroid Build Coastguard Worker   frame_dropper_.Enable(frame_dropping_enabled);
1828*d9f75844SAndroid Build Coastguard Worker   if (frame_dropping_enabled && frame_dropper_.DropFrame()) {
1829*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_VERBOSE)
1830*d9f75844SAndroid Build Coastguard Worker         << "Drop Frame: "
1831*d9f75844SAndroid Build Coastguard Worker            "target bitrate "
1832*d9f75844SAndroid Build Coastguard Worker         << (last_encoder_rate_settings_
1833*d9f75844SAndroid Build Coastguard Worker                 ? last_encoder_rate_settings_->encoder_target.bps()
1834*d9f75844SAndroid Build Coastguard Worker                 : 0)
1835*d9f75844SAndroid Build Coastguard Worker         << ", input frame rate " << framerate_fps;
1836*d9f75844SAndroid Build Coastguard Worker     OnDroppedFrame(
1837*d9f75844SAndroid Build Coastguard Worker         EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
1838*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.Union(video_frame.update_rect());
1839*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_is_valid_ &= video_frame.has_update_rect();
1840*d9f75844SAndroid Build Coastguard Worker     return;
1841*d9f75844SAndroid Build Coastguard Worker   }
1842*d9f75844SAndroid Build Coastguard Worker 
1843*d9f75844SAndroid Build Coastguard Worker   EncodeVideoFrame(video_frame, time_when_posted_us);
1844*d9f75844SAndroid Build Coastguard Worker }
1845*d9f75844SAndroid Build Coastguard Worker 
EncodeVideoFrame(const VideoFrame & video_frame,int64_t time_when_posted_us)1846*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
1847*d9f75844SAndroid Build Coastguard Worker                                           int64_t time_when_posted_us) {
1848*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
1849*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_VERBOSE) << __func__ << " posted " << time_when_posted_us
1850*d9f75844SAndroid Build Coastguard Worker                       << " ntp time " << video_frame.ntp_time_ms();
1851*d9f75844SAndroid Build Coastguard Worker 
1852*d9f75844SAndroid Build Coastguard Worker   // If the encoder fail we can't continue to encode frames. When this happens
1853*d9f75844SAndroid Build Coastguard Worker   // the WebrtcVideoSender is notified and the whole VideoSendStream is
1854*d9f75844SAndroid Build Coastguard Worker   // recreated.
1855*d9f75844SAndroid Build Coastguard Worker   if (encoder_failed_ || !encoder_initialized_)
1856*d9f75844SAndroid Build Coastguard Worker     return;
1857*d9f75844SAndroid Build Coastguard Worker 
1858*d9f75844SAndroid Build Coastguard Worker   // It's possible that EncodeVideoFrame can be called after we've completed
1859*d9f75844SAndroid Build Coastguard Worker   // a Stop() operation. Check if the encoder_ is set before continuing.
1860*d9f75844SAndroid Build Coastguard Worker   // See: bugs.webrtc.org/12857
1861*d9f75844SAndroid Build Coastguard Worker   if (!encoder_)
1862*d9f75844SAndroid Build Coastguard Worker     return;
1863*d9f75844SAndroid Build Coastguard Worker 
1864*d9f75844SAndroid Build Coastguard Worker   TraceFrameDropEnd();
1865*d9f75844SAndroid Build Coastguard Worker 
1866*d9f75844SAndroid Build Coastguard Worker   // Encoder metadata needs to be updated before encode complete callback.
1867*d9f75844SAndroid Build Coastguard Worker   VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
1868*d9f75844SAndroid Build Coastguard Worker   if (info.implementation_name != encoder_info_.implementation_name ||
1869*d9f75844SAndroid Build Coastguard Worker       info.is_hardware_accelerated != encoder_info_.is_hardware_accelerated) {
1870*d9f75844SAndroid Build Coastguard Worker     encoder_stats_observer_->OnEncoderImplementationChanged({
1871*d9f75844SAndroid Build Coastguard Worker         .name = info.implementation_name,
1872*d9f75844SAndroid Build Coastguard Worker         .is_hardware_accelerated = info.is_hardware_accelerated,
1873*d9f75844SAndroid Build Coastguard Worker     });
1874*d9f75844SAndroid Build Coastguard Worker     if (bitrate_adjuster_) {
1875*d9f75844SAndroid Build Coastguard Worker       // Encoder implementation changed, reset overshoot detector states.
1876*d9f75844SAndroid Build Coastguard Worker       bitrate_adjuster_->Reset();
1877*d9f75844SAndroid Build Coastguard Worker     }
1878*d9f75844SAndroid Build Coastguard Worker   }
1879*d9f75844SAndroid Build Coastguard Worker 
1880*d9f75844SAndroid Build Coastguard Worker   if (encoder_info_ != info) {
1881*d9f75844SAndroid Build Coastguard Worker     OnEncoderSettingsChanged();
1882*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.ConfigureEncodeUsageResource();
1883*d9f75844SAndroid Build Coastguard Worker     // Re-configure scalers when encoder info changed. Consider two cases:
1884*d9f75844SAndroid Build Coastguard Worker     // 1. When the status of the scaler changes from enabled to disabled, if we
1885*d9f75844SAndroid Build Coastguard Worker     // don't do this CL, scaler will adapt up/down to trigger an unnecessary
1886*d9f75844SAndroid Build Coastguard Worker     // full ReconfigureEncoder() when the scaler should be banned.
1887*d9f75844SAndroid Build Coastguard Worker     // 2. When the status of the scaler changes from disabled to enabled, if we
1888*d9f75844SAndroid Build Coastguard Worker     // don't do this CL, scaler will not work until some code trigger
1889*d9f75844SAndroid Build Coastguard Worker     // ReconfigureEncoder(). In extreme cases, the scaler doesn't even work for
1890*d9f75844SAndroid Build Coastguard Worker     // a long time when we expect that the scaler should work.
1891*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.ConfigureQualityScaler(info);
1892*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.ConfigureBandwidthQualityScaler(info);
1893*d9f75844SAndroid Build Coastguard Worker 
1894*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Encoder info changed to " << info.ToString();
1895*d9f75844SAndroid Build Coastguard Worker   }
1896*d9f75844SAndroid Build Coastguard Worker 
1897*d9f75844SAndroid Build Coastguard Worker   if (bitrate_adjuster_) {
1898*d9f75844SAndroid Build Coastguard Worker     for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
1899*d9f75844SAndroid Build Coastguard Worker       if (info.fps_allocation[si] != encoder_info_.fps_allocation[si]) {
1900*d9f75844SAndroid Build Coastguard Worker         bitrate_adjuster_->OnEncoderInfo(info);
1901*d9f75844SAndroid Build Coastguard Worker         break;
1902*d9f75844SAndroid Build Coastguard Worker       }
1903*d9f75844SAndroid Build Coastguard Worker     }
1904*d9f75844SAndroid Build Coastguard Worker   }
1905*d9f75844SAndroid Build Coastguard Worker   encoder_info_ = info;
1906*d9f75844SAndroid Build Coastguard Worker   last_encode_info_ms_ = clock_->TimeInMilliseconds();
1907*d9f75844SAndroid Build Coastguard Worker 
1908*d9f75844SAndroid Build Coastguard Worker   VideoFrame out_frame(video_frame);
1909*d9f75844SAndroid Build Coastguard Worker   // Crop or scale the frame if needed. Dimension may be reduced to fit encoder
1910*d9f75844SAndroid Build Coastguard Worker   // requirements, e.g. some encoders may require them to be divisible by 4.
1911*d9f75844SAndroid Build Coastguard Worker   if ((crop_width_ > 0 || crop_height_ > 0) &&
1912*d9f75844SAndroid Build Coastguard Worker       (out_frame.video_frame_buffer()->type() !=
1913*d9f75844SAndroid Build Coastguard Worker            VideoFrameBuffer::Type::kNative ||
1914*d9f75844SAndroid Build Coastguard Worker        !info.supports_native_handle)) {
1915*d9f75844SAndroid Build Coastguard Worker     int cropped_width = video_frame.width() - crop_width_;
1916*d9f75844SAndroid Build Coastguard Worker     int cropped_height = video_frame.height() - crop_height_;
1917*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<VideoFrameBuffer> cropped_buffer;
1918*d9f75844SAndroid Build Coastguard Worker     // TODO(ilnik): Remove scaling if cropping is too big, as it should never
1919*d9f75844SAndroid Build Coastguard Worker     // happen after SinkWants signaled correctly from ReconfigureEncoder.
1920*d9f75844SAndroid Build Coastguard Worker     VideoFrame::UpdateRect update_rect = video_frame.update_rect();
1921*d9f75844SAndroid Build Coastguard Worker     if (crop_width_ < 4 && crop_height_ < 4) {
1922*d9f75844SAndroid Build Coastguard Worker       // The difference is small, crop without scaling.
1923*d9f75844SAndroid Build Coastguard Worker       cropped_buffer = video_frame.video_frame_buffer()->CropAndScale(
1924*d9f75844SAndroid Build Coastguard Worker           crop_width_ / 2, crop_height_ / 2, cropped_width, cropped_height,
1925*d9f75844SAndroid Build Coastguard Worker           cropped_width, cropped_height);
1926*d9f75844SAndroid Build Coastguard Worker       update_rect.offset_x -= crop_width_ / 2;
1927*d9f75844SAndroid Build Coastguard Worker       update_rect.offset_y -= crop_height_ / 2;
1928*d9f75844SAndroid Build Coastguard Worker       update_rect.Intersect(
1929*d9f75844SAndroid Build Coastguard Worker           VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height});
1930*d9f75844SAndroid Build Coastguard Worker 
1931*d9f75844SAndroid Build Coastguard Worker     } else {
1932*d9f75844SAndroid Build Coastguard Worker       // The difference is large, scale it.
1933*d9f75844SAndroid Build Coastguard Worker       cropped_buffer = video_frame.video_frame_buffer()->Scale(cropped_width,
1934*d9f75844SAndroid Build Coastguard Worker                                                                cropped_height);
1935*d9f75844SAndroid Build Coastguard Worker       if (!update_rect.IsEmpty()) {
1936*d9f75844SAndroid Build Coastguard Worker         // Since we can't reason about pixels after scaling, we invalidate whole
1937*d9f75844SAndroid Build Coastguard Worker         // picture, if anything changed.
1938*d9f75844SAndroid Build Coastguard Worker         update_rect =
1939*d9f75844SAndroid Build Coastguard Worker             VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height};
1940*d9f75844SAndroid Build Coastguard Worker       }
1941*d9f75844SAndroid Build Coastguard Worker     }
1942*d9f75844SAndroid Build Coastguard Worker     if (!cropped_buffer) {
1943*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Cropping and scaling frame failed, dropping frame.";
1944*d9f75844SAndroid Build Coastguard Worker       return;
1945*d9f75844SAndroid Build Coastguard Worker     }
1946*d9f75844SAndroid Build Coastguard Worker 
1947*d9f75844SAndroid Build Coastguard Worker     out_frame.set_video_frame_buffer(cropped_buffer);
1948*d9f75844SAndroid Build Coastguard Worker     out_frame.set_update_rect(update_rect);
1949*d9f75844SAndroid Build Coastguard Worker     out_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
1950*d9f75844SAndroid Build Coastguard Worker     // Since accumulated_update_rect_ is constructed before cropping,
1951*d9f75844SAndroid Build Coastguard Worker     // we can't trust it. If any changes were pending, we invalidate whole
1952*d9f75844SAndroid Build Coastguard Worker     // frame here.
1953*d9f75844SAndroid Build Coastguard Worker     if (!accumulated_update_rect_.IsEmpty()) {
1954*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_ =
1955*d9f75844SAndroid Build Coastguard Worker           VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()};
1956*d9f75844SAndroid Build Coastguard Worker       accumulated_update_rect_is_valid_ = false;
1957*d9f75844SAndroid Build Coastguard Worker     }
1958*d9f75844SAndroid Build Coastguard Worker   }
1959*d9f75844SAndroid Build Coastguard Worker 
1960*d9f75844SAndroid Build Coastguard Worker   if (!accumulated_update_rect_is_valid_) {
1961*d9f75844SAndroid Build Coastguard Worker     out_frame.clear_update_rect();
1962*d9f75844SAndroid Build Coastguard Worker   } else if (!accumulated_update_rect_.IsEmpty() &&
1963*d9f75844SAndroid Build Coastguard Worker              out_frame.has_update_rect()) {
1964*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.Union(out_frame.update_rect());
1965*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.Intersect(
1966*d9f75844SAndroid Build Coastguard Worker         VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()});
1967*d9f75844SAndroid Build Coastguard Worker     out_frame.set_update_rect(accumulated_update_rect_);
1968*d9f75844SAndroid Build Coastguard Worker     accumulated_update_rect_.MakeEmptyUpdate();
1969*d9f75844SAndroid Build Coastguard Worker   }
1970*d9f75844SAndroid Build Coastguard Worker   accumulated_update_rect_is_valid_ = true;
1971*d9f75844SAndroid Build Coastguard Worker 
1972*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
1973*d9f75844SAndroid Build Coastguard Worker                           "Encode");
1974*d9f75844SAndroid Build Coastguard Worker 
1975*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.OnEncodeStarted(out_frame, time_when_posted_us);
1976*d9f75844SAndroid Build Coastguard Worker 
1977*d9f75844SAndroid Build Coastguard Worker   // The encoder should get the size that it expects.
1978*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(send_codec_.width <= out_frame.width() &&
1979*d9f75844SAndroid Build Coastguard Worker              send_codec_.height <= out_frame.height())
1980*d9f75844SAndroid Build Coastguard Worker       << "Encoder configured to " << send_codec_.width << "x"
1981*d9f75844SAndroid Build Coastguard Worker       << send_codec_.height << " received a too small frame "
1982*d9f75844SAndroid Build Coastguard Worker       << out_frame.width() << "x" << out_frame.height();
1983*d9f75844SAndroid Build Coastguard Worker 
1984*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp",
1985*d9f75844SAndroid Build Coastguard Worker                out_frame.timestamp());
1986*d9f75844SAndroid Build Coastguard Worker 
1987*d9f75844SAndroid Build Coastguard Worker   frame_encode_metadata_writer_.OnEncodeStarted(out_frame);
1988*d9f75844SAndroid Build Coastguard Worker 
1989*d9f75844SAndroid Build Coastguard Worker   const int32_t encode_status = encoder_->Encode(out_frame, &next_frame_types_);
1990*d9f75844SAndroid Build Coastguard Worker   was_encode_called_since_last_initialization_ = true;
1991*d9f75844SAndroid Build Coastguard Worker 
1992*d9f75844SAndroid Build Coastguard Worker   if (encode_status < 0) {
1993*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Encoder failed, failing encoder format: "
1994*d9f75844SAndroid Build Coastguard Worker                       << encoder_config_.video_format.ToString();
1995*d9f75844SAndroid Build Coastguard Worker     RequestEncoderSwitch();
1996*d9f75844SAndroid Build Coastguard Worker     return;
1997*d9f75844SAndroid Build Coastguard Worker   }
1998*d9f75844SAndroid Build Coastguard Worker 
1999*d9f75844SAndroid Build Coastguard Worker   for (auto& it : next_frame_types_) {
2000*d9f75844SAndroid Build Coastguard Worker     it = VideoFrameType::kVideoFrameDelta;
2001*d9f75844SAndroid Build Coastguard Worker   }
2002*d9f75844SAndroid Build Coastguard Worker }
2003*d9f75844SAndroid Build Coastguard Worker 
RequestRefreshFrame()2004*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::RequestRefreshFrame() {
2005*d9f75844SAndroid Build Coastguard Worker   worker_queue_->PostTask(SafeTask(task_safety_.flag(), [this] {
2006*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(worker_queue_);
2007*d9f75844SAndroid Build Coastguard Worker     video_source_sink_controller_.RequestRefreshFrame();
2008*d9f75844SAndroid Build Coastguard Worker   }));
2009*d9f75844SAndroid Build Coastguard Worker }
2010*d9f75844SAndroid Build Coastguard Worker 
SendKeyFrame(const std::vector<VideoFrameType> & layers)2011*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::SendKeyFrame(
2012*d9f75844SAndroid Build Coastguard Worker     const std::vector<VideoFrameType>& layers) {
2013*d9f75844SAndroid Build Coastguard Worker   if (!encoder_queue_.IsCurrent()) {
2014*d9f75844SAndroid Build Coastguard Worker     encoder_queue_.PostTask([this, layers] { SendKeyFrame(layers); });
2015*d9f75844SAndroid Build Coastguard Worker     return;
2016*d9f75844SAndroid Build Coastguard Worker   }
2017*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2018*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
2019*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!next_frame_types_.empty());
2020*d9f75844SAndroid Build Coastguard Worker 
2021*d9f75844SAndroid Build Coastguard Worker   if (frame_cadence_adapter_)
2022*d9f75844SAndroid Build Coastguard Worker     frame_cadence_adapter_->ProcessKeyFrameRequest();
2023*d9f75844SAndroid Build Coastguard Worker 
2024*d9f75844SAndroid Build Coastguard Worker   if (!encoder_) {
2025*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_INFO) << __func__ << " no encoder.";
2026*d9f75844SAndroid Build Coastguard Worker     return;  // Shutting down, or not configured yet.
2027*d9f75844SAndroid Build Coastguard Worker   }
2028*d9f75844SAndroid Build Coastguard Worker 
2029*d9f75844SAndroid Build Coastguard Worker   if (!layers.empty()) {
2030*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(layers.size(), next_frame_types_.size());
2031*d9f75844SAndroid Build Coastguard Worker     for (size_t i = 0; i < layers.size() && i < next_frame_types_.size(); i++) {
2032*d9f75844SAndroid Build Coastguard Worker       next_frame_types_[i] = layers[i];
2033*d9f75844SAndroid Build Coastguard Worker     }
2034*d9f75844SAndroid Build Coastguard Worker   } else {
2035*d9f75844SAndroid Build Coastguard Worker     std::fill(next_frame_types_.begin(), next_frame_types_.end(),
2036*d9f75844SAndroid Build Coastguard Worker               VideoFrameType::kVideoFrameKey);
2037*d9f75844SAndroid Build Coastguard Worker   }
2038*d9f75844SAndroid Build Coastguard Worker }
2039*d9f75844SAndroid Build Coastguard Worker 
OnLossNotification(const VideoEncoder::LossNotification & loss_notification)2040*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnLossNotification(
2041*d9f75844SAndroid Build Coastguard Worker     const VideoEncoder::LossNotification& loss_notification) {
2042*d9f75844SAndroid Build Coastguard Worker   if (!encoder_queue_.IsCurrent()) {
2043*d9f75844SAndroid Build Coastguard Worker     encoder_queue_.PostTask(
2044*d9f75844SAndroid Build Coastguard Worker         [this, loss_notification] { OnLossNotification(loss_notification); });
2045*d9f75844SAndroid Build Coastguard Worker     return;
2046*d9f75844SAndroid Build Coastguard Worker   }
2047*d9f75844SAndroid Build Coastguard Worker 
2048*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2049*d9f75844SAndroid Build Coastguard Worker   if (encoder_) {
2050*d9f75844SAndroid Build Coastguard Worker     encoder_->OnLossNotification(loss_notification);
2051*d9f75844SAndroid Build Coastguard Worker   }
2052*d9f75844SAndroid Build Coastguard Worker }
2053*d9f75844SAndroid Build Coastguard Worker 
AugmentEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)2054*d9f75844SAndroid Build Coastguard Worker EncodedImage VideoStreamEncoder::AugmentEncodedImage(
2055*d9f75844SAndroid Build Coastguard Worker     const EncodedImage& encoded_image,
2056*d9f75844SAndroid Build Coastguard Worker     const CodecSpecificInfo* codec_specific_info) {
2057*d9f75844SAndroid Build Coastguard Worker   EncodedImage image_copy(encoded_image);
2058*d9f75844SAndroid Build Coastguard Worker   const size_t spatial_idx = encoded_image.SpatialIndex().value_or(0);
2059*d9f75844SAndroid Build Coastguard Worker   frame_encode_metadata_writer_.FillTimingInfo(spatial_idx, &image_copy);
2060*d9f75844SAndroid Build Coastguard Worker   frame_encode_metadata_writer_.UpdateBitstream(codec_specific_info,
2061*d9f75844SAndroid Build Coastguard Worker                                                 &image_copy);
2062*d9f75844SAndroid Build Coastguard Worker   VideoCodecType codec_type = codec_specific_info
2063*d9f75844SAndroid Build Coastguard Worker                                   ? codec_specific_info->codecType
2064*d9f75844SAndroid Build Coastguard Worker                                   : VideoCodecType::kVideoCodecGeneric;
2065*d9f75844SAndroid Build Coastguard Worker   if (image_copy.qp_ < 0 && qp_parsing_allowed_) {
2066*d9f75844SAndroid Build Coastguard Worker     // Parse encoded frame QP if that was not provided by encoder.
2067*d9f75844SAndroid Build Coastguard Worker     image_copy.qp_ = qp_parser_
2068*d9f75844SAndroid Build Coastguard Worker                          .Parse(codec_type, spatial_idx, image_copy.data(),
2069*d9f75844SAndroid Build Coastguard Worker                                 image_copy.size())
2070*d9f75844SAndroid Build Coastguard Worker                          .value_or(-1);
2071*d9f75844SAndroid Build Coastguard Worker   }
2072*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_VERBOSE) << __func__ << " spatial_idx " << spatial_idx << " qp "
2073*d9f75844SAndroid Build Coastguard Worker                       << image_copy.qp_;
2074*d9f75844SAndroid Build Coastguard Worker   image_copy.SetAtTargetQuality(codec_type == kVideoCodecVP8 &&
2075*d9f75844SAndroid Build Coastguard Worker                                 image_copy.qp_ <= kVp8SteadyStateQpThreshold);
2076*d9f75844SAndroid Build Coastguard Worker 
2077*d9f75844SAndroid Build Coastguard Worker   // Piggyback ALR experiment group id and simulcast id into the content type.
2078*d9f75844SAndroid Build Coastguard Worker   const uint8_t experiment_id =
2079*d9f75844SAndroid Build Coastguard Worker       experiment_groups_[videocontenttypehelpers::IsScreenshare(
2080*d9f75844SAndroid Build Coastguard Worker           image_copy.content_type_)];
2081*d9f75844SAndroid Build Coastguard Worker 
2082*d9f75844SAndroid Build Coastguard Worker   // TODO(ilnik): This will force content type extension to be present even
2083*d9f75844SAndroid Build Coastguard Worker   // for realtime video. At the expense of miniscule overhead we will get
2084*d9f75844SAndroid Build Coastguard Worker   // sliced receive statistics.
2085*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(videocontenttypehelpers::SetExperimentId(&image_copy.content_type_,
2086*d9f75844SAndroid Build Coastguard Worker                                                      experiment_id));
2087*d9f75844SAndroid Build Coastguard Worker   // We count simulcast streams from 1 on the wire. That's why we set simulcast
2088*d9f75844SAndroid Build Coastguard Worker   // id in content type to +1 of that is actual simulcast index. This is because
2089*d9f75844SAndroid Build Coastguard Worker   // value 0 on the wire is reserved for 'no simulcast stream specified'.
2090*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(videocontenttypehelpers::SetSimulcastId(
2091*d9f75844SAndroid Build Coastguard Worker       &image_copy.content_type_, static_cast<uint8_t>(spatial_idx + 1)));
2092*d9f75844SAndroid Build Coastguard Worker 
2093*d9f75844SAndroid Build Coastguard Worker   return image_copy;
2094*d9f75844SAndroid Build Coastguard Worker }
2095*d9f75844SAndroid Build Coastguard Worker 
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)2096*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
2097*d9f75844SAndroid Build Coastguard Worker     const EncodedImage& encoded_image,
2098*d9f75844SAndroid Build Coastguard Worker     const CodecSpecificInfo* codec_specific_info) {
2099*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded",
2100*d9f75844SAndroid Build Coastguard Worker                        "timestamp", encoded_image.Timestamp());
2101*d9f75844SAndroid Build Coastguard Worker 
2102*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/10520): Signal the simulcast id explicitly.
2103*d9f75844SAndroid Build Coastguard Worker 
2104*d9f75844SAndroid Build Coastguard Worker   const size_t spatial_idx = encoded_image.SpatialIndex().value_or(0);
2105*d9f75844SAndroid Build Coastguard Worker   const VideoCodecType codec_type = codec_specific_info
2106*d9f75844SAndroid Build Coastguard Worker                                         ? codec_specific_info->codecType
2107*d9f75844SAndroid Build Coastguard Worker                                         : VideoCodecType::kVideoCodecGeneric;
2108*d9f75844SAndroid Build Coastguard Worker   EncodedImage image_copy =
2109*d9f75844SAndroid Build Coastguard Worker       AugmentEncodedImage(encoded_image, codec_specific_info);
2110*d9f75844SAndroid Build Coastguard Worker 
2111*d9f75844SAndroid Build Coastguard Worker   // Post a task because `send_codec_` requires `encoder_queue_` lock and we
2112*d9f75844SAndroid Build Coastguard Worker   // need to update on quality convergence.
2113*d9f75844SAndroid Build Coastguard Worker   unsigned int image_width = image_copy._encodedWidth;
2114*d9f75844SAndroid Build Coastguard Worker   unsigned int image_height = image_copy._encodedHeight;
2115*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, codec_type, image_width, image_height,
2116*d9f75844SAndroid Build Coastguard Worker                            spatial_idx,
2117*d9f75844SAndroid Build Coastguard Worker                            at_target_quality = image_copy.IsAtTargetQuality()] {
2118*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2119*d9f75844SAndroid Build Coastguard Worker 
2120*d9f75844SAndroid Build Coastguard Worker     // Let the frame cadence adapter know about quality convergence.
2121*d9f75844SAndroid Build Coastguard Worker     if (frame_cadence_adapter_)
2122*d9f75844SAndroid Build Coastguard Worker       frame_cadence_adapter_->UpdateLayerQualityConvergence(spatial_idx,
2123*d9f75844SAndroid Build Coastguard Worker                                                             at_target_quality);
2124*d9f75844SAndroid Build Coastguard Worker 
2125*d9f75844SAndroid Build Coastguard Worker     // Currently, the internal quality scaler is used for VP9 instead of the
2126*d9f75844SAndroid Build Coastguard Worker     // webrtc qp scaler (in the no-svc case or if only a single spatial layer is
2127*d9f75844SAndroid Build Coastguard Worker     // encoded). It has to be explicitly detected and reported to adaptation
2128*d9f75844SAndroid Build Coastguard Worker     // metrics.
2129*d9f75844SAndroid Build Coastguard Worker     if (codec_type == VideoCodecType::kVideoCodecVP9 &&
2130*d9f75844SAndroid Build Coastguard Worker         send_codec_.VP9()->automaticResizeOn) {
2131*d9f75844SAndroid Build Coastguard Worker       unsigned int expected_width = send_codec_.width;
2132*d9f75844SAndroid Build Coastguard Worker       unsigned int expected_height = send_codec_.height;
2133*d9f75844SAndroid Build Coastguard Worker       int num_active_layers = 0;
2134*d9f75844SAndroid Build Coastguard Worker       for (int i = 0; i < send_codec_.VP9()->numberOfSpatialLayers; ++i) {
2135*d9f75844SAndroid Build Coastguard Worker         if (send_codec_.spatialLayers[i].active) {
2136*d9f75844SAndroid Build Coastguard Worker           ++num_active_layers;
2137*d9f75844SAndroid Build Coastguard Worker           expected_width = send_codec_.spatialLayers[i].width;
2138*d9f75844SAndroid Build Coastguard Worker           expected_height = send_codec_.spatialLayers[i].height;
2139*d9f75844SAndroid Build Coastguard Worker         }
2140*d9f75844SAndroid Build Coastguard Worker       }
2141*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_LE(num_active_layers, 1)
2142*d9f75844SAndroid Build Coastguard Worker           << "VP9 quality scaling is enabled for "
2143*d9f75844SAndroid Build Coastguard Worker              "SVC with several active layers.";
2144*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnEncoderInternalScalerUpdate(
2145*d9f75844SAndroid Build Coastguard Worker           image_width < expected_width || image_height < expected_height);
2146*d9f75844SAndroid Build Coastguard Worker     }
2147*d9f75844SAndroid Build Coastguard Worker   });
2148*d9f75844SAndroid Build Coastguard Worker 
2149*d9f75844SAndroid Build Coastguard Worker   // Encoded is called on whatever thread the real encoder implementation run
2150*d9f75844SAndroid Build Coastguard Worker   // on. In the case of hardware encoders, there might be several encoders
2151*d9f75844SAndroid Build Coastguard Worker   // running in parallel on different threads.
2152*d9f75844SAndroid Build Coastguard Worker   encoder_stats_observer_->OnSendEncodedImage(image_copy, codec_specific_info);
2153*d9f75844SAndroid Build Coastguard Worker 
2154*d9f75844SAndroid Build Coastguard Worker   EncodedImageCallback::Result result =
2155*d9f75844SAndroid Build Coastguard Worker       sink_->OnEncodedImage(image_copy, codec_specific_info);
2156*d9f75844SAndroid Build Coastguard Worker 
2157*d9f75844SAndroid Build Coastguard Worker   // We are only interested in propagating the meta-data about the image, not
2158*d9f75844SAndroid Build Coastguard Worker   // encoded data itself, to the post encode function. Since we cannot be sure
2159*d9f75844SAndroid Build Coastguard Worker   // the pointer will still be valid when run on the task queue, set it to null.
2160*d9f75844SAndroid Build Coastguard Worker   DataSize frame_size = DataSize::Bytes(image_copy.size());
2161*d9f75844SAndroid Build Coastguard Worker   image_copy.ClearEncodedData();
2162*d9f75844SAndroid Build Coastguard Worker 
2163*d9f75844SAndroid Build Coastguard Worker   int temporal_index = 0;
2164*d9f75844SAndroid Build Coastguard Worker   if (codec_specific_info) {
2165*d9f75844SAndroid Build Coastguard Worker     if (codec_specific_info->codecType == kVideoCodecVP9) {
2166*d9f75844SAndroid Build Coastguard Worker       temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx;
2167*d9f75844SAndroid Build Coastguard Worker     } else if (codec_specific_info->codecType == kVideoCodecVP8) {
2168*d9f75844SAndroid Build Coastguard Worker       temporal_index = codec_specific_info->codecSpecific.VP8.temporalIdx;
2169*d9f75844SAndroid Build Coastguard Worker     }
2170*d9f75844SAndroid Build Coastguard Worker   }
2171*d9f75844SAndroid Build Coastguard Worker   if (temporal_index == kNoTemporalIdx) {
2172*d9f75844SAndroid Build Coastguard Worker     temporal_index = 0;
2173*d9f75844SAndroid Build Coastguard Worker   }
2174*d9f75844SAndroid Build Coastguard Worker 
2175*d9f75844SAndroid Build Coastguard Worker   RunPostEncode(image_copy, clock_->CurrentTime().us(), temporal_index,
2176*d9f75844SAndroid Build Coastguard Worker                 frame_size);
2177*d9f75844SAndroid Build Coastguard Worker 
2178*d9f75844SAndroid Build Coastguard Worker   if (result.error == Result::OK) {
2179*d9f75844SAndroid Build Coastguard Worker     // In case of an internal encoder running on a separate thread, the
2180*d9f75844SAndroid Build Coastguard Worker     // decision to drop a frame might be a frame late and signaled via
2181*d9f75844SAndroid Build Coastguard Worker     // atomic flag. This is because we can't easily wait for the worker thread
2182*d9f75844SAndroid Build Coastguard Worker     // without risking deadlocks, eg during shutdown when the worker thread
2183*d9f75844SAndroid Build Coastguard Worker     // might be waiting for the internal encoder threads to stop.
2184*d9f75844SAndroid Build Coastguard Worker     if (pending_frame_drops_.load() > 0) {
2185*d9f75844SAndroid Build Coastguard Worker       int pending_drops = pending_frame_drops_.fetch_sub(1);
2186*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_GT(pending_drops, 0);
2187*d9f75844SAndroid Build Coastguard Worker       result.drop_next_frame = true;
2188*d9f75844SAndroid Build Coastguard Worker     }
2189*d9f75844SAndroid Build Coastguard Worker   }
2190*d9f75844SAndroid Build Coastguard Worker 
2191*d9f75844SAndroid Build Coastguard Worker   return result;
2192*d9f75844SAndroid Build Coastguard Worker }
2193*d9f75844SAndroid Build Coastguard Worker 
OnDroppedFrame(DropReason reason)2194*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
2195*d9f75844SAndroid Build Coastguard Worker   switch (reason) {
2196*d9f75844SAndroid Build Coastguard Worker     case DropReason::kDroppedByMediaOptimizations:
2197*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
2198*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kMediaOptimization);
2199*d9f75844SAndroid Build Coastguard Worker       break;
2200*d9f75844SAndroid Build Coastguard Worker     case DropReason::kDroppedByEncoder:
2201*d9f75844SAndroid Build Coastguard Worker       encoder_stats_observer_->OnFrameDropped(
2202*d9f75844SAndroid Build Coastguard Worker           VideoStreamEncoderObserver::DropReason::kEncoder);
2203*d9f75844SAndroid Build Coastguard Worker       break;
2204*d9f75844SAndroid Build Coastguard Worker   }
2205*d9f75844SAndroid Build Coastguard Worker   sink_->OnDroppedFrame(reason);
2206*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, reason] {
2207*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2208*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.OnFrameDropped(reason);
2209*d9f75844SAndroid Build Coastguard Worker   });
2210*d9f75844SAndroid Build Coastguard Worker }
2211*d9f75844SAndroid Build Coastguard Worker 
UpdateTargetBitrate(DataRate target_bitrate,double cwnd_reduce_ratio)2212*d9f75844SAndroid Build Coastguard Worker DataRate VideoStreamEncoder::UpdateTargetBitrate(DataRate target_bitrate,
2213*d9f75844SAndroid Build Coastguard Worker                                                  double cwnd_reduce_ratio) {
2214*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2215*d9f75844SAndroid Build Coastguard Worker   DataRate updated_target_bitrate = target_bitrate;
2216*d9f75844SAndroid Build Coastguard Worker 
2217*d9f75844SAndroid Build Coastguard Worker   // Drop frames when congestion window pushback ratio is larger than 1
2218*d9f75844SAndroid Build Coastguard Worker   // percent and target bitrate is larger than codec min bitrate.
2219*d9f75844SAndroid Build Coastguard Worker   // When target_bitrate is 0 means codec is paused, skip frame dropping.
2220*d9f75844SAndroid Build Coastguard Worker   if (cwnd_reduce_ratio > 0.01 && target_bitrate.bps() > 0 &&
2221*d9f75844SAndroid Build Coastguard Worker       target_bitrate.bps() > send_codec_.minBitrate * 1000) {
2222*d9f75844SAndroid Build Coastguard Worker     int reduce_bitrate_bps = std::min(
2223*d9f75844SAndroid Build Coastguard Worker         static_cast<int>(target_bitrate.bps() * cwnd_reduce_ratio),
2224*d9f75844SAndroid Build Coastguard Worker         static_cast<int>(target_bitrate.bps() - send_codec_.minBitrate * 1000));
2225*d9f75844SAndroid Build Coastguard Worker     if (reduce_bitrate_bps > 0) {
2226*d9f75844SAndroid Build Coastguard Worker       // At maximum the congestion window can drop 1/2 frames.
2227*d9f75844SAndroid Build Coastguard Worker       cwnd_frame_drop_interval_ = std::max(
2228*d9f75844SAndroid Build Coastguard Worker           2, static_cast<int>(target_bitrate.bps() / reduce_bitrate_bps));
2229*d9f75844SAndroid Build Coastguard Worker       // Reduce target bitrate accordingly.
2230*d9f75844SAndroid Build Coastguard Worker       updated_target_bitrate =
2231*d9f75844SAndroid Build Coastguard Worker           target_bitrate - (target_bitrate / cwnd_frame_drop_interval_.value());
2232*d9f75844SAndroid Build Coastguard Worker       return updated_target_bitrate;
2233*d9f75844SAndroid Build Coastguard Worker     }
2234*d9f75844SAndroid Build Coastguard Worker   }
2235*d9f75844SAndroid Build Coastguard Worker   cwnd_frame_drop_interval_.reset();
2236*d9f75844SAndroid Build Coastguard Worker   return updated_target_bitrate;
2237*d9f75844SAndroid Build Coastguard Worker }
2238*d9f75844SAndroid Build Coastguard Worker 
OnBitrateUpdated(DataRate target_bitrate,DataRate stable_target_bitrate,DataRate link_allocation,uint8_t fraction_lost,int64_t round_trip_time_ms,double cwnd_reduce_ratio)2239*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnBitrateUpdated(DataRate target_bitrate,
2240*d9f75844SAndroid Build Coastguard Worker                                           DataRate stable_target_bitrate,
2241*d9f75844SAndroid Build Coastguard Worker                                           DataRate link_allocation,
2242*d9f75844SAndroid Build Coastguard Worker                                           uint8_t fraction_lost,
2243*d9f75844SAndroid Build Coastguard Worker                                           int64_t round_trip_time_ms,
2244*d9f75844SAndroid Build Coastguard Worker                                           double cwnd_reduce_ratio) {
2245*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(link_allocation, target_bitrate);
2246*d9f75844SAndroid Build Coastguard Worker   if (!encoder_queue_.IsCurrent()) {
2247*d9f75844SAndroid Build Coastguard Worker     encoder_queue_.PostTask([this, target_bitrate, stable_target_bitrate,
2248*d9f75844SAndroid Build Coastguard Worker                              link_allocation, fraction_lost, round_trip_time_ms,
2249*d9f75844SAndroid Build Coastguard Worker                              cwnd_reduce_ratio] {
2250*d9f75844SAndroid Build Coastguard Worker       DataRate updated_target_bitrate =
2251*d9f75844SAndroid Build Coastguard Worker           UpdateTargetBitrate(target_bitrate, cwnd_reduce_ratio);
2252*d9f75844SAndroid Build Coastguard Worker       OnBitrateUpdated(updated_target_bitrate, stable_target_bitrate,
2253*d9f75844SAndroid Build Coastguard Worker                        link_allocation, fraction_lost, round_trip_time_ms,
2254*d9f75844SAndroid Build Coastguard Worker                        cwnd_reduce_ratio);
2255*d9f75844SAndroid Build Coastguard Worker     });
2256*d9f75844SAndroid Build Coastguard Worker     return;
2257*d9f75844SAndroid Build Coastguard Worker   }
2258*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2259*d9f75844SAndroid Build Coastguard Worker 
2260*d9f75844SAndroid Build Coastguard Worker   const bool video_is_suspended = target_bitrate == DataRate::Zero();
2261*d9f75844SAndroid Build Coastguard Worker   const bool video_suspension_changed = video_is_suspended != EncoderPaused();
2262*d9f75844SAndroid Build Coastguard Worker 
2263*d9f75844SAndroid Build Coastguard Worker   if (!video_is_suspended && settings_.encoder_switch_request_callback &&
2264*d9f75844SAndroid Build Coastguard Worker       encoder_selector_) {
2265*d9f75844SAndroid Build Coastguard Worker     if (auto encoder = encoder_selector_->OnAvailableBitrate(link_allocation)) {
2266*d9f75844SAndroid Build Coastguard Worker       settings_.encoder_switch_request_callback->RequestEncoderSwitch(
2267*d9f75844SAndroid Build Coastguard Worker           *encoder, /*allow_default_fallback=*/false);
2268*d9f75844SAndroid Build Coastguard Worker     }
2269*d9f75844SAndroid Build Coastguard Worker   }
2270*d9f75844SAndroid Build Coastguard Worker 
2271*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
2272*d9f75844SAndroid Build Coastguard Worker 
2273*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << target_bitrate.bps()
2274*d9f75844SAndroid Build Coastguard Worker                       << " stable bitrate = " << stable_target_bitrate.bps()
2275*d9f75844SAndroid Build Coastguard Worker                       << " link allocation bitrate = " << link_allocation.bps()
2276*d9f75844SAndroid Build Coastguard Worker                       << " packet loss " << static_cast<int>(fraction_lost)
2277*d9f75844SAndroid Build Coastguard Worker                       << " rtt " << round_trip_time_ms;
2278*d9f75844SAndroid Build Coastguard Worker 
2279*d9f75844SAndroid Build Coastguard Worker   if (encoder_) {
2280*d9f75844SAndroid Build Coastguard Worker     encoder_->OnPacketLossRateUpdate(static_cast<float>(fraction_lost) / 256.f);
2281*d9f75844SAndroid Build Coastguard Worker     encoder_->OnRttUpdate(round_trip_time_ms);
2282*d9f75844SAndroid Build Coastguard Worker   }
2283*d9f75844SAndroid Build Coastguard Worker 
2284*d9f75844SAndroid Build Coastguard Worker   uint32_t framerate_fps = GetInputFramerateFps();
2285*d9f75844SAndroid Build Coastguard Worker   frame_dropper_.SetRates((target_bitrate.bps() + 500) / 1000, framerate_fps);
2286*d9f75844SAndroid Build Coastguard Worker 
2287*d9f75844SAndroid Build Coastguard Worker   EncoderRateSettings new_rate_settings{
2288*d9f75844SAndroid Build Coastguard Worker       VideoBitrateAllocation(), static_cast<double>(framerate_fps),
2289*d9f75844SAndroid Build Coastguard Worker       link_allocation, target_bitrate, stable_target_bitrate};
2290*d9f75844SAndroid Build Coastguard Worker   SetEncoderRates(UpdateBitrateAllocation(new_rate_settings));
2291*d9f75844SAndroid Build Coastguard Worker 
2292*d9f75844SAndroid Build Coastguard Worker   if (target_bitrate.bps() != 0)
2293*d9f75844SAndroid Build Coastguard Worker     encoder_target_bitrate_bps_ = target_bitrate.bps();
2294*d9f75844SAndroid Build Coastguard Worker 
2295*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.SetTargetBitrate(target_bitrate);
2296*d9f75844SAndroid Build Coastguard Worker 
2297*d9f75844SAndroid Build Coastguard Worker   if (video_suspension_changed) {
2298*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Video suspend state changed to: "
2299*d9f75844SAndroid Build Coastguard Worker                      << (video_is_suspended ? "suspended" : "not suspended");
2300*d9f75844SAndroid Build Coastguard Worker     encoder_stats_observer_->OnSuspendChange(video_is_suspended);
2301*d9f75844SAndroid Build Coastguard Worker 
2302*d9f75844SAndroid Build Coastguard Worker     if (!video_is_suspended && pending_frame_ &&
2303*d9f75844SAndroid Build Coastguard Worker         !DropDueToSize(pending_frame_->size())) {
2304*d9f75844SAndroid Build Coastguard Worker       // A pending stored frame can be processed.
2305*d9f75844SAndroid Build Coastguard Worker       int64_t pending_time_us =
2306*d9f75844SAndroid Build Coastguard Worker           clock_->CurrentTime().us() - pending_frame_post_time_us_;
2307*d9f75844SAndroid Build Coastguard Worker       if (pending_time_us < kPendingFrameTimeoutMs * 1000)
2308*d9f75844SAndroid Build Coastguard Worker         EncodeVideoFrame(*pending_frame_, pending_frame_post_time_us_);
2309*d9f75844SAndroid Build Coastguard Worker       pending_frame_.reset();
2310*d9f75844SAndroid Build Coastguard Worker     } else if (!video_is_suspended && !pending_frame_ &&
2311*d9f75844SAndroid Build Coastguard Worker                encoder_paused_and_dropped_frame_) {
2312*d9f75844SAndroid Build Coastguard Worker       // A frame was enqueued during pause-state, but since it was a native
2313*d9f75844SAndroid Build Coastguard Worker       // frame we could not store it in `pending_frame_` so request a
2314*d9f75844SAndroid Build Coastguard Worker       // refresh-frame instead.
2315*d9f75844SAndroid Build Coastguard Worker       RequestRefreshFrame();
2316*d9f75844SAndroid Build Coastguard Worker     }
2317*d9f75844SAndroid Build Coastguard Worker   }
2318*d9f75844SAndroid Build Coastguard Worker }
2319*d9f75844SAndroid Build Coastguard Worker 
DropDueToSize(uint32_t pixel_count) const2320*d9f75844SAndroid Build Coastguard Worker bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
2321*d9f75844SAndroid Build Coastguard Worker   if (!encoder_ || !stream_resource_manager_.DropInitialFrames() ||
2322*d9f75844SAndroid Build Coastguard Worker       !encoder_target_bitrate_bps_.has_value()) {
2323*d9f75844SAndroid Build Coastguard Worker     return false;
2324*d9f75844SAndroid Build Coastguard Worker   }
2325*d9f75844SAndroid Build Coastguard Worker 
2326*d9f75844SAndroid Build Coastguard Worker   bool simulcast_or_svc =
2327*d9f75844SAndroid Build Coastguard Worker       (send_codec_.codecType == VideoCodecType::kVideoCodecVP9 &&
2328*d9f75844SAndroid Build Coastguard Worker        send_codec_.VP9().numberOfSpatialLayers > 1) ||
2329*d9f75844SAndroid Build Coastguard Worker       (send_codec_.numberOfSimulcastStreams > 1 ||
2330*d9f75844SAndroid Build Coastguard Worker        encoder_config_.simulcast_layers.size() > 1);
2331*d9f75844SAndroid Build Coastguard Worker 
2332*d9f75844SAndroid Build Coastguard Worker   if (simulcast_or_svc) {
2333*d9f75844SAndroid Build Coastguard Worker     if (stream_resource_manager_.SingleActiveStreamPixels()) {
2334*d9f75844SAndroid Build Coastguard Worker       pixel_count = stream_resource_manager_.SingleActiveStreamPixels().value();
2335*d9f75844SAndroid Build Coastguard Worker     } else {
2336*d9f75844SAndroid Build Coastguard Worker       return false;
2337*d9f75844SAndroid Build Coastguard Worker     }
2338*d9f75844SAndroid Build Coastguard Worker   }
2339*d9f75844SAndroid Build Coastguard Worker 
2340*d9f75844SAndroid Build Coastguard Worker   uint32_t bitrate_bps =
2341*d9f75844SAndroid Build Coastguard Worker       stream_resource_manager_.UseBandwidthAllocationBps().value_or(
2342*d9f75844SAndroid Build Coastguard Worker           encoder_target_bitrate_bps_.value());
2343*d9f75844SAndroid Build Coastguard Worker 
2344*d9f75844SAndroid Build Coastguard Worker   absl::optional<VideoEncoder::ResolutionBitrateLimits> encoder_bitrate_limits =
2345*d9f75844SAndroid Build Coastguard Worker       GetEncoderInfoWithBitrateLimitUpdate(
2346*d9f75844SAndroid Build Coastguard Worker           encoder_->GetEncoderInfo(), encoder_config_, default_limits_allowed_)
2347*d9f75844SAndroid Build Coastguard Worker           .GetEncoderBitrateLimitsForResolution(pixel_count);
2348*d9f75844SAndroid Build Coastguard Worker 
2349*d9f75844SAndroid Build Coastguard Worker   if (encoder_bitrate_limits.has_value()) {
2350*d9f75844SAndroid Build Coastguard Worker     // Use bitrate limits provided by encoder.
2351*d9f75844SAndroid Build Coastguard Worker     return bitrate_bps <
2352*d9f75844SAndroid Build Coastguard Worker            static_cast<uint32_t>(encoder_bitrate_limits->min_start_bitrate_bps);
2353*d9f75844SAndroid Build Coastguard Worker   }
2354*d9f75844SAndroid Build Coastguard Worker 
2355*d9f75844SAndroid Build Coastguard Worker   if (bitrate_bps < 300000 /* qvga */) {
2356*d9f75844SAndroid Build Coastguard Worker     return pixel_count > 320 * 240;
2357*d9f75844SAndroid Build Coastguard Worker   } else if (bitrate_bps < 500000 /* vga */) {
2358*d9f75844SAndroid Build Coastguard Worker     return pixel_count > 640 * 480;
2359*d9f75844SAndroid Build Coastguard Worker   }
2360*d9f75844SAndroid Build Coastguard Worker   return false;
2361*d9f75844SAndroid Build Coastguard Worker }
2362*d9f75844SAndroid Build Coastguard Worker 
OnVideoSourceRestrictionsUpdated(VideoSourceRestrictions restrictions,const VideoAdaptationCounters & adaptation_counters,rtc::scoped_refptr<Resource> reason,const VideoSourceRestrictions & unfiltered_restrictions)2363*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::OnVideoSourceRestrictionsUpdated(
2364*d9f75844SAndroid Build Coastguard Worker     VideoSourceRestrictions restrictions,
2365*d9f75844SAndroid Build Coastguard Worker     const VideoAdaptationCounters& adaptation_counters,
2366*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<Resource> reason,
2367*d9f75844SAndroid Build Coastguard Worker     const VideoSourceRestrictions& unfiltered_restrictions) {
2368*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2369*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Updating sink restrictions from "
2370*d9f75844SAndroid Build Coastguard Worker                    << (reason ? reason->Name() : std::string("<null>"))
2371*d9f75844SAndroid Build Coastguard Worker                    << " to " << restrictions.ToString();
2372*d9f75844SAndroid Build Coastguard Worker 
2373*d9f75844SAndroid Build Coastguard Worker   // TODO(webrtc:14451) Split video_source_sink_controller_
2374*d9f75844SAndroid Build Coastguard Worker   // so that ownership on restrictions/wants is kept on &encoder_queue_
2375*d9f75844SAndroid Build Coastguard Worker   latest_restrictions_ = restrictions;
2376*d9f75844SAndroid Build Coastguard Worker 
2377*d9f75844SAndroid Build Coastguard Worker   worker_queue_->PostTask(SafeTask(
2378*d9f75844SAndroid Build Coastguard Worker       task_safety_.flag(), [this, restrictions = std::move(restrictions)]() {
2379*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK_RUN_ON(worker_queue_);
2380*d9f75844SAndroid Build Coastguard Worker         video_source_sink_controller_.SetRestrictions(std::move(restrictions));
2381*d9f75844SAndroid Build Coastguard Worker         video_source_sink_controller_.PushSourceSinkSettings();
2382*d9f75844SAndroid Build Coastguard Worker       }));
2383*d9f75844SAndroid Build Coastguard Worker }
2384*d9f75844SAndroid Build Coastguard Worker 
RunPostEncode(const EncodedImage & encoded_image,int64_t time_sent_us,int temporal_index,DataSize frame_size)2385*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::RunPostEncode(const EncodedImage& encoded_image,
2386*d9f75844SAndroid Build Coastguard Worker                                        int64_t time_sent_us,
2387*d9f75844SAndroid Build Coastguard Worker                                        int temporal_index,
2388*d9f75844SAndroid Build Coastguard Worker                                        DataSize frame_size) {
2389*d9f75844SAndroid Build Coastguard Worker   if (!encoder_queue_.IsCurrent()) {
2390*d9f75844SAndroid Build Coastguard Worker     encoder_queue_.PostTask([this, encoded_image, time_sent_us, temporal_index,
2391*d9f75844SAndroid Build Coastguard Worker                              frame_size] {
2392*d9f75844SAndroid Build Coastguard Worker       RunPostEncode(encoded_image, time_sent_us, temporal_index, frame_size);
2393*d9f75844SAndroid Build Coastguard Worker     });
2394*d9f75844SAndroid Build Coastguard Worker     return;
2395*d9f75844SAndroid Build Coastguard Worker   }
2396*d9f75844SAndroid Build Coastguard Worker 
2397*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&encoder_queue_);
2398*d9f75844SAndroid Build Coastguard Worker 
2399*d9f75844SAndroid Build Coastguard Worker   absl::optional<int> encode_duration_us;
2400*d9f75844SAndroid Build Coastguard Worker   if (encoded_image.timing_.flags != VideoSendTiming::kInvalid) {
2401*d9f75844SAndroid Build Coastguard Worker     encode_duration_us =
2402*d9f75844SAndroid Build Coastguard Worker         TimeDelta::Millis(encoded_image.timing_.encode_finish_ms -
2403*d9f75844SAndroid Build Coastguard Worker                           encoded_image.timing_.encode_start_ms)
2404*d9f75844SAndroid Build Coastguard Worker             .us();
2405*d9f75844SAndroid Build Coastguard Worker   }
2406*d9f75844SAndroid Build Coastguard Worker 
2407*d9f75844SAndroid Build Coastguard Worker   // Run post encode tasks, such as overuse detection and frame rate/drop
2408*d9f75844SAndroid Build Coastguard Worker   // stats for internal encoders.
2409*d9f75844SAndroid Build Coastguard Worker   const bool keyframe =
2410*d9f75844SAndroid Build Coastguard Worker       encoded_image._frameType == VideoFrameType::kVideoFrameKey;
2411*d9f75844SAndroid Build Coastguard Worker 
2412*d9f75844SAndroid Build Coastguard Worker   if (!frame_size.IsZero()) {
2413*d9f75844SAndroid Build Coastguard Worker     frame_dropper_.Fill(frame_size.bytes(), !keyframe);
2414*d9f75844SAndroid Build Coastguard Worker   }
2415*d9f75844SAndroid Build Coastguard Worker 
2416*d9f75844SAndroid Build Coastguard Worker   stream_resource_manager_.OnEncodeCompleted(encoded_image, time_sent_us,
2417*d9f75844SAndroid Build Coastguard Worker                                              encode_duration_us, frame_size);
2418*d9f75844SAndroid Build Coastguard Worker   if (bitrate_adjuster_) {
2419*d9f75844SAndroid Build Coastguard Worker     bitrate_adjuster_->OnEncodedFrame(
2420*d9f75844SAndroid Build Coastguard Worker         frame_size, encoded_image.SpatialIndex().value_or(0), temporal_index);
2421*d9f75844SAndroid Build Coastguard Worker   }
2422*d9f75844SAndroid Build Coastguard Worker }
2423*d9f75844SAndroid Build Coastguard Worker 
ReleaseEncoder()2424*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::ReleaseEncoder() {
2425*d9f75844SAndroid Build Coastguard Worker   if (!encoder_ || !encoder_initialized_) {
2426*d9f75844SAndroid Build Coastguard Worker     return;
2427*d9f75844SAndroid Build Coastguard Worker   }
2428*d9f75844SAndroid Build Coastguard Worker   encoder_->Release();
2429*d9f75844SAndroid Build Coastguard Worker   encoder_initialized_ = false;
2430*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release");
2431*d9f75844SAndroid Build Coastguard Worker }
2432*d9f75844SAndroid Build Coastguard Worker 
2433*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::AutomaticAnimationDetectionExperiment
ParseAutomatincAnimationDetectionFieldTrial() const2434*d9f75844SAndroid Build Coastguard Worker VideoStreamEncoder::ParseAutomatincAnimationDetectionFieldTrial() const {
2435*d9f75844SAndroid Build Coastguard Worker   AutomaticAnimationDetectionExperiment result;
2436*d9f75844SAndroid Build Coastguard Worker 
2437*d9f75844SAndroid Build Coastguard Worker   result.Parser()->Parse(
2438*d9f75844SAndroid Build Coastguard Worker       field_trials_.Lookup("WebRTC-AutomaticAnimationDetectionScreenshare"));
2439*d9f75844SAndroid Build Coastguard Worker 
2440*d9f75844SAndroid Build Coastguard Worker   if (!result.enabled) {
2441*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Automatic animation detection experiment is disabled.";
2442*d9f75844SAndroid Build Coastguard Worker     return result;
2443*d9f75844SAndroid Build Coastguard Worker   }
2444*d9f75844SAndroid Build Coastguard Worker 
2445*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Automatic animation detection experiment settings:"
2446*d9f75844SAndroid Build Coastguard Worker                       " min_duration_ms="
2447*d9f75844SAndroid Build Coastguard Worker                    << result.min_duration_ms
2448*d9f75844SAndroid Build Coastguard Worker                    << " min_area_ration=" << result.min_area_ratio
2449*d9f75844SAndroid Build Coastguard Worker                    << " min_fps=" << result.min_fps;
2450*d9f75844SAndroid Build Coastguard Worker 
2451*d9f75844SAndroid Build Coastguard Worker   return result;
2452*d9f75844SAndroid Build Coastguard Worker }
2453*d9f75844SAndroid Build Coastguard Worker 
CheckForAnimatedContent(const VideoFrame & frame,int64_t time_when_posted_in_us)2454*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::CheckForAnimatedContent(
2455*d9f75844SAndroid Build Coastguard Worker     const VideoFrame& frame,
2456*d9f75844SAndroid Build Coastguard Worker     int64_t time_when_posted_in_us) {
2457*d9f75844SAndroid Build Coastguard Worker   if (!automatic_animation_detection_experiment_.enabled ||
2458*d9f75844SAndroid Build Coastguard Worker       encoder_config_.content_type !=
2459*d9f75844SAndroid Build Coastguard Worker           VideoEncoderConfig::ContentType::kScreen ||
2460*d9f75844SAndroid Build Coastguard Worker       stream_resource_manager_.degradation_preference() !=
2461*d9f75844SAndroid Build Coastguard Worker           DegradationPreference::BALANCED) {
2462*d9f75844SAndroid Build Coastguard Worker     return;
2463*d9f75844SAndroid Build Coastguard Worker   }
2464*d9f75844SAndroid Build Coastguard Worker 
2465*d9f75844SAndroid Build Coastguard Worker   if (expect_resize_state_ == ExpectResizeState::kResize && last_frame_info_ &&
2466*d9f75844SAndroid Build Coastguard Worker       last_frame_info_->width != frame.width() &&
2467*d9f75844SAndroid Build Coastguard Worker       last_frame_info_->height != frame.height()) {
2468*d9f75844SAndroid Build Coastguard Worker     // On applying resolution cap there will be one frame with no/different
2469*d9f75844SAndroid Build Coastguard Worker     // update, which should be skipped.
2470*d9f75844SAndroid Build Coastguard Worker     // It can be delayed by several frames.
2471*d9f75844SAndroid Build Coastguard Worker     expect_resize_state_ = ExpectResizeState::kFirstFrameAfterResize;
2472*d9f75844SAndroid Build Coastguard Worker     return;
2473*d9f75844SAndroid Build Coastguard Worker   }
2474*d9f75844SAndroid Build Coastguard Worker 
2475*d9f75844SAndroid Build Coastguard Worker   if (expect_resize_state_ == ExpectResizeState::kFirstFrameAfterResize) {
2476*d9f75844SAndroid Build Coastguard Worker     // The first frame after resize should have new, scaled update_rect.
2477*d9f75844SAndroid Build Coastguard Worker     if (frame.has_update_rect()) {
2478*d9f75844SAndroid Build Coastguard Worker       last_update_rect_ = frame.update_rect();
2479*d9f75844SAndroid Build Coastguard Worker     } else {
2480*d9f75844SAndroid Build Coastguard Worker       last_update_rect_ = absl::nullopt;
2481*d9f75844SAndroid Build Coastguard Worker     }
2482*d9f75844SAndroid Build Coastguard Worker     expect_resize_state_ = ExpectResizeState::kNoResize;
2483*d9f75844SAndroid Build Coastguard Worker   }
2484*d9f75844SAndroid Build Coastguard Worker 
2485*d9f75844SAndroid Build Coastguard Worker   bool should_cap_resolution = false;
2486*d9f75844SAndroid Build Coastguard Worker   if (!frame.has_update_rect()) {
2487*d9f75844SAndroid Build Coastguard Worker     last_update_rect_ = absl::nullopt;
2488*d9f75844SAndroid Build Coastguard Worker     animation_start_time_ = Timestamp::PlusInfinity();
2489*d9f75844SAndroid Build Coastguard Worker   } else if ((!last_update_rect_ ||
2490*d9f75844SAndroid Build Coastguard Worker               frame.update_rect() != *last_update_rect_)) {
2491*d9f75844SAndroid Build Coastguard Worker     last_update_rect_ = frame.update_rect();
2492*d9f75844SAndroid Build Coastguard Worker     animation_start_time_ = Timestamp::Micros(time_when_posted_in_us);
2493*d9f75844SAndroid Build Coastguard Worker   } else {
2494*d9f75844SAndroid Build Coastguard Worker     TimeDelta animation_duration =
2495*d9f75844SAndroid Build Coastguard Worker         Timestamp::Micros(time_when_posted_in_us) - animation_start_time_;
2496*d9f75844SAndroid Build Coastguard Worker     float area_ratio = static_cast<float>(last_update_rect_->width *
2497*d9f75844SAndroid Build Coastguard Worker                                           last_update_rect_->height) /
2498*d9f75844SAndroid Build Coastguard Worker                        (frame.width() * frame.height());
2499*d9f75844SAndroid Build Coastguard Worker     if (animation_duration.ms() >=
2500*d9f75844SAndroid Build Coastguard Worker             automatic_animation_detection_experiment_.min_duration_ms &&
2501*d9f75844SAndroid Build Coastguard Worker         area_ratio >=
2502*d9f75844SAndroid Build Coastguard Worker             automatic_animation_detection_experiment_.min_area_ratio &&
2503*d9f75844SAndroid Build Coastguard Worker         encoder_stats_observer_->GetInputFrameRate() >=
2504*d9f75844SAndroid Build Coastguard Worker             automatic_animation_detection_experiment_.min_fps) {
2505*d9f75844SAndroid Build Coastguard Worker       should_cap_resolution = true;
2506*d9f75844SAndroid Build Coastguard Worker     }
2507*d9f75844SAndroid Build Coastguard Worker   }
2508*d9f75844SAndroid Build Coastguard Worker   if (cap_resolution_due_to_video_content_ != should_cap_resolution) {
2509*d9f75844SAndroid Build Coastguard Worker     expect_resize_state_ = should_cap_resolution ? ExpectResizeState::kResize
2510*d9f75844SAndroid Build Coastguard Worker                                                  : ExpectResizeState::kNoResize;
2511*d9f75844SAndroid Build Coastguard Worker     cap_resolution_due_to_video_content_ = should_cap_resolution;
2512*d9f75844SAndroid Build Coastguard Worker     if (should_cap_resolution) {
2513*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO) << "Applying resolution cap due to animation detection.";
2514*d9f75844SAndroid Build Coastguard Worker     } else {
2515*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO) << "Removing resolution cap due to no consistent "
2516*d9f75844SAndroid Build Coastguard Worker                           "animation detection.";
2517*d9f75844SAndroid Build Coastguard Worker     }
2518*d9f75844SAndroid Build Coastguard Worker     // TODO(webrtc:14451) Split video_source_sink_controller_
2519*d9f75844SAndroid Build Coastguard Worker     // so that ownership on restrictions/wants is kept on &encoder_queue_
2520*d9f75844SAndroid Build Coastguard Worker     if (should_cap_resolution) {
2521*d9f75844SAndroid Build Coastguard Worker       animate_restrictions_ =
2522*d9f75844SAndroid Build Coastguard Worker           VideoSourceRestrictions(kMaxAnimationPixels,
2523*d9f75844SAndroid Build Coastguard Worker                                   /* target_pixels_per_frame= */ absl::nullopt,
2524*d9f75844SAndroid Build Coastguard Worker                                   /* max_frame_rate= */ absl::nullopt);
2525*d9f75844SAndroid Build Coastguard Worker     } else {
2526*d9f75844SAndroid Build Coastguard Worker       animate_restrictions_.reset();
2527*d9f75844SAndroid Build Coastguard Worker     }
2528*d9f75844SAndroid Build Coastguard Worker 
2529*d9f75844SAndroid Build Coastguard Worker     worker_queue_->PostTask(
2530*d9f75844SAndroid Build Coastguard Worker         SafeTask(task_safety_.flag(), [this, should_cap_resolution]() {
2531*d9f75844SAndroid Build Coastguard Worker           RTC_DCHECK_RUN_ON(worker_queue_);
2532*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.SetPixelsPerFrameUpperLimit(
2533*d9f75844SAndroid Build Coastguard Worker               should_cap_resolution
2534*d9f75844SAndroid Build Coastguard Worker                   ? absl::optional<size_t>(kMaxAnimationPixels)
2535*d9f75844SAndroid Build Coastguard Worker                   : absl::nullopt);
2536*d9f75844SAndroid Build Coastguard Worker           video_source_sink_controller_.PushSourceSinkSettings();
2537*d9f75844SAndroid Build Coastguard Worker         }));
2538*d9f75844SAndroid Build Coastguard Worker   }
2539*d9f75844SAndroid Build Coastguard Worker }
2540*d9f75844SAndroid Build Coastguard Worker 
InjectAdaptationResource(rtc::scoped_refptr<Resource> resource,VideoAdaptationReason reason)2541*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::InjectAdaptationResource(
2542*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<Resource> resource,
2543*d9f75844SAndroid Build Coastguard Worker     VideoAdaptationReason reason) {
2544*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, resource = std::move(resource), reason] {
2545*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2546*d9f75844SAndroid Build Coastguard Worker     additional_resources_.push_back(resource);
2547*d9f75844SAndroid Build Coastguard Worker     stream_resource_manager_.AddResource(resource, reason);
2548*d9f75844SAndroid Build Coastguard Worker   });
2549*d9f75844SAndroid Build Coastguard Worker }
2550*d9f75844SAndroid Build Coastguard Worker 
InjectAdaptationConstraint(AdaptationConstraint * adaptation_constraint)2551*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::InjectAdaptationConstraint(
2552*d9f75844SAndroid Build Coastguard Worker     AdaptationConstraint* adaptation_constraint) {
2553*d9f75844SAndroid Build Coastguard Worker   rtc::Event event;
2554*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, adaptation_constraint, &event] {
2555*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2556*d9f75844SAndroid Build Coastguard Worker     if (!resource_adaptation_processor_) {
2557*d9f75844SAndroid Build Coastguard Worker       // The VideoStreamEncoder was stopped and the processor destroyed before
2558*d9f75844SAndroid Build Coastguard Worker       // this task had a chance to execute. No action needed.
2559*d9f75844SAndroid Build Coastguard Worker       return;
2560*d9f75844SAndroid Build Coastguard Worker     }
2561*d9f75844SAndroid Build Coastguard Worker     adaptation_constraints_.push_back(adaptation_constraint);
2562*d9f75844SAndroid Build Coastguard Worker     video_stream_adapter_->AddAdaptationConstraint(adaptation_constraint);
2563*d9f75844SAndroid Build Coastguard Worker     event.Set();
2564*d9f75844SAndroid Build Coastguard Worker   });
2565*d9f75844SAndroid Build Coastguard Worker   event.Wait(rtc::Event::kForever);
2566*d9f75844SAndroid Build Coastguard Worker }
2567*d9f75844SAndroid Build Coastguard Worker 
AddRestrictionsListenerForTesting(VideoSourceRestrictionsListener * restrictions_listener)2568*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::AddRestrictionsListenerForTesting(
2569*d9f75844SAndroid Build Coastguard Worker     VideoSourceRestrictionsListener* restrictions_listener) {
2570*d9f75844SAndroid Build Coastguard Worker   rtc::Event event;
2571*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, restrictions_listener, &event] {
2572*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2573*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(resource_adaptation_processor_);
2574*d9f75844SAndroid Build Coastguard Worker     video_stream_adapter_->AddRestrictionsListener(restrictions_listener);
2575*d9f75844SAndroid Build Coastguard Worker     event.Set();
2576*d9f75844SAndroid Build Coastguard Worker   });
2577*d9f75844SAndroid Build Coastguard Worker   event.Wait(rtc::Event::kForever);
2578*d9f75844SAndroid Build Coastguard Worker }
2579*d9f75844SAndroid Build Coastguard Worker 
RemoveRestrictionsListenerForTesting(VideoSourceRestrictionsListener * restrictions_listener)2580*d9f75844SAndroid Build Coastguard Worker void VideoStreamEncoder::RemoveRestrictionsListenerForTesting(
2581*d9f75844SAndroid Build Coastguard Worker     VideoSourceRestrictionsListener* restrictions_listener) {
2582*d9f75844SAndroid Build Coastguard Worker   rtc::Event event;
2583*d9f75844SAndroid Build Coastguard Worker   encoder_queue_.PostTask([this, restrictions_listener, &event] {
2584*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&encoder_queue_);
2585*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(resource_adaptation_processor_);
2586*d9f75844SAndroid Build Coastguard Worker     video_stream_adapter_->RemoveRestrictionsListener(restrictions_listener);
2587*d9f75844SAndroid Build Coastguard Worker     event.Set();
2588*d9f75844SAndroid Build Coastguard Worker   });
2589*d9f75844SAndroid Build Coastguard Worker   event.Wait(rtc::Event::kForever);
2590*d9f75844SAndroid Build Coastguard Worker }
2591*d9f75844SAndroid Build Coastguard Worker 
2592*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
2593