blob: 9572512002952a05118e0b952dbeac3792704d84 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/video_stream_encoder.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000012
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000013#include <algorithm>
perkj57c21f92016-06-17 07:27:16 -070014#include <limits>
sprangc5d62e22017-04-02 23:53:04 -070015#include <numeric>
Per512ecb32016-09-23 15:52:06 +020016#include <utility>
niklase@google.com470e71d2011-07-07 08:21:25 +000017
Niels Möller6bb5ab92019-01-11 11:11:10 +010018#include "absl/memory/memory.h"
Niels Möller4dc66c52018-10-05 14:17:58 +020019#include "api/video/encoded_image.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/video/i420_buffer.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080021#include "api/video/video_bitrate_allocator_factory.h"
Sergey Silkin8b9b5f92018-12-10 09:28:53 +010022#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/include/video_codec_initializer.h"
24#include "modules/video_coding/include/video_coding.h"
Niels Möller6bb5ab92019-01-11 11:11:10 +010025#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/arraysize.h"
27#include "rtc_base/checks.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010028#include "rtc_base/experiments/alr_experiment.h"
Åsa Perssona945aee2018-04-24 16:53:25 +020029#include "rtc_base/experiments/quality_scaling_experiment.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010030#include "rtc_base/experiments/rate_control_settings.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/location.h"
32#include "rtc_base/logging.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020033#include "rtc_base/strings/string_builder.h"
Karl Wiberg80ba3332018-02-05 10:33:35 +010034#include "rtc_base/system/fallthrough.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "rtc_base/trace_event.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020037#include "system_wrappers/include/field_trial.h"
nisseea3a7982017-05-15 02:42:11 -070038
niklase@google.com470e71d2011-07-07 08:21:25 +000039namespace webrtc {
40
perkj26091b12016-09-01 01:17:40 -070041namespace {
sprangb1ca0732017-02-01 08:38:12 -080042
asapersson6ffb67d2016-09-12 00:10:45 -070043// Time interval for logging frame counts.
44const int64_t kFrameLogIntervalMs = 60000;
sprangc5d62e22017-04-02 23:53:04 -070045const int kMinFramerateFps = 2;
perkj26091b12016-09-01 01:17:40 -070046
Sebastian Janssona3177052018-04-10 13:05:49 +020047// Time to keep a single cached pending frame in paused state.
48const int64_t kPendingFrameTimeoutMs = 1000;
49
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020050const char kInitialFramedropFieldTrial[] = "WebRTC-InitialFramedrop";
Niels Möller6bb5ab92019-01-11 11:11:10 +010051constexpr char kFrameDropperFieldTrial[] = "WebRTC-FrameDropper";
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020052
kthelgason2bc68642017-02-07 07:02:22 -080053// The maximum number of frames to drop at beginning of stream
54// to try and achieve desired bitrate.
55const int kMaxInitialFramedrop = 4;
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020056// When the first change in BWE above this threshold occurs,
57// enable DropFrameDueToSize logic.
58const float kFramedropThreshold = 0.3;
kthelgason2bc68642017-02-07 07:02:22 -080059
Niels Möller6bb5ab92019-01-11 11:11:10 +010060// Averaging window spanning 90 frames at default 30fps, matching old media
61// optimization module defaults.
62const int64_t kFrameRateAvergingWindowSizeMs = (1000 / 30) * 90;
63
Erik Språngb7cb7b52019-02-26 15:52:33 +010064const size_t kDefaultPayloadSize = 1440;
65
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070066// Initial limits for BALANCED degradation preference.
asaperssonf7e294d2017-06-13 23:25:22 -070067int MinFps(int pixels) {
68 if (pixels <= 320 * 240) {
69 return 7;
70 } else if (pixels <= 480 * 270) {
71 return 10;
72 } else if (pixels <= 640 * 480) {
73 return 15;
74 } else {
75 return std::numeric_limits<int>::max();
76 }
77}
78
79int MaxFps(int pixels) {
80 if (pixels <= 320 * 240) {
81 return 10;
82 } else if (pixels <= 480 * 270) {
83 return 15;
84 } else {
85 return std::numeric_limits<int>::max();
86 }
87}
88
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020089uint32_t abs_diff(uint32_t a, uint32_t b) {
90 return (a < b) ? b - a : a - b;
91}
92
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070093bool IsResolutionScalingEnabled(DegradationPreference degradation_preference) {
94 return degradation_preference == DegradationPreference::MAINTAIN_FRAMERATE ||
95 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -070096}
97
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070098bool IsFramerateScalingEnabled(DegradationPreference degradation_preference) {
99 return degradation_preference == DegradationPreference::MAINTAIN_RESOLUTION ||
100 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -0700101}
102
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200103// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
104// pipelining encoders better (multiple input frames before something comes
105// out). This should effectively turn off CPU adaptations for systems that
106// remotely cope with the load right now.
107CpuOveruseOptions GetCpuOveruseOptions(
Niels Möller213618e2018-07-24 09:29:58 +0200108 const VideoStreamEncoderSettings& settings,
Niels Möller4db138e2018-04-19 09:04:13 +0200109 bool full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200110 CpuOveruseOptions options;
111
Niels Möller4db138e2018-04-19 09:04:13 +0200112 if (full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200113 options.low_encode_usage_threshold_percent = 150;
114 options.high_encode_usage_threshold_percent = 200;
115 }
116 if (settings.experiment_cpu_load_estimator) {
117 options.filter_time_ms = 5 * rtc::kNumMillisecsPerSec;
118 }
119
120 return options;
121}
122
Erik Språngb7cb7b52019-02-26 15:52:33 +0100123bool RequiresEncoderReset(const VideoCodec& previous_send_codec,
124 const VideoCodec& new_send_codec) {
125 // Does not check startBitrate or maxFramerate.
126 if (new_send_codec.codecType != previous_send_codec.codecType ||
127 new_send_codec.width != previous_send_codec.width ||
128 new_send_codec.height != previous_send_codec.height ||
129 new_send_codec.maxBitrate != previous_send_codec.maxBitrate ||
130 new_send_codec.minBitrate != previous_send_codec.minBitrate ||
131 new_send_codec.qpMax != previous_send_codec.qpMax ||
132 new_send_codec.numberOfSimulcastStreams !=
133 previous_send_codec.numberOfSimulcastStreams ||
134 new_send_codec.mode != previous_send_codec.mode) {
135 return true;
136 }
137
138 switch (new_send_codec.codecType) {
139 case kVideoCodecVP8:
140 if (new_send_codec.VP8() != previous_send_codec.VP8()) {
141 return true;
142 }
143 break;
144
145 case kVideoCodecVP9:
146 if (new_send_codec.VP9() != previous_send_codec.VP9()) {
147 return true;
148 }
149 break;
150
151 case kVideoCodecH264:
152 if (new_send_codec.H264() != previous_send_codec.H264()) {
153 return true;
154 }
155 break;
156
157 default:
158 break;
159 }
160
161 for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
162 if (new_send_codec.simulcastStream[i] !=
163 previous_send_codec.simulcastStream[i])
164 return true;
165 }
166 return false;
167}
Erik Språng6a7baa72019-02-26 18:31:00 +0100168
169std::array<uint8_t, 2> GetExperimentGroups() {
170 std::array<uint8_t, 2> experiment_groups;
171 absl::optional<AlrExperimentSettings> experiment_settings =
172 AlrExperimentSettings::CreateFromFieldTrial(
173 AlrExperimentSettings::kStrictPacingAndProbingExperimentName);
174 if (experiment_settings) {
175 experiment_groups[0] = experiment_settings->group_id + 1;
176 } else {
177 experiment_groups[0] = 0;
178 }
179 experiment_settings = AlrExperimentSettings::CreateFromFieldTrial(
180 AlrExperimentSettings::kScreenshareProbingBweExperimentName);
181 if (experiment_settings) {
182 experiment_groups[1] = experiment_settings->group_id + 1;
183 } else {
184 experiment_groups[1] = 0;
185 }
186 return experiment_groups;
187}
perkj26091b12016-09-01 01:17:40 -0700188} // namespace
189
perkja49cbd32016-09-16 07:53:41 -0700190// VideoSourceProxy is responsible ensuring thread safety between calls to
mflodmancc3d4422017-08-03 08:27:51 -0700191// VideoStreamEncoder::SetSource that will happen on libjingle's worker thread
192// when a video capturer is connected to the encoder and the encoder task queue
perkja49cbd32016-09-16 07:53:41 -0700193// (encoder_queue_) where the encoder reports its VideoSinkWants.
mflodmancc3d4422017-08-03 08:27:51 -0700194class VideoStreamEncoder::VideoSourceProxy {
perkja49cbd32016-09-16 07:53:41 -0700195 public:
mflodmancc3d4422017-08-03 08:27:51 -0700196 explicit VideoSourceProxy(VideoStreamEncoder* video_stream_encoder)
197 : video_stream_encoder_(video_stream_encoder),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700198 degradation_preference_(DegradationPreference::DISABLED),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200199 source_(nullptr),
200 max_framerate_(std::numeric_limits<int>::max()) {}
perkja49cbd32016-09-16 07:53:41 -0700201
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700202 void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
203 const DegradationPreference& degradation_preference) {
perkj803d97f2016-11-01 11:45:46 -0700204 // Called on libjingle's worker thread.
perkja49cbd32016-09-16 07:53:41 -0700205 RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
206 rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr;
perkj803d97f2016-11-01 11:45:46 -0700207 rtc::VideoSinkWants wants;
perkja49cbd32016-09-16 07:53:41 -0700208 {
209 rtc::CritScope lock(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700210 degradation_preference_ = degradation_preference;
perkja49cbd32016-09-16 07:53:41 -0700211 old_source = source_;
212 source_ = source;
sprangfda496a2017-06-15 04:21:07 -0700213 wants = GetActiveSinkWantsInternal();
perkja49cbd32016-09-16 07:53:41 -0700214 }
215
216 if (old_source != source && old_source != nullptr) {
mflodmancc3d4422017-08-03 08:27:51 -0700217 old_source->RemoveSink(video_stream_encoder_);
perkja49cbd32016-09-16 07:53:41 -0700218 }
219
220 if (!source) {
221 return;
222 }
223
mflodmancc3d4422017-08-03 08:27:51 -0700224 source->AddOrUpdateSink(video_stream_encoder_, wants);
perkja49cbd32016-09-16 07:53:41 -0700225 }
226
Åsa Persson8c1bf952018-09-13 10:42:19 +0200227 void SetMaxFramerate(int max_framerate) {
228 RTC_DCHECK_GT(max_framerate, 0);
229 rtc::CritScope lock(&crit_);
230 if (max_framerate == max_framerate_)
231 return;
232
233 RTC_LOG(LS_INFO) << "Set max framerate: " << max_framerate;
234 max_framerate_ = max_framerate;
235 if (source_) {
236 source_->AddOrUpdateSink(video_stream_encoder_,
237 GetActiveSinkWantsInternal());
238 }
239 }
240
perkj803d97f2016-11-01 11:45:46 -0700241 void SetWantsRotationApplied(bool rotation_applied) {
242 rtc::CritScope lock(&crit_);
243 sink_wants_.rotation_applied = rotation_applied;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200244 if (source_) {
245 source_->AddOrUpdateSink(video_stream_encoder_,
246 GetActiveSinkWantsInternal());
247 }
sprangc5d62e22017-04-02 23:53:04 -0700248 }
249
sprangfda496a2017-06-15 04:21:07 -0700250 rtc::VideoSinkWants GetActiveSinkWants() {
251 rtc::CritScope lock(&crit_);
252 return GetActiveSinkWantsInternal();
perkj803d97f2016-11-01 11:45:46 -0700253 }
254
asaperssonf7e294d2017-06-13 23:25:22 -0700255 void ResetPixelFpsCount() {
256 rtc::CritScope lock(&crit_);
257 sink_wants_.max_pixel_count = std::numeric_limits<int>::max();
258 sink_wants_.target_pixel_count.reset();
259 sink_wants_.max_framerate_fps = std::numeric_limits<int>::max();
260 if (source_)
Åsa Persson8c1bf952018-09-13 10:42:19 +0200261 source_->AddOrUpdateSink(video_stream_encoder_,
262 GetActiveSinkWantsInternal());
asaperssonf7e294d2017-06-13 23:25:22 -0700263 }
264
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100265 bool RequestResolutionLowerThan(int pixel_count,
266 int min_pixels_per_frame,
267 bool* min_pixels_reached) {
perkj803d97f2016-11-01 11:45:46 -0700268 // Called on the encoder task queue.
269 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700270 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700271 // This can happen since |degradation_preference_| is set on libjingle's
272 // worker thread but the adaptation is done on the encoder task queue.
asaperssond0de2952017-04-21 01:47:31 -0700273 return false;
perkj803d97f2016-11-01 11:45:46 -0700274 }
asapersson13874762017-06-07 00:01:02 -0700275 // The input video frame size will have a resolution less than or equal to
276 // |max_pixel_count| depending on how the source can scale the frame size.
kthelgason5e13d412016-12-01 03:59:51 -0800277 const int pixels_wanted = (pixel_count * 3) / 5;
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100278 if (pixels_wanted >= sink_wants_.max_pixel_count) {
279 return false;
280 }
281 if (pixels_wanted < min_pixels_per_frame) {
282 *min_pixels_reached = true;
asaperssond0de2952017-04-21 01:47:31 -0700283 return false;
asapersson13874762017-06-07 00:01:02 -0700284 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100285 RTC_LOG(LS_INFO) << "Scaling down resolution, max pixels: "
286 << pixels_wanted;
sprangc5d62e22017-04-02 23:53:04 -0700287 sink_wants_.max_pixel_count = pixels_wanted;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200288 sink_wants_.target_pixel_count = absl::nullopt;
mflodmancc3d4422017-08-03 08:27:51 -0700289 source_->AddOrUpdateSink(video_stream_encoder_,
290 GetActiveSinkWantsInternal());
asaperssond0de2952017-04-21 01:47:31 -0700291 return true;
sprangc5d62e22017-04-02 23:53:04 -0700292 }
293
sprangfda496a2017-06-15 04:21:07 -0700294 int RequestFramerateLowerThan(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700295 // Called on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700296 // The input video frame rate will be scaled down to 2/3, rounding down.
sprangfda496a2017-06-15 04:21:07 -0700297 int framerate_wanted = (fps * 2) / 3;
298 return RestrictFramerate(framerate_wanted) ? framerate_wanted : -1;
perkj803d97f2016-11-01 11:45:46 -0700299 }
300
asapersson13874762017-06-07 00:01:02 -0700301 bool RequestHigherResolutionThan(int pixel_count) {
302 // Called on the encoder task queue.
perkj803d97f2016-11-01 11:45:46 -0700303 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700304 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700305 // This can happen since |degradation_preference_| is set on libjingle's
306 // worker thread but the adaptation is done on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700307 return false;
perkj803d97f2016-11-01 11:45:46 -0700308 }
asapersson13874762017-06-07 00:01:02 -0700309 int max_pixels_wanted = pixel_count;
310 if (max_pixels_wanted != std::numeric_limits<int>::max())
311 max_pixels_wanted = pixel_count * 4;
sprangc5d62e22017-04-02 23:53:04 -0700312
asapersson13874762017-06-07 00:01:02 -0700313 if (max_pixels_wanted <= sink_wants_.max_pixel_count)
314 return false;
315
316 sink_wants_.max_pixel_count = max_pixels_wanted;
317 if (max_pixels_wanted == std::numeric_limits<int>::max()) {
sprangc5d62e22017-04-02 23:53:04 -0700318 // Remove any constraints.
319 sink_wants_.target_pixel_count.reset();
sprangc5d62e22017-04-02 23:53:04 -0700320 } else {
321 // On step down we request at most 3/5 the pixel count of the previous
322 // resolution, so in order to take "one step up" we request a resolution
323 // as close as possible to 5/3 of the current resolution. The actual pixel
324 // count selected depends on the capabilities of the source. In order to
325 // not take a too large step up, we cap the requested pixel count to be at
326 // most four time the current number of pixels.
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100327 sink_wants_.target_pixel_count = (pixel_count * 5) / 3;
sprangc5d62e22017-04-02 23:53:04 -0700328 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100329 RTC_LOG(LS_INFO) << "Scaling up resolution, max pixels: "
330 << max_pixels_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700331 source_->AddOrUpdateSink(video_stream_encoder_,
332 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700333 return true;
sprangc5d62e22017-04-02 23:53:04 -0700334 }
335
sprangfda496a2017-06-15 04:21:07 -0700336 // Request upgrade in framerate. Returns the new requested frame, or -1 if
337 // no change requested. Note that maxint may be returned if limits due to
338 // adaptation requests are removed completely. In that case, consider
339 // |max_framerate_| to be the current limit (assuming the capturer complies).
340 int RequestHigherFramerateThan(int fps) {
asapersson13874762017-06-07 00:01:02 -0700341 // Called on the encoder task queue.
342 // The input frame rate will be scaled up to the last step, with rounding.
343 int framerate_wanted = fps;
344 if (fps != std::numeric_limits<int>::max())
345 framerate_wanted = (fps * 3) / 2;
346
sprangfda496a2017-06-15 04:21:07 -0700347 return IncreaseFramerate(framerate_wanted) ? framerate_wanted : -1;
asapersson13874762017-06-07 00:01:02 -0700348 }
349
350 bool RestrictFramerate(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700351 // Called on the encoder task queue.
352 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700353 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
354 return false;
355
356 const int fps_wanted = std::max(kMinFramerateFps, fps);
357 if (fps_wanted >= sink_wants_.max_framerate_fps)
358 return false;
359
Mirko Bonadei675513b2017-11-09 11:09:25 +0100360 RTC_LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700361 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700362 source_->AddOrUpdateSink(video_stream_encoder_,
363 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700364 return true;
365 }
366
367 bool IncreaseFramerate(int fps) {
368 // Called on the encoder task queue.
369 rtc::CritScope lock(&crit_);
370 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
371 return false;
372
373 const int fps_wanted = std::max(kMinFramerateFps, fps);
374 if (fps_wanted <= sink_wants_.max_framerate_fps)
375 return false;
376
Mirko Bonadei675513b2017-11-09 11:09:25 +0100377 RTC_LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700378 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700379 source_->AddOrUpdateSink(video_stream_encoder_,
380 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700381 return true;
perkj803d97f2016-11-01 11:45:46 -0700382 }
383
perkja49cbd32016-09-16 07:53:41 -0700384 private:
sprangfda496a2017-06-15 04:21:07 -0700385 rtc::VideoSinkWants GetActiveSinkWantsInternal()
danilchapa37de392017-09-09 04:17:22 -0700386 RTC_EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
sprangfda496a2017-06-15 04:21:07 -0700387 rtc::VideoSinkWants wants = sink_wants_;
388 // Clear any constraints from the current sink wants that don't apply to
389 // the used degradation_preference.
390 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700391 case DegradationPreference::BALANCED:
sprangfda496a2017-06-15 04:21:07 -0700392 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700393 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangfda496a2017-06-15 04:21:07 -0700394 wants.max_framerate_fps = std::numeric_limits<int>::max();
395 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700396 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangfda496a2017-06-15 04:21:07 -0700397 wants.max_pixel_count = std::numeric_limits<int>::max();
398 wants.target_pixel_count.reset();
399 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700400 case DegradationPreference::DISABLED:
sprangfda496a2017-06-15 04:21:07 -0700401 wants.max_pixel_count = std::numeric_limits<int>::max();
402 wants.target_pixel_count.reset();
403 wants.max_framerate_fps = std::numeric_limits<int>::max();
404 }
Åsa Persson8c1bf952018-09-13 10:42:19 +0200405 // Limit to configured max framerate.
406 wants.max_framerate_fps = std::min(max_framerate_, wants.max_framerate_fps);
sprangfda496a2017-06-15 04:21:07 -0700407 return wants;
408 }
409
perkja49cbd32016-09-16 07:53:41 -0700410 rtc::CriticalSection crit_;
411 rtc::SequencedTaskChecker main_checker_;
mflodmancc3d4422017-08-03 08:27:51 -0700412 VideoStreamEncoder* const video_stream_encoder_;
danilchapa37de392017-09-09 04:17:22 -0700413 rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(&crit_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700414 DegradationPreference degradation_preference_ RTC_GUARDED_BY(&crit_);
danilchapa37de392017-09-09 04:17:22 -0700415 rtc::VideoSourceInterface<VideoFrame>* source_ RTC_GUARDED_BY(&crit_);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200416 int max_framerate_ RTC_GUARDED_BY(&crit_);
perkja49cbd32016-09-16 07:53:41 -0700417
418 RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
419};
420
Åsa Persson0122e842017-10-16 12:19:23 +0200421VideoStreamEncoder::VideoStreamEncoder(
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100422 Clock* clock,
Åsa Persson0122e842017-10-16 12:19:23 +0200423 uint32_t number_of_cores,
Niels Möller213618e2018-07-24 09:29:58 +0200424 VideoStreamEncoderObserver* encoder_stats_observer,
425 const VideoStreamEncoderSettings& settings,
Sebastian Jansson74682c12019-03-01 11:50:20 +0100426 std::unique_ptr<OveruseFrameDetector> overuse_detector,
427 TaskQueueFactory* task_queue_factory)
perkj26091b12016-09-01 01:17:40 -0700428 : shutdown_event_(true /* manual_reset */, false),
429 number_of_cores_(number_of_cores),
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200430 initial_framedrop_(0),
431 initial_framedrop_on_bwe_enabled_(
432 webrtc::field_trial::IsEnabled(kInitialFramedropFieldTrial)),
Åsa Perssona945aee2018-04-24 16:53:25 +0200433 quality_scaling_experiment_enabled_(QualityScalingExperiment::Enabled()),
perkja49cbd32016-09-16 07:53:41 -0700434 source_proxy_(new VideoSourceProxy(this)),
Pera48ddb72016-09-29 11:48:50 +0200435 sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700436 settings_(settings),
Erik Språng7ca375c2019-02-06 16:20:17 +0100437 rate_control_settings_(RateControlSettings::ParseFromFieldTrials()),
Niels Möller73f29cb2018-01-31 16:09:31 +0100438 overuse_detector_(std::move(overuse_detector)),
Niels Möller213618e2018-07-24 09:29:58 +0200439 encoder_stats_observer_(encoder_stats_observer),
Erik Språng6a7baa72019-02-26 18:31:00 +0100440 encoder_initialized_(false),
sprangfda496a2017-06-15 04:21:07 -0700441 max_framerate_(-1),
perkjfa10b552016-10-02 23:45:26 -0700442 pending_encoder_reconfiguration_(false),
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000443 pending_encoder_creation_(false),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200444 crop_width_(0),
445 crop_height_(0),
perkj26091b12016-09-01 01:17:40 -0700446 encoder_start_bitrate_bps_(0),
Pera48ddb72016-09-29 11:48:50 +0200447 max_data_payload_length_(0),
pbos@webrtc.org143451d2015-03-18 14:40:03 +0000448 last_observed_bitrate_bps_(0),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000449 encoder_paused_and_dropped_frame_(false),
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100450 clock_(clock),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700451 degradation_preference_(DegradationPreference::DISABLED),
Yuwei Huangd9f99c12017-10-24 15:40:52 -0700452 posted_frames_waiting_for_encode_(0),
perkj26091b12016-09-01 01:17:40 -0700453 last_captured_timestamp_(0),
454 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
455 clock_->TimeInMilliseconds()),
asapersson6ffb67d2016-09-12 00:10:45 -0700456 last_frame_log_ms_(clock_->TimeInMilliseconds()),
457 captured_frame_count_(0),
458 dropped_frame_count_(0),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200459 pending_frame_post_time_us_(0),
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100460 accumulated_update_rect_{0, 0, 0, 0},
sprang1a646ee2016-12-01 06:34:11 -0800461 bitrate_observer_(nullptr),
Erik Språng6a7baa72019-02-26 18:31:00 +0100462 last_framerate_fps_(0),
Niels Möller6bb5ab92019-01-11 11:11:10 +0100463 force_disable_frame_dropper_(false),
464 input_framerate_(kFrameRateAvergingWindowSizeMs, 1000),
465 pending_frame_drops_(0),
Erik Språngd7329ca2019-02-21 21:19:53 +0100466 next_frame_types_(1, kVideoFrameDelta),
Erik Språng6a7baa72019-02-26 18:31:00 +0100467 frame_encoder_timer_(this),
468 experiment_groups_(GetExperimentGroups()),
Sebastian Jansson74682c12019-03-01 11:50:20 +0100469 encoder_queue_(task_queue_factory->CreateTaskQueue(
470 "EncoderQueue",
471 TaskQueueFactory::Priority::NORMAL)) {
Niels Möller213618e2018-07-24 09:29:58 +0200472 RTC_DCHECK(encoder_stats_observer);
Niels Möller73f29cb2018-01-31 16:09:31 +0100473 RTC_DCHECK(overuse_detector_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100474 RTC_DCHECK_GE(number_of_cores, 1);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000475}
476
mflodmancc3d4422017-08-03 08:27:51 -0700477VideoStreamEncoder::~VideoStreamEncoder() {
perkja49cbd32016-09-16 07:53:41 -0700478 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700479 RTC_DCHECK(shutdown_event_.Wait(0))
480 << "Must call ::Stop() before destruction.";
481}
482
mflodmancc3d4422017-08-03 08:27:51 -0700483void VideoStreamEncoder::Stop() {
perkja49cbd32016-09-16 07:53:41 -0700484 RTC_DCHECK_RUN_ON(&thread_checker_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700485 source_proxy_->SetSource(nullptr, DegradationPreference());
perkja49cbd32016-09-16 07:53:41 -0700486 encoder_queue_.PostTask([this] {
487 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangfda496a2017-06-15 04:21:07 -0700488 overuse_detector_->StopCheckForOveruse();
Erik Språngb7cb7b52019-02-26 15:52:33 +0100489 rate_allocator_ = nullptr;
sprang1a646ee2016-12-01 06:34:11 -0800490 bitrate_observer_ = nullptr;
Erik Språng6a7baa72019-02-26 18:31:00 +0100491 ReleaseEncoder();
kthelgason876222f2016-11-29 01:44:11 -0800492 quality_scaler_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700493 shutdown_event_.Set();
494 });
495
496 shutdown_event_.Wait(rtc::Event::kForever);
perkj26091b12016-09-01 01:17:40 -0700497}
498
Niels Möller0327c2d2018-05-21 14:09:31 +0200499void VideoStreamEncoder::SetBitrateAllocationObserver(
sprang1a646ee2016-12-01 06:34:11 -0800500 VideoBitrateAllocationObserver* bitrate_observer) {
501 RTC_DCHECK_RUN_ON(&thread_checker_);
502 encoder_queue_.PostTask([this, bitrate_observer] {
503 RTC_DCHECK_RUN_ON(&encoder_queue_);
504 RTC_DCHECK(!bitrate_observer_);
505 bitrate_observer_ = bitrate_observer;
506 });
507}
508
mflodmancc3d4422017-08-03 08:27:51 -0700509void VideoStreamEncoder::SetSource(
perkj803d97f2016-11-01 11:45:46 -0700510 rtc::VideoSourceInterface<VideoFrame>* source,
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700511 const DegradationPreference& degradation_preference) {
perkja49cbd32016-09-16 07:53:41 -0700512 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj803d97f2016-11-01 11:45:46 -0700513 source_proxy_->SetSource(source, degradation_preference);
514 encoder_queue_.PostTask([this, degradation_preference] {
515 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -0700516 if (degradation_preference_ != degradation_preference) {
517 // Reset adaptation state, so that we're not tricked into thinking there's
518 // an already pending request of the same type.
519 last_adaptation_request_.reset();
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700520 if (degradation_preference == DegradationPreference::BALANCED ||
521 degradation_preference_ == DegradationPreference::BALANCED) {
asaperssonf7e294d2017-06-13 23:25:22 -0700522 // TODO(asapersson): Consider removing |adapt_counters_| map and use one
523 // AdaptCounter for all modes.
524 source_proxy_->ResetPixelFpsCount();
525 adapt_counters_.clear();
526 }
sprangc5d62e22017-04-02 23:53:04 -0700527 }
sprangb1ca0732017-02-01 08:38:12 -0800528 degradation_preference_ = degradation_preference;
Niels Möller4db138e2018-04-19 09:04:13 +0200529
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000530 if (encoder_)
Erik Språng7ca375c2019-02-06 16:20:17 +0100531 ConfigureQualityScaler(encoder_->GetEncoderInfo());
Niels Möller4db138e2018-04-19 09:04:13 +0200532
Niels Möller7dc26b72017-12-06 10:27:48 +0100533 if (!IsFramerateScalingEnabled(degradation_preference) &&
534 max_framerate_ != -1) {
535 // If frame rate scaling is no longer allowed, remove any potential
536 // allowance for longer frame intervals.
537 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
538 }
perkj803d97f2016-11-01 11:45:46 -0700539 });
perkja49cbd32016-09-16 07:53:41 -0700540}
541
mflodmancc3d4422017-08-03 08:27:51 -0700542void VideoStreamEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
perkj803d97f2016-11-01 11:45:46 -0700543 source_proxy_->SetWantsRotationApplied(rotation_applied);
perkj26091b12016-09-01 01:17:40 -0700544 encoder_queue_.PostTask([this, sink] {
545 RTC_DCHECK_RUN_ON(&encoder_queue_);
546 sink_ = sink;
547 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000548}
549
mflodmancc3d4422017-08-03 08:27:51 -0700550void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
perkj26091b12016-09-01 01:17:40 -0700551 encoder_queue_.PostTask([this, start_bitrate_bps] {
552 RTC_DCHECK_RUN_ON(&encoder_queue_);
553 encoder_start_bitrate_bps_ = start_bitrate_bps;
554 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000555}
Peter Boström00b9d212016-05-19 16:59:03 +0200556
mflodmancc3d4422017-08-03 08:27:51 -0700557void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200558 size_t max_data_payload_length) {
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100559 // TODO(srte): This struct should be replaced by a lambda with move capture
560 // when C++14 lambda is allowed.
561 struct ConfigureEncoderTask {
562 void operator()() {
Yves Gerey665174f2018-06-19 15:03:05 +0200563 encoder->ConfigureEncoderOnTaskQueue(std::move(config),
564 max_data_payload_length);
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100565 }
566 VideoStreamEncoder* encoder;
567 VideoEncoderConfig config;
568 size_t max_data_payload_length;
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100569 };
Yves Gerey665174f2018-06-19 15:03:05 +0200570 encoder_queue_.PostTask(
571 ConfigureEncoderTask{this, std::move(config), max_data_payload_length});
perkj26091b12016-09-01 01:17:40 -0700572}
573
mflodmancc3d4422017-08-03 08:27:51 -0700574void VideoStreamEncoder::ConfigureEncoderOnTaskQueue(
575 VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200576 size_t max_data_payload_length) {
perkj26091b12016-09-01 01:17:40 -0700577 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700578 RTC_DCHECK(sink_);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100579 RTC_LOG(LS_INFO) << "ConfigureEncoder requested.";
Pera48ddb72016-09-29 11:48:50 +0200580
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000581 pending_encoder_creation_ =
Erik Språngd7329ca2019-02-21 21:19:53 +0100582 (!encoder_ || encoder_config_.video_format != config.video_format ||
583 max_data_payload_length_ != max_data_payload_length);
Pera48ddb72016-09-29 11:48:50 +0200584 encoder_config_ = std::move(config);
Erik Språngd7329ca2019-02-21 21:19:53 +0100585 max_data_payload_length_ = max_data_payload_length;
perkjfa10b552016-10-02 23:45:26 -0700586 pending_encoder_reconfiguration_ = true;
Pera48ddb72016-09-29 11:48:50 +0200587
perkjfa10b552016-10-02 23:45:26 -0700588 // Reconfigure the encoder now if the encoder has an internal source or
Per21d45d22016-10-30 21:37:57 +0100589 // if the frame resolution is known. Otherwise, the reconfiguration is
590 // deferred until the next frame to minimize the number of reconfigurations.
591 // The codec configuration depends on incoming video frame size.
592 if (last_frame_info_) {
593 ReconfigureEncoder();
Erik Språngd7329ca2019-02-21 21:19:53 +0100594 } else {
595 codec_info_ = settings_.encoder_factory->QueryVideoEncoder(
596 encoder_config_.video_format);
597 if (HasInternalSource()) {
598 last_frame_info_ = VideoFrameInfo(176, 144, false);
599 ReconfigureEncoder();
600 }
perkjfa10b552016-10-02 23:45:26 -0700601 }
602}
perkj26091b12016-09-01 01:17:40 -0700603
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800604// TODO(bugs.webrtc.org/8807): Currently this always does a hard
605// reconfiguration, but this isn't always necessary. Add in logic to only update
606// the VideoBitrateAllocator and call OnEncoderConfigurationChanged with a
607// "soft" reconfiguration.
mflodmancc3d4422017-08-03 08:27:51 -0700608void VideoStreamEncoder::ReconfigureEncoder() {
perkjfa10b552016-10-02 23:45:26 -0700609 RTC_DCHECK(pending_encoder_reconfiguration_);
610 std::vector<VideoStream> streams =
611 encoder_config_.video_stream_factory->CreateEncoderStreams(
612 last_frame_info_->width, last_frame_info_->height, encoder_config_);
perkj26091b12016-09-01 01:17:40 -0700613
ilnik6b826ef2017-06-16 06:53:48 -0700614 // TODO(ilnik): If configured resolution is significantly less than provided,
615 // e.g. because there are not enough SSRCs for all simulcast streams,
616 // signal new resolutions via SinkWants to video source.
617
618 // Stream dimensions may be not equal to given because of a simulcast
619 // restrictions.
Florent Castelli450b5482018-11-29 17:32:47 +0100620 auto highest_stream = std::max_element(
621 streams.begin(), streams.end(),
622 [](const webrtc::VideoStream& a, const webrtc::VideoStream& b) {
623 return std::tie(a.width, a.height) < std::tie(b.width, b.height);
624 });
625 int highest_stream_width = static_cast<int>(highest_stream->width);
626 int highest_stream_height = static_cast<int>(highest_stream->height);
ilnik6b826ef2017-06-16 06:53:48 -0700627 // Dimension may be reduced to be, e.g. divisible by 4.
628 RTC_CHECK_GE(last_frame_info_->width, highest_stream_width);
629 RTC_CHECK_GE(last_frame_info_->height, highest_stream_height);
630 crop_width_ = last_frame_info_->width - highest_stream_width;
631 crop_height_ = last_frame_info_->height - highest_stream_height;
632
Erik Språng08127a92016-11-16 16:41:30 +0100633 VideoCodec codec;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800634 if (!VideoCodecInitializer::SetupCodec(encoder_config_, streams, &codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100635 RTC_LOG(LS_ERROR) << "Failed to create encoder configuration.";
Erik Språng08127a92016-11-16 16:41:30 +0100636 }
perkjfa10b552016-10-02 23:45:26 -0700637
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800638 rate_allocator_ =
639 settings_.bitrate_allocator_factory->CreateVideoBitrateAllocator(codec);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800640
“Michael277a6562018-06-01 14:09:19 -0500641 // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9.
642 if (encoder_config_.codec_type == kVideoCodecVP9) {
“Michael277a6562018-06-01 14:09:19 -0500643 // Lower max bitrate to the level codec actually can produce.
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100644 streams[0].max_bitrate_bps = std::min<int>(
645 streams[0].max_bitrate_bps, SvcRateAllocator::GetMaxBitrateBps(codec));
“Michael277a6562018-06-01 14:09:19 -0500646 streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100647 // target_bitrate_bps specifies the maximum padding bitrate.
“Michael277a6562018-06-01 14:09:19 -0500648 streams[0].target_bitrate_bps =
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100649 SvcRateAllocator::GetPaddingBitrateBps(codec);
“Michael277a6562018-06-01 14:09:19 -0500650 }
651
perkjfa10b552016-10-02 23:45:26 -0700652 codec.startBitrate =
653 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
654 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
655 codec.expect_encode_from_texture = last_frame_info_->is_texture;
Erik Språngd7329ca2019-02-21 21:19:53 +0100656 // Make sure the start bit rate is sane...
657 RTC_DCHECK_LE(codec.startBitrate, 1000000);
sprangfda496a2017-06-15 04:21:07 -0700658 max_framerate_ = codec.maxFramerate;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200659
660 // Inform source about max configured framerate.
661 int max_framerate = 0;
662 for (const auto& stream : streams) {
663 max_framerate = std::max(stream.max_framerate, max_framerate);
664 }
665 source_proxy_->SetMaxFramerate(max_framerate);
Stefan Holmere5904162015-03-26 11:11:06 +0100666
Erik Språngb7cb7b52019-02-26 15:52:33 +0100667 if (codec.maxBitrate == 0) {
668 // max is one bit per pixel
669 codec.maxBitrate =
670 (static_cast<int>(codec.height) * static_cast<int>(codec.width) *
671 static_cast<int>(codec.maxFramerate)) /
672 1000;
673 if (codec.startBitrate > codec.maxBitrate) {
674 // But if the user tries to set a higher start bit rate we will
675 // increase the max accordingly.
676 codec.maxBitrate = codec.startBitrate;
677 }
678 }
679
680 if (codec.startBitrate > codec.maxBitrate) {
681 codec.startBitrate = codec.maxBitrate;
682 }
683
684 // Reset (release existing encoder) if one exists and anything except
685 // start bitrate or max framerate has changed. Don't call Release() if
686 // |pending_encoder_creation_| as that means this is a new encoder
687 // that has not yet been initialized.
688 const bool reset_required = RequiresEncoderReset(codec, send_codec_);
689 send_codec_ = codec;
690
Niels Möller4db138e2018-04-19 09:04:13 +0200691 // Keep the same encoder, as long as the video_format is unchanged.
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100692 // Encoder creation block is split in two since EncoderInfo needed to start
693 // CPU adaptation with the correct settings should be polled after
694 // encoder_->InitEncode().
Erik Språngb7cb7b52019-02-26 15:52:33 +0100695 bool success = true;
Erik Språng6a7baa72019-02-26 18:31:00 +0100696 if (pending_encoder_creation_ || reset_required) {
697 ReleaseEncoder();
698 if (pending_encoder_creation_) {
699 encoder_ = settings_.encoder_factory->CreateVideoEncoder(
700 encoder_config_.video_format);
701 // TODO(nisse): What to do if creating the encoder fails? Crash,
702 // or just discard incoming frames?
703 RTC_CHECK(encoder_);
704 codec_info_ = settings_.encoder_factory->QueryVideoEncoder(
705 encoder_config_.video_format);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100706 }
Erik Språng6a7baa72019-02-26 18:31:00 +0100707
708 if (encoder_->InitEncode(&send_codec_, number_of_cores_,
709 max_data_payload_length_ > 0
710 ? max_data_payload_length_
711 : kDefaultPayloadSize) != 0) {
712 RTC_LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
713 "codec type: "
714 << CodecTypeToPayloadString(send_codec_.codecType)
715 << " (" << send_codec_.codecType << ")";
716 ReleaseEncoder();
717 success = false;
718 } else {
719 encoder_initialized_ = true;
720 encoder_->RegisterEncodeCompleteCallback(this);
721 frame_encoder_timer_.OnEncoderInit(send_codec_, HasInternalSource());
722 }
723
724 frame_encoder_timer_.Reset();
Erik Språngb7cb7b52019-02-26 15:52:33 +0100725 }
Erik Språngd7329ca2019-02-21 21:19:53 +0100726
727 if (success) {
Erik Språngd7329ca2019-02-21 21:19:53 +0100728 next_frame_types_.clear();
729 next_frame_types_.resize(
730 std::max(static_cast<int>(codec.numberOfSimulcastStreams), 1),
731 kVideoFrameKey);
732 RTC_LOG(LS_VERBOSE) << " max bitrate " << codec.maxBitrate
733 << " start bitrate " << codec.startBitrate
734 << " max frame rate " << codec.maxFramerate
735 << " max payload size " << max_data_payload_length_;
736 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100737 RTC_LOG(LS_ERROR) << "Failed to configure encoder.";
Erik Språngb7cb7b52019-02-26 15:52:33 +0100738 rate_allocator_ = nullptr;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000739 }
Peter Boström905f8e72016-03-02 16:59:56 +0100740
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100741 if (pending_encoder_creation_) {
742 overuse_detector_->StopCheckForOveruse();
743 overuse_detector_->StartCheckForOveruse(
744 GetCpuOveruseOptions(
745 settings_, encoder_->GetEncoderInfo().is_hardware_accelerated),
746 this);
747 pending_encoder_creation_ = false;
748 }
749
Niels Möller6bb5ab92019-01-11 11:11:10 +0100750 int num_layers;
751 if (codec.codecType == kVideoCodecVP8) {
752 num_layers = codec.VP8()->numberOfTemporalLayers;
753 } else if (codec.codecType == kVideoCodecVP9) {
754 num_layers = codec.VP9()->numberOfTemporalLayers;
Johnny Lee1a1c52b2019-02-08 14:25:40 -0500755 } else if (codec.codecType == kVideoCodecH264) {
756 num_layers = codec.H264()->numberOfTemporalLayers;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100757 } else if (codec.codecType == kVideoCodecGeneric &&
758 codec.numberOfSimulcastStreams > 0) {
759 // This is mainly for unit testing, disabling frame dropping.
760 // TODO(sprang): Add a better way to disable frame dropping.
761 num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
762 } else {
763 num_layers = 1;
764 }
765
766 frame_dropper_.Reset();
767 frame_dropper_.SetRates(codec.startBitrate, max_framerate_);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100768 // Force-disable frame dropper if either:
769 // * We have screensharing with layers.
770 // * "WebRTC-FrameDropper" field trial is "Disabled".
771 force_disable_frame_dropper_ =
772 field_trial::IsDisabled(kFrameDropperFieldTrial) ||
773 (num_layers > 1 && codec.mode == VideoCodecMode::kScreensharing);
774
Erik Språng7ca375c2019-02-06 16:20:17 +0100775 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
776 if (rate_control_settings_.UseEncoderBitrateAdjuster()) {
777 bitrate_adjuster_ = absl::make_unique<EncoderBitrateAdjuster>(codec);
778 bitrate_adjuster_->OnEncoderInfo(info);
779 }
780
Niels Möller6bb5ab92019-01-11 11:11:10 +0100781 if (rate_allocator_ && last_observed_bitrate_bps_ > 0) {
782 // We have a new rate allocator instance and already configured target
783 // bitrate. Update the rate allocation and notify observsers.
Erik Språngd7329ca2019-02-21 21:19:53 +0100784 const uint32_t framerate_fps = GetInputFramerateFps();
785 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(
786 last_observed_bitrate_bps_, framerate_fps),
787 framerate_fps);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100788 }
ilnik35b7de42017-03-15 04:24:21 -0700789
Niels Möller213618e2018-07-24 09:29:58 +0200790 encoder_stats_observer_->OnEncoderReconfigured(encoder_config_, streams);
Per512ecb32016-09-23 15:52:06 +0200791
perkjfa10b552016-10-02 23:45:26 -0700792 pending_encoder_reconfiguration_ = false;
Erik Språng08127a92016-11-16 16:41:30 +0100793
Pera48ddb72016-09-29 11:48:50 +0200794 sink_->OnEncoderConfigurationChanged(
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100795 std::move(streams), encoder_config_.content_type,
796 encoder_config_.min_transmit_bitrate_bps);
kthelgason876222f2016-11-29 01:44:11 -0800797
Niels Möller7dc26b72017-12-06 10:27:48 +0100798 // Get the current target framerate, ie the maximum framerate as specified by
799 // the current codec configuration, or any limit imposed by cpu adaption in
800 // maintain-resolution or balanced mode. This is used to make sure overuse
801 // detection doesn't needlessly trigger in low and/or variable framerate
802 // scenarios.
803 int target_framerate = std::min(
804 max_framerate_, source_proxy_->GetActiveSinkWants().max_framerate_fps);
805 overuse_detector_->OnTargetFramerateUpdated(target_framerate);
Niels Möller2d061182018-04-24 09:13:08 +0200806
Erik Språng7ca375c2019-02-06 16:20:17 +0100807 ConfigureQualityScaler(info);
kthelgason2bc68642017-02-07 07:02:22 -0800808}
809
Erik Språng7ca375c2019-02-06 16:20:17 +0100810void VideoStreamEncoder::ConfigureQualityScaler(
811 const VideoEncoder::EncoderInfo& encoder_info) {
kthelgason2bc68642017-02-07 07:02:22 -0800812 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +0100813 const auto scaling_settings = encoder_info.scaling_settings;
asapersson36e9eb42017-03-31 05:29:12 -0700814 const bool quality_scaling_allowed =
asapersson91914e22017-06-01 00:34:08 -0700815 IsResolutionScalingEnabled(degradation_preference_) &&
Niels Möller225c7872018-02-22 15:03:53 +0100816 scaling_settings.thresholds;
kthelgason3af6cc02017-03-22 00:25:28 -0700817
asapersson36e9eb42017-03-31 05:29:12 -0700818 if (quality_scaling_allowed) {
asapersson09f05612017-05-15 23:40:18 -0700819 if (quality_scaler_.get() == nullptr) {
820 // Quality scaler has not already been configured.
Niels Möller225c7872018-02-22 15:03:53 +0100821
Åsa Perssona945aee2018-04-24 16:53:25 +0200822 // Use experimental thresholds if available.
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200823 absl::optional<VideoEncoder::QpThresholds> experimental_thresholds;
Åsa Perssona945aee2018-04-24 16:53:25 +0200824 if (quality_scaling_experiment_enabled_) {
825 experimental_thresholds = QualityScalingExperiment::GetQpThresholds(
826 encoder_config_.codec_type);
827 }
Karl Wiberg918f50c2018-07-05 11:40:33 +0200828 // Since the interface is non-public, absl::make_unique can't do this
829 // upcast.
Niels Möller225c7872018-02-22 15:03:53 +0100830 AdaptationObserverInterface* observer = this;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200831 quality_scaler_ = absl::make_unique<QualityScaler>(
Åsa Perssona945aee2018-04-24 16:53:25 +0200832 observer, experimental_thresholds ? *experimental_thresholds
833 : *(scaling_settings.thresholds));
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200834 has_seen_first_significant_bwe_change_ = false;
835 initial_framedrop_ = 0;
kthelgason876222f2016-11-29 01:44:11 -0800836 }
837 } else {
838 quality_scaler_.reset(nullptr);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200839 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason876222f2016-11-29 01:44:11 -0800840 }
asapersson09f05612017-05-15 23:40:18 -0700841
Niels Möller213618e2018-07-24 09:29:58 +0200842 encoder_stats_observer_->OnAdaptationChanged(
843 VideoStreamEncoderObserver::AdaptationReason::kNone,
844 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000845}
846
mflodmancc3d4422017-08-03 08:27:51 -0700847void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
perkj26091b12016-09-01 01:17:40 -0700848 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_);
perkj26091b12016-09-01 01:17:40 -0700849 VideoFrame incoming_frame = video_frame;
850
851 // Local time in webrtc time base.
ilnik04f4d122017-06-19 07:18:55 -0700852 int64_t current_time_us = clock_->TimeInMicroseconds();
853 int64_t current_time_ms = current_time_us / rtc::kNumMicrosecsPerMillisec;
854 // In some cases, e.g., when the frame from decoder is fed to encoder,
855 // the timestamp may be set to the future. As the encoding pipeline assumes
856 // capture time to be less than present time, we should reset the capture
857 // timestamps here. Otherwise there may be issues with RTP send stream.
858 if (incoming_frame.timestamp_us() > current_time_us)
859 incoming_frame.set_timestamp_us(current_time_us);
perkj26091b12016-09-01 01:17:40 -0700860
861 // Capture time may come from clock with an offset and drift from clock_.
862 int64_t capture_ntp_time_ms;
nisse891419f2017-01-12 10:02:22 -0800863 if (video_frame.ntp_time_ms() > 0) {
perkj26091b12016-09-01 01:17:40 -0700864 capture_ntp_time_ms = video_frame.ntp_time_ms();
865 } else if (video_frame.render_time_ms() != 0) {
866 capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
867 } else {
nisse1c0dea82017-01-30 02:43:18 -0800868 capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
perkj26091b12016-09-01 01:17:40 -0700869 }
870 incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
871
872 // Convert NTP time, in ms, to RTP timestamp.
873 const int kMsToRtpTimestamp = 90;
874 incoming_frame.set_timestamp(
875 kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
876
877 if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
878 // We don't allow the same capture time for two frames, drop this one.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100879 RTC_LOG(LS_WARNING) << "Same/old NTP timestamp ("
880 << incoming_frame.ntp_time_ms()
881 << " <= " << last_captured_timestamp_
882 << ") for incoming frame. Dropping.";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100883 encoder_queue_.PostTask([this, incoming_frame]() {
884 RTC_DCHECK_RUN_ON(&encoder_queue_);
885 accumulated_update_rect_.Union(incoming_frame.update_rect());
886 });
perkj26091b12016-09-01 01:17:40 -0700887 return;
888 }
889
asapersson6ffb67d2016-09-12 00:10:45 -0700890 bool log_stats = false;
nisse1c0dea82017-01-30 02:43:18 -0800891 if (current_time_ms - last_frame_log_ms_ > kFrameLogIntervalMs) {
892 last_frame_log_ms_ = current_time_ms;
asapersson6ffb67d2016-09-12 00:10:45 -0700893 log_stats = true;
894 }
895
perkj26091b12016-09-01 01:17:40 -0700896 last_captured_timestamp_ = incoming_frame.ntp_time_ms();
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200897
898 int64_t post_time_us = rtc::TimeMicros();
899 ++posted_frames_waiting_for_encode_;
900
901 encoder_queue_.PostTask(
902 [this, incoming_frame, post_time_us, log_stats]() {
903 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller213618e2018-07-24 09:29:58 +0200904 encoder_stats_observer_->OnIncomingFrame(incoming_frame.width(),
905 incoming_frame.height());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200906 ++captured_frame_count_;
907 const int posted_frames_waiting_for_encode =
908 posted_frames_waiting_for_encode_.fetch_sub(1);
909 RTC_DCHECK_GT(posted_frames_waiting_for_encode, 0);
910 if (posted_frames_waiting_for_encode == 1) {
Sebastian Janssona3177052018-04-10 13:05:49 +0200911 MaybeEncodeVideoFrame(incoming_frame, post_time_us);
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200912 } else {
913 // There is a newer frame in flight. Do not encode this frame.
914 RTC_LOG(LS_VERBOSE)
915 << "Incoming frame dropped due to that the encoder is blocked.";
916 ++dropped_frame_count_;
Niels Möller213618e2018-07-24 09:29:58 +0200917 encoder_stats_observer_->OnFrameDropped(
918 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100919 accumulated_update_rect_.Union(incoming_frame.update_rect());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200920 }
921 if (log_stats) {
922 RTC_LOG(LS_INFO) << "Number of frames: captured "
923 << captured_frame_count_
924 << ", dropped (due to encoder blocked) "
925 << dropped_frame_count_ << ", interval_ms "
926 << kFrameLogIntervalMs;
927 captured_frame_count_ = 0;
928 dropped_frame_count_ = 0;
929 }
930 });
perkj26091b12016-09-01 01:17:40 -0700931}
932
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200933void VideoStreamEncoder::OnDiscardedFrame() {
Niels Möller213618e2018-07-24 09:29:58 +0200934 encoder_stats_observer_->OnFrameDropped(
935 VideoStreamEncoderObserver::DropReason::kSource);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200936}
937
mflodmancc3d4422017-08-03 08:27:51 -0700938bool VideoStreamEncoder::EncoderPaused() const {
perkj26091b12016-09-01 01:17:40 -0700939 RTC_DCHECK_RUN_ON(&encoder_queue_);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000940 // Pause video if paused by caller or as long as the network is down or the
941 // pacer queue has grown too large in buffered mode.
perkj57c21f92016-06-17 07:27:16 -0700942 // If the pacer queue has grown too large or the network is down,
perkjfea93092016-05-14 00:58:48 -0700943 // last_observed_bitrate_bps_ will be 0.
perkj26091b12016-09-01 01:17:40 -0700944 return last_observed_bitrate_bps_ == 0;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000945}
946
mflodmancc3d4422017-08-03 08:27:51 -0700947void VideoStreamEncoder::TraceFrameDropStart() {
perkj26091b12016-09-01 01:17:40 -0700948 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000949 // Start trace event only on the first frame after encoder is paused.
950 if (!encoder_paused_and_dropped_frame_) {
951 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
952 }
953 encoder_paused_and_dropped_frame_ = true;
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000954}
955
mflodmancc3d4422017-08-03 08:27:51 -0700956void VideoStreamEncoder::TraceFrameDropEnd() {
perkj26091b12016-09-01 01:17:40 -0700957 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000958 // End trace event on first frame after encoder resumes, if frame was dropped.
959 if (encoder_paused_and_dropped_frame_) {
960 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
961 }
962 encoder_paused_and_dropped_frame_ = false;
963}
964
Niels Möller6bb5ab92019-01-11 11:11:10 +0100965VideoBitrateAllocation
966VideoStreamEncoder::GetBitrateAllocationAndNotifyObserver(
967 const uint32_t target_bitrate_bps,
968 uint32_t framerate_fps) {
969 // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
970 // might cap the bitrate to the min bitrate configured.
971 VideoBitrateAllocation bitrate_allocation;
972 if (rate_allocator_ && target_bitrate_bps > 0) {
973 bitrate_allocation =
974 rate_allocator_->GetAllocation(target_bitrate_bps, framerate_fps);
975 }
976
977 if (bitrate_observer_ && bitrate_allocation.get_sum_bps() > 0) {
978 bitrate_observer_->OnBitrateAllocationUpdated(bitrate_allocation);
979 }
980
Erik Språng7ca375c2019-02-06 16:20:17 +0100981 if (bitrate_adjuster_) {
Erik Språng0e1a1f92019-02-18 18:45:13 +0100982 VideoBitrateAllocation adjusted_allocation =
983 bitrate_adjuster_->AdjustRateAllocation(bitrate_allocation,
984 framerate_fps);
985 RTC_LOG(LS_VERBOSE) << "Adjusting allocation, fps = " << framerate_fps
986 << ", from " << bitrate_allocation.ToString() << ", to "
987 << adjusted_allocation.ToString();
988 return adjusted_allocation;
Erik Språng7ca375c2019-02-06 16:20:17 +0100989 }
Niels Möller6bb5ab92019-01-11 11:11:10 +0100990 return bitrate_allocation;
991}
992
993uint32_t VideoStreamEncoder::GetInputFramerateFps() {
994 const uint32_t default_fps = max_framerate_ != -1 ? max_framerate_ : 30;
Erik Språngd7329ca2019-02-21 21:19:53 +0100995 absl::optional<uint32_t> input_fps =
996 input_framerate_.Rate(clock_->TimeInMilliseconds());
997 if (!input_fps || *input_fps == 0) {
998 return default_fps;
999 }
1000 return *input_fps;
1001}
1002
1003void VideoStreamEncoder::SetEncoderRates(
1004 const VideoBitrateAllocation& bitrate_allocation,
1005 uint32_t framerate_fps) {
Erik Språng6a7baa72019-02-26 18:31:00 +01001006 if (!encoder_) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001007 return;
1008 }
1009
1010 // |bitrate_allocation| is 0 it means that the network is down or the send
1011 // pacer is full. We currently only report this if the encoder has an internal
1012 // source. If the encoder does not have an internal source, higher levels
1013 // are expected to not call AddVideoFrame. We do this since its unclear
1014 // how current encoder implementations behave when given a zero target
1015 // bitrate.
1016 // TODO(perkj): Make sure all known encoder implementations handle zero
1017 // target bitrate and remove this check.
1018 if (!HasInternalSource() && bitrate_allocation.get_sum_bps() == 0) {
1019 return;
1020 }
1021
1022 RTC_DCHECK_GT(framerate_fps, 0);
Erik Språng6a7baa72019-02-26 18:31:00 +01001023 if (bitrate_allocation != last_bitrate_allocation_ ||
1024 framerate_fps != last_framerate_fps_) {
1025 int res = encoder_->SetRateAllocation(bitrate_allocation, framerate_fps);
1026 if (res != 0) {
1027 RTC_LOG(LS_WARNING) << "Error set encoder rate (total bitrate bps = "
1028 << bitrate_allocation.get_sum_bps()
1029 << ", framerate = " << framerate_fps << "): " << res;
1030 }
1031
1032 frame_encoder_timer_.OnSetRates(bitrate_allocation, framerate_fps);
1033 }
1034
1035 last_bitrate_allocation_ = bitrate_allocation;
1036 last_framerate_fps_ = framerate_fps;
Niels Möller6bb5ab92019-01-11 11:11:10 +01001037}
1038
Sebastian Janssona3177052018-04-10 13:05:49 +02001039void VideoStreamEncoder::MaybeEncodeVideoFrame(const VideoFrame& video_frame,
1040 int64_t time_when_posted_us) {
perkj26091b12016-09-01 01:17:40 -07001041 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -08001042
Per21d45d22016-10-30 21:37:57 +01001043 if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
perkjfa10b552016-10-02 23:45:26 -07001044 video_frame.height() != last_frame_info_->height ||
perkjfa10b552016-10-02 23:45:26 -07001045 video_frame.is_texture() != last_frame_info_->is_texture) {
1046 pending_encoder_reconfiguration_ = true;
Oskar Sundbom8e07c132018-01-08 16:45:42 +01001047 last_frame_info_ = VideoFrameInfo(video_frame.width(), video_frame.height(),
1048 video_frame.is_texture());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001049 RTC_LOG(LS_INFO) << "Video frame parameters changed: dimensions="
1050 << last_frame_info_->width << "x"
1051 << last_frame_info_->height
1052 << ", texture=" << last_frame_info_->is_texture << ".";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001053 // Force full frame update, since resolution has changed.
1054 accumulated_update_rect_ =
1055 VideoFrame::UpdateRect{0, 0, video_frame.width(), video_frame.height()};
perkjfa10b552016-10-02 23:45:26 -07001056 }
1057
Niels Möller4db138e2018-04-19 09:04:13 +02001058 // We have to create then encoder before the frame drop logic,
1059 // because the latter depends on encoder_->GetScalingSettings.
1060 // According to the testcase
1061 // InitialFrameDropOffWhenEncoderDisabledScaling, the return value
1062 // from GetScalingSettings should enable or disable the frame drop.
1063
Erik Språnga8d48ab2019-02-08 14:17:40 +01001064 // Update input frame rate before we start using it. If we update it after
Erik Språngd7329ca2019-02-21 21:19:53 +01001065 // any potential frame drop we are going to artificially increase frame sizes.
1066 // Poll the rate before updating, otherwise we risk the rate being estimated
1067 // a little too high at the start of the call when then window is small.
Niels Möller6bb5ab92019-01-11 11:11:10 +01001068 uint32_t framerate_fps = GetInputFramerateFps();
Erik Språngd7329ca2019-02-21 21:19:53 +01001069 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
Niels Möller6bb5ab92019-01-11 11:11:10 +01001070
Niels Möller4db138e2018-04-19 09:04:13 +02001071 int64_t now_ms = clock_->TimeInMilliseconds();
1072 if (pending_encoder_reconfiguration_) {
1073 ReconfigureEncoder();
1074 last_parameters_update_ms_.emplace(now_ms);
1075 } else if (!last_parameters_update_ms_ ||
1076 now_ms - *last_parameters_update_ms_ >=
1077 vcm::VCMProcessTimer::kDefaultProcessIntervalMs) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001078 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(
1079 last_observed_bitrate_bps_, framerate_fps),
1080 framerate_fps);
Niels Möller4db138e2018-04-19 09:04:13 +02001081 last_parameters_update_ms_.emplace(now_ms);
1082 }
1083
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001084 // Because pending frame will be dropped in any case, we need to
1085 // remember its updated region.
1086 if (pending_frame_) {
1087 encoder_stats_observer_->OnFrameDropped(
1088 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1089 accumulated_update_rect_.Union(pending_frame_->update_rect());
1090 }
1091
Sebastian Janssona3177052018-04-10 13:05:49 +02001092 if (DropDueToSize(video_frame.size())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001093 RTC_LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
Åsa Persson875841d2018-01-08 08:49:53 +01001094 int count = GetConstAdaptCounter().ResolutionCount(kQuality);
kthelgason2bc68642017-02-07 07:02:22 -08001095 AdaptDown(kQuality);
Åsa Persson875841d2018-01-08 08:49:53 +01001096 if (GetConstAdaptCounter().ResolutionCount(kQuality) > count) {
Niels Möller213618e2018-07-24 09:29:58 +02001097 encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
Åsa Persson875841d2018-01-08 08:49:53 +01001098 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001099 ++initial_framedrop_;
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001100 // Storing references to a native buffer risks blocking frame capture.
1101 if (video_frame.video_frame_buffer()->type() !=
1102 VideoFrameBuffer::Type::kNative) {
1103 pending_frame_ = video_frame;
1104 pending_frame_post_time_us_ = time_when_posted_us;
1105 } else {
1106 // Ensure that any previously stored frame is dropped.
1107 pending_frame_.reset();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001108 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001109 }
kthelgason2bc68642017-02-07 07:02:22 -08001110 return;
1111 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001112 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason2bc68642017-02-07 07:02:22 -08001113
perkj26091b12016-09-01 01:17:40 -07001114 if (EncoderPaused()) {
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001115 // Storing references to a native buffer risks blocking frame capture.
1116 if (video_frame.video_frame_buffer()->type() !=
1117 VideoFrameBuffer::Type::kNative) {
1118 if (pending_frame_)
1119 TraceFrameDropStart();
1120 pending_frame_ = video_frame;
1121 pending_frame_post_time_us_ = time_when_posted_us;
1122 } else {
1123 // Ensure that any previously stored frame is dropped.
1124 pending_frame_.reset();
Sebastian Janssona3177052018-04-10 13:05:49 +02001125 TraceFrameDropStart();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001126 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001127 }
perkj26091b12016-09-01 01:17:40 -07001128 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001129 }
Sebastian Janssona3177052018-04-10 13:05:49 +02001130
1131 pending_frame_.reset();
Niels Möller6bb5ab92019-01-11 11:11:10 +01001132
1133 frame_dropper_.Leak(framerate_fps);
1134 // Frame dropping is enabled iff frame dropping is not force-disabled, and
1135 // rate controller is not trusted.
1136 const bool frame_dropping_enabled =
1137 !force_disable_frame_dropper_ &&
1138 !encoder_info_.has_trusted_rate_controller;
1139 frame_dropper_.Enable(frame_dropping_enabled);
1140 if (frame_dropping_enabled && frame_dropper_.DropFrame()) {
1141 RTC_LOG(LS_VERBOSE) << "Drop Frame: "
1142 << "target bitrate " << last_observed_bitrate_bps_
1143 << ", input frame rate " << framerate_fps;
1144 OnDroppedFrame(
1145 EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001146 accumulated_update_rect_.Union(video_frame.update_rect());
Niels Möller6bb5ab92019-01-11 11:11:10 +01001147 return;
1148 }
1149
Sebastian Janssona3177052018-04-10 13:05:49 +02001150 EncodeVideoFrame(video_frame, time_when_posted_us);
1151}
1152
1153void VideoStreamEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
1154 int64_t time_when_posted_us) {
1155 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -07001156 TraceFrameDropEnd();
niklase@google.com470e71d2011-07-07 08:21:25 +00001157
ilnik6b826ef2017-06-16 06:53:48 -07001158 VideoFrame out_frame(video_frame);
1159 // Crop frame if needed.
1160 if (crop_width_ > 0 || crop_height_ > 0) {
1161 int cropped_width = video_frame.width() - crop_width_;
1162 int cropped_height = video_frame.height() - crop_height_;
1163 rtc::scoped_refptr<I420Buffer> cropped_buffer =
1164 I420Buffer::Create(cropped_width, cropped_height);
1165 // TODO(ilnik): Remove scaling if cropping is too big, as it should never
1166 // happen after SinkWants signaled correctly from ReconfigureEncoder.
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001167 VideoFrame::UpdateRect update_rect = video_frame.update_rect();
ilnik6b826ef2017-06-16 06:53:48 -07001168 if (crop_width_ < 4 && crop_height_ < 4) {
1169 cropped_buffer->CropAndScaleFrom(
1170 *video_frame.video_frame_buffer()->ToI420(), crop_width_ / 2,
1171 crop_height_ / 2, cropped_width, cropped_height);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001172 update_rect.offset_x -= crop_width_ / 2;
1173 update_rect.offset_y -= crop_height_ / 2;
1174 update_rect.Intersect(
1175 VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height});
1176
ilnik6b826ef2017-06-16 06:53:48 -07001177 } else {
1178 cropped_buffer->ScaleFrom(
1179 *video_frame.video_frame_buffer()->ToI420().get());
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001180 update_rect = VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height};
ilnik6b826ef2017-06-16 06:53:48 -07001181 }
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001182 out_frame = VideoFrame::Builder()
1183 .set_video_frame_buffer(cropped_buffer)
1184 .set_timestamp_rtp(video_frame.timestamp())
1185 .set_timestamp_ms(video_frame.render_time_ms())
1186 .set_rotation(video_frame.rotation())
1187 .set_id(video_frame.id())
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001188 .set_update_rect(update_rect)
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001189 .build();
ilnik6b826ef2017-06-16 06:53:48 -07001190 out_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001191 // Since accumulated_update_rect_ is constructed before cropping,
1192 // we can't trust it. If any changes were pending, we invalidate whole
1193 // frame here.
1194 if (!accumulated_update_rect_.IsEmpty()) {
1195 accumulated_update_rect_ =
1196 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()};
1197 }
1198 }
1199
1200 if (!accumulated_update_rect_.IsEmpty()) {
1201 accumulated_update_rect_.Union(out_frame.update_rect());
1202 accumulated_update_rect_.Intersect(
1203 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()});
1204 out_frame.set_update_rect(accumulated_update_rect_);
1205 accumulated_update_rect_.MakeEmptyUpdate();
ilnik6b826ef2017-06-16 06:53:48 -07001206 }
1207
Magnus Jedvert26679d62015-04-07 14:07:41 +02001208 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +00001209 "Encode");
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +00001210
Niels Möller7dc26b72017-12-06 10:27:48 +01001211 overuse_detector_->FrameCaptured(out_frame, time_when_posted_us);
perkjd52063f2016-09-07 06:32:18 -07001212
Erik Språnge2fd86a2018-10-24 11:32:39 +02001213 // Encoder metadata needs to be updated before encode complete callback.
1214 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
1215 if (info.implementation_name != encoder_info_.implementation_name) {
1216 encoder_stats_observer_->OnEncoderImplementationChanged(
1217 info.implementation_name);
Erik Språng7ca375c2019-02-06 16:20:17 +01001218 if (bitrate_adjuster_) {
1219 // Encoder implementation changed, reset overshoot detector states.
1220 bitrate_adjuster_->Reset();
1221 }
Erik Språnge2fd86a2018-10-24 11:32:39 +02001222 }
Erik Språng7ca375c2019-02-06 16:20:17 +01001223
1224 if (bitrate_adjuster_) {
1225 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
1226 if (info.fps_allocation[si] != encoder_info_.fps_allocation[si]) {
1227 bitrate_adjuster_->OnEncoderInfo(info);
1228 break;
1229 }
1230 }
1231 }
1232
Erik Språnge2fd86a2018-10-24 11:32:39 +02001233 encoder_info_ = info;
Erik Språngb7cb7b52019-02-26 15:52:33 +01001234 RTC_DCHECK_EQ(send_codec_.width, out_frame.width());
1235 RTC_DCHECK_EQ(send_codec_.height, out_frame.height());
Erik Språngd7329ca2019-02-21 21:19:53 +01001236 const VideoFrameBuffer::Type buffer_type =
1237 out_frame.video_frame_buffer()->type();
1238 const bool is_buffer_type_supported =
1239 buffer_type == VideoFrameBuffer::Type::kI420 ||
1240 (buffer_type == VideoFrameBuffer::Type::kNative &&
Erik Språng6a7baa72019-02-26 18:31:00 +01001241 info.supports_native_handle);
Erik Språngd7329ca2019-02-21 21:19:53 +01001242
1243 if (!is_buffer_type_supported) {
1244 // This module only supports software encoding.
1245 rtc::scoped_refptr<I420BufferInterface> converted_buffer(
1246 out_frame.video_frame_buffer()->ToI420());
1247
1248 if (!converted_buffer) {
1249 RTC_LOG(LS_ERROR) << "Frame conversion failed, dropping frame.";
1250 return;
1251 }
1252
1253 // UpdatedRect is not propagated because buffer was converted,
1254 // therefore we can't guarantee that pixels outside of UpdateRect didn't
1255 // change comparing to the previous frame.
1256 out_frame = VideoFrame::Builder()
1257 .set_video_frame_buffer(converted_buffer)
1258 .set_timestamp_rtp(out_frame.timestamp())
1259 .set_timestamp_ms(out_frame.render_time_ms())
1260 .set_rotation(out_frame.rotation())
1261 .set_id(out_frame.id())
1262 .build();
1263 }
Erik Språng6a7baa72019-02-26 18:31:00 +01001264
1265 TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp",
1266 out_frame.timestamp());
1267
1268 frame_encoder_timer_.OnEncodeStarted(out_frame.timestamp(),
1269 out_frame.render_time_ms());
1270
Niels Möllerc8d2e732019-03-06 12:00:33 +01001271 const int32_t encode_status = encoder_->Encode(out_frame, &next_frame_types_);
Erik Språng6a7baa72019-02-26 18:31:00 +01001272
Erik Språngd7329ca2019-02-21 21:19:53 +01001273 if (encode_status < 0) {
1274 RTC_LOG(LS_ERROR) << "Failed to encode frame. Error code: "
1275 << encode_status;
1276 return;
1277 }
1278
1279 for (auto& it : next_frame_types_) {
1280 it = kVideoFrameDelta;
1281 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001282}
niklase@google.com470e71d2011-07-07 08:21:25 +00001283
mflodmancc3d4422017-08-03 08:27:51 -07001284void VideoStreamEncoder::SendKeyFrame() {
perkj26091b12016-09-01 01:17:40 -07001285 if (!encoder_queue_.IsCurrent()) {
1286 encoder_queue_.PostTask([this] { SendKeyFrame(); });
1287 return;
1288 }
1289 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller1c9aa1e2018-02-16 10:27:23 +01001290 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
Erik Språngd7329ca2019-02-21 21:19:53 +01001291 RTC_DCHECK(!next_frame_types_.empty());
1292 next_frame_types_[0] = kVideoFrameKey;
1293 if (HasInternalSource()) {
1294 // Try to request the frame if we have an external encoder with
1295 // internal source since AddVideoFrame never will be called.
Erik Språng6a7baa72019-02-26 18:31:00 +01001296
1297 // TODO(nisse): Used only with internal source. Delete as soon as
1298 // that feature is removed. The only implementation I've been able
1299 // to find ignores what's in the frame. With one exception: It seems
1300 // a few test cases, e.g.,
1301 // VideoSendStreamTest.VideoSendStreamStopSetEncoderRateToZero, set
1302 // internal_source to true and use FakeEncoder. And the latter will
1303 // happily encode this 1x1 frame and pass it on down the pipeline.
1304 if (encoder_->Encode(VideoFrame::Builder()
1305 .set_video_frame_buffer(I420Buffer::Create(1, 1))
1306 .set_rotation(kVideoRotation_0)
1307 .set_timestamp_us(0)
1308 .build(),
Erik Språng6a7baa72019-02-26 18:31:00 +01001309 &next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001310 // Try to remove just-performed keyframe request, if stream still exists.
1311 next_frame_types_[0] = kVideoFrameDelta;
1312 }
1313 }
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00001314}
1315
mflodmancc3d4422017-08-03 08:27:51 -07001316EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001317 const EncodedImage& encoded_image,
1318 const CodecSpecificInfo* codec_specific_info,
1319 const RTPFragmentationHeader* fragmentation) {
Erik Språng6a7baa72019-02-26 18:31:00 +01001320 const int64_t time_sent_us = rtc::TimeMicros();
1321
1322 TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded",
1323 "timestamp", encoded_image.Timestamp());
1324 const size_t spatial_idx = encoded_image.SpatialIndex().value_or(0);
1325 EncodedImage image_copy(encoded_image);
1326
1327 frame_encoder_timer_.FillTimingInfo(
1328 spatial_idx, &image_copy, time_sent_us / rtc::kNumMicrosecsPerMillisec);
1329
1330 // Piggyback ALR experiment group id and simulcast id into the content type.
1331 const uint8_t experiment_id =
1332 experiment_groups_[videocontenttypehelpers::IsScreenshare(
1333 image_copy.content_type_)];
1334
1335 // TODO(ilnik): This will force content type extension to be present even
1336 // for realtime video. At the expense of miniscule overhead we will get
1337 // sliced receive statistics.
1338 RTC_CHECK(videocontenttypehelpers::SetExperimentId(&image_copy.content_type_,
1339 experiment_id));
1340 // We count simulcast streams from 1 on the wire. That's why we set simulcast
1341 // id in content type to +1 of that is actual simulcast index. This is because
1342 // value 0 on the wire is reserved for 'no simulcast stream specified'.
1343 RTC_CHECK(videocontenttypehelpers::SetSimulcastId(
1344 &image_copy.content_type_, static_cast<uint8_t>(spatial_idx + 1)));
1345
perkj26091b12016-09-01 01:17:40 -07001346 // Encoded is called on whatever thread the real encoder implementation run
1347 // on. In the case of hardware encoders, there might be several encoders
1348 // running in parallel on different threads.
Erik Språng6a7baa72019-02-26 18:31:00 +01001349 encoder_stats_observer_->OnSendEncodedImage(image_copy, codec_specific_info);
sprang3911c262016-04-15 01:24:14 -07001350
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001351 EncodedImageCallback::Result result =
Erik Språng6a7baa72019-02-26 18:31:00 +01001352 sink_->OnEncodedImage(image_copy, codec_specific_info, fragmentation);
perkjbc75d972016-05-02 06:31:25 -07001353
Erik Språng7ca375c2019-02-06 16:20:17 +01001354 // We are only interested in propagating the meta-data about the image, not
1355 // encoded data itself, to the post encode function. Since we cannot be sure
1356 // the pointer will still be valid when run on the task queue, set it to null.
Erik Språng6a7baa72019-02-26 18:31:00 +01001357 image_copy.set_buffer(nullptr, 0);
Niels Möller83dbeac2017-12-14 16:39:44 +01001358
Erik Språng7ca375c2019-02-06 16:20:17 +01001359 int temporal_index = 0;
1360 if (codec_specific_info) {
1361 if (codec_specific_info->codecType == kVideoCodecVP9) {
1362 temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx;
1363 } else if (codec_specific_info->codecType == kVideoCodecVP8) {
1364 temporal_index = codec_specific_info->codecSpecific.VP8.temporalIdx;
1365 }
1366 }
1367 if (temporal_index == kNoTemporalIdx) {
1368 temporal_index = 0;
Niels Möller83dbeac2017-12-14 16:39:44 +01001369 }
1370
Erik Språng6a7baa72019-02-26 18:31:00 +01001371 RunPostEncode(image_copy, time_sent_us, temporal_index);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001372
1373 if (result.error == Result::OK) {
1374 // In case of an internal encoder running on a separate thread, the
1375 // decision to drop a frame might be a frame late and signaled via
1376 // atomic flag. This is because we can't easily wait for the worker thread
1377 // without risking deadlocks, eg during shutdown when the worker thread
1378 // might be waiting for the internal encoder threads to stop.
1379 if (pending_frame_drops_.load() > 0) {
1380 int pending_drops = pending_frame_drops_.fetch_sub(1);
1381 RTC_DCHECK_GT(pending_drops, 0);
1382 result.drop_next_frame = true;
1383 }
1384 }
perkj803d97f2016-11-01 11:45:46 -07001385
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001386 return result;
Peter Boströmb7d9a972015-12-18 16:01:11 +01001387}
1388
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001389void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
1390 switch (reason) {
1391 case DropReason::kDroppedByMediaOptimizations:
Niels Möller213618e2018-07-24 09:29:58 +02001392 encoder_stats_observer_->OnFrameDropped(
1393 VideoStreamEncoderObserver::DropReason::kMediaOptimization);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001394 encoder_queue_.PostTask([this] {
1395 RTC_DCHECK_RUN_ON(&encoder_queue_);
1396 if (quality_scaler_)
Åsa Perssona945aee2018-04-24 16:53:25 +02001397 quality_scaler_->ReportDroppedFrameByMediaOpt();
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001398 });
1399 break;
1400 case DropReason::kDroppedByEncoder:
Niels Möller213618e2018-07-24 09:29:58 +02001401 encoder_stats_observer_->OnFrameDropped(
1402 VideoStreamEncoderObserver::DropReason::kEncoder);
Åsa Perssona945aee2018-04-24 16:53:25 +02001403 encoder_queue_.PostTask([this] {
1404 RTC_DCHECK_RUN_ON(&encoder_queue_);
1405 if (quality_scaler_)
1406 quality_scaler_->ReportDroppedFrameByEncoder();
1407 });
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001408 break;
1409 }
kthelgason876222f2016-11-29 01:44:11 -08001410}
1411
Erik Språng610c7632019-03-06 15:37:33 +01001412void VideoStreamEncoder::OnBitrateUpdated(DataRate target_bitrate,
1413 DataRate target_headroom,
mflodmancc3d4422017-08-03 08:27:51 -07001414 uint8_t fraction_lost,
1415 int64_t round_trip_time_ms) {
perkj26091b12016-09-01 01:17:40 -07001416 if (!encoder_queue_.IsCurrent()) {
Erik Språng610c7632019-03-06 15:37:33 +01001417 encoder_queue_.PostTask([this, target_bitrate, target_headroom,
1418 fraction_lost, round_trip_time_ms] {
1419 OnBitrateUpdated(target_bitrate, target_headroom, fraction_lost,
1420 round_trip_time_ms);
1421 });
perkj26091b12016-09-01 01:17:40 -07001422 return;
1423 }
1424 RTC_DCHECK_RUN_ON(&encoder_queue_);
1425 RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
1426
Erik Språng610c7632019-03-06 15:37:33 +01001427 RTC_LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << target_bitrate.bps()
1428 << " headroom = " << target_headroom.bps()
Mirko Bonadei675513b2017-11-09 11:09:25 +01001429 << " packet loss " << static_cast<int>(fraction_lost)
1430 << " rtt " << round_trip_time_ms;
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001431 // On significant changes to BWE at the start of the call,
1432 // enable frame drops to quickly react to jumps in available bandwidth.
1433 if (encoder_start_bitrate_bps_ != 0 &&
1434 !has_seen_first_significant_bwe_change_ && quality_scaler_ &&
1435 initial_framedrop_on_bwe_enabled_ &&
Erik Språng610c7632019-03-06 15:37:33 +01001436 abs_diff(target_bitrate.bps(), encoder_start_bitrate_bps_) >=
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001437 kFramedropThreshold * encoder_start_bitrate_bps_) {
1438 // Reset initial framedrop feature when first real BW estimate arrives.
1439 // TODO(kthelgason): Update BitrateAllocator to not call OnBitrateUpdated
1440 // without an actual BW estimate.
1441 initial_framedrop_ = 0;
1442 has_seen_first_significant_bwe_change_ = true;
1443 }
perkj26091b12016-09-01 01:17:40 -07001444
Niels Möller6bb5ab92019-01-11 11:11:10 +01001445 uint32_t framerate_fps = GetInputFramerateFps();
Erik Språng610c7632019-03-06 15:37:33 +01001446 frame_dropper_.SetRates((target_bitrate.bps() + 500) / 1000, framerate_fps);
1447 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(target_bitrate.bps(),
1448 framerate_fps),
1449 framerate_fps);
perkj26091b12016-09-01 01:17:40 -07001450
Erik Språng610c7632019-03-06 15:37:33 +01001451 encoder_start_bitrate_bps_ = target_bitrate.bps() != 0
1452 ? target_bitrate.bps()
1453 : encoder_start_bitrate_bps_;
1454 bool video_is_suspended = target_bitrate == DataRate::Zero();
Erik Språng08127a92016-11-16 16:41:30 +01001455 bool video_suspension_changed = video_is_suspended != EncoderPaused();
Erik Språng610c7632019-03-06 15:37:33 +01001456 last_observed_bitrate_bps_ = target_bitrate.bps();
Peter Boströmd153a372015-11-10 15:27:12 +00001457
sprang552c7c72017-02-13 04:41:45 -08001458 if (video_suspension_changed) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001459 RTC_LOG(LS_INFO) << "Video suspend state changed to: "
1460 << (video_is_suspended ? "suspended" : "not suspended");
Niels Möller213618e2018-07-24 09:29:58 +02001461 encoder_stats_observer_->OnSuspendChange(video_is_suspended);
mflodman101f2502016-06-09 17:21:19 +02001462 }
Sebastian Janssona3177052018-04-10 13:05:49 +02001463 if (video_suspension_changed && !video_is_suspended && pending_frame_ &&
1464 !DropDueToSize(pending_frame_->size())) {
1465 int64_t pending_time_us = rtc::TimeMicros() - pending_frame_post_time_us_;
1466 if (pending_time_us < kPendingFrameTimeoutMs * 1000)
1467 EncodeVideoFrame(*pending_frame_, pending_frame_post_time_us_);
1468 pending_frame_.reset();
1469 }
1470}
1471
1472bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001473 if (initial_framedrop_ < kMaxInitialFramedrop &&
Sebastian Janssona3177052018-04-10 13:05:49 +02001474 encoder_start_bitrate_bps_ > 0) {
1475 if (encoder_start_bitrate_bps_ < 300000 /* qvga */) {
1476 return pixel_count > 320 * 240;
1477 } else if (encoder_start_bitrate_bps_ < 500000 /* vga */) {
1478 return pixel_count > 640 * 480;
1479 }
1480 }
1481 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001482}
1483
mflodmancc3d4422017-08-03 08:27:51 -07001484void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001485 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -07001486 AdaptationRequest adaptation_request = {
1487 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001488 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001489 AdaptationRequest::Mode::kAdaptDown};
asapersson09f05612017-05-15 23:40:18 -07001490
sprangc5d62e22017-04-02 23:53:04 -07001491 bool downgrade_requested =
1492 last_adaptation_request_ &&
1493 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
1494
sprangc5d62e22017-04-02 23:53:04 -07001495 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001496 case DegradationPreference::BALANCED:
asaperssonf7e294d2017-06-13 23:25:22 -07001497 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001498 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangc5d62e22017-04-02 23:53:04 -07001499 if (downgrade_requested &&
1500 adaptation_request.input_pixel_count_ >=
1501 last_adaptation_request_->input_pixel_count_) {
1502 // Don't request lower resolution if the current resolution is not
1503 // lower than the last time we asked for the resolution to be lowered.
1504 return;
1505 }
1506 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001507 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangc5d62e22017-04-02 23:53:04 -07001508 if (adaptation_request.framerate_fps_ <= 0 ||
1509 (downgrade_requested &&
1510 adaptation_request.framerate_fps_ < kMinFramerateFps)) {
1511 // If no input fps estimate available, can't determine how to scale down
1512 // framerate. Otherwise, don't request lower framerate if we don't have
1513 // a valid frame rate. Since framerate, unlike resolution, is a measure
1514 // we have to estimate, and can fluctuate naturally over time, don't
1515 // make the same kind of limitations as for resolution, but trust the
1516 // overuse detector to not trigger too often.
1517 return;
1518 }
1519 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001520 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001521 return;
sprang84a37592017-02-10 07:04:27 -08001522 }
sprangc5d62e22017-04-02 23:53:04 -07001523
sprangc5d62e22017-04-02 23:53:04 -07001524 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001525 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001526 // Try scale down framerate, if lower.
1527 int fps = MinFps(last_frame_info_->pixel_count());
1528 if (source_proxy_->RestrictFramerate(fps)) {
1529 GetAdaptCounter().IncrementFramerate(reason);
1530 break;
1531 }
1532 // Scale down resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001533 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001534 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001535 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001536 // Scale down resolution.
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001537 bool min_pixels_reached = false;
asaperssond0de2952017-04-21 01:47:31 -07001538 if (!source_proxy_->RequestResolutionLowerThan(
asapersson142fcc92017-08-17 08:58:54 -07001539 adaptation_request.input_pixel_count_,
Erik Språnge2fd86a2018-10-24 11:32:39 +02001540 encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame,
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001541 &min_pixels_reached)) {
1542 if (min_pixels_reached)
Niels Möller213618e2018-07-24 09:29:58 +02001543 encoder_stats_observer_->OnMinPixelLimitReached();
asaperssond0de2952017-04-21 01:47:31 -07001544 return;
1545 }
asaperssonf7e294d2017-06-13 23:25:22 -07001546 GetAdaptCounter().IncrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001547 break;
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001548 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001549 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001550 // Scale down framerate.
sprangfda496a2017-06-15 04:21:07 -07001551 const int requested_framerate = source_proxy_->RequestFramerateLowerThan(
1552 adaptation_request.framerate_fps_);
1553 if (requested_framerate == -1)
asapersson13874762017-06-07 00:01:02 -07001554 return;
sprangfda496a2017-06-15 04:21:07 -07001555 RTC_DCHECK_NE(max_framerate_, -1);
Niels Möller7dc26b72017-12-06 10:27:48 +01001556 overuse_detector_->OnTargetFramerateUpdated(
1557 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001558 GetAdaptCounter().IncrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001559 break;
sprangfda496a2017-06-15 04:21:07 -07001560 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001561 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001562 RTC_NOTREACHED();
1563 }
1564
asaperssond0de2952017-04-21 01:47:31 -07001565 last_adaptation_request_.emplace(adaptation_request);
1566
asapersson09f05612017-05-15 23:40:18 -07001567 UpdateAdaptationStats(reason);
asaperssond0de2952017-04-21 01:47:31 -07001568
Mirko Bonadei675513b2017-11-09 11:09:25 +01001569 RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
perkj26091b12016-09-01 01:17:40 -07001570}
1571
mflodmancc3d4422017-08-03 08:27:51 -07001572void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001573 RTC_DCHECK_RUN_ON(&encoder_queue_);
asapersson09f05612017-05-15 23:40:18 -07001574
1575 const AdaptCounter& adapt_counter = GetConstAdaptCounter();
1576 int num_downgrades = adapt_counter.TotalCount(reason);
1577 if (num_downgrades == 0)
perkj803d97f2016-11-01 11:45:46 -07001578 return;
asapersson09f05612017-05-15 23:40:18 -07001579 RTC_DCHECK_GT(num_downgrades, 0);
1580
sprangc5d62e22017-04-02 23:53:04 -07001581 AdaptationRequest adaptation_request = {
1582 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001583 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001584 AdaptationRequest::Mode::kAdaptUp};
1585
1586 bool adapt_up_requested =
1587 last_adaptation_request_ &&
1588 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp;
asapersson09f05612017-05-15 23:40:18 -07001589
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001590 if (degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE) {
asaperssonf7e294d2017-06-13 23:25:22 -07001591 if (adapt_up_requested &&
1592 adaptation_request.input_pixel_count_ <=
1593 last_adaptation_request_->input_pixel_count_) {
1594 // Don't request higher resolution if the current resolution is not
1595 // higher than the last time we asked for the resolution to be higher.
sprangc5d62e22017-04-02 23:53:04 -07001596 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001597 }
sprangb1ca0732017-02-01 08:38:12 -08001598 }
sprangc5d62e22017-04-02 23:53:04 -07001599
sprangc5d62e22017-04-02 23:53:04 -07001600 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001601 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001602 // Try scale up framerate, if higher.
1603 int fps = MaxFps(last_frame_info_->pixel_count());
1604 if (source_proxy_->IncreaseFramerate(fps)) {
1605 GetAdaptCounter().DecrementFramerate(reason, fps);
1606 // Reset framerate in case of fewer fps steps down than up.
1607 if (adapt_counter.FramerateCount() == 0 &&
1608 fps != std::numeric_limits<int>::max()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001609 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asaperssonf7e294d2017-06-13 23:25:22 -07001610 source_proxy_->IncreaseFramerate(std::numeric_limits<int>::max());
1611 }
1612 break;
1613 }
1614 // Scale up resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001615 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001616 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001617 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001618 // Scale up resolution.
1619 int pixel_count = adaptation_request.input_pixel_count_;
1620 if (adapt_counter.ResolutionCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001621 RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001622 pixel_count = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001623 }
asapersson13874762017-06-07 00:01:02 -07001624 if (!source_proxy_->RequestHigherResolutionThan(pixel_count))
1625 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001626 GetAdaptCounter().DecrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001627 break;
asapersson13874762017-06-07 00:01:02 -07001628 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001629 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001630 // Scale up framerate.
1631 int fps = adaptation_request.framerate_fps_;
1632 if (adapt_counter.FramerateCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001633 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001634 fps = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001635 }
sprangfda496a2017-06-15 04:21:07 -07001636
1637 const int requested_framerate =
1638 source_proxy_->RequestHigherFramerateThan(fps);
1639 if (requested_framerate == -1) {
Niels Möller7dc26b72017-12-06 10:27:48 +01001640 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
asapersson13874762017-06-07 00:01:02 -07001641 return;
sprangfda496a2017-06-15 04:21:07 -07001642 }
Niels Möller7dc26b72017-12-06 10:27:48 +01001643 overuse_detector_->OnTargetFramerateUpdated(
1644 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001645 GetAdaptCounter().DecrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001646 break;
asapersson13874762017-06-07 00:01:02 -07001647 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001648 case DegradationPreference::DISABLED:
asaperssonf7e294d2017-06-13 23:25:22 -07001649 return;
sprangc5d62e22017-04-02 23:53:04 -07001650 }
1651
asaperssond0de2952017-04-21 01:47:31 -07001652 last_adaptation_request_.emplace(adaptation_request);
1653
asapersson09f05612017-05-15 23:40:18 -07001654 UpdateAdaptationStats(reason);
1655
Mirko Bonadei675513b2017-11-09 11:09:25 +01001656 RTC_LOG(LS_INFO) << adapt_counter.ToString();
asapersson09f05612017-05-15 23:40:18 -07001657}
1658
Niels Möller213618e2018-07-24 09:29:58 +02001659// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
mflodmancc3d4422017-08-03 08:27:51 -07001660void VideoStreamEncoder::UpdateAdaptationStats(AdaptReason reason) {
asaperssond0de2952017-04-21 01:47:31 -07001661 switch (reason) {
asaperssond0de2952017-04-21 01:47:31 -07001662 case kCpu:
Niels Möller213618e2018-07-24 09:29:58 +02001663 encoder_stats_observer_->OnAdaptationChanged(
1664 VideoStreamEncoderObserver::AdaptationReason::kCpu,
1665 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asapersson09f05612017-05-15 23:40:18 -07001666 break;
1667 case kQuality:
Niels Möller213618e2018-07-24 09:29:58 +02001668 encoder_stats_observer_->OnAdaptationChanged(
1669 VideoStreamEncoderObserver::AdaptationReason::kQuality,
1670 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asaperssond0de2952017-04-21 01:47:31 -07001671 break;
1672 }
perkj26091b12016-09-01 01:17:40 -07001673}
1674
Niels Möller213618e2018-07-24 09:29:58 +02001675VideoStreamEncoderObserver::AdaptationSteps VideoStreamEncoder::GetActiveCounts(
mflodmancc3d4422017-08-03 08:27:51 -07001676 AdaptReason reason) {
Niels Möller213618e2018-07-24 09:29:58 +02001677 VideoStreamEncoderObserver::AdaptationSteps counts =
mflodmancc3d4422017-08-03 08:27:51 -07001678 GetConstAdaptCounter().Counts(reason);
asapersson09f05612017-05-15 23:40:18 -07001679 switch (reason) {
1680 case kCpu:
1681 if (!IsFramerateScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001682 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001683 if (!IsResolutionScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001684 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001685 break;
1686 case kQuality:
1687 if (!IsFramerateScalingEnabled(degradation_preference_) ||
1688 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001689 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001690 }
1691 if (!IsResolutionScalingEnabled(degradation_preference_) ||
1692 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001693 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001694 }
1695 break;
sprangc5d62e22017-04-02 23:53:04 -07001696 }
asapersson09f05612017-05-15 23:40:18 -07001697 return counts;
sprangc5d62e22017-04-02 23:53:04 -07001698}
1699
mflodmancc3d4422017-08-03 08:27:51 -07001700VideoStreamEncoder::AdaptCounter& VideoStreamEncoder::GetAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001701 return adapt_counters_[degradation_preference_];
1702}
1703
mflodmancc3d4422017-08-03 08:27:51 -07001704const VideoStreamEncoder::AdaptCounter&
1705VideoStreamEncoder::GetConstAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001706 return adapt_counters_[degradation_preference_];
1707}
1708
Erik Språng7ca375c2019-02-06 16:20:17 +01001709void VideoStreamEncoder::RunPostEncode(EncodedImage encoded_image,
Niels Möller6bb5ab92019-01-11 11:11:10 +01001710 int64_t time_sent_us,
Erik Språng7ca375c2019-02-06 16:20:17 +01001711 int temporal_index) {
Niels Möller6bb5ab92019-01-11 11:11:10 +01001712 if (!encoder_queue_.IsCurrent()) {
Erik Språng7ca375c2019-02-06 16:20:17 +01001713 encoder_queue_.PostTask(
1714 [this, encoded_image, time_sent_us, temporal_index] {
1715 RunPostEncode(encoded_image, time_sent_us, temporal_index);
1716 });
Niels Möller6bb5ab92019-01-11 11:11:10 +01001717 return;
1718 }
1719
1720 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +01001721
1722 absl::optional<int> encode_duration_us;
1723 if (encoded_image.timing_.flags != VideoSendTiming::kInvalid) {
1724 encode_duration_us =
1725 // TODO(nisse): Maybe use capture_time_ms_ rather than encode_start_ms_?
1726 rtc::kNumMicrosecsPerMillisec *
1727 (encoded_image.timing_.encode_finish_ms -
1728 encoded_image.timing_.encode_start_ms);
1729 }
1730
1731 // Run post encode tasks, such as overuse detection and frame rate/drop
1732 // stats for internal encoders.
1733 const size_t frame_size = encoded_image.size();
Niels Möller87e2d782019-03-07 10:18:23 +01001734 const bool keyframe =
1735 encoded_image._frameType == VideoFrameType::kVideoFrameKey;
Erik Språng7ca375c2019-02-06 16:20:17 +01001736
1737 if (frame_size > 0) {
1738 frame_dropper_.Fill(frame_size, !keyframe);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001739 }
1740
Erik Språngd7329ca2019-02-21 21:19:53 +01001741 if (HasInternalSource()) {
Niels Möller6bb5ab92019-01-11 11:11:10 +01001742 // Update frame dropper after the fact for internal sources.
1743 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
1744 frame_dropper_.Leak(GetInputFramerateFps());
1745 // Signal to encoder to drop next frame.
1746 if (frame_dropper_.DropFrame()) {
1747 pending_frame_drops_.fetch_add(1);
1748 }
1749 }
1750
Erik Språng7ca375c2019-02-06 16:20:17 +01001751 overuse_detector_->FrameSent(
1752 encoded_image.Timestamp(), time_sent_us,
1753 encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec,
1754 encode_duration_us);
1755 if (quality_scaler_ && encoded_image.qp_ >= 0)
Sebastian Janssonb6789402019-03-01 15:40:49 +01001756 quality_scaler_->ReportQp(encoded_image.qp_, time_sent_us);
Erik Språng7ca375c2019-02-06 16:20:17 +01001757 if (bitrate_adjuster_) {
1758 bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index);
1759 }
Niels Möller6bb5ab92019-01-11 11:11:10 +01001760}
1761
Erik Språngd7329ca2019-02-21 21:19:53 +01001762bool VideoStreamEncoder::HasInternalSource() const {
1763 // TODO(sprang): Checking both info from encoder and from encoder factory
1764 // until we have deprecated and removed the encoder factory info.
1765 return codec_info_.has_internal_source || encoder_info_.has_internal_source;
1766}
1767
Erik Språng6a7baa72019-02-26 18:31:00 +01001768void VideoStreamEncoder::ReleaseEncoder() {
1769 if (!encoder_ || !encoder_initialized_) {
1770 return;
1771 }
1772 encoder_->Release();
1773 encoder_initialized_ = false;
1774 TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release");
1775}
1776
asapersson09f05612017-05-15 23:40:18 -07001777// Class holding adaptation information.
mflodmancc3d4422017-08-03 08:27:51 -07001778VideoStreamEncoder::AdaptCounter::AdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001779 fps_counters_.resize(kScaleReasonSize);
1780 resolution_counters_.resize(kScaleReasonSize);
asaperssonf7e294d2017-06-13 23:25:22 -07001781 static_assert(kScaleReasonSize == 2, "Update MoveCount.");
asapersson09f05612017-05-15 23:40:18 -07001782}
1783
mflodmancc3d4422017-08-03 08:27:51 -07001784VideoStreamEncoder::AdaptCounter::~AdaptCounter() {}
asapersson09f05612017-05-15 23:40:18 -07001785
mflodmancc3d4422017-08-03 08:27:51 -07001786std::string VideoStreamEncoder::AdaptCounter::ToString() const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001787 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001788 ss << "Downgrade counts: fps: {" << ToString(fps_counters_);
1789 ss << "}, resolution: {" << ToString(resolution_counters_) << "}";
Jonas Olsson84df1c72018-09-14 16:59:32 +02001790 return ss.Release();
asapersson09f05612017-05-15 23:40:18 -07001791}
1792
Niels Möller213618e2018-07-24 09:29:58 +02001793VideoStreamEncoderObserver::AdaptationSteps
1794VideoStreamEncoder::AdaptCounter::Counts(int reason) const {
1795 VideoStreamEncoderObserver::AdaptationSteps counts;
1796 counts.num_framerate_reductions = fps_counters_[reason];
1797 counts.num_resolution_reductions = resolution_counters_[reason];
asapersson09f05612017-05-15 23:40:18 -07001798 return counts;
1799}
1800
mflodmancc3d4422017-08-03 08:27:51 -07001801void VideoStreamEncoder::AdaptCounter::IncrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001802 ++(fps_counters_[reason]);
asapersson09f05612017-05-15 23:40:18 -07001803}
1804
mflodmancc3d4422017-08-03 08:27:51 -07001805void VideoStreamEncoder::AdaptCounter::IncrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001806 ++(resolution_counters_[reason]);
1807}
1808
mflodmancc3d4422017-08-03 08:27:51 -07001809void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001810 if (fps_counters_[reason] == 0) {
1811 // Balanced mode: Adapt up is in a different order, switch reason.
1812 // E.g. framerate adapt down: quality (2), framerate adapt up: cpu (3).
1813 // 1. Down resolution (cpu): res={quality:0,cpu:1}, fps={quality:0,cpu:0}
1814 // 2. Down fps (quality): res={quality:0,cpu:1}, fps={quality:1,cpu:0}
1815 // 3. Up fps (cpu): res={quality:1,cpu:0}, fps={quality:0,cpu:0}
1816 // 4. Up resolution (quality): res={quality:0,cpu:0}, fps={quality:0,cpu:0}
1817 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1818 RTC_DCHECK_GT(FramerateCount(), 0) << "Framerate not downgraded.";
1819 MoveCount(&resolution_counters_, reason);
1820 MoveCount(&fps_counters_, (reason + 1) % kScaleReasonSize);
1821 }
1822 --(fps_counters_[reason]);
1823 RTC_DCHECK_GE(fps_counters_[reason], 0);
1824}
1825
mflodmancc3d4422017-08-03 08:27:51 -07001826void VideoStreamEncoder::AdaptCounter::DecrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001827 if (resolution_counters_[reason] == 0) {
1828 // Balanced mode: Adapt up is in a different order, switch reason.
1829 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1830 RTC_DCHECK_GT(ResolutionCount(), 0) << "Resolution not downgraded.";
1831 MoveCount(&fps_counters_, reason);
1832 MoveCount(&resolution_counters_, (reason + 1) % kScaleReasonSize);
1833 }
1834 --(resolution_counters_[reason]);
1835 RTC_DCHECK_GE(resolution_counters_[reason], 0);
1836}
1837
mflodmancc3d4422017-08-03 08:27:51 -07001838void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason,
1839 int cur_fps) {
asaperssonf7e294d2017-06-13 23:25:22 -07001840 DecrementFramerate(reason);
1841 // Reset if at max fps (i.e. in case of fewer steps up than down).
1842 if (cur_fps == std::numeric_limits<int>::max())
1843 std::fill(fps_counters_.begin(), fps_counters_.end(), 0);
asapersson09f05612017-05-15 23:40:18 -07001844}
1845
mflodmancc3d4422017-08-03 08:27:51 -07001846int VideoStreamEncoder::AdaptCounter::FramerateCount() const {
asapersson09f05612017-05-15 23:40:18 -07001847 return Count(fps_counters_);
1848}
1849
mflodmancc3d4422017-08-03 08:27:51 -07001850int VideoStreamEncoder::AdaptCounter::ResolutionCount() const {
asapersson09f05612017-05-15 23:40:18 -07001851 return Count(resolution_counters_);
1852}
1853
mflodmancc3d4422017-08-03 08:27:51 -07001854int VideoStreamEncoder::AdaptCounter::FramerateCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001855 return fps_counters_[reason];
1856}
1857
mflodmancc3d4422017-08-03 08:27:51 -07001858int VideoStreamEncoder::AdaptCounter::ResolutionCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001859 return resolution_counters_[reason];
1860}
1861
mflodmancc3d4422017-08-03 08:27:51 -07001862int VideoStreamEncoder::AdaptCounter::TotalCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001863 return FramerateCount(reason) + ResolutionCount(reason);
1864}
1865
mflodmancc3d4422017-08-03 08:27:51 -07001866int VideoStreamEncoder::AdaptCounter::Count(
1867 const std::vector<int>& counters) const {
asapersson09f05612017-05-15 23:40:18 -07001868 return std::accumulate(counters.begin(), counters.end(), 0);
1869}
1870
mflodmancc3d4422017-08-03 08:27:51 -07001871void VideoStreamEncoder::AdaptCounter::MoveCount(std::vector<int>* counters,
1872 int from_reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001873 int to_reason = (from_reason + 1) % kScaleReasonSize;
1874 ++((*counters)[to_reason]);
1875 --((*counters)[from_reason]);
1876}
1877
mflodmancc3d4422017-08-03 08:27:51 -07001878std::string VideoStreamEncoder::AdaptCounter::ToString(
asapersson09f05612017-05-15 23:40:18 -07001879 const std::vector<int>& counters) const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001880 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001881 for (size_t reason = 0; reason < kScaleReasonSize; ++reason) {
1882 ss << (reason ? " cpu" : "quality") << ":" << counters[reason];
sprangc5d62e22017-04-02 23:53:04 -07001883 }
Jonas Olsson84df1c72018-09-14 16:59:32 +02001884 return ss.Release();
sprangc5d62e22017-04-02 23:53:04 -07001885}
1886
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001887} // namespace webrtc