blob: 6066ac5d754d954c2498649e2d74ac54aed80613 [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"
Åsa Perssona945aee2018-04-24 16:53:25 +020028#include "rtc_base/experiments/quality_scaling_experiment.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010029#include "rtc_base/experiments/rate_control_settings.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/location.h"
31#include "rtc_base/logging.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020032#include "rtc_base/strings/string_builder.h"
Karl Wiberg80ba3332018-02-05 10:33:35 +010033#include "rtc_base/system/fallthrough.h"
Steve Anton10542f22019-01-11 09:11:00 -080034#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "rtc_base/trace_event.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020036#include "system_wrappers/include/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "video/overuse_frame_detector.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
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070064// Initial limits for BALANCED degradation preference.
asaperssonf7e294d2017-06-13 23:25:22 -070065int MinFps(int pixels) {
66 if (pixels <= 320 * 240) {
67 return 7;
68 } else if (pixels <= 480 * 270) {
69 return 10;
70 } else if (pixels <= 640 * 480) {
71 return 15;
72 } else {
73 return std::numeric_limits<int>::max();
74 }
75}
76
77int MaxFps(int pixels) {
78 if (pixels <= 320 * 240) {
79 return 10;
80 } else if (pixels <= 480 * 270) {
81 return 15;
82 } else {
83 return std::numeric_limits<int>::max();
84 }
85}
86
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020087uint32_t abs_diff(uint32_t a, uint32_t b) {
88 return (a < b) ? b - a : a - b;
89}
90
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070091bool IsResolutionScalingEnabled(DegradationPreference degradation_preference) {
92 return degradation_preference == DegradationPreference::MAINTAIN_FRAMERATE ||
93 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -070094}
95
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070096bool IsFramerateScalingEnabled(DegradationPreference degradation_preference) {
97 return degradation_preference == DegradationPreference::MAINTAIN_RESOLUTION ||
98 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -070099}
100
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200101// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
102// pipelining encoders better (multiple input frames before something comes
103// out). This should effectively turn off CPU adaptations for systems that
104// remotely cope with the load right now.
105CpuOveruseOptions GetCpuOveruseOptions(
Niels Möller213618e2018-07-24 09:29:58 +0200106 const VideoStreamEncoderSettings& settings,
Niels Möller4db138e2018-04-19 09:04:13 +0200107 bool full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200108 CpuOveruseOptions options;
109
Niels Möller4db138e2018-04-19 09:04:13 +0200110 if (full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200111 options.low_encode_usage_threshold_percent = 150;
112 options.high_encode_usage_threshold_percent = 200;
113 }
114 if (settings.experiment_cpu_load_estimator) {
115 options.filter_time_ms = 5 * rtc::kNumMillisecsPerSec;
116 }
117
118 return options;
119}
120
perkj26091b12016-09-01 01:17:40 -0700121} // namespace
122
perkja49cbd32016-09-16 07:53:41 -0700123// VideoSourceProxy is responsible ensuring thread safety between calls to
mflodmancc3d4422017-08-03 08:27:51 -0700124// VideoStreamEncoder::SetSource that will happen on libjingle's worker thread
125// when a video capturer is connected to the encoder and the encoder task queue
perkja49cbd32016-09-16 07:53:41 -0700126// (encoder_queue_) where the encoder reports its VideoSinkWants.
mflodmancc3d4422017-08-03 08:27:51 -0700127class VideoStreamEncoder::VideoSourceProxy {
perkja49cbd32016-09-16 07:53:41 -0700128 public:
mflodmancc3d4422017-08-03 08:27:51 -0700129 explicit VideoSourceProxy(VideoStreamEncoder* video_stream_encoder)
130 : video_stream_encoder_(video_stream_encoder),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700131 degradation_preference_(DegradationPreference::DISABLED),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200132 source_(nullptr),
133 max_framerate_(std::numeric_limits<int>::max()) {}
perkja49cbd32016-09-16 07:53:41 -0700134
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700135 void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
136 const DegradationPreference& degradation_preference) {
perkj803d97f2016-11-01 11:45:46 -0700137 // Called on libjingle's worker thread.
perkja49cbd32016-09-16 07:53:41 -0700138 RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
139 rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr;
perkj803d97f2016-11-01 11:45:46 -0700140 rtc::VideoSinkWants wants;
perkja49cbd32016-09-16 07:53:41 -0700141 {
142 rtc::CritScope lock(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700143 degradation_preference_ = degradation_preference;
perkja49cbd32016-09-16 07:53:41 -0700144 old_source = source_;
145 source_ = source;
sprangfda496a2017-06-15 04:21:07 -0700146 wants = GetActiveSinkWantsInternal();
perkja49cbd32016-09-16 07:53:41 -0700147 }
148
149 if (old_source != source && old_source != nullptr) {
mflodmancc3d4422017-08-03 08:27:51 -0700150 old_source->RemoveSink(video_stream_encoder_);
perkja49cbd32016-09-16 07:53:41 -0700151 }
152
153 if (!source) {
154 return;
155 }
156
mflodmancc3d4422017-08-03 08:27:51 -0700157 source->AddOrUpdateSink(video_stream_encoder_, wants);
perkja49cbd32016-09-16 07:53:41 -0700158 }
159
Åsa Persson8c1bf952018-09-13 10:42:19 +0200160 void SetMaxFramerate(int max_framerate) {
161 RTC_DCHECK_GT(max_framerate, 0);
162 rtc::CritScope lock(&crit_);
163 if (max_framerate == max_framerate_)
164 return;
165
166 RTC_LOG(LS_INFO) << "Set max framerate: " << max_framerate;
167 max_framerate_ = max_framerate;
168 if (source_) {
169 source_->AddOrUpdateSink(video_stream_encoder_,
170 GetActiveSinkWantsInternal());
171 }
172 }
173
perkj803d97f2016-11-01 11:45:46 -0700174 void SetWantsRotationApplied(bool rotation_applied) {
175 rtc::CritScope lock(&crit_);
176 sink_wants_.rotation_applied = rotation_applied;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200177 if (source_) {
178 source_->AddOrUpdateSink(video_stream_encoder_,
179 GetActiveSinkWantsInternal());
180 }
sprangc5d62e22017-04-02 23:53:04 -0700181 }
182
sprangfda496a2017-06-15 04:21:07 -0700183 rtc::VideoSinkWants GetActiveSinkWants() {
184 rtc::CritScope lock(&crit_);
185 return GetActiveSinkWantsInternal();
perkj803d97f2016-11-01 11:45:46 -0700186 }
187
asaperssonf7e294d2017-06-13 23:25:22 -0700188 void ResetPixelFpsCount() {
189 rtc::CritScope lock(&crit_);
190 sink_wants_.max_pixel_count = std::numeric_limits<int>::max();
191 sink_wants_.target_pixel_count.reset();
192 sink_wants_.max_framerate_fps = std::numeric_limits<int>::max();
193 if (source_)
Åsa Persson8c1bf952018-09-13 10:42:19 +0200194 source_->AddOrUpdateSink(video_stream_encoder_,
195 GetActiveSinkWantsInternal());
asaperssonf7e294d2017-06-13 23:25:22 -0700196 }
197
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100198 bool RequestResolutionLowerThan(int pixel_count,
199 int min_pixels_per_frame,
200 bool* min_pixels_reached) {
perkj803d97f2016-11-01 11:45:46 -0700201 // Called on the encoder task queue.
202 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700203 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700204 // This can happen since |degradation_preference_| is set on libjingle's
205 // worker thread but the adaptation is done on the encoder task queue.
asaperssond0de2952017-04-21 01:47:31 -0700206 return false;
perkj803d97f2016-11-01 11:45:46 -0700207 }
asapersson13874762017-06-07 00:01:02 -0700208 // The input video frame size will have a resolution less than or equal to
209 // |max_pixel_count| depending on how the source can scale the frame size.
kthelgason5e13d412016-12-01 03:59:51 -0800210 const int pixels_wanted = (pixel_count * 3) / 5;
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100211 if (pixels_wanted >= sink_wants_.max_pixel_count) {
212 return false;
213 }
214 if (pixels_wanted < min_pixels_per_frame) {
215 *min_pixels_reached = true;
asaperssond0de2952017-04-21 01:47:31 -0700216 return false;
asapersson13874762017-06-07 00:01:02 -0700217 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100218 RTC_LOG(LS_INFO) << "Scaling down resolution, max pixels: "
219 << pixels_wanted;
sprangc5d62e22017-04-02 23:53:04 -0700220 sink_wants_.max_pixel_count = pixels_wanted;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200221 sink_wants_.target_pixel_count = absl::nullopt;
mflodmancc3d4422017-08-03 08:27:51 -0700222 source_->AddOrUpdateSink(video_stream_encoder_,
223 GetActiveSinkWantsInternal());
asaperssond0de2952017-04-21 01:47:31 -0700224 return true;
sprangc5d62e22017-04-02 23:53:04 -0700225 }
226
sprangfda496a2017-06-15 04:21:07 -0700227 int RequestFramerateLowerThan(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700228 // Called on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700229 // The input video frame rate will be scaled down to 2/3, rounding down.
sprangfda496a2017-06-15 04:21:07 -0700230 int framerate_wanted = (fps * 2) / 3;
231 return RestrictFramerate(framerate_wanted) ? framerate_wanted : -1;
perkj803d97f2016-11-01 11:45:46 -0700232 }
233
asapersson13874762017-06-07 00:01:02 -0700234 bool RequestHigherResolutionThan(int pixel_count) {
235 // Called on the encoder task queue.
perkj803d97f2016-11-01 11:45:46 -0700236 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700237 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700238 // This can happen since |degradation_preference_| is set on libjingle's
239 // worker thread but the adaptation is done on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700240 return false;
perkj803d97f2016-11-01 11:45:46 -0700241 }
asapersson13874762017-06-07 00:01:02 -0700242 int max_pixels_wanted = pixel_count;
243 if (max_pixels_wanted != std::numeric_limits<int>::max())
244 max_pixels_wanted = pixel_count * 4;
sprangc5d62e22017-04-02 23:53:04 -0700245
asapersson13874762017-06-07 00:01:02 -0700246 if (max_pixels_wanted <= sink_wants_.max_pixel_count)
247 return false;
248
249 sink_wants_.max_pixel_count = max_pixels_wanted;
250 if (max_pixels_wanted == std::numeric_limits<int>::max()) {
sprangc5d62e22017-04-02 23:53:04 -0700251 // Remove any constraints.
252 sink_wants_.target_pixel_count.reset();
sprangc5d62e22017-04-02 23:53:04 -0700253 } else {
254 // On step down we request at most 3/5 the pixel count of the previous
255 // resolution, so in order to take "one step up" we request a resolution
256 // as close as possible to 5/3 of the current resolution. The actual pixel
257 // count selected depends on the capabilities of the source. In order to
258 // not take a too large step up, we cap the requested pixel count to be at
259 // most four time the current number of pixels.
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100260 sink_wants_.target_pixel_count = (pixel_count * 5) / 3;
sprangc5d62e22017-04-02 23:53:04 -0700261 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100262 RTC_LOG(LS_INFO) << "Scaling up resolution, max pixels: "
263 << max_pixels_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700264 source_->AddOrUpdateSink(video_stream_encoder_,
265 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700266 return true;
sprangc5d62e22017-04-02 23:53:04 -0700267 }
268
sprangfda496a2017-06-15 04:21:07 -0700269 // Request upgrade in framerate. Returns the new requested frame, or -1 if
270 // no change requested. Note that maxint may be returned if limits due to
271 // adaptation requests are removed completely. In that case, consider
272 // |max_framerate_| to be the current limit (assuming the capturer complies).
273 int RequestHigherFramerateThan(int fps) {
asapersson13874762017-06-07 00:01:02 -0700274 // Called on the encoder task queue.
275 // The input frame rate will be scaled up to the last step, with rounding.
276 int framerate_wanted = fps;
277 if (fps != std::numeric_limits<int>::max())
278 framerate_wanted = (fps * 3) / 2;
279
sprangfda496a2017-06-15 04:21:07 -0700280 return IncreaseFramerate(framerate_wanted) ? framerate_wanted : -1;
asapersson13874762017-06-07 00:01:02 -0700281 }
282
283 bool RestrictFramerate(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700284 // Called on the encoder task queue.
285 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700286 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
287 return false;
288
289 const int fps_wanted = std::max(kMinFramerateFps, fps);
290 if (fps_wanted >= sink_wants_.max_framerate_fps)
291 return false;
292
Mirko Bonadei675513b2017-11-09 11:09:25 +0100293 RTC_LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700294 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700295 source_->AddOrUpdateSink(video_stream_encoder_,
296 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700297 return true;
298 }
299
300 bool IncreaseFramerate(int fps) {
301 // Called on the encoder task queue.
302 rtc::CritScope lock(&crit_);
303 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
304 return false;
305
306 const int fps_wanted = std::max(kMinFramerateFps, fps);
307 if (fps_wanted <= sink_wants_.max_framerate_fps)
308 return false;
309
Mirko Bonadei675513b2017-11-09 11:09:25 +0100310 RTC_LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700311 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700312 source_->AddOrUpdateSink(video_stream_encoder_,
313 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700314 return true;
perkj803d97f2016-11-01 11:45:46 -0700315 }
316
perkja49cbd32016-09-16 07:53:41 -0700317 private:
sprangfda496a2017-06-15 04:21:07 -0700318 rtc::VideoSinkWants GetActiveSinkWantsInternal()
danilchapa37de392017-09-09 04:17:22 -0700319 RTC_EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
sprangfda496a2017-06-15 04:21:07 -0700320 rtc::VideoSinkWants wants = sink_wants_;
321 // Clear any constraints from the current sink wants that don't apply to
322 // the used degradation_preference.
323 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700324 case DegradationPreference::BALANCED:
sprangfda496a2017-06-15 04:21:07 -0700325 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700326 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangfda496a2017-06-15 04:21:07 -0700327 wants.max_framerate_fps = std::numeric_limits<int>::max();
328 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700329 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangfda496a2017-06-15 04:21:07 -0700330 wants.max_pixel_count = std::numeric_limits<int>::max();
331 wants.target_pixel_count.reset();
332 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700333 case DegradationPreference::DISABLED:
sprangfda496a2017-06-15 04:21:07 -0700334 wants.max_pixel_count = std::numeric_limits<int>::max();
335 wants.target_pixel_count.reset();
336 wants.max_framerate_fps = std::numeric_limits<int>::max();
337 }
Åsa Persson8c1bf952018-09-13 10:42:19 +0200338 // Limit to configured max framerate.
339 wants.max_framerate_fps = std::min(max_framerate_, wants.max_framerate_fps);
sprangfda496a2017-06-15 04:21:07 -0700340 return wants;
341 }
342
perkja49cbd32016-09-16 07:53:41 -0700343 rtc::CriticalSection crit_;
344 rtc::SequencedTaskChecker main_checker_;
mflodmancc3d4422017-08-03 08:27:51 -0700345 VideoStreamEncoder* const video_stream_encoder_;
danilchapa37de392017-09-09 04:17:22 -0700346 rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(&crit_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700347 DegradationPreference degradation_preference_ RTC_GUARDED_BY(&crit_);
danilchapa37de392017-09-09 04:17:22 -0700348 rtc::VideoSourceInterface<VideoFrame>* source_ RTC_GUARDED_BY(&crit_);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200349 int max_framerate_ RTC_GUARDED_BY(&crit_);
perkja49cbd32016-09-16 07:53:41 -0700350
351 RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
352};
353
Åsa Persson0122e842017-10-16 12:19:23 +0200354VideoStreamEncoder::VideoStreamEncoder(
355 uint32_t number_of_cores,
Niels Möller213618e2018-07-24 09:29:58 +0200356 VideoStreamEncoderObserver* encoder_stats_observer,
357 const VideoStreamEncoderSettings& settings,
Åsa Persson0122e842017-10-16 12:19:23 +0200358 std::unique_ptr<OveruseFrameDetector> overuse_detector)
perkj26091b12016-09-01 01:17:40 -0700359 : shutdown_event_(true /* manual_reset */, false),
360 number_of_cores_(number_of_cores),
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200361 initial_framedrop_(0),
362 initial_framedrop_on_bwe_enabled_(
363 webrtc::field_trial::IsEnabled(kInitialFramedropFieldTrial)),
Åsa Perssona945aee2018-04-24 16:53:25 +0200364 quality_scaling_experiment_enabled_(QualityScalingExperiment::Enabled()),
perkja49cbd32016-09-16 07:53:41 -0700365 source_proxy_(new VideoSourceProxy(this)),
Pera48ddb72016-09-29 11:48:50 +0200366 sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700367 settings_(settings),
Erik Språng7ca375c2019-02-06 16:20:17 +0100368 rate_control_settings_(RateControlSettings::ParseFromFieldTrials()),
Niels Möllera0565992017-10-24 11:37:08 +0200369 video_sender_(Clock::GetRealTimeClock(), this),
Niels Möller73f29cb2018-01-31 16:09:31 +0100370 overuse_detector_(std::move(overuse_detector)),
Niels Möller213618e2018-07-24 09:29:58 +0200371 encoder_stats_observer_(encoder_stats_observer),
sprangfda496a2017-06-15 04:21:07 -0700372 max_framerate_(-1),
perkjfa10b552016-10-02 23:45:26 -0700373 pending_encoder_reconfiguration_(false),
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000374 pending_encoder_creation_(false),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200375 crop_width_(0),
376 crop_height_(0),
perkj26091b12016-09-01 01:17:40 -0700377 encoder_start_bitrate_bps_(0),
Pera48ddb72016-09-29 11:48:50 +0200378 max_data_payload_length_(0),
pbos@webrtc.org143451d2015-03-18 14:40:03 +0000379 last_observed_bitrate_bps_(0),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000380 encoder_paused_and_dropped_frame_(false),
perkj26091b12016-09-01 01:17:40 -0700381 clock_(Clock::GetRealTimeClock()),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700382 degradation_preference_(DegradationPreference::DISABLED),
Yuwei Huangd9f99c12017-10-24 15:40:52 -0700383 posted_frames_waiting_for_encode_(0),
perkj26091b12016-09-01 01:17:40 -0700384 last_captured_timestamp_(0),
385 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
386 clock_->TimeInMilliseconds()),
asapersson6ffb67d2016-09-12 00:10:45 -0700387 last_frame_log_ms_(clock_->TimeInMilliseconds()),
388 captured_frame_count_(0),
389 dropped_frame_count_(0),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200390 pending_frame_post_time_us_(0),
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100391 accumulated_update_rect_{0, 0, 0, 0},
sprang1a646ee2016-12-01 06:34:11 -0800392 bitrate_observer_(nullptr),
Niels Möller6bb5ab92019-01-11 11:11:10 +0100393 force_disable_frame_dropper_(false),
394 input_framerate_(kFrameRateAvergingWindowSizeMs, 1000),
395 pending_frame_drops_(0),
perkj26091b12016-09-01 01:17:40 -0700396 encoder_queue_("EncoderQueue") {
Niels Möller213618e2018-07-24 09:29:58 +0200397 RTC_DCHECK(encoder_stats_observer);
Niels Möller73f29cb2018-01-31 16:09:31 +0100398 RTC_DCHECK(overuse_detector_);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000399}
400
mflodmancc3d4422017-08-03 08:27:51 -0700401VideoStreamEncoder::~VideoStreamEncoder() {
perkja49cbd32016-09-16 07:53:41 -0700402 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700403 RTC_DCHECK(shutdown_event_.Wait(0))
404 << "Must call ::Stop() before destruction.";
405}
406
mflodmancc3d4422017-08-03 08:27:51 -0700407void VideoStreamEncoder::Stop() {
perkja49cbd32016-09-16 07:53:41 -0700408 RTC_DCHECK_RUN_ON(&thread_checker_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700409 source_proxy_->SetSource(nullptr, DegradationPreference());
perkja49cbd32016-09-16 07:53:41 -0700410 encoder_queue_.PostTask([this] {
411 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangfda496a2017-06-15 04:21:07 -0700412 overuse_detector_->StopCheckForOveruse();
Erik Språng08127a92016-11-16 16:41:30 +0100413 rate_allocator_.reset();
sprang1a646ee2016-12-01 06:34:11 -0800414 bitrate_observer_ = nullptr;
Niels Möllerbf3dbb42018-03-16 13:38:46 +0100415 video_sender_.RegisterExternalEncoder(nullptr, false);
kthelgason876222f2016-11-29 01:44:11 -0800416 quality_scaler_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700417 shutdown_event_.Set();
418 });
419
420 shutdown_event_.Wait(rtc::Event::kForever);
perkj26091b12016-09-01 01:17:40 -0700421}
422
Niels Möller0327c2d2018-05-21 14:09:31 +0200423void VideoStreamEncoder::SetBitrateAllocationObserver(
sprang1a646ee2016-12-01 06:34:11 -0800424 VideoBitrateAllocationObserver* bitrate_observer) {
425 RTC_DCHECK_RUN_ON(&thread_checker_);
426 encoder_queue_.PostTask([this, bitrate_observer] {
427 RTC_DCHECK_RUN_ON(&encoder_queue_);
428 RTC_DCHECK(!bitrate_observer_);
429 bitrate_observer_ = bitrate_observer;
430 });
431}
432
mflodmancc3d4422017-08-03 08:27:51 -0700433void VideoStreamEncoder::SetSource(
perkj803d97f2016-11-01 11:45:46 -0700434 rtc::VideoSourceInterface<VideoFrame>* source,
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700435 const DegradationPreference& degradation_preference) {
perkja49cbd32016-09-16 07:53:41 -0700436 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj803d97f2016-11-01 11:45:46 -0700437 source_proxy_->SetSource(source, degradation_preference);
438 encoder_queue_.PostTask([this, degradation_preference] {
439 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -0700440 if (degradation_preference_ != degradation_preference) {
441 // Reset adaptation state, so that we're not tricked into thinking there's
442 // an already pending request of the same type.
443 last_adaptation_request_.reset();
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700444 if (degradation_preference == DegradationPreference::BALANCED ||
445 degradation_preference_ == DegradationPreference::BALANCED) {
asaperssonf7e294d2017-06-13 23:25:22 -0700446 // TODO(asapersson): Consider removing |adapt_counters_| map and use one
447 // AdaptCounter for all modes.
448 source_proxy_->ResetPixelFpsCount();
449 adapt_counters_.clear();
450 }
sprangc5d62e22017-04-02 23:53:04 -0700451 }
sprangb1ca0732017-02-01 08:38:12 -0800452 degradation_preference_ = degradation_preference;
Niels Möller4db138e2018-04-19 09:04:13 +0200453
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000454 if (encoder_)
Erik Språng7ca375c2019-02-06 16:20:17 +0100455 ConfigureQualityScaler(encoder_->GetEncoderInfo());
Niels Möller4db138e2018-04-19 09:04:13 +0200456
Niels Möller7dc26b72017-12-06 10:27:48 +0100457 if (!IsFramerateScalingEnabled(degradation_preference) &&
458 max_framerate_ != -1) {
459 // If frame rate scaling is no longer allowed, remove any potential
460 // allowance for longer frame intervals.
461 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
462 }
perkj803d97f2016-11-01 11:45:46 -0700463 });
perkja49cbd32016-09-16 07:53:41 -0700464}
465
mflodmancc3d4422017-08-03 08:27:51 -0700466void VideoStreamEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
perkj803d97f2016-11-01 11:45:46 -0700467 source_proxy_->SetWantsRotationApplied(rotation_applied);
perkj26091b12016-09-01 01:17:40 -0700468 encoder_queue_.PostTask([this, sink] {
469 RTC_DCHECK_RUN_ON(&encoder_queue_);
470 sink_ = sink;
471 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000472}
473
mflodmancc3d4422017-08-03 08:27:51 -0700474void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
perkj26091b12016-09-01 01:17:40 -0700475 encoder_queue_.PostTask([this, start_bitrate_bps] {
476 RTC_DCHECK_RUN_ON(&encoder_queue_);
477 encoder_start_bitrate_bps_ = start_bitrate_bps;
478 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000479}
Peter Boström00b9d212016-05-19 16:59:03 +0200480
mflodmancc3d4422017-08-03 08:27:51 -0700481void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200482 size_t max_data_payload_length) {
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100483 // TODO(srte): This struct should be replaced by a lambda with move capture
484 // when C++14 lambda is allowed.
485 struct ConfigureEncoderTask {
486 void operator()() {
Yves Gerey665174f2018-06-19 15:03:05 +0200487 encoder->ConfigureEncoderOnTaskQueue(std::move(config),
488 max_data_payload_length);
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100489 }
490 VideoStreamEncoder* encoder;
491 VideoEncoderConfig config;
492 size_t max_data_payload_length;
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100493 };
Yves Gerey665174f2018-06-19 15:03:05 +0200494 encoder_queue_.PostTask(
495 ConfigureEncoderTask{this, std::move(config), max_data_payload_length});
perkj26091b12016-09-01 01:17:40 -0700496}
497
mflodmancc3d4422017-08-03 08:27:51 -0700498void VideoStreamEncoder::ConfigureEncoderOnTaskQueue(
499 VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200500 size_t max_data_payload_length) {
perkj26091b12016-09-01 01:17:40 -0700501 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700502 RTC_DCHECK(sink_);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100503 RTC_LOG(LS_INFO) << "ConfigureEncoder requested.";
Pera48ddb72016-09-29 11:48:50 +0200504
505 max_data_payload_length_ = max_data_payload_length;
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000506 pending_encoder_creation_ =
507 (!encoder_ || encoder_config_.video_format != config.video_format);
Pera48ddb72016-09-29 11:48:50 +0200508 encoder_config_ = std::move(config);
perkjfa10b552016-10-02 23:45:26 -0700509 pending_encoder_reconfiguration_ = true;
Pera48ddb72016-09-29 11:48:50 +0200510
perkjfa10b552016-10-02 23:45:26 -0700511 // Reconfigure the encoder now if the encoder has an internal source or
Per21d45d22016-10-30 21:37:57 +0100512 // if the frame resolution is known. Otherwise, the reconfiguration is
513 // deferred until the next frame to minimize the number of reconfigurations.
514 // The codec configuration depends on incoming video frame size.
515 if (last_frame_info_) {
516 ReconfigureEncoder();
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000517 } else if (settings_.encoder_factory
518 ->QueryVideoEncoder(encoder_config_.video_format)
519 .has_internal_source) {
520 last_frame_info_ = VideoFrameInfo(176, 144, false);
521 ReconfigureEncoder();
perkjfa10b552016-10-02 23:45:26 -0700522 }
523}
perkj26091b12016-09-01 01:17:40 -0700524
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800525// TODO(bugs.webrtc.org/8807): Currently this always does a hard
526// reconfiguration, but this isn't always necessary. Add in logic to only update
527// the VideoBitrateAllocator and call OnEncoderConfigurationChanged with a
528// "soft" reconfiguration.
mflodmancc3d4422017-08-03 08:27:51 -0700529void VideoStreamEncoder::ReconfigureEncoder() {
perkjfa10b552016-10-02 23:45:26 -0700530 RTC_DCHECK(pending_encoder_reconfiguration_);
531 std::vector<VideoStream> streams =
532 encoder_config_.video_stream_factory->CreateEncoderStreams(
533 last_frame_info_->width, last_frame_info_->height, encoder_config_);
perkj26091b12016-09-01 01:17:40 -0700534
ilnik6b826ef2017-06-16 06:53:48 -0700535 // TODO(ilnik): If configured resolution is significantly less than provided,
536 // e.g. because there are not enough SSRCs for all simulcast streams,
537 // signal new resolutions via SinkWants to video source.
538
539 // Stream dimensions may be not equal to given because of a simulcast
540 // restrictions.
Florent Castelli450b5482018-11-29 17:32:47 +0100541 auto highest_stream = std::max_element(
542 streams.begin(), streams.end(),
543 [](const webrtc::VideoStream& a, const webrtc::VideoStream& b) {
544 return std::tie(a.width, a.height) < std::tie(b.width, b.height);
545 });
546 int highest_stream_width = static_cast<int>(highest_stream->width);
547 int highest_stream_height = static_cast<int>(highest_stream->height);
ilnik6b826ef2017-06-16 06:53:48 -0700548 // Dimension may be reduced to be, e.g. divisible by 4.
549 RTC_CHECK_GE(last_frame_info_->width, highest_stream_width);
550 RTC_CHECK_GE(last_frame_info_->height, highest_stream_height);
551 crop_width_ = last_frame_info_->width - highest_stream_width;
552 crop_height_ = last_frame_info_->height - highest_stream_height;
553
Erik Språng08127a92016-11-16 16:41:30 +0100554 VideoCodec codec;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800555 if (!VideoCodecInitializer::SetupCodec(encoder_config_, streams, &codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100556 RTC_LOG(LS_ERROR) << "Failed to create encoder configuration.";
Erik Språng08127a92016-11-16 16:41:30 +0100557 }
perkjfa10b552016-10-02 23:45:26 -0700558
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800559 rate_allocator_ =
560 settings_.bitrate_allocator_factory->CreateVideoBitrateAllocator(codec);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800561
“Michael277a6562018-06-01 14:09:19 -0500562 // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9.
563 if (encoder_config_.codec_type == kVideoCodecVP9) {
“Michael277a6562018-06-01 14:09:19 -0500564 // Lower max bitrate to the level codec actually can produce.
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100565 streams[0].max_bitrate_bps = std::min<int>(
566 streams[0].max_bitrate_bps, SvcRateAllocator::GetMaxBitrateBps(codec));
“Michael277a6562018-06-01 14:09:19 -0500567 streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100568 // target_bitrate_bps specifies the maximum padding bitrate.
“Michael277a6562018-06-01 14:09:19 -0500569 streams[0].target_bitrate_bps =
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100570 SvcRateAllocator::GetPaddingBitrateBps(codec);
“Michael277a6562018-06-01 14:09:19 -0500571 }
572
perkjfa10b552016-10-02 23:45:26 -0700573 codec.startBitrate =
574 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
575 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
576 codec.expect_encode_from_texture = last_frame_info_->is_texture;
sprangfda496a2017-06-15 04:21:07 -0700577 max_framerate_ = codec.maxFramerate;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200578
579 // Inform source about max configured framerate.
580 int max_framerate = 0;
581 for (const auto& stream : streams) {
582 max_framerate = std::max(stream.max_framerate, max_framerate);
583 }
584 source_proxy_->SetMaxFramerate(max_framerate);
Stefan Holmere5904162015-03-26 11:11:06 +0100585
Niels Möller4db138e2018-04-19 09:04:13 +0200586 // Keep the same encoder, as long as the video_format is unchanged.
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100587 // Encoder creation block is split in two since EncoderInfo needed to start
588 // CPU adaptation with the correct settings should be polled after
589 // encoder_->InitEncode().
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000590 if (pending_encoder_creation_) {
Niels Möller4db138e2018-04-19 09:04:13 +0200591 if (encoder_) {
592 video_sender_.RegisterExternalEncoder(nullptr, false);
593 }
594
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000595 encoder_ = settings_.encoder_factory->CreateVideoEncoder(
596 encoder_config_.video_format);
597 // TODO(nisse): What to do if creating the encoder fails? Crash,
598 // or just discard incoming frames?
599 RTC_CHECK(encoder_);
600
601 const webrtc::VideoEncoderFactory::CodecInfo info =
602 settings_.encoder_factory->QueryVideoEncoder(
603 encoder_config_.video_format);
Niels Möller4db138e2018-04-19 09:04:13 +0200604
Niels Möller4db138e2018-04-19 09:04:13 +0200605 video_sender_.RegisterExternalEncoder(encoder_.get(),
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000606 info.has_internal_source);
Niels Möller4db138e2018-04-19 09:04:13 +0200607 }
608 // RegisterSendCodec implies an unconditional call to
609 // encoder_->InitEncode().
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200610 bool success = video_sender_.RegisterSendCodec(
perkjfa10b552016-10-02 23:45:26 -0700611 &codec, number_of_cores_,
612 static_cast<uint32_t>(max_data_payload_length_)) == VCM_OK;
Peter Boström905f8e72016-03-02 16:59:56 +0100613 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100614 RTC_LOG(LS_ERROR) << "Failed to configure encoder.";
sprangfe627f32017-03-29 08:24:59 -0700615 rate_allocator_.reset();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000616 }
Peter Boström905f8e72016-03-02 16:59:56 +0100617
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100618 if (pending_encoder_creation_) {
619 overuse_detector_->StopCheckForOveruse();
620 overuse_detector_->StartCheckForOveruse(
621 GetCpuOveruseOptions(
622 settings_, encoder_->GetEncoderInfo().is_hardware_accelerated),
623 this);
624 pending_encoder_creation_ = false;
625 }
626
Niels Möller6bb5ab92019-01-11 11:11:10 +0100627 int num_layers;
628 if (codec.codecType == kVideoCodecVP8) {
629 num_layers = codec.VP8()->numberOfTemporalLayers;
630 } else if (codec.codecType == kVideoCodecVP9) {
631 num_layers = codec.VP9()->numberOfTemporalLayers;
Johnny Lee1a1c52b2019-02-08 14:25:40 -0500632 } else if (codec.codecType == kVideoCodecH264) {
633 num_layers = codec.H264()->numberOfTemporalLayers;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100634 } else if (codec.codecType == kVideoCodecGeneric &&
635 codec.numberOfSimulcastStreams > 0) {
636 // This is mainly for unit testing, disabling frame dropping.
637 // TODO(sprang): Add a better way to disable frame dropping.
638 num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
639 } else {
640 num_layers = 1;
641 }
642
643 frame_dropper_.Reset();
644 frame_dropper_.SetRates(codec.startBitrate, max_framerate_);
645 uint32_t framerate_fps = GetInputFramerateFps();
646 // Force-disable frame dropper if either:
647 // * We have screensharing with layers.
648 // * "WebRTC-FrameDropper" field trial is "Disabled".
649 force_disable_frame_dropper_ =
650 field_trial::IsDisabled(kFrameDropperFieldTrial) ||
651 (num_layers > 1 && codec.mode == VideoCodecMode::kScreensharing);
652
Erik Språng7ca375c2019-02-06 16:20:17 +0100653 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
654 if (rate_control_settings_.UseEncoderBitrateAdjuster()) {
655 bitrate_adjuster_ = absl::make_unique<EncoderBitrateAdjuster>(codec);
656 bitrate_adjuster_->OnEncoderInfo(info);
657 }
658
Niels Möller6bb5ab92019-01-11 11:11:10 +0100659 if (rate_allocator_ && last_observed_bitrate_bps_ > 0) {
660 // We have a new rate allocator instance and already configured target
661 // bitrate. Update the rate allocation and notify observsers.
662 VideoBitrateAllocation bitrate_allocation =
663 GetBitrateAllocationAndNotifyObserver(last_observed_bitrate_bps_,
664 framerate_fps);
665
666 video_sender_.SetChannelParameters(bitrate_allocation, framerate_fps);
667 }
ilnik35b7de42017-03-15 04:24:21 -0700668
Niels Möller213618e2018-07-24 09:29:58 +0200669 encoder_stats_observer_->OnEncoderReconfigured(encoder_config_, streams);
Per512ecb32016-09-23 15:52:06 +0200670
perkjfa10b552016-10-02 23:45:26 -0700671 pending_encoder_reconfiguration_ = false;
Erik Språng08127a92016-11-16 16:41:30 +0100672
Pera48ddb72016-09-29 11:48:50 +0200673 sink_->OnEncoderConfigurationChanged(
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100674 std::move(streams), encoder_config_.content_type,
675 encoder_config_.min_transmit_bitrate_bps);
kthelgason876222f2016-11-29 01:44:11 -0800676
Niels Möller7dc26b72017-12-06 10:27:48 +0100677 // Get the current target framerate, ie the maximum framerate as specified by
678 // the current codec configuration, or any limit imposed by cpu adaption in
679 // maintain-resolution or balanced mode. This is used to make sure overuse
680 // detection doesn't needlessly trigger in low and/or variable framerate
681 // scenarios.
682 int target_framerate = std::min(
683 max_framerate_, source_proxy_->GetActiveSinkWants().max_framerate_fps);
684 overuse_detector_->OnTargetFramerateUpdated(target_framerate);
Niels Möller2d061182018-04-24 09:13:08 +0200685
Erik Språng7ca375c2019-02-06 16:20:17 +0100686 ConfigureQualityScaler(info);
kthelgason2bc68642017-02-07 07:02:22 -0800687}
688
Erik Språng7ca375c2019-02-06 16:20:17 +0100689void VideoStreamEncoder::ConfigureQualityScaler(
690 const VideoEncoder::EncoderInfo& encoder_info) {
kthelgason2bc68642017-02-07 07:02:22 -0800691 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +0100692 const auto scaling_settings = encoder_info.scaling_settings;
asapersson36e9eb42017-03-31 05:29:12 -0700693 const bool quality_scaling_allowed =
asapersson91914e22017-06-01 00:34:08 -0700694 IsResolutionScalingEnabled(degradation_preference_) &&
Niels Möller225c7872018-02-22 15:03:53 +0100695 scaling_settings.thresholds;
kthelgason3af6cc02017-03-22 00:25:28 -0700696
asapersson36e9eb42017-03-31 05:29:12 -0700697 if (quality_scaling_allowed) {
asapersson09f05612017-05-15 23:40:18 -0700698 if (quality_scaler_.get() == nullptr) {
699 // Quality scaler has not already been configured.
Niels Möller225c7872018-02-22 15:03:53 +0100700
Åsa Perssona945aee2018-04-24 16:53:25 +0200701 // Use experimental thresholds if available.
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200702 absl::optional<VideoEncoder::QpThresholds> experimental_thresholds;
Åsa Perssona945aee2018-04-24 16:53:25 +0200703 if (quality_scaling_experiment_enabled_) {
704 experimental_thresholds = QualityScalingExperiment::GetQpThresholds(
705 encoder_config_.codec_type);
706 }
Karl Wiberg918f50c2018-07-05 11:40:33 +0200707 // Since the interface is non-public, absl::make_unique can't do this
708 // upcast.
Niels Möller225c7872018-02-22 15:03:53 +0100709 AdaptationObserverInterface* observer = this;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200710 quality_scaler_ = absl::make_unique<QualityScaler>(
Åsa Perssona945aee2018-04-24 16:53:25 +0200711 observer, experimental_thresholds ? *experimental_thresholds
712 : *(scaling_settings.thresholds));
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200713 has_seen_first_significant_bwe_change_ = false;
714 initial_framedrop_ = 0;
kthelgason876222f2016-11-29 01:44:11 -0800715 }
716 } else {
717 quality_scaler_.reset(nullptr);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200718 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason876222f2016-11-29 01:44:11 -0800719 }
asapersson09f05612017-05-15 23:40:18 -0700720
Niels Möller213618e2018-07-24 09:29:58 +0200721 encoder_stats_observer_->OnAdaptationChanged(
722 VideoStreamEncoderObserver::AdaptationReason::kNone,
723 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000724}
725
mflodmancc3d4422017-08-03 08:27:51 -0700726void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
perkj26091b12016-09-01 01:17:40 -0700727 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_);
perkj26091b12016-09-01 01:17:40 -0700728 VideoFrame incoming_frame = video_frame;
729
730 // Local time in webrtc time base.
ilnik04f4d122017-06-19 07:18:55 -0700731 int64_t current_time_us = clock_->TimeInMicroseconds();
732 int64_t current_time_ms = current_time_us / rtc::kNumMicrosecsPerMillisec;
733 // In some cases, e.g., when the frame from decoder is fed to encoder,
734 // the timestamp may be set to the future. As the encoding pipeline assumes
735 // capture time to be less than present time, we should reset the capture
736 // timestamps here. Otherwise there may be issues with RTP send stream.
737 if (incoming_frame.timestamp_us() > current_time_us)
738 incoming_frame.set_timestamp_us(current_time_us);
perkj26091b12016-09-01 01:17:40 -0700739
740 // Capture time may come from clock with an offset and drift from clock_.
741 int64_t capture_ntp_time_ms;
nisse891419f2017-01-12 10:02:22 -0800742 if (video_frame.ntp_time_ms() > 0) {
perkj26091b12016-09-01 01:17:40 -0700743 capture_ntp_time_ms = video_frame.ntp_time_ms();
744 } else if (video_frame.render_time_ms() != 0) {
745 capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
746 } else {
nisse1c0dea82017-01-30 02:43:18 -0800747 capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
perkj26091b12016-09-01 01:17:40 -0700748 }
749 incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
750
751 // Convert NTP time, in ms, to RTP timestamp.
752 const int kMsToRtpTimestamp = 90;
753 incoming_frame.set_timestamp(
754 kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
755
756 if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
757 // We don't allow the same capture time for two frames, drop this one.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100758 RTC_LOG(LS_WARNING) << "Same/old NTP timestamp ("
759 << incoming_frame.ntp_time_ms()
760 << " <= " << last_captured_timestamp_
761 << ") for incoming frame. Dropping.";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100762 encoder_queue_.PostTask([this, incoming_frame]() {
763 RTC_DCHECK_RUN_ON(&encoder_queue_);
764 accumulated_update_rect_.Union(incoming_frame.update_rect());
765 });
perkj26091b12016-09-01 01:17:40 -0700766 return;
767 }
768
asapersson6ffb67d2016-09-12 00:10:45 -0700769 bool log_stats = false;
nisse1c0dea82017-01-30 02:43:18 -0800770 if (current_time_ms - last_frame_log_ms_ > kFrameLogIntervalMs) {
771 last_frame_log_ms_ = current_time_ms;
asapersson6ffb67d2016-09-12 00:10:45 -0700772 log_stats = true;
773 }
774
perkj26091b12016-09-01 01:17:40 -0700775 last_captured_timestamp_ = incoming_frame.ntp_time_ms();
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200776
777 int64_t post_time_us = rtc::TimeMicros();
778 ++posted_frames_waiting_for_encode_;
779
780 encoder_queue_.PostTask(
781 [this, incoming_frame, post_time_us, log_stats]() {
782 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller213618e2018-07-24 09:29:58 +0200783 encoder_stats_observer_->OnIncomingFrame(incoming_frame.width(),
784 incoming_frame.height());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200785 ++captured_frame_count_;
786 const int posted_frames_waiting_for_encode =
787 posted_frames_waiting_for_encode_.fetch_sub(1);
788 RTC_DCHECK_GT(posted_frames_waiting_for_encode, 0);
789 if (posted_frames_waiting_for_encode == 1) {
Sebastian Janssona3177052018-04-10 13:05:49 +0200790 MaybeEncodeVideoFrame(incoming_frame, post_time_us);
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200791 } else {
792 // There is a newer frame in flight. Do not encode this frame.
793 RTC_LOG(LS_VERBOSE)
794 << "Incoming frame dropped due to that the encoder is blocked.";
795 ++dropped_frame_count_;
Niels Möller213618e2018-07-24 09:29:58 +0200796 encoder_stats_observer_->OnFrameDropped(
797 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100798 accumulated_update_rect_.Union(incoming_frame.update_rect());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200799 }
800 if (log_stats) {
801 RTC_LOG(LS_INFO) << "Number of frames: captured "
802 << captured_frame_count_
803 << ", dropped (due to encoder blocked) "
804 << dropped_frame_count_ << ", interval_ms "
805 << kFrameLogIntervalMs;
806 captured_frame_count_ = 0;
807 dropped_frame_count_ = 0;
808 }
809 });
perkj26091b12016-09-01 01:17:40 -0700810}
811
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200812void VideoStreamEncoder::OnDiscardedFrame() {
Niels Möller213618e2018-07-24 09:29:58 +0200813 encoder_stats_observer_->OnFrameDropped(
814 VideoStreamEncoderObserver::DropReason::kSource);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200815}
816
mflodmancc3d4422017-08-03 08:27:51 -0700817bool VideoStreamEncoder::EncoderPaused() const {
perkj26091b12016-09-01 01:17:40 -0700818 RTC_DCHECK_RUN_ON(&encoder_queue_);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000819 // Pause video if paused by caller or as long as the network is down or the
820 // pacer queue has grown too large in buffered mode.
perkj57c21f92016-06-17 07:27:16 -0700821 // If the pacer queue has grown too large or the network is down,
perkjfea93092016-05-14 00:58:48 -0700822 // last_observed_bitrate_bps_ will be 0.
perkj26091b12016-09-01 01:17:40 -0700823 return last_observed_bitrate_bps_ == 0;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000824}
825
mflodmancc3d4422017-08-03 08:27:51 -0700826void VideoStreamEncoder::TraceFrameDropStart() {
perkj26091b12016-09-01 01:17:40 -0700827 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000828 // Start trace event only on the first frame after encoder is paused.
829 if (!encoder_paused_and_dropped_frame_) {
830 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
831 }
832 encoder_paused_and_dropped_frame_ = true;
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000833}
834
mflodmancc3d4422017-08-03 08:27:51 -0700835void VideoStreamEncoder::TraceFrameDropEnd() {
perkj26091b12016-09-01 01:17:40 -0700836 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000837 // End trace event on first frame after encoder resumes, if frame was dropped.
838 if (encoder_paused_and_dropped_frame_) {
839 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
840 }
841 encoder_paused_and_dropped_frame_ = false;
842}
843
Niels Möller6bb5ab92019-01-11 11:11:10 +0100844VideoBitrateAllocation
845VideoStreamEncoder::GetBitrateAllocationAndNotifyObserver(
846 const uint32_t target_bitrate_bps,
847 uint32_t framerate_fps) {
848 // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
849 // might cap the bitrate to the min bitrate configured.
850 VideoBitrateAllocation bitrate_allocation;
851 if (rate_allocator_ && target_bitrate_bps > 0) {
852 bitrate_allocation =
853 rate_allocator_->GetAllocation(target_bitrate_bps, framerate_fps);
854 }
855
856 if (bitrate_observer_ && bitrate_allocation.get_sum_bps() > 0) {
857 bitrate_observer_->OnBitrateAllocationUpdated(bitrate_allocation);
858 }
859
Erik Språng7ca375c2019-02-06 16:20:17 +0100860 if (bitrate_adjuster_) {
Erik Språng0e1a1f92019-02-18 18:45:13 +0100861 VideoBitrateAllocation adjusted_allocation =
862 bitrate_adjuster_->AdjustRateAllocation(bitrate_allocation,
863 framerate_fps);
864 RTC_LOG(LS_VERBOSE) << "Adjusting allocation, fps = " << framerate_fps
865 << ", from " << bitrate_allocation.ToString() << ", to "
866 << adjusted_allocation.ToString();
867 return adjusted_allocation;
Erik Språng7ca375c2019-02-06 16:20:17 +0100868 }
Niels Möller6bb5ab92019-01-11 11:11:10 +0100869 return bitrate_allocation;
870}
871
872uint32_t VideoStreamEncoder::GetInputFramerateFps() {
873 const uint32_t default_fps = max_framerate_ != -1 ? max_framerate_ : 30;
874 return input_framerate_.Rate(clock_->TimeInMilliseconds())
875 .value_or(default_fps);
876}
877
Sebastian Janssona3177052018-04-10 13:05:49 +0200878void VideoStreamEncoder::MaybeEncodeVideoFrame(const VideoFrame& video_frame,
879 int64_t time_when_posted_us) {
perkj26091b12016-09-01 01:17:40 -0700880 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800881
Per21d45d22016-10-30 21:37:57 +0100882 if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
perkjfa10b552016-10-02 23:45:26 -0700883 video_frame.height() != last_frame_info_->height ||
perkjfa10b552016-10-02 23:45:26 -0700884 video_frame.is_texture() != last_frame_info_->is_texture) {
885 pending_encoder_reconfiguration_ = true;
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100886 last_frame_info_ = VideoFrameInfo(video_frame.width(), video_frame.height(),
887 video_frame.is_texture());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100888 RTC_LOG(LS_INFO) << "Video frame parameters changed: dimensions="
889 << last_frame_info_->width << "x"
890 << last_frame_info_->height
891 << ", texture=" << last_frame_info_->is_texture << ".";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100892 // Force full frame update, since resolution has changed.
893 accumulated_update_rect_ =
894 VideoFrame::UpdateRect{0, 0, video_frame.width(), video_frame.height()};
perkjfa10b552016-10-02 23:45:26 -0700895 }
896
Niels Möller4db138e2018-04-19 09:04:13 +0200897 // We have to create then encoder before the frame drop logic,
898 // because the latter depends on encoder_->GetScalingSettings.
899 // According to the testcase
900 // InitialFrameDropOffWhenEncoderDisabledScaling, the return value
901 // from GetScalingSettings should enable or disable the frame drop.
902
Erik Språnga8d48ab2019-02-08 14:17:40 +0100903 // Update input frame rate before we start using it. If we update it after
904 // any potential frame drop we are going to artifically increase frame sizes.
905 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
Niels Möller6bb5ab92019-01-11 11:11:10 +0100906 uint32_t framerate_fps = GetInputFramerateFps();
907
Niels Möller4db138e2018-04-19 09:04:13 +0200908 int64_t now_ms = clock_->TimeInMilliseconds();
909 if (pending_encoder_reconfiguration_) {
910 ReconfigureEncoder();
911 last_parameters_update_ms_.emplace(now_ms);
912 } else if (!last_parameters_update_ms_ ||
913 now_ms - *last_parameters_update_ms_ >=
914 vcm::VCMProcessTimer::kDefaultProcessIntervalMs) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100915 video_sender_.SetChannelParameters(
916 GetBitrateAllocationAndNotifyObserver(last_observed_bitrate_bps_,
917 framerate_fps),
918 framerate_fps);
Niels Möller4db138e2018-04-19 09:04:13 +0200919 last_parameters_update_ms_.emplace(now_ms);
920 }
921
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100922 // Because pending frame will be dropped in any case, we need to
923 // remember its updated region.
924 if (pending_frame_) {
925 encoder_stats_observer_->OnFrameDropped(
926 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
927 accumulated_update_rect_.Union(pending_frame_->update_rect());
928 }
929
Sebastian Janssona3177052018-04-10 13:05:49 +0200930 if (DropDueToSize(video_frame.size())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100931 RTC_LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
Åsa Persson875841d2018-01-08 08:49:53 +0100932 int count = GetConstAdaptCounter().ResolutionCount(kQuality);
kthelgason2bc68642017-02-07 07:02:22 -0800933 AdaptDown(kQuality);
Åsa Persson875841d2018-01-08 08:49:53 +0100934 if (GetConstAdaptCounter().ResolutionCount(kQuality) > count) {
Niels Möller213618e2018-07-24 09:29:58 +0200935 encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
Åsa Persson875841d2018-01-08 08:49:53 +0100936 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200937 ++initial_framedrop_;
Sebastian Jansson0d70e372018-04-17 13:57:13 +0200938 // Storing references to a native buffer risks blocking frame capture.
939 if (video_frame.video_frame_buffer()->type() !=
940 VideoFrameBuffer::Type::kNative) {
941 pending_frame_ = video_frame;
942 pending_frame_post_time_us_ = time_when_posted_us;
943 } else {
944 // Ensure that any previously stored frame is dropped.
945 pending_frame_.reset();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100946 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +0200947 }
kthelgason2bc68642017-02-07 07:02:22 -0800948 return;
949 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200950 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason2bc68642017-02-07 07:02:22 -0800951
perkj26091b12016-09-01 01:17:40 -0700952 if (EncoderPaused()) {
Sebastian Jansson0d70e372018-04-17 13:57:13 +0200953 // Storing references to a native buffer risks blocking frame capture.
954 if (video_frame.video_frame_buffer()->type() !=
955 VideoFrameBuffer::Type::kNative) {
956 if (pending_frame_)
957 TraceFrameDropStart();
958 pending_frame_ = video_frame;
959 pending_frame_post_time_us_ = time_when_posted_us;
960 } else {
961 // Ensure that any previously stored frame is dropped.
962 pending_frame_.reset();
Sebastian Janssona3177052018-04-10 13:05:49 +0200963 TraceFrameDropStart();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100964 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +0200965 }
perkj26091b12016-09-01 01:17:40 -0700966 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000967 }
Sebastian Janssona3177052018-04-10 13:05:49 +0200968
969 pending_frame_.reset();
Niels Möller6bb5ab92019-01-11 11:11:10 +0100970
971 frame_dropper_.Leak(framerate_fps);
972 // Frame dropping is enabled iff frame dropping is not force-disabled, and
973 // rate controller is not trusted.
974 const bool frame_dropping_enabled =
975 !force_disable_frame_dropper_ &&
976 !encoder_info_.has_trusted_rate_controller;
977 frame_dropper_.Enable(frame_dropping_enabled);
978 if (frame_dropping_enabled && frame_dropper_.DropFrame()) {
979 RTC_LOG(LS_VERBOSE) << "Drop Frame: "
980 << "target bitrate " << last_observed_bitrate_bps_
981 << ", input frame rate " << framerate_fps;
982 OnDroppedFrame(
983 EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100984 accumulated_update_rect_.Union(video_frame.update_rect());
Niels Möller6bb5ab92019-01-11 11:11:10 +0100985 return;
986 }
987
Sebastian Janssona3177052018-04-10 13:05:49 +0200988 EncodeVideoFrame(video_frame, time_when_posted_us);
989}
990
991void VideoStreamEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
992 int64_t time_when_posted_us) {
993 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700994 TraceFrameDropEnd();
niklase@google.com470e71d2011-07-07 08:21:25 +0000995
ilnik6b826ef2017-06-16 06:53:48 -0700996 VideoFrame out_frame(video_frame);
997 // Crop frame if needed.
998 if (crop_width_ > 0 || crop_height_ > 0) {
999 int cropped_width = video_frame.width() - crop_width_;
1000 int cropped_height = video_frame.height() - crop_height_;
1001 rtc::scoped_refptr<I420Buffer> cropped_buffer =
1002 I420Buffer::Create(cropped_width, cropped_height);
1003 // TODO(ilnik): Remove scaling if cropping is too big, as it should never
1004 // happen after SinkWants signaled correctly from ReconfigureEncoder.
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001005 VideoFrame::UpdateRect update_rect = video_frame.update_rect();
ilnik6b826ef2017-06-16 06:53:48 -07001006 if (crop_width_ < 4 && crop_height_ < 4) {
1007 cropped_buffer->CropAndScaleFrom(
1008 *video_frame.video_frame_buffer()->ToI420(), crop_width_ / 2,
1009 crop_height_ / 2, cropped_width, cropped_height);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001010 update_rect.offset_x -= crop_width_ / 2;
1011 update_rect.offset_y -= crop_height_ / 2;
1012 update_rect.Intersect(
1013 VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height});
1014
ilnik6b826ef2017-06-16 06:53:48 -07001015 } else {
1016 cropped_buffer->ScaleFrom(
1017 *video_frame.video_frame_buffer()->ToI420().get());
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001018 update_rect = VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height};
ilnik6b826ef2017-06-16 06:53:48 -07001019 }
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001020 out_frame = VideoFrame::Builder()
1021 .set_video_frame_buffer(cropped_buffer)
1022 .set_timestamp_rtp(video_frame.timestamp())
1023 .set_timestamp_ms(video_frame.render_time_ms())
1024 .set_rotation(video_frame.rotation())
1025 .set_id(video_frame.id())
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001026 .set_update_rect(update_rect)
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001027 .build();
ilnik6b826ef2017-06-16 06:53:48 -07001028 out_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001029 // Since accumulated_update_rect_ is constructed before cropping,
1030 // we can't trust it. If any changes were pending, we invalidate whole
1031 // frame here.
1032 if (!accumulated_update_rect_.IsEmpty()) {
1033 accumulated_update_rect_ =
1034 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()};
1035 }
1036 }
1037
1038 if (!accumulated_update_rect_.IsEmpty()) {
1039 accumulated_update_rect_.Union(out_frame.update_rect());
1040 accumulated_update_rect_.Intersect(
1041 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()});
1042 out_frame.set_update_rect(accumulated_update_rect_);
1043 accumulated_update_rect_.MakeEmptyUpdate();
ilnik6b826ef2017-06-16 06:53:48 -07001044 }
1045
Magnus Jedvert26679d62015-04-07 14:07:41 +02001046 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +00001047 "Encode");
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +00001048
Niels Möller7dc26b72017-12-06 10:27:48 +01001049 overuse_detector_->FrameCaptured(out_frame, time_when_posted_us);
perkjd52063f2016-09-07 06:32:18 -07001050
Erik Språnge2fd86a2018-10-24 11:32:39 +02001051 // Encoder metadata needs to be updated before encode complete callback.
1052 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
1053 if (info.implementation_name != encoder_info_.implementation_name) {
1054 encoder_stats_observer_->OnEncoderImplementationChanged(
1055 info.implementation_name);
Erik Språng7ca375c2019-02-06 16:20:17 +01001056 if (bitrate_adjuster_) {
1057 // Encoder implementation changed, reset overshoot detector states.
1058 bitrate_adjuster_->Reset();
1059 }
Erik Språnge2fd86a2018-10-24 11:32:39 +02001060 }
Erik Språng7ca375c2019-02-06 16:20:17 +01001061
1062 if (bitrate_adjuster_) {
1063 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
1064 if (info.fps_allocation[si] != encoder_info_.fps_allocation[si]) {
1065 bitrate_adjuster_->OnEncoderInfo(info);
1066 break;
1067 }
1068 }
1069 }
1070
Erik Språnge2fd86a2018-10-24 11:32:39 +02001071 encoder_info_ = info;
Erik Språngeee39202018-11-15 17:52:43 +01001072 video_sender_.AddVideoFrame(out_frame, nullptr, encoder_info_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001073}
niklase@google.com470e71d2011-07-07 08:21:25 +00001074
mflodmancc3d4422017-08-03 08:27:51 -07001075void VideoStreamEncoder::SendKeyFrame() {
perkj26091b12016-09-01 01:17:40 -07001076 if (!encoder_queue_.IsCurrent()) {
1077 encoder_queue_.PostTask([this] { SendKeyFrame(); });
1078 return;
1079 }
1080 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller1c9aa1e2018-02-16 10:27:23 +01001081 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
Peter Boströmcd5c25c2016-04-21 16:48:08 +02001082 video_sender_.IntraFrameRequest(0);
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00001083}
1084
mflodmancc3d4422017-08-03 08:27:51 -07001085EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001086 const EncodedImage& encoded_image,
1087 const CodecSpecificInfo* codec_specific_info,
1088 const RTPFragmentationHeader* fragmentation) {
perkj26091b12016-09-01 01:17:40 -07001089 // Encoded is called on whatever thread the real encoder implementation run
1090 // on. In the case of hardware encoders, there might be several encoders
1091 // running in parallel on different threads.
Niels Möller213618e2018-07-24 09:29:58 +02001092 encoder_stats_observer_->OnSendEncodedImage(encoded_image,
1093 codec_specific_info);
sprang3911c262016-04-15 01:24:14 -07001094
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001095 EncodedImageCallback::Result result =
1096 sink_->OnEncodedImage(encoded_image, codec_specific_info, fragmentation);
perkjbc75d972016-05-02 06:31:25 -07001097
Niels Möller7dc26b72017-12-06 10:27:48 +01001098 int64_t time_sent_us = rtc::TimeMicros();
Erik Språng7ca375c2019-02-06 16:20:17 +01001099 // We are only interested in propagating the meta-data about the image, not
1100 // encoded data itself, to the post encode function. Since we cannot be sure
1101 // the pointer will still be valid when run on the task queue, set it to null.
1102 EncodedImage encoded_image_metadata = encoded_image;
1103 encoded_image_metadata.set_buffer(nullptr, 0);
Niels Möller83dbeac2017-12-14 16:39:44 +01001104
Erik Språng7ca375c2019-02-06 16:20:17 +01001105 int temporal_index = 0;
1106 if (codec_specific_info) {
1107 if (codec_specific_info->codecType == kVideoCodecVP9) {
1108 temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx;
1109 } else if (codec_specific_info->codecType == kVideoCodecVP8) {
1110 temporal_index = codec_specific_info->codecSpecific.VP8.temporalIdx;
1111 }
1112 }
1113 if (temporal_index == kNoTemporalIdx) {
1114 temporal_index = 0;
Niels Möller83dbeac2017-12-14 16:39:44 +01001115 }
1116
Erik Språng7ca375c2019-02-06 16:20:17 +01001117 RunPostEncode(encoded_image_metadata, time_sent_us, temporal_index);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001118
1119 if (result.error == Result::OK) {
1120 // In case of an internal encoder running on a separate thread, the
1121 // decision to drop a frame might be a frame late and signaled via
1122 // atomic flag. This is because we can't easily wait for the worker thread
1123 // without risking deadlocks, eg during shutdown when the worker thread
1124 // might be waiting for the internal encoder threads to stop.
1125 if (pending_frame_drops_.load() > 0) {
1126 int pending_drops = pending_frame_drops_.fetch_sub(1);
1127 RTC_DCHECK_GT(pending_drops, 0);
1128 result.drop_next_frame = true;
1129 }
1130 }
perkj803d97f2016-11-01 11:45:46 -07001131
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001132 return result;
Peter Boströmb7d9a972015-12-18 16:01:11 +01001133}
1134
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001135void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
1136 switch (reason) {
1137 case DropReason::kDroppedByMediaOptimizations:
Niels Möller213618e2018-07-24 09:29:58 +02001138 encoder_stats_observer_->OnFrameDropped(
1139 VideoStreamEncoderObserver::DropReason::kMediaOptimization);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001140 encoder_queue_.PostTask([this] {
1141 RTC_DCHECK_RUN_ON(&encoder_queue_);
1142 if (quality_scaler_)
Åsa Perssona945aee2018-04-24 16:53:25 +02001143 quality_scaler_->ReportDroppedFrameByMediaOpt();
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001144 });
1145 break;
1146 case DropReason::kDroppedByEncoder:
Niels Möller213618e2018-07-24 09:29:58 +02001147 encoder_stats_observer_->OnFrameDropped(
1148 VideoStreamEncoderObserver::DropReason::kEncoder);
Åsa Perssona945aee2018-04-24 16:53:25 +02001149 encoder_queue_.PostTask([this] {
1150 RTC_DCHECK_RUN_ON(&encoder_queue_);
1151 if (quality_scaler_)
1152 quality_scaler_->ReportDroppedFrameByEncoder();
1153 });
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001154 break;
1155 }
kthelgason876222f2016-11-29 01:44:11 -08001156}
1157
mflodmancc3d4422017-08-03 08:27:51 -07001158void VideoStreamEncoder::OnBitrateUpdated(uint32_t bitrate_bps,
1159 uint8_t fraction_lost,
1160 int64_t round_trip_time_ms) {
perkj26091b12016-09-01 01:17:40 -07001161 if (!encoder_queue_.IsCurrent()) {
1162 encoder_queue_.PostTask(
1163 [this, bitrate_bps, fraction_lost, round_trip_time_ms] {
1164 OnBitrateUpdated(bitrate_bps, fraction_lost, round_trip_time_ms);
1165 });
1166 return;
1167 }
1168 RTC_DCHECK_RUN_ON(&encoder_queue_);
1169 RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
1170
Mirko Bonadei675513b2017-11-09 11:09:25 +01001171 RTC_LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << bitrate_bps
1172 << " packet loss " << static_cast<int>(fraction_lost)
1173 << " rtt " << round_trip_time_ms;
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001174 // On significant changes to BWE at the start of the call,
1175 // enable frame drops to quickly react to jumps in available bandwidth.
1176 if (encoder_start_bitrate_bps_ != 0 &&
1177 !has_seen_first_significant_bwe_change_ && quality_scaler_ &&
1178 initial_framedrop_on_bwe_enabled_ &&
1179 abs_diff(bitrate_bps, encoder_start_bitrate_bps_) >=
1180 kFramedropThreshold * encoder_start_bitrate_bps_) {
1181 // Reset initial framedrop feature when first real BW estimate arrives.
1182 // TODO(kthelgason): Update BitrateAllocator to not call OnBitrateUpdated
1183 // without an actual BW estimate.
1184 initial_framedrop_ = 0;
1185 has_seen_first_significant_bwe_change_ = true;
1186 }
perkj26091b12016-09-01 01:17:40 -07001187
Niels Möller6bb5ab92019-01-11 11:11:10 +01001188 uint32_t framerate_fps = GetInputFramerateFps();
1189 frame_dropper_.SetRates((bitrate_bps + 500) / 1000, framerate_fps);
1190
1191 VideoBitrateAllocation bitrate_allocation =
1192 GetBitrateAllocationAndNotifyObserver(bitrate_bps, framerate_fps);
1193 video_sender_.SetChannelParameters(bitrate_allocation, framerate_fps);
perkj26091b12016-09-01 01:17:40 -07001194
1195 encoder_start_bitrate_bps_ =
1196 bitrate_bps != 0 ? bitrate_bps : encoder_start_bitrate_bps_;
mflodman101f2502016-06-09 17:21:19 +02001197 bool video_is_suspended = bitrate_bps == 0;
Erik Språng08127a92016-11-16 16:41:30 +01001198 bool video_suspension_changed = video_is_suspended != EncoderPaused();
perkj26091b12016-09-01 01:17:40 -07001199 last_observed_bitrate_bps_ = bitrate_bps;
Peter Boströmd153a372015-11-10 15:27:12 +00001200
sprang552c7c72017-02-13 04:41:45 -08001201 if (video_suspension_changed) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001202 RTC_LOG(LS_INFO) << "Video suspend state changed to: "
1203 << (video_is_suspended ? "suspended" : "not suspended");
Niels Möller213618e2018-07-24 09:29:58 +02001204 encoder_stats_observer_->OnSuspendChange(video_is_suspended);
mflodman101f2502016-06-09 17:21:19 +02001205 }
Sebastian Janssona3177052018-04-10 13:05:49 +02001206 if (video_suspension_changed && !video_is_suspended && pending_frame_ &&
1207 !DropDueToSize(pending_frame_->size())) {
1208 int64_t pending_time_us = rtc::TimeMicros() - pending_frame_post_time_us_;
1209 if (pending_time_us < kPendingFrameTimeoutMs * 1000)
1210 EncodeVideoFrame(*pending_frame_, pending_frame_post_time_us_);
1211 pending_frame_.reset();
1212 }
1213}
1214
1215bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001216 if (initial_framedrop_ < kMaxInitialFramedrop &&
Sebastian Janssona3177052018-04-10 13:05:49 +02001217 encoder_start_bitrate_bps_ > 0) {
1218 if (encoder_start_bitrate_bps_ < 300000 /* qvga */) {
1219 return pixel_count > 320 * 240;
1220 } else if (encoder_start_bitrate_bps_ < 500000 /* vga */) {
1221 return pixel_count > 640 * 480;
1222 }
1223 }
1224 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001225}
1226
mflodmancc3d4422017-08-03 08:27:51 -07001227void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001228 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -07001229 AdaptationRequest adaptation_request = {
1230 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001231 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001232 AdaptationRequest::Mode::kAdaptDown};
asapersson09f05612017-05-15 23:40:18 -07001233
sprangc5d62e22017-04-02 23:53:04 -07001234 bool downgrade_requested =
1235 last_adaptation_request_ &&
1236 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
1237
sprangc5d62e22017-04-02 23:53:04 -07001238 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001239 case DegradationPreference::BALANCED:
asaperssonf7e294d2017-06-13 23:25:22 -07001240 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001241 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangc5d62e22017-04-02 23:53:04 -07001242 if (downgrade_requested &&
1243 adaptation_request.input_pixel_count_ >=
1244 last_adaptation_request_->input_pixel_count_) {
1245 // Don't request lower resolution if the current resolution is not
1246 // lower than the last time we asked for the resolution to be lowered.
1247 return;
1248 }
1249 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001250 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangc5d62e22017-04-02 23:53:04 -07001251 if (adaptation_request.framerate_fps_ <= 0 ||
1252 (downgrade_requested &&
1253 adaptation_request.framerate_fps_ < kMinFramerateFps)) {
1254 // If no input fps estimate available, can't determine how to scale down
1255 // framerate. Otherwise, don't request lower framerate if we don't have
1256 // a valid frame rate. Since framerate, unlike resolution, is a measure
1257 // we have to estimate, and can fluctuate naturally over time, don't
1258 // make the same kind of limitations as for resolution, but trust the
1259 // overuse detector to not trigger too often.
1260 return;
1261 }
1262 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001263 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001264 return;
sprang84a37592017-02-10 07:04:27 -08001265 }
sprangc5d62e22017-04-02 23:53:04 -07001266
sprangc5d62e22017-04-02 23:53:04 -07001267 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001268 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001269 // Try scale down framerate, if lower.
1270 int fps = MinFps(last_frame_info_->pixel_count());
1271 if (source_proxy_->RestrictFramerate(fps)) {
1272 GetAdaptCounter().IncrementFramerate(reason);
1273 break;
1274 }
1275 // Scale down resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001276 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001277 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001278 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001279 // Scale down resolution.
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001280 bool min_pixels_reached = false;
asaperssond0de2952017-04-21 01:47:31 -07001281 if (!source_proxy_->RequestResolutionLowerThan(
asapersson142fcc92017-08-17 08:58:54 -07001282 adaptation_request.input_pixel_count_,
Erik Språnge2fd86a2018-10-24 11:32:39 +02001283 encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame,
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001284 &min_pixels_reached)) {
1285 if (min_pixels_reached)
Niels Möller213618e2018-07-24 09:29:58 +02001286 encoder_stats_observer_->OnMinPixelLimitReached();
asaperssond0de2952017-04-21 01:47:31 -07001287 return;
1288 }
asaperssonf7e294d2017-06-13 23:25:22 -07001289 GetAdaptCounter().IncrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001290 break;
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001291 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001292 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001293 // Scale down framerate.
sprangfda496a2017-06-15 04:21:07 -07001294 const int requested_framerate = source_proxy_->RequestFramerateLowerThan(
1295 adaptation_request.framerate_fps_);
1296 if (requested_framerate == -1)
asapersson13874762017-06-07 00:01:02 -07001297 return;
sprangfda496a2017-06-15 04:21:07 -07001298 RTC_DCHECK_NE(max_framerate_, -1);
Niels Möller7dc26b72017-12-06 10:27:48 +01001299 overuse_detector_->OnTargetFramerateUpdated(
1300 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001301 GetAdaptCounter().IncrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001302 break;
sprangfda496a2017-06-15 04:21:07 -07001303 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001304 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001305 RTC_NOTREACHED();
1306 }
1307
asaperssond0de2952017-04-21 01:47:31 -07001308 last_adaptation_request_.emplace(adaptation_request);
1309
asapersson09f05612017-05-15 23:40:18 -07001310 UpdateAdaptationStats(reason);
asaperssond0de2952017-04-21 01:47:31 -07001311
Mirko Bonadei675513b2017-11-09 11:09:25 +01001312 RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
perkj26091b12016-09-01 01:17:40 -07001313}
1314
mflodmancc3d4422017-08-03 08:27:51 -07001315void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001316 RTC_DCHECK_RUN_ON(&encoder_queue_);
asapersson09f05612017-05-15 23:40:18 -07001317
1318 const AdaptCounter& adapt_counter = GetConstAdaptCounter();
1319 int num_downgrades = adapt_counter.TotalCount(reason);
1320 if (num_downgrades == 0)
perkj803d97f2016-11-01 11:45:46 -07001321 return;
asapersson09f05612017-05-15 23:40:18 -07001322 RTC_DCHECK_GT(num_downgrades, 0);
1323
sprangc5d62e22017-04-02 23:53:04 -07001324 AdaptationRequest adaptation_request = {
1325 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001326 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001327 AdaptationRequest::Mode::kAdaptUp};
1328
1329 bool adapt_up_requested =
1330 last_adaptation_request_ &&
1331 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp;
asapersson09f05612017-05-15 23:40:18 -07001332
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001333 if (degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE) {
asaperssonf7e294d2017-06-13 23:25:22 -07001334 if (adapt_up_requested &&
1335 adaptation_request.input_pixel_count_ <=
1336 last_adaptation_request_->input_pixel_count_) {
1337 // Don't request higher resolution if the current resolution is not
1338 // higher than the last time we asked for the resolution to be higher.
sprangc5d62e22017-04-02 23:53:04 -07001339 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001340 }
sprangb1ca0732017-02-01 08:38:12 -08001341 }
sprangc5d62e22017-04-02 23:53:04 -07001342
sprangc5d62e22017-04-02 23:53:04 -07001343 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001344 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001345 // Try scale up framerate, if higher.
1346 int fps = MaxFps(last_frame_info_->pixel_count());
1347 if (source_proxy_->IncreaseFramerate(fps)) {
1348 GetAdaptCounter().DecrementFramerate(reason, fps);
1349 // Reset framerate in case of fewer fps steps down than up.
1350 if (adapt_counter.FramerateCount() == 0 &&
1351 fps != std::numeric_limits<int>::max()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001352 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asaperssonf7e294d2017-06-13 23:25:22 -07001353 source_proxy_->IncreaseFramerate(std::numeric_limits<int>::max());
1354 }
1355 break;
1356 }
1357 // Scale up resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001358 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001359 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001360 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001361 // Scale up resolution.
1362 int pixel_count = adaptation_request.input_pixel_count_;
1363 if (adapt_counter.ResolutionCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001364 RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001365 pixel_count = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001366 }
asapersson13874762017-06-07 00:01:02 -07001367 if (!source_proxy_->RequestHigherResolutionThan(pixel_count))
1368 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001369 GetAdaptCounter().DecrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001370 break;
asapersson13874762017-06-07 00:01:02 -07001371 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001372 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001373 // Scale up framerate.
1374 int fps = adaptation_request.framerate_fps_;
1375 if (adapt_counter.FramerateCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001376 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001377 fps = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001378 }
sprangfda496a2017-06-15 04:21:07 -07001379
1380 const int requested_framerate =
1381 source_proxy_->RequestHigherFramerateThan(fps);
1382 if (requested_framerate == -1) {
Niels Möller7dc26b72017-12-06 10:27:48 +01001383 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
asapersson13874762017-06-07 00:01:02 -07001384 return;
sprangfda496a2017-06-15 04:21:07 -07001385 }
Niels Möller7dc26b72017-12-06 10:27:48 +01001386 overuse_detector_->OnTargetFramerateUpdated(
1387 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001388 GetAdaptCounter().DecrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001389 break;
asapersson13874762017-06-07 00:01:02 -07001390 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001391 case DegradationPreference::DISABLED:
asaperssonf7e294d2017-06-13 23:25:22 -07001392 return;
sprangc5d62e22017-04-02 23:53:04 -07001393 }
1394
asaperssond0de2952017-04-21 01:47:31 -07001395 last_adaptation_request_.emplace(adaptation_request);
1396
asapersson09f05612017-05-15 23:40:18 -07001397 UpdateAdaptationStats(reason);
1398
Mirko Bonadei675513b2017-11-09 11:09:25 +01001399 RTC_LOG(LS_INFO) << adapt_counter.ToString();
asapersson09f05612017-05-15 23:40:18 -07001400}
1401
Niels Möller213618e2018-07-24 09:29:58 +02001402// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
mflodmancc3d4422017-08-03 08:27:51 -07001403void VideoStreamEncoder::UpdateAdaptationStats(AdaptReason reason) {
asaperssond0de2952017-04-21 01:47:31 -07001404 switch (reason) {
asaperssond0de2952017-04-21 01:47:31 -07001405 case kCpu:
Niels Möller213618e2018-07-24 09:29:58 +02001406 encoder_stats_observer_->OnAdaptationChanged(
1407 VideoStreamEncoderObserver::AdaptationReason::kCpu,
1408 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asapersson09f05612017-05-15 23:40:18 -07001409 break;
1410 case kQuality:
Niels Möller213618e2018-07-24 09:29:58 +02001411 encoder_stats_observer_->OnAdaptationChanged(
1412 VideoStreamEncoderObserver::AdaptationReason::kQuality,
1413 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asaperssond0de2952017-04-21 01:47:31 -07001414 break;
1415 }
perkj26091b12016-09-01 01:17:40 -07001416}
1417
Niels Möller213618e2018-07-24 09:29:58 +02001418VideoStreamEncoderObserver::AdaptationSteps VideoStreamEncoder::GetActiveCounts(
mflodmancc3d4422017-08-03 08:27:51 -07001419 AdaptReason reason) {
Niels Möller213618e2018-07-24 09:29:58 +02001420 VideoStreamEncoderObserver::AdaptationSteps counts =
mflodmancc3d4422017-08-03 08:27:51 -07001421 GetConstAdaptCounter().Counts(reason);
asapersson09f05612017-05-15 23:40:18 -07001422 switch (reason) {
1423 case kCpu:
1424 if (!IsFramerateScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001425 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001426 if (!IsResolutionScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001427 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001428 break;
1429 case kQuality:
1430 if (!IsFramerateScalingEnabled(degradation_preference_) ||
1431 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001432 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001433 }
1434 if (!IsResolutionScalingEnabled(degradation_preference_) ||
1435 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001436 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001437 }
1438 break;
sprangc5d62e22017-04-02 23:53:04 -07001439 }
asapersson09f05612017-05-15 23:40:18 -07001440 return counts;
sprangc5d62e22017-04-02 23:53:04 -07001441}
1442
mflodmancc3d4422017-08-03 08:27:51 -07001443VideoStreamEncoder::AdaptCounter& VideoStreamEncoder::GetAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001444 return adapt_counters_[degradation_preference_];
1445}
1446
mflodmancc3d4422017-08-03 08:27:51 -07001447const VideoStreamEncoder::AdaptCounter&
1448VideoStreamEncoder::GetConstAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001449 return adapt_counters_[degradation_preference_];
1450}
1451
Erik Språng7ca375c2019-02-06 16:20:17 +01001452void VideoStreamEncoder::RunPostEncode(EncodedImage encoded_image,
Niels Möller6bb5ab92019-01-11 11:11:10 +01001453 int64_t time_sent_us,
Erik Språng7ca375c2019-02-06 16:20:17 +01001454 int temporal_index) {
Niels Möller6bb5ab92019-01-11 11:11:10 +01001455 if (!encoder_queue_.IsCurrent()) {
Erik Språng7ca375c2019-02-06 16:20:17 +01001456 encoder_queue_.PostTask(
1457 [this, encoded_image, time_sent_us, temporal_index] {
1458 RunPostEncode(encoded_image, time_sent_us, temporal_index);
1459 });
Niels Möller6bb5ab92019-01-11 11:11:10 +01001460 return;
1461 }
1462
1463 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +01001464
1465 absl::optional<int> encode_duration_us;
1466 if (encoded_image.timing_.flags != VideoSendTiming::kInvalid) {
1467 encode_duration_us =
1468 // TODO(nisse): Maybe use capture_time_ms_ rather than encode_start_ms_?
1469 rtc::kNumMicrosecsPerMillisec *
1470 (encoded_image.timing_.encode_finish_ms -
1471 encoded_image.timing_.encode_start_ms);
1472 }
1473
1474 // Run post encode tasks, such as overuse detection and frame rate/drop
1475 // stats for internal encoders.
1476 const size_t frame_size = encoded_image.size();
1477 const bool keyframe = encoded_image._frameType == FrameType::kVideoFrameKey;
1478
1479 if (frame_size > 0) {
1480 frame_dropper_.Fill(frame_size, !keyframe);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001481 }
1482
1483 if (encoder_info_.has_internal_source) {
1484 // Update frame dropper after the fact for internal sources.
1485 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
1486 frame_dropper_.Leak(GetInputFramerateFps());
1487 // Signal to encoder to drop next frame.
1488 if (frame_dropper_.DropFrame()) {
1489 pending_frame_drops_.fetch_add(1);
1490 }
1491 }
1492
Erik Språng7ca375c2019-02-06 16:20:17 +01001493 overuse_detector_->FrameSent(
1494 encoded_image.Timestamp(), time_sent_us,
1495 encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec,
1496 encode_duration_us);
1497 if (quality_scaler_ && encoded_image.qp_ >= 0)
1498 quality_scaler_->ReportQp(encoded_image.qp_);
1499 if (bitrate_adjuster_) {
1500 bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index);
1501 }
Niels Möller6bb5ab92019-01-11 11:11:10 +01001502}
1503
asapersson09f05612017-05-15 23:40:18 -07001504// Class holding adaptation information.
mflodmancc3d4422017-08-03 08:27:51 -07001505VideoStreamEncoder::AdaptCounter::AdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001506 fps_counters_.resize(kScaleReasonSize);
1507 resolution_counters_.resize(kScaleReasonSize);
asaperssonf7e294d2017-06-13 23:25:22 -07001508 static_assert(kScaleReasonSize == 2, "Update MoveCount.");
asapersson09f05612017-05-15 23:40:18 -07001509}
1510
mflodmancc3d4422017-08-03 08:27:51 -07001511VideoStreamEncoder::AdaptCounter::~AdaptCounter() {}
asapersson09f05612017-05-15 23:40:18 -07001512
mflodmancc3d4422017-08-03 08:27:51 -07001513std::string VideoStreamEncoder::AdaptCounter::ToString() const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001514 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001515 ss << "Downgrade counts: fps: {" << ToString(fps_counters_);
1516 ss << "}, resolution: {" << ToString(resolution_counters_) << "}";
Jonas Olsson84df1c72018-09-14 16:59:32 +02001517 return ss.Release();
asapersson09f05612017-05-15 23:40:18 -07001518}
1519
Niels Möller213618e2018-07-24 09:29:58 +02001520VideoStreamEncoderObserver::AdaptationSteps
1521VideoStreamEncoder::AdaptCounter::Counts(int reason) const {
1522 VideoStreamEncoderObserver::AdaptationSteps counts;
1523 counts.num_framerate_reductions = fps_counters_[reason];
1524 counts.num_resolution_reductions = resolution_counters_[reason];
asapersson09f05612017-05-15 23:40:18 -07001525 return counts;
1526}
1527
mflodmancc3d4422017-08-03 08:27:51 -07001528void VideoStreamEncoder::AdaptCounter::IncrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001529 ++(fps_counters_[reason]);
asapersson09f05612017-05-15 23:40:18 -07001530}
1531
mflodmancc3d4422017-08-03 08:27:51 -07001532void VideoStreamEncoder::AdaptCounter::IncrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001533 ++(resolution_counters_[reason]);
1534}
1535
mflodmancc3d4422017-08-03 08:27:51 -07001536void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001537 if (fps_counters_[reason] == 0) {
1538 // Balanced mode: Adapt up is in a different order, switch reason.
1539 // E.g. framerate adapt down: quality (2), framerate adapt up: cpu (3).
1540 // 1. Down resolution (cpu): res={quality:0,cpu:1}, fps={quality:0,cpu:0}
1541 // 2. Down fps (quality): res={quality:0,cpu:1}, fps={quality:1,cpu:0}
1542 // 3. Up fps (cpu): res={quality:1,cpu:0}, fps={quality:0,cpu:0}
1543 // 4. Up resolution (quality): res={quality:0,cpu:0}, fps={quality:0,cpu:0}
1544 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1545 RTC_DCHECK_GT(FramerateCount(), 0) << "Framerate not downgraded.";
1546 MoveCount(&resolution_counters_, reason);
1547 MoveCount(&fps_counters_, (reason + 1) % kScaleReasonSize);
1548 }
1549 --(fps_counters_[reason]);
1550 RTC_DCHECK_GE(fps_counters_[reason], 0);
1551}
1552
mflodmancc3d4422017-08-03 08:27:51 -07001553void VideoStreamEncoder::AdaptCounter::DecrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001554 if (resolution_counters_[reason] == 0) {
1555 // Balanced mode: Adapt up is in a different order, switch reason.
1556 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1557 RTC_DCHECK_GT(ResolutionCount(), 0) << "Resolution not downgraded.";
1558 MoveCount(&fps_counters_, reason);
1559 MoveCount(&resolution_counters_, (reason + 1) % kScaleReasonSize);
1560 }
1561 --(resolution_counters_[reason]);
1562 RTC_DCHECK_GE(resolution_counters_[reason], 0);
1563}
1564
mflodmancc3d4422017-08-03 08:27:51 -07001565void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason,
1566 int cur_fps) {
asaperssonf7e294d2017-06-13 23:25:22 -07001567 DecrementFramerate(reason);
1568 // Reset if at max fps (i.e. in case of fewer steps up than down).
1569 if (cur_fps == std::numeric_limits<int>::max())
1570 std::fill(fps_counters_.begin(), fps_counters_.end(), 0);
asapersson09f05612017-05-15 23:40:18 -07001571}
1572
mflodmancc3d4422017-08-03 08:27:51 -07001573int VideoStreamEncoder::AdaptCounter::FramerateCount() const {
asapersson09f05612017-05-15 23:40:18 -07001574 return Count(fps_counters_);
1575}
1576
mflodmancc3d4422017-08-03 08:27:51 -07001577int VideoStreamEncoder::AdaptCounter::ResolutionCount() const {
asapersson09f05612017-05-15 23:40:18 -07001578 return Count(resolution_counters_);
1579}
1580
mflodmancc3d4422017-08-03 08:27:51 -07001581int VideoStreamEncoder::AdaptCounter::FramerateCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001582 return fps_counters_[reason];
1583}
1584
mflodmancc3d4422017-08-03 08:27:51 -07001585int VideoStreamEncoder::AdaptCounter::ResolutionCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001586 return resolution_counters_[reason];
1587}
1588
mflodmancc3d4422017-08-03 08:27:51 -07001589int VideoStreamEncoder::AdaptCounter::TotalCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001590 return FramerateCount(reason) + ResolutionCount(reason);
1591}
1592
mflodmancc3d4422017-08-03 08:27:51 -07001593int VideoStreamEncoder::AdaptCounter::Count(
1594 const std::vector<int>& counters) const {
asapersson09f05612017-05-15 23:40:18 -07001595 return std::accumulate(counters.begin(), counters.end(), 0);
1596}
1597
mflodmancc3d4422017-08-03 08:27:51 -07001598void VideoStreamEncoder::AdaptCounter::MoveCount(std::vector<int>* counters,
1599 int from_reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001600 int to_reason = (from_reason + 1) % kScaleReasonSize;
1601 ++((*counters)[to_reason]);
1602 --((*counters)[from_reason]);
1603}
1604
mflodmancc3d4422017-08-03 08:27:51 -07001605std::string VideoStreamEncoder::AdaptCounter::ToString(
asapersson09f05612017-05-15 23:40:18 -07001606 const std::vector<int>& counters) const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001607 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001608 for (size_t reason = 0; reason < kScaleReasonSize; ++reason) {
1609 ss << (reason ? " cpu" : "quality") << ":" << counters[reason];
sprangc5d62e22017-04-02 23:53:04 -07001610 }
Jonas Olsson84df1c72018-09-14 16:59:32 +02001611 return ss.Release();
sprangc5d62e22017-04-02 23:53:04 -07001612}
1613
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001614} // namespace webrtc