blob: fcae1d6865ce9bfa7ff5fb79c5a434bc5b6571f2 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/video_stream_encoder.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000012
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000013#include <algorithm>
perkj57c21f92016-06-17 07:27:16 -070014#include <limits>
sprangc5d62e22017-04-02 23:53:04 -070015#include <numeric>
Per512ecb32016-09-23 15:52:06 +020016#include <utility>
niklase@google.com470e71d2011-07-07 08:21:25 +000017
Niels Möller6bb5ab92019-01-11 11:11:10 +010018#include "absl/memory/memory.h"
Niels Möller4dc66c52018-10-05 14:17:58 +020019#include "api/video/encoded_image.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/video/i420_buffer.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080021#include "api/video/video_bitrate_allocator_factory.h"
Sergey Silkin8b9b5f92018-12-10 09:28:53 +010022#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/include/video_codec_initializer.h"
24#include "modules/video_coding/include/video_coding.h"
Niels Möller6bb5ab92019-01-11 11:11:10 +010025#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/arraysize.h"
27#include "rtc_base/checks.h"
Erik Språng6a7baa72019-02-26 18:31:00 +010028#include "rtc_base/experiments/alr_experiment.h"
Åsa Perssona945aee2018-04-24 16:53:25 +020029#include "rtc_base/experiments/quality_scaling_experiment.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010030#include "rtc_base/experiments/rate_control_settings.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/location.h"
32#include "rtc_base/logging.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020033#include "rtc_base/strings/string_builder.h"
Karl Wiberg80ba3332018-02-05 10:33:35 +010034#include "rtc_base/system/fallthrough.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "rtc_base/trace_event.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020037#include "system_wrappers/include/field_trial.h"
nisseea3a7982017-05-15 02:42:11 -070038
niklase@google.com470e71d2011-07-07 08:21:25 +000039namespace webrtc {
40
perkj26091b12016-09-01 01:17:40 -070041namespace {
sprangb1ca0732017-02-01 08:38:12 -080042
asapersson6ffb67d2016-09-12 00:10:45 -070043// Time interval for logging frame counts.
44const int64_t kFrameLogIntervalMs = 60000;
sprangc5d62e22017-04-02 23:53:04 -070045const int kMinFramerateFps = 2;
perkj26091b12016-09-01 01:17:40 -070046
Sebastian Janssona3177052018-04-10 13:05:49 +020047// Time to keep a single cached pending frame in paused state.
48const int64_t kPendingFrameTimeoutMs = 1000;
49
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020050const char kInitialFramedropFieldTrial[] = "WebRTC-InitialFramedrop";
Niels Möller6bb5ab92019-01-11 11:11:10 +010051constexpr char kFrameDropperFieldTrial[] = "WebRTC-FrameDropper";
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020052
kthelgason2bc68642017-02-07 07:02:22 -080053// The maximum number of frames to drop at beginning of stream
54// to try and achieve desired bitrate.
55const int kMaxInitialFramedrop = 4;
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020056// When the first change in BWE above this threshold occurs,
57// enable DropFrameDueToSize logic.
58const float kFramedropThreshold = 0.3;
kthelgason2bc68642017-02-07 07:02:22 -080059
Niels Möller6bb5ab92019-01-11 11:11:10 +010060// Averaging window spanning 90 frames at default 30fps, matching old media
61// optimization module defaults.
62const int64_t kFrameRateAvergingWindowSizeMs = (1000 / 30) * 90;
63
Erik Språngb7cb7b52019-02-26 15:52:33 +010064const size_t kDefaultPayloadSize = 1440;
65
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070066// Initial limits for BALANCED degradation preference.
asaperssonf7e294d2017-06-13 23:25:22 -070067int MinFps(int pixels) {
68 if (pixels <= 320 * 240) {
69 return 7;
70 } else if (pixels <= 480 * 270) {
71 return 10;
72 } else if (pixels <= 640 * 480) {
73 return 15;
74 } else {
75 return std::numeric_limits<int>::max();
76 }
77}
78
79int MaxFps(int pixels) {
80 if (pixels <= 320 * 240) {
81 return 10;
82 } else if (pixels <= 480 * 270) {
83 return 15;
84 } else {
85 return std::numeric_limits<int>::max();
86 }
87}
88
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020089uint32_t abs_diff(uint32_t a, uint32_t b) {
90 return (a < b) ? b - a : a - b;
91}
92
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070093bool IsResolutionScalingEnabled(DegradationPreference degradation_preference) {
94 return degradation_preference == DegradationPreference::MAINTAIN_FRAMERATE ||
95 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -070096}
97
Taylor Brandstetter49fcc102018-05-16 14:20:41 -070098bool IsFramerateScalingEnabled(DegradationPreference degradation_preference) {
99 return degradation_preference == DegradationPreference::MAINTAIN_RESOLUTION ||
100 degradation_preference == DegradationPreference::BALANCED;
asapersson09f05612017-05-15 23:40:18 -0700101}
102
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200103// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
104// pipelining encoders better (multiple input frames before something comes
105// out). This should effectively turn off CPU adaptations for systems that
106// remotely cope with the load right now.
107CpuOveruseOptions GetCpuOveruseOptions(
Niels Möller213618e2018-07-24 09:29:58 +0200108 const VideoStreamEncoderSettings& settings,
Niels Möller4db138e2018-04-19 09:04:13 +0200109 bool full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200110 CpuOveruseOptions options;
111
Niels Möller4db138e2018-04-19 09:04:13 +0200112 if (full_overuse_time) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200113 options.low_encode_usage_threshold_percent = 150;
114 options.high_encode_usage_threshold_percent = 200;
115 }
116 if (settings.experiment_cpu_load_estimator) {
117 options.filter_time_ms = 5 * rtc::kNumMillisecsPerSec;
118 }
119
120 return options;
121}
122
Erik Språngb7cb7b52019-02-26 15:52:33 +0100123bool RequiresEncoderReset(const VideoCodec& previous_send_codec,
124 const VideoCodec& new_send_codec) {
125 // Does not check startBitrate or maxFramerate.
126 if (new_send_codec.codecType != previous_send_codec.codecType ||
127 new_send_codec.width != previous_send_codec.width ||
128 new_send_codec.height != previous_send_codec.height ||
129 new_send_codec.maxBitrate != previous_send_codec.maxBitrate ||
130 new_send_codec.minBitrate != previous_send_codec.minBitrate ||
131 new_send_codec.qpMax != previous_send_codec.qpMax ||
132 new_send_codec.numberOfSimulcastStreams !=
133 previous_send_codec.numberOfSimulcastStreams ||
134 new_send_codec.mode != previous_send_codec.mode) {
135 return true;
136 }
137
138 switch (new_send_codec.codecType) {
139 case kVideoCodecVP8:
140 if (new_send_codec.VP8() != previous_send_codec.VP8()) {
141 return true;
142 }
143 break;
144
145 case kVideoCodecVP9:
146 if (new_send_codec.VP9() != previous_send_codec.VP9()) {
147 return true;
148 }
149 break;
150
151 case kVideoCodecH264:
152 if (new_send_codec.H264() != previous_send_codec.H264()) {
153 return true;
154 }
155 break;
156
157 default:
158 break;
159 }
160
161 for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
162 if (new_send_codec.simulcastStream[i] !=
163 previous_send_codec.simulcastStream[i])
164 return true;
165 }
166 return false;
167}
Erik Språng6a7baa72019-02-26 18:31:00 +0100168
169std::array<uint8_t, 2> GetExperimentGroups() {
170 std::array<uint8_t, 2> experiment_groups;
171 absl::optional<AlrExperimentSettings> experiment_settings =
172 AlrExperimentSettings::CreateFromFieldTrial(
173 AlrExperimentSettings::kStrictPacingAndProbingExperimentName);
174 if (experiment_settings) {
175 experiment_groups[0] = experiment_settings->group_id + 1;
176 } else {
177 experiment_groups[0] = 0;
178 }
179 experiment_settings = AlrExperimentSettings::CreateFromFieldTrial(
180 AlrExperimentSettings::kScreenshareProbingBweExperimentName);
181 if (experiment_settings) {
182 experiment_groups[1] = experiment_settings->group_id + 1;
183 } else {
184 experiment_groups[1] = 0;
185 }
186 return experiment_groups;
187}
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100188
189// Limit allocation across TLs in bitrate allocation according to number of TLs
190// in EncoderInfo.
191VideoBitrateAllocation UpdateAllocationFromEncoderInfo(
192 const VideoBitrateAllocation& allocation,
193 const VideoEncoder::EncoderInfo& encoder_info) {
194 if (allocation.get_sum_bps() == 0) {
195 return allocation;
196 }
197 VideoBitrateAllocation new_allocation;
198 for (int si = 0; si < kMaxSpatialLayers; ++si) {
199 if (encoder_info.fps_allocation[si].size() == 1 &&
200 allocation.IsSpatialLayerUsed(si)) {
201 // One TL is signalled to be used by the encoder. Do not distribute
202 // bitrate allocation across TLs (use sum at ti:0).
203 new_allocation.SetBitrate(si, 0, allocation.GetSpatialLayerSum(si));
204 } else {
205 for (int ti = 0; ti < kMaxTemporalStreams; ++ti) {
206 if (allocation.HasBitrate(si, ti))
207 new_allocation.SetBitrate(si, ti, allocation.GetBitrate(si, ti));
208 }
209 }
210 }
211 return new_allocation;
212}
perkj26091b12016-09-01 01:17:40 -0700213} // namespace
214
perkja49cbd32016-09-16 07:53:41 -0700215// VideoSourceProxy is responsible ensuring thread safety between calls to
mflodmancc3d4422017-08-03 08:27:51 -0700216// VideoStreamEncoder::SetSource that will happen on libjingle's worker thread
217// when a video capturer is connected to the encoder and the encoder task queue
perkja49cbd32016-09-16 07:53:41 -0700218// (encoder_queue_) where the encoder reports its VideoSinkWants.
mflodmancc3d4422017-08-03 08:27:51 -0700219class VideoStreamEncoder::VideoSourceProxy {
perkja49cbd32016-09-16 07:53:41 -0700220 public:
mflodmancc3d4422017-08-03 08:27:51 -0700221 explicit VideoSourceProxy(VideoStreamEncoder* video_stream_encoder)
222 : video_stream_encoder_(video_stream_encoder),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700223 degradation_preference_(DegradationPreference::DISABLED),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200224 source_(nullptr),
225 max_framerate_(std::numeric_limits<int>::max()) {}
perkja49cbd32016-09-16 07:53:41 -0700226
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700227 void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
228 const DegradationPreference& degradation_preference) {
perkj803d97f2016-11-01 11:45:46 -0700229 // Called on libjingle's worker thread.
perkja49cbd32016-09-16 07:53:41 -0700230 RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
231 rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr;
perkj803d97f2016-11-01 11:45:46 -0700232 rtc::VideoSinkWants wants;
perkja49cbd32016-09-16 07:53:41 -0700233 {
234 rtc::CritScope lock(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700235 degradation_preference_ = degradation_preference;
perkja49cbd32016-09-16 07:53:41 -0700236 old_source = source_;
237 source_ = source;
sprangfda496a2017-06-15 04:21:07 -0700238 wants = GetActiveSinkWantsInternal();
perkja49cbd32016-09-16 07:53:41 -0700239 }
240
241 if (old_source != source && old_source != nullptr) {
mflodmancc3d4422017-08-03 08:27:51 -0700242 old_source->RemoveSink(video_stream_encoder_);
perkja49cbd32016-09-16 07:53:41 -0700243 }
244
245 if (!source) {
246 return;
247 }
248
mflodmancc3d4422017-08-03 08:27:51 -0700249 source->AddOrUpdateSink(video_stream_encoder_, wants);
perkja49cbd32016-09-16 07:53:41 -0700250 }
251
Åsa Persson8c1bf952018-09-13 10:42:19 +0200252 void SetMaxFramerate(int max_framerate) {
253 RTC_DCHECK_GT(max_framerate, 0);
254 rtc::CritScope lock(&crit_);
255 if (max_framerate == max_framerate_)
256 return;
257
258 RTC_LOG(LS_INFO) << "Set max framerate: " << max_framerate;
259 max_framerate_ = max_framerate;
260 if (source_) {
261 source_->AddOrUpdateSink(video_stream_encoder_,
262 GetActiveSinkWantsInternal());
263 }
264 }
265
perkj803d97f2016-11-01 11:45:46 -0700266 void SetWantsRotationApplied(bool rotation_applied) {
267 rtc::CritScope lock(&crit_);
268 sink_wants_.rotation_applied = rotation_applied;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200269 if (source_) {
270 source_->AddOrUpdateSink(video_stream_encoder_,
271 GetActiveSinkWantsInternal());
272 }
sprangc5d62e22017-04-02 23:53:04 -0700273 }
274
sprangfda496a2017-06-15 04:21:07 -0700275 rtc::VideoSinkWants GetActiveSinkWants() {
276 rtc::CritScope lock(&crit_);
277 return GetActiveSinkWantsInternal();
perkj803d97f2016-11-01 11:45:46 -0700278 }
279
asaperssonf7e294d2017-06-13 23:25:22 -0700280 void ResetPixelFpsCount() {
281 rtc::CritScope lock(&crit_);
282 sink_wants_.max_pixel_count = std::numeric_limits<int>::max();
283 sink_wants_.target_pixel_count.reset();
284 sink_wants_.max_framerate_fps = std::numeric_limits<int>::max();
285 if (source_)
Åsa Persson8c1bf952018-09-13 10:42:19 +0200286 source_->AddOrUpdateSink(video_stream_encoder_,
287 GetActiveSinkWantsInternal());
asaperssonf7e294d2017-06-13 23:25:22 -0700288 }
289
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100290 bool RequestResolutionLowerThan(int pixel_count,
291 int min_pixels_per_frame,
292 bool* min_pixels_reached) {
perkj803d97f2016-11-01 11:45:46 -0700293 // Called on the encoder task queue.
294 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700295 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700296 // This can happen since |degradation_preference_| is set on libjingle's
297 // worker thread but the adaptation is done on the encoder task queue.
asaperssond0de2952017-04-21 01:47:31 -0700298 return false;
perkj803d97f2016-11-01 11:45:46 -0700299 }
asapersson13874762017-06-07 00:01:02 -0700300 // The input video frame size will have a resolution less than or equal to
301 // |max_pixel_count| depending on how the source can scale the frame size.
kthelgason5e13d412016-12-01 03:59:51 -0800302 const int pixels_wanted = (pixel_count * 3) / 5;
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100303 if (pixels_wanted >= sink_wants_.max_pixel_count) {
304 return false;
305 }
306 if (pixels_wanted < min_pixels_per_frame) {
307 *min_pixels_reached = true;
asaperssond0de2952017-04-21 01:47:31 -0700308 return false;
asapersson13874762017-06-07 00:01:02 -0700309 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100310 RTC_LOG(LS_INFO) << "Scaling down resolution, max pixels: "
311 << pixels_wanted;
sprangc5d62e22017-04-02 23:53:04 -0700312 sink_wants_.max_pixel_count = pixels_wanted;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200313 sink_wants_.target_pixel_count = absl::nullopt;
mflodmancc3d4422017-08-03 08:27:51 -0700314 source_->AddOrUpdateSink(video_stream_encoder_,
315 GetActiveSinkWantsInternal());
asaperssond0de2952017-04-21 01:47:31 -0700316 return true;
sprangc5d62e22017-04-02 23:53:04 -0700317 }
318
sprangfda496a2017-06-15 04:21:07 -0700319 int RequestFramerateLowerThan(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700320 // Called on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700321 // The input video frame rate will be scaled down to 2/3, rounding down.
sprangfda496a2017-06-15 04:21:07 -0700322 int framerate_wanted = (fps * 2) / 3;
323 return RestrictFramerate(framerate_wanted) ? framerate_wanted : -1;
perkj803d97f2016-11-01 11:45:46 -0700324 }
325
asapersson13874762017-06-07 00:01:02 -0700326 bool RequestHigherResolutionThan(int pixel_count) {
327 // Called on the encoder task queue.
perkj803d97f2016-11-01 11:45:46 -0700328 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700329 if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
asapersson02465b82017-04-10 01:12:52 -0700330 // This can happen since |degradation_preference_| is set on libjingle's
331 // worker thread but the adaptation is done on the encoder task queue.
asapersson13874762017-06-07 00:01:02 -0700332 return false;
perkj803d97f2016-11-01 11:45:46 -0700333 }
asapersson13874762017-06-07 00:01:02 -0700334 int max_pixels_wanted = pixel_count;
335 if (max_pixels_wanted != std::numeric_limits<int>::max())
336 max_pixels_wanted = pixel_count * 4;
sprangc5d62e22017-04-02 23:53:04 -0700337
asapersson13874762017-06-07 00:01:02 -0700338 if (max_pixels_wanted <= sink_wants_.max_pixel_count)
339 return false;
340
341 sink_wants_.max_pixel_count = max_pixels_wanted;
342 if (max_pixels_wanted == std::numeric_limits<int>::max()) {
sprangc5d62e22017-04-02 23:53:04 -0700343 // Remove any constraints.
344 sink_wants_.target_pixel_count.reset();
sprangc5d62e22017-04-02 23:53:04 -0700345 } else {
346 // On step down we request at most 3/5 the pixel count of the previous
347 // resolution, so in order to take "one step up" we request a resolution
348 // as close as possible to 5/3 of the current resolution. The actual pixel
349 // count selected depends on the capabilities of the source. In order to
350 // not take a too large step up, we cap the requested pixel count to be at
351 // most four time the current number of pixels.
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100352 sink_wants_.target_pixel_count = (pixel_count * 5) / 3;
sprangc5d62e22017-04-02 23:53:04 -0700353 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100354 RTC_LOG(LS_INFO) << "Scaling up resolution, max pixels: "
355 << max_pixels_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700356 source_->AddOrUpdateSink(video_stream_encoder_,
357 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700358 return true;
sprangc5d62e22017-04-02 23:53:04 -0700359 }
360
sprangfda496a2017-06-15 04:21:07 -0700361 // Request upgrade in framerate. Returns the new requested frame, or -1 if
362 // no change requested. Note that maxint may be returned if limits due to
363 // adaptation requests are removed completely. In that case, consider
364 // |max_framerate_| to be the current limit (assuming the capturer complies).
365 int RequestHigherFramerateThan(int fps) {
asapersson13874762017-06-07 00:01:02 -0700366 // Called on the encoder task queue.
367 // The input frame rate will be scaled up to the last step, with rounding.
368 int framerate_wanted = fps;
369 if (fps != std::numeric_limits<int>::max())
370 framerate_wanted = (fps * 3) / 2;
371
sprangfda496a2017-06-15 04:21:07 -0700372 return IncreaseFramerate(framerate_wanted) ? framerate_wanted : -1;
asapersson13874762017-06-07 00:01:02 -0700373 }
374
375 bool RestrictFramerate(int fps) {
sprangc5d62e22017-04-02 23:53:04 -0700376 // Called on the encoder task queue.
377 rtc::CritScope lock(&crit_);
asapersson13874762017-06-07 00:01:02 -0700378 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
379 return false;
380
381 const int fps_wanted = std::max(kMinFramerateFps, fps);
382 if (fps_wanted >= sink_wants_.max_framerate_fps)
383 return false;
384
Mirko Bonadei675513b2017-11-09 11:09:25 +0100385 RTC_LOG(LS_INFO) << "Scaling down framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700386 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700387 source_->AddOrUpdateSink(video_stream_encoder_,
388 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700389 return true;
390 }
391
392 bool IncreaseFramerate(int fps) {
393 // Called on the encoder task queue.
394 rtc::CritScope lock(&crit_);
395 if (!source_ || !IsFramerateScalingEnabled(degradation_preference_))
396 return false;
397
398 const int fps_wanted = std::max(kMinFramerateFps, fps);
399 if (fps_wanted <= sink_wants_.max_framerate_fps)
400 return false;
401
Mirko Bonadei675513b2017-11-09 11:09:25 +0100402 RTC_LOG(LS_INFO) << "Scaling up framerate: " << fps_wanted;
asapersson13874762017-06-07 00:01:02 -0700403 sink_wants_.max_framerate_fps = fps_wanted;
mflodmancc3d4422017-08-03 08:27:51 -0700404 source_->AddOrUpdateSink(video_stream_encoder_,
405 GetActiveSinkWantsInternal());
asapersson13874762017-06-07 00:01:02 -0700406 return true;
perkj803d97f2016-11-01 11:45:46 -0700407 }
408
perkja49cbd32016-09-16 07:53:41 -0700409 private:
sprangfda496a2017-06-15 04:21:07 -0700410 rtc::VideoSinkWants GetActiveSinkWantsInternal()
danilchapa37de392017-09-09 04:17:22 -0700411 RTC_EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
sprangfda496a2017-06-15 04:21:07 -0700412 rtc::VideoSinkWants wants = sink_wants_;
413 // Clear any constraints from the current sink wants that don't apply to
414 // the used degradation_preference.
415 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700416 case DegradationPreference::BALANCED:
sprangfda496a2017-06-15 04:21:07 -0700417 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700418 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangfda496a2017-06-15 04:21:07 -0700419 wants.max_framerate_fps = std::numeric_limits<int>::max();
420 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700421 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangfda496a2017-06-15 04:21:07 -0700422 wants.max_pixel_count = std::numeric_limits<int>::max();
423 wants.target_pixel_count.reset();
424 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700425 case DegradationPreference::DISABLED:
sprangfda496a2017-06-15 04:21:07 -0700426 wants.max_pixel_count = std::numeric_limits<int>::max();
427 wants.target_pixel_count.reset();
428 wants.max_framerate_fps = std::numeric_limits<int>::max();
429 }
Åsa Persson8c1bf952018-09-13 10:42:19 +0200430 // Limit to configured max framerate.
431 wants.max_framerate_fps = std::min(max_framerate_, wants.max_framerate_fps);
sprangfda496a2017-06-15 04:21:07 -0700432 return wants;
433 }
434
perkja49cbd32016-09-16 07:53:41 -0700435 rtc::CriticalSection crit_;
436 rtc::SequencedTaskChecker main_checker_;
mflodmancc3d4422017-08-03 08:27:51 -0700437 VideoStreamEncoder* const video_stream_encoder_;
danilchapa37de392017-09-09 04:17:22 -0700438 rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(&crit_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700439 DegradationPreference degradation_preference_ RTC_GUARDED_BY(&crit_);
danilchapa37de392017-09-09 04:17:22 -0700440 rtc::VideoSourceInterface<VideoFrame>* source_ RTC_GUARDED_BY(&crit_);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200441 int max_framerate_ RTC_GUARDED_BY(&crit_);
perkja49cbd32016-09-16 07:53:41 -0700442
443 RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
444};
445
Åsa Persson0122e842017-10-16 12:19:23 +0200446VideoStreamEncoder::VideoStreamEncoder(
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100447 Clock* clock,
Åsa Persson0122e842017-10-16 12:19:23 +0200448 uint32_t number_of_cores,
Niels Möller213618e2018-07-24 09:29:58 +0200449 VideoStreamEncoderObserver* encoder_stats_observer,
450 const VideoStreamEncoderSettings& settings,
Sebastian Jansson74682c12019-03-01 11:50:20 +0100451 std::unique_ptr<OveruseFrameDetector> overuse_detector,
452 TaskQueueFactory* task_queue_factory)
perkj26091b12016-09-01 01:17:40 -0700453 : shutdown_event_(true /* manual_reset */, false),
454 number_of_cores_(number_of_cores),
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200455 initial_framedrop_(0),
456 initial_framedrop_on_bwe_enabled_(
457 webrtc::field_trial::IsEnabled(kInitialFramedropFieldTrial)),
Åsa Perssona945aee2018-04-24 16:53:25 +0200458 quality_scaling_experiment_enabled_(QualityScalingExperiment::Enabled()),
perkja49cbd32016-09-16 07:53:41 -0700459 source_proxy_(new VideoSourceProxy(this)),
Pera48ddb72016-09-29 11:48:50 +0200460 sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700461 settings_(settings),
Erik Språng7ca375c2019-02-06 16:20:17 +0100462 rate_control_settings_(RateControlSettings::ParseFromFieldTrials()),
Niels Möller73f29cb2018-01-31 16:09:31 +0100463 overuse_detector_(std::move(overuse_detector)),
Niels Möller213618e2018-07-24 09:29:58 +0200464 encoder_stats_observer_(encoder_stats_observer),
Erik Språng6a7baa72019-02-26 18:31:00 +0100465 encoder_initialized_(false),
sprangfda496a2017-06-15 04:21:07 -0700466 max_framerate_(-1),
perkjfa10b552016-10-02 23:45:26 -0700467 pending_encoder_reconfiguration_(false),
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000468 pending_encoder_creation_(false),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200469 crop_width_(0),
470 crop_height_(0),
perkj26091b12016-09-01 01:17:40 -0700471 encoder_start_bitrate_bps_(0),
Pera48ddb72016-09-29 11:48:50 +0200472 max_data_payload_length_(0),
pbos@webrtc.org143451d2015-03-18 14:40:03 +0000473 last_observed_bitrate_bps_(0),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000474 encoder_paused_and_dropped_frame_(false),
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100475 clock_(clock),
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700476 degradation_preference_(DegradationPreference::DISABLED),
Yuwei Huangd9f99c12017-10-24 15:40:52 -0700477 posted_frames_waiting_for_encode_(0),
perkj26091b12016-09-01 01:17:40 -0700478 last_captured_timestamp_(0),
479 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
480 clock_->TimeInMilliseconds()),
asapersson6ffb67d2016-09-12 00:10:45 -0700481 last_frame_log_ms_(clock_->TimeInMilliseconds()),
482 captured_frame_count_(0),
483 dropped_frame_count_(0),
Erik Språnge2fd86a2018-10-24 11:32:39 +0200484 pending_frame_post_time_us_(0),
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100485 accumulated_update_rect_{0, 0, 0, 0},
sprang1a646ee2016-12-01 06:34:11 -0800486 bitrate_observer_(nullptr),
Erik Språng6a7baa72019-02-26 18:31:00 +0100487 last_framerate_fps_(0),
Niels Möller6bb5ab92019-01-11 11:11:10 +0100488 force_disable_frame_dropper_(false),
489 input_framerate_(kFrameRateAvergingWindowSizeMs, 1000),
490 pending_frame_drops_(0),
Niels Möller8f7ce222019-03-21 15:43:58 +0100491 next_frame_types_(1, VideoFrameType::kVideoFrameDelta),
Erik Språng6a7baa72019-02-26 18:31:00 +0100492 frame_encoder_timer_(this),
493 experiment_groups_(GetExperimentGroups()),
Sebastian Jansson74682c12019-03-01 11:50:20 +0100494 encoder_queue_(task_queue_factory->CreateTaskQueue(
495 "EncoderQueue",
496 TaskQueueFactory::Priority::NORMAL)) {
Niels Möller213618e2018-07-24 09:29:58 +0200497 RTC_DCHECK(encoder_stats_observer);
Niels Möller73f29cb2018-01-31 16:09:31 +0100498 RTC_DCHECK(overuse_detector_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100499 RTC_DCHECK_GE(number_of_cores, 1);
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000500}
501
mflodmancc3d4422017-08-03 08:27:51 -0700502VideoStreamEncoder::~VideoStreamEncoder() {
perkja49cbd32016-09-16 07:53:41 -0700503 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700504 RTC_DCHECK(shutdown_event_.Wait(0))
505 << "Must call ::Stop() before destruction.";
506}
507
mflodmancc3d4422017-08-03 08:27:51 -0700508void VideoStreamEncoder::Stop() {
perkja49cbd32016-09-16 07:53:41 -0700509 RTC_DCHECK_RUN_ON(&thread_checker_);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700510 source_proxy_->SetSource(nullptr, DegradationPreference());
perkja49cbd32016-09-16 07:53:41 -0700511 encoder_queue_.PostTask([this] {
512 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangfda496a2017-06-15 04:21:07 -0700513 overuse_detector_->StopCheckForOveruse();
Erik Språngb7cb7b52019-02-26 15:52:33 +0100514 rate_allocator_ = nullptr;
sprang1a646ee2016-12-01 06:34:11 -0800515 bitrate_observer_ = nullptr;
Erik Språng6a7baa72019-02-26 18:31:00 +0100516 ReleaseEncoder();
kthelgason876222f2016-11-29 01:44:11 -0800517 quality_scaler_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700518 shutdown_event_.Set();
519 });
520
521 shutdown_event_.Wait(rtc::Event::kForever);
perkj26091b12016-09-01 01:17:40 -0700522}
523
Niels Möller0327c2d2018-05-21 14:09:31 +0200524void VideoStreamEncoder::SetBitrateAllocationObserver(
sprang1a646ee2016-12-01 06:34:11 -0800525 VideoBitrateAllocationObserver* bitrate_observer) {
526 RTC_DCHECK_RUN_ON(&thread_checker_);
527 encoder_queue_.PostTask([this, bitrate_observer] {
528 RTC_DCHECK_RUN_ON(&encoder_queue_);
529 RTC_DCHECK(!bitrate_observer_);
530 bitrate_observer_ = bitrate_observer;
531 });
532}
533
mflodmancc3d4422017-08-03 08:27:51 -0700534void VideoStreamEncoder::SetSource(
perkj803d97f2016-11-01 11:45:46 -0700535 rtc::VideoSourceInterface<VideoFrame>* source,
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700536 const DegradationPreference& degradation_preference) {
perkja49cbd32016-09-16 07:53:41 -0700537 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj803d97f2016-11-01 11:45:46 -0700538 source_proxy_->SetSource(source, degradation_preference);
539 encoder_queue_.PostTask([this, degradation_preference] {
540 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -0700541 if (degradation_preference_ != degradation_preference) {
542 // Reset adaptation state, so that we're not tricked into thinking there's
543 // an already pending request of the same type.
544 last_adaptation_request_.reset();
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700545 if (degradation_preference == DegradationPreference::BALANCED ||
546 degradation_preference_ == DegradationPreference::BALANCED) {
asaperssonf7e294d2017-06-13 23:25:22 -0700547 // TODO(asapersson): Consider removing |adapt_counters_| map and use one
548 // AdaptCounter for all modes.
549 source_proxy_->ResetPixelFpsCount();
550 adapt_counters_.clear();
551 }
sprangc5d62e22017-04-02 23:53:04 -0700552 }
sprangb1ca0732017-02-01 08:38:12 -0800553 degradation_preference_ = degradation_preference;
Niels Möller4db138e2018-04-19 09:04:13 +0200554
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000555 if (encoder_)
Erik Språng7ca375c2019-02-06 16:20:17 +0100556 ConfigureQualityScaler(encoder_->GetEncoderInfo());
Niels Möller4db138e2018-04-19 09:04:13 +0200557
Niels Möller7dc26b72017-12-06 10:27:48 +0100558 if (!IsFramerateScalingEnabled(degradation_preference) &&
559 max_framerate_ != -1) {
560 // If frame rate scaling is no longer allowed, remove any potential
561 // allowance for longer frame intervals.
562 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
563 }
perkj803d97f2016-11-01 11:45:46 -0700564 });
perkja49cbd32016-09-16 07:53:41 -0700565}
566
mflodmancc3d4422017-08-03 08:27:51 -0700567void VideoStreamEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
perkj803d97f2016-11-01 11:45:46 -0700568 source_proxy_->SetWantsRotationApplied(rotation_applied);
perkj26091b12016-09-01 01:17:40 -0700569 encoder_queue_.PostTask([this, sink] {
570 RTC_DCHECK_RUN_ON(&encoder_queue_);
571 sink_ = sink;
572 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000573}
574
mflodmancc3d4422017-08-03 08:27:51 -0700575void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
perkj26091b12016-09-01 01:17:40 -0700576 encoder_queue_.PostTask([this, start_bitrate_bps] {
577 RTC_DCHECK_RUN_ON(&encoder_queue_);
578 encoder_start_bitrate_bps_ = start_bitrate_bps;
579 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000580}
Peter Boström00b9d212016-05-19 16:59:03 +0200581
mflodmancc3d4422017-08-03 08:27:51 -0700582void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200583 size_t max_data_payload_length) {
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100584 // TODO(srte): This struct should be replaced by a lambda with move capture
585 // when C++14 lambda is allowed.
586 struct ConfigureEncoderTask {
587 void operator()() {
Yves Gerey665174f2018-06-19 15:03:05 +0200588 encoder->ConfigureEncoderOnTaskQueue(std::move(config),
589 max_data_payload_length);
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100590 }
591 VideoStreamEncoder* encoder;
592 VideoEncoderConfig config;
593 size_t max_data_payload_length;
Sebastian Jansson3dc01252018-03-19 19:27:44 +0100594 };
Yves Gerey665174f2018-06-19 15:03:05 +0200595 encoder_queue_.PostTask(
596 ConfigureEncoderTask{this, std::move(config), max_data_payload_length});
perkj26091b12016-09-01 01:17:40 -0700597}
598
mflodmancc3d4422017-08-03 08:27:51 -0700599void VideoStreamEncoder::ConfigureEncoderOnTaskQueue(
600 VideoEncoderConfig config,
Niels Möllerf1338562018-04-26 09:51:47 +0200601 size_t max_data_payload_length) {
perkj26091b12016-09-01 01:17:40 -0700602 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700603 RTC_DCHECK(sink_);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100604 RTC_LOG(LS_INFO) << "ConfigureEncoder requested.";
Pera48ddb72016-09-29 11:48:50 +0200605
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000606 pending_encoder_creation_ =
Erik Språngd7329ca2019-02-21 21:19:53 +0100607 (!encoder_ || encoder_config_.video_format != config.video_format ||
608 max_data_payload_length_ != max_data_payload_length);
Pera48ddb72016-09-29 11:48:50 +0200609 encoder_config_ = std::move(config);
Erik Språngd7329ca2019-02-21 21:19:53 +0100610 max_data_payload_length_ = max_data_payload_length;
perkjfa10b552016-10-02 23:45:26 -0700611 pending_encoder_reconfiguration_ = true;
Pera48ddb72016-09-29 11:48:50 +0200612
perkjfa10b552016-10-02 23:45:26 -0700613 // Reconfigure the encoder now if the encoder has an internal source or
Per21d45d22016-10-30 21:37:57 +0100614 // if the frame resolution is known. Otherwise, the reconfiguration is
615 // deferred until the next frame to minimize the number of reconfigurations.
616 // The codec configuration depends on incoming video frame size.
617 if (last_frame_info_) {
618 ReconfigureEncoder();
Erik Språngd7329ca2019-02-21 21:19:53 +0100619 } else {
620 codec_info_ = settings_.encoder_factory->QueryVideoEncoder(
621 encoder_config_.video_format);
622 if (HasInternalSource()) {
623 last_frame_info_ = VideoFrameInfo(176, 144, false);
624 ReconfigureEncoder();
625 }
perkjfa10b552016-10-02 23:45:26 -0700626 }
627}
perkj26091b12016-09-01 01:17:40 -0700628
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800629// TODO(bugs.webrtc.org/8807): Currently this always does a hard
630// reconfiguration, but this isn't always necessary. Add in logic to only update
631// the VideoBitrateAllocator and call OnEncoderConfigurationChanged with a
632// "soft" reconfiguration.
mflodmancc3d4422017-08-03 08:27:51 -0700633void VideoStreamEncoder::ReconfigureEncoder() {
perkjfa10b552016-10-02 23:45:26 -0700634 RTC_DCHECK(pending_encoder_reconfiguration_);
635 std::vector<VideoStream> streams =
636 encoder_config_.video_stream_factory->CreateEncoderStreams(
637 last_frame_info_->width, last_frame_info_->height, encoder_config_);
perkj26091b12016-09-01 01:17:40 -0700638
ilnik6b826ef2017-06-16 06:53:48 -0700639 // TODO(ilnik): If configured resolution is significantly less than provided,
640 // e.g. because there are not enough SSRCs for all simulcast streams,
641 // signal new resolutions via SinkWants to video source.
642
643 // Stream dimensions may be not equal to given because of a simulcast
644 // restrictions.
Florent Castelli450b5482018-11-29 17:32:47 +0100645 auto highest_stream = std::max_element(
646 streams.begin(), streams.end(),
647 [](const webrtc::VideoStream& a, const webrtc::VideoStream& b) {
648 return std::tie(a.width, a.height) < std::tie(b.width, b.height);
649 });
650 int highest_stream_width = static_cast<int>(highest_stream->width);
651 int highest_stream_height = static_cast<int>(highest_stream->height);
ilnik6b826ef2017-06-16 06:53:48 -0700652 // Dimension may be reduced to be, e.g. divisible by 4.
653 RTC_CHECK_GE(last_frame_info_->width, highest_stream_width);
654 RTC_CHECK_GE(last_frame_info_->height, highest_stream_height);
655 crop_width_ = last_frame_info_->width - highest_stream_width;
656 crop_height_ = last_frame_info_->height - highest_stream_height;
657
Erik Språng08127a92016-11-16 16:41:30 +0100658 VideoCodec codec;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800659 if (!VideoCodecInitializer::SetupCodec(encoder_config_, streams, &codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100660 RTC_LOG(LS_ERROR) << "Failed to create encoder configuration.";
Erik Språng08127a92016-11-16 16:41:30 +0100661 }
perkjfa10b552016-10-02 23:45:26 -0700662
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800663 rate_allocator_ =
664 settings_.bitrate_allocator_factory->CreateVideoBitrateAllocator(codec);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800665
“Michael277a6562018-06-01 14:09:19 -0500666 // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9.
667 if (encoder_config_.codec_type == kVideoCodecVP9) {
“Michael277a6562018-06-01 14:09:19 -0500668 // Lower max bitrate to the level codec actually can produce.
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100669 streams[0].max_bitrate_bps = std::min<int>(
670 streams[0].max_bitrate_bps, SvcRateAllocator::GetMaxBitrateBps(codec));
“Michael277a6562018-06-01 14:09:19 -0500671 streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100672 // target_bitrate_bps specifies the maximum padding bitrate.
“Michael277a6562018-06-01 14:09:19 -0500673 streams[0].target_bitrate_bps =
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100674 SvcRateAllocator::GetPaddingBitrateBps(codec);
“Michael277a6562018-06-01 14:09:19 -0500675 }
676
perkjfa10b552016-10-02 23:45:26 -0700677 codec.startBitrate =
678 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
679 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
680 codec.expect_encode_from_texture = last_frame_info_->is_texture;
Erik Språngd7329ca2019-02-21 21:19:53 +0100681 // Make sure the start bit rate is sane...
682 RTC_DCHECK_LE(codec.startBitrate, 1000000);
sprangfda496a2017-06-15 04:21:07 -0700683 max_framerate_ = codec.maxFramerate;
Åsa Persson8c1bf952018-09-13 10:42:19 +0200684
685 // Inform source about max configured framerate.
686 int max_framerate = 0;
687 for (const auto& stream : streams) {
688 max_framerate = std::max(stream.max_framerate, max_framerate);
689 }
690 source_proxy_->SetMaxFramerate(max_framerate);
Stefan Holmere5904162015-03-26 11:11:06 +0100691
Erik Språngb7cb7b52019-02-26 15:52:33 +0100692 if (codec.maxBitrate == 0) {
693 // max is one bit per pixel
694 codec.maxBitrate =
695 (static_cast<int>(codec.height) * static_cast<int>(codec.width) *
696 static_cast<int>(codec.maxFramerate)) /
697 1000;
698 if (codec.startBitrate > codec.maxBitrate) {
699 // But if the user tries to set a higher start bit rate we will
700 // increase the max accordingly.
701 codec.maxBitrate = codec.startBitrate;
702 }
703 }
704
705 if (codec.startBitrate > codec.maxBitrate) {
706 codec.startBitrate = codec.maxBitrate;
707 }
708
709 // Reset (release existing encoder) if one exists and anything except
710 // start bitrate or max framerate has changed. Don't call Release() if
711 // |pending_encoder_creation_| as that means this is a new encoder
712 // that has not yet been initialized.
713 const bool reset_required = RequiresEncoderReset(codec, send_codec_);
714 send_codec_ = codec;
715
Niels Möller4db138e2018-04-19 09:04:13 +0200716 // Keep the same encoder, as long as the video_format is unchanged.
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100717 // Encoder creation block is split in two since EncoderInfo needed to start
718 // CPU adaptation with the correct settings should be polled after
719 // encoder_->InitEncode().
Erik Språngb7cb7b52019-02-26 15:52:33 +0100720 bool success = true;
Erik Språng6a7baa72019-02-26 18:31:00 +0100721 if (pending_encoder_creation_ || reset_required) {
722 ReleaseEncoder();
723 if (pending_encoder_creation_) {
724 encoder_ = settings_.encoder_factory->CreateVideoEncoder(
725 encoder_config_.video_format);
726 // TODO(nisse): What to do if creating the encoder fails? Crash,
727 // or just discard incoming frames?
728 RTC_CHECK(encoder_);
729 codec_info_ = settings_.encoder_factory->QueryVideoEncoder(
730 encoder_config_.video_format);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100731 }
Erik Språng6a7baa72019-02-26 18:31:00 +0100732
733 if (encoder_->InitEncode(&send_codec_, number_of_cores_,
734 max_data_payload_length_ > 0
735 ? max_data_payload_length_
736 : kDefaultPayloadSize) != 0) {
737 RTC_LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
738 "codec type: "
739 << CodecTypeToPayloadString(send_codec_.codecType)
740 << " (" << send_codec_.codecType << ")";
741 ReleaseEncoder();
742 success = false;
743 } else {
744 encoder_initialized_ = true;
745 encoder_->RegisterEncodeCompleteCallback(this);
746 frame_encoder_timer_.OnEncoderInit(send_codec_, HasInternalSource());
747 }
748
749 frame_encoder_timer_.Reset();
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100750 last_encode_info_ms_ = absl::nullopt;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100751 }
Erik Språngd7329ca2019-02-21 21:19:53 +0100752
753 if (success) {
Erik Språngd7329ca2019-02-21 21:19:53 +0100754 next_frame_types_.clear();
755 next_frame_types_.resize(
756 std::max(static_cast<int>(codec.numberOfSimulcastStreams), 1),
Niels Möller8f7ce222019-03-21 15:43:58 +0100757 VideoFrameType::kVideoFrameKey);
Erik Språngd7329ca2019-02-21 21:19:53 +0100758 RTC_LOG(LS_VERBOSE) << " max bitrate " << codec.maxBitrate
759 << " start bitrate " << codec.startBitrate
760 << " max frame rate " << codec.maxFramerate
761 << " max payload size " << max_data_payload_length_;
762 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100763 RTC_LOG(LS_ERROR) << "Failed to configure encoder.";
Erik Språngb7cb7b52019-02-26 15:52:33 +0100764 rate_allocator_ = nullptr;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000765 }
Peter Boström905f8e72016-03-02 16:59:56 +0100766
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100767 if (pending_encoder_creation_) {
768 overuse_detector_->StopCheckForOveruse();
769 overuse_detector_->StartCheckForOveruse(
Sebastian Janssoncda86dd2019-03-11 17:26:36 +0100770 &encoder_queue_,
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100771 GetCpuOveruseOptions(
772 settings_, encoder_->GetEncoderInfo().is_hardware_accelerated),
773 this);
774 pending_encoder_creation_ = false;
775 }
776
Niels Möller6bb5ab92019-01-11 11:11:10 +0100777 int num_layers;
778 if (codec.codecType == kVideoCodecVP8) {
779 num_layers = codec.VP8()->numberOfTemporalLayers;
780 } else if (codec.codecType == kVideoCodecVP9) {
781 num_layers = codec.VP9()->numberOfTemporalLayers;
Johnny Lee1a1c52b2019-02-08 14:25:40 -0500782 } else if (codec.codecType == kVideoCodecH264) {
783 num_layers = codec.H264()->numberOfTemporalLayers;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100784 } else if (codec.codecType == kVideoCodecGeneric &&
785 codec.numberOfSimulcastStreams > 0) {
786 // This is mainly for unit testing, disabling frame dropping.
787 // TODO(sprang): Add a better way to disable frame dropping.
788 num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
789 } else {
790 num_layers = 1;
791 }
792
793 frame_dropper_.Reset();
794 frame_dropper_.SetRates(codec.startBitrate, max_framerate_);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100795 // Force-disable frame dropper if either:
796 // * We have screensharing with layers.
797 // * "WebRTC-FrameDropper" field trial is "Disabled".
798 force_disable_frame_dropper_ =
799 field_trial::IsDisabled(kFrameDropperFieldTrial) ||
800 (num_layers > 1 && codec.mode == VideoCodecMode::kScreensharing);
801
Erik Språng7ca375c2019-02-06 16:20:17 +0100802 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
803 if (rate_control_settings_.UseEncoderBitrateAdjuster()) {
804 bitrate_adjuster_ = absl::make_unique<EncoderBitrateAdjuster>(codec);
805 bitrate_adjuster_->OnEncoderInfo(info);
806 }
807
Niels Möller6bb5ab92019-01-11 11:11:10 +0100808 if (rate_allocator_ && last_observed_bitrate_bps_ > 0) {
809 // We have a new rate allocator instance and already configured target
810 // bitrate. Update the rate allocation and notify observsers.
Erik Språngd7329ca2019-02-21 21:19:53 +0100811 const uint32_t framerate_fps = GetInputFramerateFps();
812 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(
813 last_observed_bitrate_bps_, framerate_fps),
814 framerate_fps);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100815 }
ilnik35b7de42017-03-15 04:24:21 -0700816
Niels Möller213618e2018-07-24 09:29:58 +0200817 encoder_stats_observer_->OnEncoderReconfigured(encoder_config_, streams);
Per512ecb32016-09-23 15:52:06 +0200818
perkjfa10b552016-10-02 23:45:26 -0700819 pending_encoder_reconfiguration_ = false;
Erik Språng08127a92016-11-16 16:41:30 +0100820
Pera48ddb72016-09-29 11:48:50 +0200821 sink_->OnEncoderConfigurationChanged(
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100822 std::move(streams), encoder_config_.content_type,
823 encoder_config_.min_transmit_bitrate_bps);
kthelgason876222f2016-11-29 01:44:11 -0800824
Niels Möller7dc26b72017-12-06 10:27:48 +0100825 // Get the current target framerate, ie the maximum framerate as specified by
826 // the current codec configuration, or any limit imposed by cpu adaption in
827 // maintain-resolution or balanced mode. This is used to make sure overuse
828 // detection doesn't needlessly trigger in low and/or variable framerate
829 // scenarios.
830 int target_framerate = std::min(
831 max_framerate_, source_proxy_->GetActiveSinkWants().max_framerate_fps);
832 overuse_detector_->OnTargetFramerateUpdated(target_framerate);
Niels Möller2d061182018-04-24 09:13:08 +0200833
Erik Språng7ca375c2019-02-06 16:20:17 +0100834 ConfigureQualityScaler(info);
kthelgason2bc68642017-02-07 07:02:22 -0800835}
836
Erik Språng7ca375c2019-02-06 16:20:17 +0100837void VideoStreamEncoder::ConfigureQualityScaler(
838 const VideoEncoder::EncoderInfo& encoder_info) {
kthelgason2bc68642017-02-07 07:02:22 -0800839 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +0100840 const auto scaling_settings = encoder_info.scaling_settings;
asapersson36e9eb42017-03-31 05:29:12 -0700841 const bool quality_scaling_allowed =
asapersson91914e22017-06-01 00:34:08 -0700842 IsResolutionScalingEnabled(degradation_preference_) &&
Niels Möller225c7872018-02-22 15:03:53 +0100843 scaling_settings.thresholds;
kthelgason3af6cc02017-03-22 00:25:28 -0700844
asapersson36e9eb42017-03-31 05:29:12 -0700845 if (quality_scaling_allowed) {
Benjamin Wright1f4173e2019-03-13 17:59:32 -0700846 if (quality_scaler_ == nullptr) {
asapersson09f05612017-05-15 23:40:18 -0700847 // Quality scaler has not already been configured.
Niels Möller225c7872018-02-22 15:03:53 +0100848
Åsa Perssona945aee2018-04-24 16:53:25 +0200849 // Use experimental thresholds if available.
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200850 absl::optional<VideoEncoder::QpThresholds> experimental_thresholds;
Åsa Perssona945aee2018-04-24 16:53:25 +0200851 if (quality_scaling_experiment_enabled_) {
852 experimental_thresholds = QualityScalingExperiment::GetQpThresholds(
853 encoder_config_.codec_type);
854 }
Karl Wiberg918f50c2018-07-05 11:40:33 +0200855 // Since the interface is non-public, absl::make_unique can't do this
856 // upcast.
Niels Möller225c7872018-02-22 15:03:53 +0100857 AdaptationObserverInterface* observer = this;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200858 quality_scaler_ = absl::make_unique<QualityScaler>(
Sebastian Janssoncda86dd2019-03-11 17:26:36 +0100859 &encoder_queue_, observer,
860 experimental_thresholds ? *experimental_thresholds
861 : *(scaling_settings.thresholds));
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200862 has_seen_first_significant_bwe_change_ = false;
863 initial_framedrop_ = 0;
kthelgason876222f2016-11-29 01:44:11 -0800864 }
865 } else {
866 quality_scaler_.reset(nullptr);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +0200867 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason876222f2016-11-29 01:44:11 -0800868 }
asapersson09f05612017-05-15 23:40:18 -0700869
Niels Möller213618e2018-07-24 09:29:58 +0200870 encoder_stats_observer_->OnAdaptationChanged(
871 VideoStreamEncoderObserver::AdaptationReason::kNone,
872 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000873}
874
mflodmancc3d4422017-08-03 08:27:51 -0700875void VideoStreamEncoder::OnFrame(const VideoFrame& video_frame) {
perkj26091b12016-09-01 01:17:40 -0700876 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_);
perkj26091b12016-09-01 01:17:40 -0700877 VideoFrame incoming_frame = video_frame;
878
879 // Local time in webrtc time base.
ilnik04f4d122017-06-19 07:18:55 -0700880 int64_t current_time_us = clock_->TimeInMicroseconds();
881 int64_t current_time_ms = current_time_us / rtc::kNumMicrosecsPerMillisec;
882 // In some cases, e.g., when the frame from decoder is fed to encoder,
883 // the timestamp may be set to the future. As the encoding pipeline assumes
884 // capture time to be less than present time, we should reset the capture
885 // timestamps here. Otherwise there may be issues with RTP send stream.
886 if (incoming_frame.timestamp_us() > current_time_us)
887 incoming_frame.set_timestamp_us(current_time_us);
perkj26091b12016-09-01 01:17:40 -0700888
889 // Capture time may come from clock with an offset and drift from clock_.
890 int64_t capture_ntp_time_ms;
nisse891419f2017-01-12 10:02:22 -0800891 if (video_frame.ntp_time_ms() > 0) {
perkj26091b12016-09-01 01:17:40 -0700892 capture_ntp_time_ms = video_frame.ntp_time_ms();
893 } else if (video_frame.render_time_ms() != 0) {
894 capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
895 } else {
nisse1c0dea82017-01-30 02:43:18 -0800896 capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
perkj26091b12016-09-01 01:17:40 -0700897 }
898 incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
899
900 // Convert NTP time, in ms, to RTP timestamp.
901 const int kMsToRtpTimestamp = 90;
902 incoming_frame.set_timestamp(
903 kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
904
905 if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
906 // We don't allow the same capture time for two frames, drop this one.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100907 RTC_LOG(LS_WARNING) << "Same/old NTP timestamp ("
908 << incoming_frame.ntp_time_ms()
909 << " <= " << last_captured_timestamp_
910 << ") for incoming frame. Dropping.";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100911 encoder_queue_.PostTask([this, incoming_frame]() {
912 RTC_DCHECK_RUN_ON(&encoder_queue_);
913 accumulated_update_rect_.Union(incoming_frame.update_rect());
914 });
perkj26091b12016-09-01 01:17:40 -0700915 return;
916 }
917
asapersson6ffb67d2016-09-12 00:10:45 -0700918 bool log_stats = false;
nisse1c0dea82017-01-30 02:43:18 -0800919 if (current_time_ms - last_frame_log_ms_ > kFrameLogIntervalMs) {
920 last_frame_log_ms_ = current_time_ms;
asapersson6ffb67d2016-09-12 00:10:45 -0700921 log_stats = true;
922 }
923
perkj26091b12016-09-01 01:17:40 -0700924 last_captured_timestamp_ = incoming_frame.ntp_time_ms();
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200925
926 int64_t post_time_us = rtc::TimeMicros();
927 ++posted_frames_waiting_for_encode_;
928
929 encoder_queue_.PostTask(
930 [this, incoming_frame, post_time_us, log_stats]() {
931 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller213618e2018-07-24 09:29:58 +0200932 encoder_stats_observer_->OnIncomingFrame(incoming_frame.width(),
933 incoming_frame.height());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200934 ++captured_frame_count_;
935 const int posted_frames_waiting_for_encode =
936 posted_frames_waiting_for_encode_.fetch_sub(1);
937 RTC_DCHECK_GT(posted_frames_waiting_for_encode, 0);
938 if (posted_frames_waiting_for_encode == 1) {
Sebastian Janssona3177052018-04-10 13:05:49 +0200939 MaybeEncodeVideoFrame(incoming_frame, post_time_us);
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200940 } else {
941 // There is a newer frame in flight. Do not encode this frame.
942 RTC_LOG(LS_VERBOSE)
943 << "Incoming frame dropped due to that the encoder is blocked.";
944 ++dropped_frame_count_;
Niels Möller213618e2018-07-24 09:29:58 +0200945 encoder_stats_observer_->OnFrameDropped(
946 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100947 accumulated_update_rect_.Union(incoming_frame.update_rect());
Sebastian Jansson3ab5c402018-04-05 12:30:50 +0200948 }
949 if (log_stats) {
950 RTC_LOG(LS_INFO) << "Number of frames: captured "
951 << captured_frame_count_
952 << ", dropped (due to encoder blocked) "
953 << dropped_frame_count_ << ", interval_ms "
954 << kFrameLogIntervalMs;
955 captured_frame_count_ = 0;
956 dropped_frame_count_ = 0;
957 }
958 });
perkj26091b12016-09-01 01:17:40 -0700959}
960
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200961void VideoStreamEncoder::OnDiscardedFrame() {
Niels Möller213618e2018-07-24 09:29:58 +0200962 encoder_stats_observer_->OnFrameDropped(
963 VideoStreamEncoderObserver::DropReason::kSource);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200964}
965
mflodmancc3d4422017-08-03 08:27:51 -0700966bool VideoStreamEncoder::EncoderPaused() const {
perkj26091b12016-09-01 01:17:40 -0700967 RTC_DCHECK_RUN_ON(&encoder_queue_);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000968 // Pause video if paused by caller or as long as the network is down or the
969 // pacer queue has grown too large in buffered mode.
perkj57c21f92016-06-17 07:27:16 -0700970 // If the pacer queue has grown too large or the network is down,
perkjfea93092016-05-14 00:58:48 -0700971 // last_observed_bitrate_bps_ will be 0.
perkj26091b12016-09-01 01:17:40 -0700972 return last_observed_bitrate_bps_ == 0;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000973}
974
mflodmancc3d4422017-08-03 08:27:51 -0700975void VideoStreamEncoder::TraceFrameDropStart() {
perkj26091b12016-09-01 01:17:40 -0700976 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000977 // Start trace event only on the first frame after encoder is paused.
978 if (!encoder_paused_and_dropped_frame_) {
979 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
980 }
981 encoder_paused_and_dropped_frame_ = true;
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000982}
983
mflodmancc3d4422017-08-03 08:27:51 -0700984void VideoStreamEncoder::TraceFrameDropEnd() {
perkj26091b12016-09-01 01:17:40 -0700985 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000986 // End trace event on first frame after encoder resumes, if frame was dropped.
987 if (encoder_paused_and_dropped_frame_) {
988 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
989 }
990 encoder_paused_and_dropped_frame_ = false;
991}
992
Niels Möller6bb5ab92019-01-11 11:11:10 +0100993VideoBitrateAllocation
994VideoStreamEncoder::GetBitrateAllocationAndNotifyObserver(
995 const uint32_t target_bitrate_bps,
996 uint32_t framerate_fps) {
997 // Only call allocators if bitrate > 0 (ie, not suspended), otherwise they
998 // might cap the bitrate to the min bitrate configured.
999 VideoBitrateAllocation bitrate_allocation;
1000 if (rate_allocator_ && target_bitrate_bps > 0) {
1001 bitrate_allocation =
1002 rate_allocator_->GetAllocation(target_bitrate_bps, framerate_fps);
1003 }
1004
1005 if (bitrate_observer_ && bitrate_allocation.get_sum_bps() > 0) {
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01001006 if (encoder_ && encoder_initialized_) {
1007 // Avoid too old encoder_info_.
1008 const int64_t kMaxDiffMs = 100;
1009 const bool updated_recently =
1010 (last_encode_info_ms_ && ((clock_->TimeInMilliseconds() -
1011 *last_encode_info_ms_) < kMaxDiffMs));
1012 // Update allocation according to info from encoder.
1013 bitrate_observer_->OnBitrateAllocationUpdated(
1014 UpdateAllocationFromEncoderInfo(
1015 bitrate_allocation,
1016 updated_recently ? encoder_info_ : encoder_->GetEncoderInfo()));
1017 } else {
1018 bitrate_observer_->OnBitrateAllocationUpdated(bitrate_allocation);
1019 }
Niels Möller6bb5ab92019-01-11 11:11:10 +01001020 }
1021
Erik Språng7ca375c2019-02-06 16:20:17 +01001022 if (bitrate_adjuster_) {
Erik Språng0e1a1f92019-02-18 18:45:13 +01001023 VideoBitrateAllocation adjusted_allocation =
1024 bitrate_adjuster_->AdjustRateAllocation(bitrate_allocation,
1025 framerate_fps);
1026 RTC_LOG(LS_VERBOSE) << "Adjusting allocation, fps = " << framerate_fps
1027 << ", from " << bitrate_allocation.ToString() << ", to "
1028 << adjusted_allocation.ToString();
1029 return adjusted_allocation;
Erik Språng7ca375c2019-02-06 16:20:17 +01001030 }
Niels Möller6bb5ab92019-01-11 11:11:10 +01001031 return bitrate_allocation;
1032}
1033
1034uint32_t VideoStreamEncoder::GetInputFramerateFps() {
1035 const uint32_t default_fps = max_framerate_ != -1 ? max_framerate_ : 30;
Erik Språngd7329ca2019-02-21 21:19:53 +01001036 absl::optional<uint32_t> input_fps =
1037 input_framerate_.Rate(clock_->TimeInMilliseconds());
1038 if (!input_fps || *input_fps == 0) {
1039 return default_fps;
1040 }
1041 return *input_fps;
1042}
1043
1044void VideoStreamEncoder::SetEncoderRates(
1045 const VideoBitrateAllocation& bitrate_allocation,
1046 uint32_t framerate_fps) {
Erik Språng6a7baa72019-02-26 18:31:00 +01001047 if (!encoder_) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001048 return;
1049 }
1050
1051 // |bitrate_allocation| is 0 it means that the network is down or the send
1052 // pacer is full. We currently only report this if the encoder has an internal
1053 // source. If the encoder does not have an internal source, higher levels
1054 // are expected to not call AddVideoFrame. We do this since its unclear
1055 // how current encoder implementations behave when given a zero target
1056 // bitrate.
1057 // TODO(perkj): Make sure all known encoder implementations handle zero
1058 // target bitrate and remove this check.
1059 if (!HasInternalSource() && bitrate_allocation.get_sum_bps() == 0) {
1060 return;
1061 }
1062
1063 RTC_DCHECK_GT(framerate_fps, 0);
Erik Språng6a7baa72019-02-26 18:31:00 +01001064 if (bitrate_allocation != last_bitrate_allocation_ ||
1065 framerate_fps != last_framerate_fps_) {
1066 int res = encoder_->SetRateAllocation(bitrate_allocation, framerate_fps);
1067 if (res != 0) {
1068 RTC_LOG(LS_WARNING) << "Error set encoder rate (total bitrate bps = "
1069 << bitrate_allocation.get_sum_bps()
1070 << ", framerate = " << framerate_fps << "): " << res;
1071 }
1072
1073 frame_encoder_timer_.OnSetRates(bitrate_allocation, framerate_fps);
1074 }
1075
1076 last_bitrate_allocation_ = bitrate_allocation;
1077 last_framerate_fps_ = framerate_fps;
Niels Möller6bb5ab92019-01-11 11:11:10 +01001078}
1079
Sebastian Janssona3177052018-04-10 13:05:49 +02001080void VideoStreamEncoder::MaybeEncodeVideoFrame(const VideoFrame& video_frame,
1081 int64_t time_when_posted_us) {
perkj26091b12016-09-01 01:17:40 -07001082 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -08001083
Per21d45d22016-10-30 21:37:57 +01001084 if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
perkjfa10b552016-10-02 23:45:26 -07001085 video_frame.height() != last_frame_info_->height ||
perkjfa10b552016-10-02 23:45:26 -07001086 video_frame.is_texture() != last_frame_info_->is_texture) {
1087 pending_encoder_reconfiguration_ = true;
Oskar Sundbom8e07c132018-01-08 16:45:42 +01001088 last_frame_info_ = VideoFrameInfo(video_frame.width(), video_frame.height(),
1089 video_frame.is_texture());
Mirko Bonadei675513b2017-11-09 11:09:25 +01001090 RTC_LOG(LS_INFO) << "Video frame parameters changed: dimensions="
1091 << last_frame_info_->width << "x"
1092 << last_frame_info_->height
1093 << ", texture=" << last_frame_info_->is_texture << ".";
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001094 // Force full frame update, since resolution has changed.
1095 accumulated_update_rect_ =
1096 VideoFrame::UpdateRect{0, 0, video_frame.width(), video_frame.height()};
perkjfa10b552016-10-02 23:45:26 -07001097 }
1098
Niels Möller4db138e2018-04-19 09:04:13 +02001099 // We have to create then encoder before the frame drop logic,
1100 // because the latter depends on encoder_->GetScalingSettings.
1101 // According to the testcase
1102 // InitialFrameDropOffWhenEncoderDisabledScaling, the return value
1103 // from GetScalingSettings should enable or disable the frame drop.
1104
Erik Språnga8d48ab2019-02-08 14:17:40 +01001105 // Update input frame rate before we start using it. If we update it after
Erik Språngd7329ca2019-02-21 21:19:53 +01001106 // any potential frame drop we are going to artificially increase frame sizes.
1107 // Poll the rate before updating, otherwise we risk the rate being estimated
1108 // a little too high at the start of the call when then window is small.
Niels Möller6bb5ab92019-01-11 11:11:10 +01001109 uint32_t framerate_fps = GetInputFramerateFps();
Erik Språngd7329ca2019-02-21 21:19:53 +01001110 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
Niels Möller6bb5ab92019-01-11 11:11:10 +01001111
Niels Möller4db138e2018-04-19 09:04:13 +02001112 int64_t now_ms = clock_->TimeInMilliseconds();
1113 if (pending_encoder_reconfiguration_) {
1114 ReconfigureEncoder();
1115 last_parameters_update_ms_.emplace(now_ms);
1116 } else if (!last_parameters_update_ms_ ||
1117 now_ms - *last_parameters_update_ms_ >=
1118 vcm::VCMProcessTimer::kDefaultProcessIntervalMs) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001119 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(
1120 last_observed_bitrate_bps_, framerate_fps),
1121 framerate_fps);
Niels Möller4db138e2018-04-19 09:04:13 +02001122 last_parameters_update_ms_.emplace(now_ms);
1123 }
1124
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001125 // Because pending frame will be dropped in any case, we need to
1126 // remember its updated region.
1127 if (pending_frame_) {
1128 encoder_stats_observer_->OnFrameDropped(
1129 VideoStreamEncoderObserver::DropReason::kEncoderQueue);
1130 accumulated_update_rect_.Union(pending_frame_->update_rect());
1131 }
1132
Sebastian Janssona3177052018-04-10 13:05:49 +02001133 if (DropDueToSize(video_frame.size())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001134 RTC_LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
Åsa Persson875841d2018-01-08 08:49:53 +01001135 int count = GetConstAdaptCounter().ResolutionCount(kQuality);
kthelgason2bc68642017-02-07 07:02:22 -08001136 AdaptDown(kQuality);
Åsa Persson875841d2018-01-08 08:49:53 +01001137 if (GetConstAdaptCounter().ResolutionCount(kQuality) > count) {
Niels Möller213618e2018-07-24 09:29:58 +02001138 encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
Åsa Persson875841d2018-01-08 08:49:53 +01001139 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001140 ++initial_framedrop_;
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001141 // Storing references to a native buffer risks blocking frame capture.
1142 if (video_frame.video_frame_buffer()->type() !=
1143 VideoFrameBuffer::Type::kNative) {
1144 pending_frame_ = video_frame;
1145 pending_frame_post_time_us_ = time_when_posted_us;
1146 } else {
1147 // Ensure that any previously stored frame is dropped.
1148 pending_frame_.reset();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001149 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001150 }
kthelgason2bc68642017-02-07 07:02:22 -08001151 return;
1152 }
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001153 initial_framedrop_ = kMaxInitialFramedrop;
kthelgason2bc68642017-02-07 07:02:22 -08001154
perkj26091b12016-09-01 01:17:40 -07001155 if (EncoderPaused()) {
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001156 // Storing references to a native buffer risks blocking frame capture.
1157 if (video_frame.video_frame_buffer()->type() !=
1158 VideoFrameBuffer::Type::kNative) {
1159 if (pending_frame_)
1160 TraceFrameDropStart();
1161 pending_frame_ = video_frame;
1162 pending_frame_post_time_us_ = time_when_posted_us;
1163 } else {
1164 // Ensure that any previously stored frame is dropped.
1165 pending_frame_.reset();
Sebastian Janssona3177052018-04-10 13:05:49 +02001166 TraceFrameDropStart();
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001167 accumulated_update_rect_.Union(video_frame.update_rect());
Sebastian Jansson0d70e372018-04-17 13:57:13 +02001168 }
perkj26091b12016-09-01 01:17:40 -07001169 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001170 }
Sebastian Janssona3177052018-04-10 13:05:49 +02001171
1172 pending_frame_.reset();
Niels Möller6bb5ab92019-01-11 11:11:10 +01001173
1174 frame_dropper_.Leak(framerate_fps);
1175 // Frame dropping is enabled iff frame dropping is not force-disabled, and
1176 // rate controller is not trusted.
1177 const bool frame_dropping_enabled =
1178 !force_disable_frame_dropper_ &&
1179 !encoder_info_.has_trusted_rate_controller;
1180 frame_dropper_.Enable(frame_dropping_enabled);
1181 if (frame_dropping_enabled && frame_dropper_.DropFrame()) {
1182 RTC_LOG(LS_VERBOSE) << "Drop Frame: "
1183 << "target bitrate " << last_observed_bitrate_bps_
1184 << ", input frame rate " << framerate_fps;
1185 OnDroppedFrame(
1186 EncodedImageCallback::DropReason::kDroppedByMediaOptimizations);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001187 accumulated_update_rect_.Union(video_frame.update_rect());
Niels Möller6bb5ab92019-01-11 11:11:10 +01001188 return;
1189 }
1190
Sebastian Janssona3177052018-04-10 13:05:49 +02001191 EncodeVideoFrame(video_frame, time_when_posted_us);
1192}
1193
1194void VideoStreamEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
1195 int64_t time_when_posted_us) {
1196 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -07001197 TraceFrameDropEnd();
niklase@google.com470e71d2011-07-07 08:21:25 +00001198
ilnik6b826ef2017-06-16 06:53:48 -07001199 VideoFrame out_frame(video_frame);
1200 // Crop frame if needed.
1201 if (crop_width_ > 0 || crop_height_ > 0) {
1202 int cropped_width = video_frame.width() - crop_width_;
1203 int cropped_height = video_frame.height() - crop_height_;
1204 rtc::scoped_refptr<I420Buffer> cropped_buffer =
1205 I420Buffer::Create(cropped_width, cropped_height);
1206 // TODO(ilnik): Remove scaling if cropping is too big, as it should never
1207 // happen after SinkWants signaled correctly from ReconfigureEncoder.
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001208 VideoFrame::UpdateRect update_rect = video_frame.update_rect();
ilnik6b826ef2017-06-16 06:53:48 -07001209 if (crop_width_ < 4 && crop_height_ < 4) {
1210 cropped_buffer->CropAndScaleFrom(
1211 *video_frame.video_frame_buffer()->ToI420(), crop_width_ / 2,
1212 crop_height_ / 2, cropped_width, cropped_height);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001213 update_rect.offset_x -= crop_width_ / 2;
1214 update_rect.offset_y -= crop_height_ / 2;
1215 update_rect.Intersect(
1216 VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height});
1217
ilnik6b826ef2017-06-16 06:53:48 -07001218 } else {
1219 cropped_buffer->ScaleFrom(
1220 *video_frame.video_frame_buffer()->ToI420().get());
Ilya Nikolaevskiy1c90cab2019-03-07 15:30:58 +01001221 if (!update_rect.IsEmpty()) {
1222 // Since we can't reason about pixels after scaling, we invalidate whole
1223 // picture, if anything changed.
1224 update_rect =
1225 VideoFrame::UpdateRect{0, 0, cropped_width, cropped_height};
1226 }
ilnik6b826ef2017-06-16 06:53:48 -07001227 }
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001228 out_frame = VideoFrame::Builder()
1229 .set_video_frame_buffer(cropped_buffer)
1230 .set_timestamp_rtp(video_frame.timestamp())
1231 .set_timestamp_ms(video_frame.render_time_ms())
1232 .set_rotation(video_frame.rotation())
1233 .set_id(video_frame.id())
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001234 .set_update_rect(update_rect)
Artem Titov1ebfb6a2019-01-03 23:49:37 +01001235 .build();
ilnik6b826ef2017-06-16 06:53:48 -07001236 out_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01001237 // Since accumulated_update_rect_ is constructed before cropping,
1238 // we can't trust it. If any changes were pending, we invalidate whole
1239 // frame here.
1240 if (!accumulated_update_rect_.IsEmpty()) {
1241 accumulated_update_rect_ =
1242 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()};
1243 }
1244 }
1245
1246 if (!accumulated_update_rect_.IsEmpty()) {
1247 accumulated_update_rect_.Union(out_frame.update_rect());
1248 accumulated_update_rect_.Intersect(
1249 VideoFrame::UpdateRect{0, 0, out_frame.width(), out_frame.height()});
1250 out_frame.set_update_rect(accumulated_update_rect_);
1251 accumulated_update_rect_.MakeEmptyUpdate();
ilnik6b826ef2017-06-16 06:53:48 -07001252 }
1253
Magnus Jedvert26679d62015-04-07 14:07:41 +02001254 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +00001255 "Encode");
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +00001256
Niels Möller7dc26b72017-12-06 10:27:48 +01001257 overuse_detector_->FrameCaptured(out_frame, time_when_posted_us);
perkjd52063f2016-09-07 06:32:18 -07001258
Erik Språnge2fd86a2018-10-24 11:32:39 +02001259 // Encoder metadata needs to be updated before encode complete callback.
1260 VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
1261 if (info.implementation_name != encoder_info_.implementation_name) {
1262 encoder_stats_observer_->OnEncoderImplementationChanged(
1263 info.implementation_name);
Erik Språng7ca375c2019-02-06 16:20:17 +01001264 if (bitrate_adjuster_) {
1265 // Encoder implementation changed, reset overshoot detector states.
1266 bitrate_adjuster_->Reset();
1267 }
Erik Språnge2fd86a2018-10-24 11:32:39 +02001268 }
Erik Språng7ca375c2019-02-06 16:20:17 +01001269
1270 if (bitrate_adjuster_) {
1271 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
1272 if (info.fps_allocation[si] != encoder_info_.fps_allocation[si]) {
1273 bitrate_adjuster_->OnEncoderInfo(info);
1274 break;
1275 }
1276 }
1277 }
1278
Erik Språnge2fd86a2018-10-24 11:32:39 +02001279 encoder_info_ = info;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01001280 last_encode_info_ms_ = clock_->TimeInMilliseconds();
Erik Språngb7cb7b52019-02-26 15:52:33 +01001281 RTC_DCHECK_EQ(send_codec_.width, out_frame.width());
1282 RTC_DCHECK_EQ(send_codec_.height, out_frame.height());
Erik Språngd7329ca2019-02-21 21:19:53 +01001283 const VideoFrameBuffer::Type buffer_type =
1284 out_frame.video_frame_buffer()->type();
1285 const bool is_buffer_type_supported =
1286 buffer_type == VideoFrameBuffer::Type::kI420 ||
1287 (buffer_type == VideoFrameBuffer::Type::kNative &&
Erik Språng6a7baa72019-02-26 18:31:00 +01001288 info.supports_native_handle);
Erik Språngd7329ca2019-02-21 21:19:53 +01001289
1290 if (!is_buffer_type_supported) {
1291 // This module only supports software encoding.
1292 rtc::scoped_refptr<I420BufferInterface> converted_buffer(
1293 out_frame.video_frame_buffer()->ToI420());
1294
1295 if (!converted_buffer) {
1296 RTC_LOG(LS_ERROR) << "Frame conversion failed, dropping frame.";
1297 return;
1298 }
1299
Ilya Nikolaevskiy1c90cab2019-03-07 15:30:58 +01001300 // UpdatedRect is reset to full update if it's not empty, because buffer was
1301 // converted, therefore we can't guarantee that pixels outside of UpdateRect
1302 // didn't change comparing to the previous frame.
1303 VideoFrame::UpdateRect update_rect =
1304 out_frame.update_rect().IsEmpty()
1305 ? out_frame.update_rect()
1306 : VideoFrame::UpdateRect{0, 0, out_frame.width(),
1307 out_frame.height()};
1308
Erik Språngd7329ca2019-02-21 21:19:53 +01001309 out_frame = VideoFrame::Builder()
1310 .set_video_frame_buffer(converted_buffer)
1311 .set_timestamp_rtp(out_frame.timestamp())
1312 .set_timestamp_ms(out_frame.render_time_ms())
1313 .set_rotation(out_frame.rotation())
1314 .set_id(out_frame.id())
Ilya Nikolaevskiy1c90cab2019-03-07 15:30:58 +01001315 .set_update_rect(update_rect)
Erik Språngd7329ca2019-02-21 21:19:53 +01001316 .build();
1317 }
Erik Språng6a7baa72019-02-26 18:31:00 +01001318
1319 TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp",
1320 out_frame.timestamp());
1321
1322 frame_encoder_timer_.OnEncodeStarted(out_frame.timestamp(),
1323 out_frame.render_time_ms());
1324
Niels Möllerc8d2e732019-03-06 12:00:33 +01001325 const int32_t encode_status = encoder_->Encode(out_frame, &next_frame_types_);
Erik Språng6a7baa72019-02-26 18:31:00 +01001326
Erik Språngd7329ca2019-02-21 21:19:53 +01001327 if (encode_status < 0) {
1328 RTC_LOG(LS_ERROR) << "Failed to encode frame. Error code: "
1329 << encode_status;
1330 return;
1331 }
1332
1333 for (auto& it : next_frame_types_) {
Niels Möller8f7ce222019-03-21 15:43:58 +01001334 it = VideoFrameType::kVideoFrameDelta;
Erik Språngd7329ca2019-02-21 21:19:53 +01001335 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001336}
niklase@google.com470e71d2011-07-07 08:21:25 +00001337
mflodmancc3d4422017-08-03 08:27:51 -07001338void VideoStreamEncoder::SendKeyFrame() {
perkj26091b12016-09-01 01:17:40 -07001339 if (!encoder_queue_.IsCurrent()) {
1340 encoder_queue_.PostTask([this] { SendKeyFrame(); });
1341 return;
1342 }
1343 RTC_DCHECK_RUN_ON(&encoder_queue_);
Niels Möller1c9aa1e2018-02-16 10:27:23 +01001344 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
Erik Språngd7329ca2019-02-21 21:19:53 +01001345 RTC_DCHECK(!next_frame_types_.empty());
Niels Möller8f7ce222019-03-21 15:43:58 +01001346 next_frame_types_[0] = VideoFrameType::kVideoFrameKey;
Erik Språngd7329ca2019-02-21 21:19:53 +01001347 if (HasInternalSource()) {
1348 // Try to request the frame if we have an external encoder with
1349 // internal source since AddVideoFrame never will be called.
Erik Språng6a7baa72019-02-26 18:31:00 +01001350
1351 // TODO(nisse): Used only with internal source. Delete as soon as
1352 // that feature is removed. The only implementation I've been able
1353 // to find ignores what's in the frame. With one exception: It seems
1354 // a few test cases, e.g.,
1355 // VideoSendStreamTest.VideoSendStreamStopSetEncoderRateToZero, set
1356 // internal_source to true and use FakeEncoder. And the latter will
1357 // happily encode this 1x1 frame and pass it on down the pipeline.
1358 if (encoder_->Encode(VideoFrame::Builder()
1359 .set_video_frame_buffer(I420Buffer::Create(1, 1))
1360 .set_rotation(kVideoRotation_0)
1361 .set_timestamp_us(0)
1362 .build(),
Erik Språng6a7baa72019-02-26 18:31:00 +01001363 &next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
Erik Språngd7329ca2019-02-21 21:19:53 +01001364 // Try to remove just-performed keyframe request, if stream still exists.
Niels Möller8f7ce222019-03-21 15:43:58 +01001365 next_frame_types_[0] = VideoFrameType::kVideoFrameDelta;
Erik Språngd7329ca2019-02-21 21:19:53 +01001366 }
1367 }
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00001368}
1369
mflodmancc3d4422017-08-03 08:27:51 -07001370EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001371 const EncodedImage& encoded_image,
1372 const CodecSpecificInfo* codec_specific_info,
1373 const RTPFragmentationHeader* fragmentation) {
Erik Språng6a7baa72019-02-26 18:31:00 +01001374 TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded",
1375 "timestamp", encoded_image.Timestamp());
1376 const size_t spatial_idx = encoded_image.SpatialIndex().value_or(0);
1377 EncodedImage image_copy(encoded_image);
1378
1379 frame_encoder_timer_.FillTimingInfo(
Erik Språng982dc792019-03-13 16:33:02 +01001380 spatial_idx, &image_copy,
1381 rtc::TimeMicros() / rtc::kNumMicrosecsPerMillisec);
Erik Språng6a7baa72019-02-26 18:31:00 +01001382
1383 // Piggyback ALR experiment group id and simulcast id into the content type.
1384 const uint8_t experiment_id =
1385 experiment_groups_[videocontenttypehelpers::IsScreenshare(
1386 image_copy.content_type_)];
1387
1388 // TODO(ilnik): This will force content type extension to be present even
1389 // for realtime video. At the expense of miniscule overhead we will get
1390 // sliced receive statistics.
1391 RTC_CHECK(videocontenttypehelpers::SetExperimentId(&image_copy.content_type_,
1392 experiment_id));
1393 // We count simulcast streams from 1 on the wire. That's why we set simulcast
1394 // id in content type to +1 of that is actual simulcast index. This is because
1395 // value 0 on the wire is reserved for 'no simulcast stream specified'.
1396 RTC_CHECK(videocontenttypehelpers::SetSimulcastId(
1397 &image_copy.content_type_, static_cast<uint8_t>(spatial_idx + 1)));
1398
perkj26091b12016-09-01 01:17:40 -07001399 // Encoded is called on whatever thread the real encoder implementation run
1400 // on. In the case of hardware encoders, there might be several encoders
1401 // running in parallel on different threads.
Erik Språng6a7baa72019-02-26 18:31:00 +01001402 encoder_stats_observer_->OnSendEncodedImage(image_copy, codec_specific_info);
sprang3911c262016-04-15 01:24:14 -07001403
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001404 EncodedImageCallback::Result result =
Erik Språng6a7baa72019-02-26 18:31:00 +01001405 sink_->OnEncodedImage(image_copy, codec_specific_info, fragmentation);
perkjbc75d972016-05-02 06:31:25 -07001406
Erik Språng7ca375c2019-02-06 16:20:17 +01001407 // We are only interested in propagating the meta-data about the image, not
1408 // encoded data itself, to the post encode function. Since we cannot be sure
1409 // the pointer will still be valid when run on the task queue, set it to null.
Erik Språng6a7baa72019-02-26 18:31:00 +01001410 image_copy.set_buffer(nullptr, 0);
Niels Möller83dbeac2017-12-14 16:39:44 +01001411
Erik Språng7ca375c2019-02-06 16:20:17 +01001412 int temporal_index = 0;
1413 if (codec_specific_info) {
1414 if (codec_specific_info->codecType == kVideoCodecVP9) {
1415 temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx;
1416 } else if (codec_specific_info->codecType == kVideoCodecVP8) {
1417 temporal_index = codec_specific_info->codecSpecific.VP8.temporalIdx;
1418 }
1419 }
1420 if (temporal_index == kNoTemporalIdx) {
1421 temporal_index = 0;
Niels Möller83dbeac2017-12-14 16:39:44 +01001422 }
1423
Erik Språng982dc792019-03-13 16:33:02 +01001424 RunPostEncode(image_copy, rtc::TimeMicros(), temporal_index);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001425
1426 if (result.error == Result::OK) {
1427 // In case of an internal encoder running on a separate thread, the
1428 // decision to drop a frame might be a frame late and signaled via
1429 // atomic flag. This is because we can't easily wait for the worker thread
1430 // without risking deadlocks, eg during shutdown when the worker thread
1431 // might be waiting for the internal encoder threads to stop.
1432 if (pending_frame_drops_.load() > 0) {
1433 int pending_drops = pending_frame_drops_.fetch_sub(1);
1434 RTC_DCHECK_GT(pending_drops, 0);
1435 result.drop_next_frame = true;
1436 }
1437 }
perkj803d97f2016-11-01 11:45:46 -07001438
Sergey Ulanov525df3f2016-08-02 17:46:41 -07001439 return result;
Peter Boströmb7d9a972015-12-18 16:01:11 +01001440}
1441
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001442void VideoStreamEncoder::OnDroppedFrame(DropReason reason) {
1443 switch (reason) {
1444 case DropReason::kDroppedByMediaOptimizations:
Niels Möller213618e2018-07-24 09:29:58 +02001445 encoder_stats_observer_->OnFrameDropped(
1446 VideoStreamEncoderObserver::DropReason::kMediaOptimization);
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001447 encoder_queue_.PostTask([this] {
1448 RTC_DCHECK_RUN_ON(&encoder_queue_);
1449 if (quality_scaler_)
Åsa Perssona945aee2018-04-24 16:53:25 +02001450 quality_scaler_->ReportDroppedFrameByMediaOpt();
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001451 });
1452 break;
1453 case DropReason::kDroppedByEncoder:
Niels Möller213618e2018-07-24 09:29:58 +02001454 encoder_stats_observer_->OnFrameDropped(
1455 VideoStreamEncoderObserver::DropReason::kEncoder);
Åsa Perssona945aee2018-04-24 16:53:25 +02001456 encoder_queue_.PostTask([this] {
1457 RTC_DCHECK_RUN_ON(&encoder_queue_);
1458 if (quality_scaler_)
1459 quality_scaler_->ReportDroppedFrameByEncoder();
1460 });
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +02001461 break;
1462 }
kthelgason876222f2016-11-29 01:44:11 -08001463}
1464
Erik Språng610c7632019-03-06 15:37:33 +01001465void VideoStreamEncoder::OnBitrateUpdated(DataRate target_bitrate,
1466 DataRate target_headroom,
mflodmancc3d4422017-08-03 08:27:51 -07001467 uint8_t fraction_lost,
1468 int64_t round_trip_time_ms) {
perkj26091b12016-09-01 01:17:40 -07001469 if (!encoder_queue_.IsCurrent()) {
Erik Språng610c7632019-03-06 15:37:33 +01001470 encoder_queue_.PostTask([this, target_bitrate, target_headroom,
1471 fraction_lost, round_trip_time_ms] {
1472 OnBitrateUpdated(target_bitrate, target_headroom, fraction_lost,
1473 round_trip_time_ms);
1474 });
perkj26091b12016-09-01 01:17:40 -07001475 return;
1476 }
1477 RTC_DCHECK_RUN_ON(&encoder_queue_);
1478 RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
1479
Erik Språng610c7632019-03-06 15:37:33 +01001480 RTC_LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << target_bitrate.bps()
1481 << " headroom = " << target_headroom.bps()
Mirko Bonadei675513b2017-11-09 11:09:25 +01001482 << " packet loss " << static_cast<int>(fraction_lost)
1483 << " rtt " << round_trip_time_ms;
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001484 // On significant changes to BWE at the start of the call,
1485 // enable frame drops to quickly react to jumps in available bandwidth.
1486 if (encoder_start_bitrate_bps_ != 0 &&
1487 !has_seen_first_significant_bwe_change_ && quality_scaler_ &&
1488 initial_framedrop_on_bwe_enabled_ &&
Erik Språng610c7632019-03-06 15:37:33 +01001489 abs_diff(target_bitrate.bps(), encoder_start_bitrate_bps_) >=
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001490 kFramedropThreshold * encoder_start_bitrate_bps_) {
1491 // Reset initial framedrop feature when first real BW estimate arrives.
1492 // TODO(kthelgason): Update BitrateAllocator to not call OnBitrateUpdated
1493 // without an actual BW estimate.
1494 initial_framedrop_ = 0;
1495 has_seen_first_significant_bwe_change_ = true;
1496 }
perkj26091b12016-09-01 01:17:40 -07001497
Elad Aloncde8ab22019-03-20 11:56:20 +01001498 if (encoder_) {
1499 encoder_->OnPacketLossRateUpdate(static_cast<float>(fraction_lost) / 256.f);
1500 encoder_->OnRttUpdate(round_trip_time_ms);
1501 }
1502
Niels Möller6bb5ab92019-01-11 11:11:10 +01001503 uint32_t framerate_fps = GetInputFramerateFps();
Erik Språng610c7632019-03-06 15:37:33 +01001504 frame_dropper_.SetRates((target_bitrate.bps() + 500) / 1000, framerate_fps);
1505 SetEncoderRates(GetBitrateAllocationAndNotifyObserver(target_bitrate.bps(),
1506 framerate_fps),
1507 framerate_fps);
perkj26091b12016-09-01 01:17:40 -07001508
Erik Språng610c7632019-03-06 15:37:33 +01001509 encoder_start_bitrate_bps_ = target_bitrate.bps() != 0
1510 ? target_bitrate.bps()
1511 : encoder_start_bitrate_bps_;
1512 bool video_is_suspended = target_bitrate == DataRate::Zero();
Erik Språng08127a92016-11-16 16:41:30 +01001513 bool video_suspension_changed = video_is_suspended != EncoderPaused();
Erik Språng610c7632019-03-06 15:37:33 +01001514 last_observed_bitrate_bps_ = target_bitrate.bps();
Peter Boströmd153a372015-11-10 15:27:12 +00001515
sprang552c7c72017-02-13 04:41:45 -08001516 if (video_suspension_changed) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001517 RTC_LOG(LS_INFO) << "Video suspend state changed to: "
1518 << (video_is_suspended ? "suspended" : "not suspended");
Niels Möller213618e2018-07-24 09:29:58 +02001519 encoder_stats_observer_->OnSuspendChange(video_is_suspended);
mflodman101f2502016-06-09 17:21:19 +02001520 }
Sebastian Janssona3177052018-04-10 13:05:49 +02001521 if (video_suspension_changed && !video_is_suspended && pending_frame_ &&
1522 !DropDueToSize(pending_frame_->size())) {
1523 int64_t pending_time_us = rtc::TimeMicros() - pending_frame_post_time_us_;
1524 if (pending_time_us < kPendingFrameTimeoutMs * 1000)
1525 EncodeVideoFrame(*pending_frame_, pending_frame_post_time_us_);
1526 pending_frame_.reset();
1527 }
1528}
1529
1530bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02001531 if (initial_framedrop_ < kMaxInitialFramedrop &&
Sebastian Janssona3177052018-04-10 13:05:49 +02001532 encoder_start_bitrate_bps_ > 0) {
1533 if (encoder_start_bitrate_bps_ < 300000 /* qvga */) {
1534 return pixel_count > 320 * 240;
1535 } else if (encoder_start_bitrate_bps_ < 500000 /* vga */) {
1536 return pixel_count > 640 * 480;
1537 }
1538 }
1539 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001540}
1541
mflodmancc3d4422017-08-03 08:27:51 -07001542void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001543 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangc5d62e22017-04-02 23:53:04 -07001544 AdaptationRequest adaptation_request = {
1545 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001546 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001547 AdaptationRequest::Mode::kAdaptDown};
asapersson09f05612017-05-15 23:40:18 -07001548
sprangc5d62e22017-04-02 23:53:04 -07001549 bool downgrade_requested =
1550 last_adaptation_request_ &&
1551 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
1552
sprangc5d62e22017-04-02 23:53:04 -07001553 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001554 case DegradationPreference::BALANCED:
asaperssonf7e294d2017-06-13 23:25:22 -07001555 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001556 case DegradationPreference::MAINTAIN_FRAMERATE:
sprangc5d62e22017-04-02 23:53:04 -07001557 if (downgrade_requested &&
1558 adaptation_request.input_pixel_count_ >=
1559 last_adaptation_request_->input_pixel_count_) {
1560 // Don't request lower resolution if the current resolution is not
1561 // lower than the last time we asked for the resolution to be lowered.
1562 return;
1563 }
1564 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001565 case DegradationPreference::MAINTAIN_RESOLUTION:
sprangc5d62e22017-04-02 23:53:04 -07001566 if (adaptation_request.framerate_fps_ <= 0 ||
1567 (downgrade_requested &&
1568 adaptation_request.framerate_fps_ < kMinFramerateFps)) {
1569 // If no input fps estimate available, can't determine how to scale down
1570 // framerate. Otherwise, don't request lower framerate if we don't have
1571 // a valid frame rate. Since framerate, unlike resolution, is a measure
1572 // we have to estimate, and can fluctuate naturally over time, don't
1573 // make the same kind of limitations as for resolution, but trust the
1574 // overuse detector to not trigger too often.
1575 return;
1576 }
1577 break;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001578 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001579 return;
sprang84a37592017-02-10 07:04:27 -08001580 }
sprangc5d62e22017-04-02 23:53:04 -07001581
sprangc5d62e22017-04-02 23:53:04 -07001582 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001583 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001584 // Try scale down framerate, if lower.
1585 int fps = MinFps(last_frame_info_->pixel_count());
1586 if (source_proxy_->RestrictFramerate(fps)) {
1587 GetAdaptCounter().IncrementFramerate(reason);
1588 break;
1589 }
1590 // Scale down resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001591 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001592 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001593 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001594 // Scale down resolution.
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001595 bool min_pixels_reached = false;
asaperssond0de2952017-04-21 01:47:31 -07001596 if (!source_proxy_->RequestResolutionLowerThan(
asapersson142fcc92017-08-17 08:58:54 -07001597 adaptation_request.input_pixel_count_,
Erik Språnge2fd86a2018-10-24 11:32:39 +02001598 encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame,
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001599 &min_pixels_reached)) {
1600 if (min_pixels_reached)
Niels Möller213618e2018-07-24 09:29:58 +02001601 encoder_stats_observer_->OnMinPixelLimitReached();
asaperssond0de2952017-04-21 01:47:31 -07001602 return;
1603 }
asaperssonf7e294d2017-06-13 23:25:22 -07001604 GetAdaptCounter().IncrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001605 break;
Åsa Perssonc3ed6302017-11-16 14:04:52 +01001606 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001607 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001608 // Scale down framerate.
sprangfda496a2017-06-15 04:21:07 -07001609 const int requested_framerate = source_proxy_->RequestFramerateLowerThan(
1610 adaptation_request.framerate_fps_);
1611 if (requested_framerate == -1)
asapersson13874762017-06-07 00:01:02 -07001612 return;
sprangfda496a2017-06-15 04:21:07 -07001613 RTC_DCHECK_NE(max_framerate_, -1);
Niels Möller7dc26b72017-12-06 10:27:48 +01001614 overuse_detector_->OnTargetFramerateUpdated(
1615 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001616 GetAdaptCounter().IncrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001617 break;
sprangfda496a2017-06-15 04:21:07 -07001618 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001619 case DegradationPreference::DISABLED:
sprangc5d62e22017-04-02 23:53:04 -07001620 RTC_NOTREACHED();
1621 }
1622
asaperssond0de2952017-04-21 01:47:31 -07001623 last_adaptation_request_.emplace(adaptation_request);
1624
asapersson09f05612017-05-15 23:40:18 -07001625 UpdateAdaptationStats(reason);
asaperssond0de2952017-04-21 01:47:31 -07001626
Mirko Bonadei675513b2017-11-09 11:09:25 +01001627 RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
perkj26091b12016-09-01 01:17:40 -07001628}
1629
mflodmancc3d4422017-08-03 08:27:51 -07001630void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -07001631 RTC_DCHECK_RUN_ON(&encoder_queue_);
asapersson09f05612017-05-15 23:40:18 -07001632
1633 const AdaptCounter& adapt_counter = GetConstAdaptCounter();
1634 int num_downgrades = adapt_counter.TotalCount(reason);
1635 if (num_downgrades == 0)
perkj803d97f2016-11-01 11:45:46 -07001636 return;
asapersson09f05612017-05-15 23:40:18 -07001637 RTC_DCHECK_GT(num_downgrades, 0);
1638
sprangc5d62e22017-04-02 23:53:04 -07001639 AdaptationRequest adaptation_request = {
1640 last_frame_info_->pixel_count(),
Niels Möller213618e2018-07-24 09:29:58 +02001641 encoder_stats_observer_->GetInputFrameRate(),
sprangc5d62e22017-04-02 23:53:04 -07001642 AdaptationRequest::Mode::kAdaptUp};
1643
1644 bool adapt_up_requested =
1645 last_adaptation_request_ &&
1646 last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp;
asapersson09f05612017-05-15 23:40:18 -07001647
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001648 if (degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE) {
asaperssonf7e294d2017-06-13 23:25:22 -07001649 if (adapt_up_requested &&
1650 adaptation_request.input_pixel_count_ <=
1651 last_adaptation_request_->input_pixel_count_) {
1652 // Don't request higher resolution if the current resolution is not
1653 // higher than the last time we asked for the resolution to be higher.
sprangc5d62e22017-04-02 23:53:04 -07001654 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001655 }
sprangb1ca0732017-02-01 08:38:12 -08001656 }
sprangc5d62e22017-04-02 23:53:04 -07001657
sprangc5d62e22017-04-02 23:53:04 -07001658 switch (degradation_preference_) {
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001659 case DegradationPreference::BALANCED: {
asaperssonf7e294d2017-06-13 23:25:22 -07001660 // Try scale up framerate, if higher.
1661 int fps = MaxFps(last_frame_info_->pixel_count());
1662 if (source_proxy_->IncreaseFramerate(fps)) {
1663 GetAdaptCounter().DecrementFramerate(reason, fps);
1664 // Reset framerate in case of fewer fps steps down than up.
1665 if (adapt_counter.FramerateCount() == 0 &&
1666 fps != std::numeric_limits<int>::max()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001667 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asaperssonf7e294d2017-06-13 23:25:22 -07001668 source_proxy_->IncreaseFramerate(std::numeric_limits<int>::max());
1669 }
1670 break;
1671 }
1672 // Scale up resolution.
Karl Wiberg80ba3332018-02-05 10:33:35 +01001673 RTC_FALLTHROUGH();
asaperssonf7e294d2017-06-13 23:25:22 -07001674 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001675 case DegradationPreference::MAINTAIN_FRAMERATE: {
asapersson13874762017-06-07 00:01:02 -07001676 // Scale up resolution.
1677 int pixel_count = adaptation_request.input_pixel_count_;
1678 if (adapt_counter.ResolutionCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001679 RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001680 pixel_count = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001681 }
asapersson13874762017-06-07 00:01:02 -07001682 if (!source_proxy_->RequestHigherResolutionThan(pixel_count))
1683 return;
asaperssonf7e294d2017-06-13 23:25:22 -07001684 GetAdaptCounter().DecrementResolution(reason);
sprangc5d62e22017-04-02 23:53:04 -07001685 break;
asapersson13874762017-06-07 00:01:02 -07001686 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001687 case DegradationPreference::MAINTAIN_RESOLUTION: {
asapersson13874762017-06-07 00:01:02 -07001688 // Scale up framerate.
1689 int fps = adaptation_request.framerate_fps_;
1690 if (adapt_counter.FramerateCount() == 1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001691 RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
asapersson13874762017-06-07 00:01:02 -07001692 fps = std::numeric_limits<int>::max();
sprangc5d62e22017-04-02 23:53:04 -07001693 }
sprangfda496a2017-06-15 04:21:07 -07001694
1695 const int requested_framerate =
1696 source_proxy_->RequestHigherFramerateThan(fps);
1697 if (requested_framerate == -1) {
Niels Möller7dc26b72017-12-06 10:27:48 +01001698 overuse_detector_->OnTargetFramerateUpdated(max_framerate_);
asapersson13874762017-06-07 00:01:02 -07001699 return;
sprangfda496a2017-06-15 04:21:07 -07001700 }
Niels Möller7dc26b72017-12-06 10:27:48 +01001701 overuse_detector_->OnTargetFramerateUpdated(
1702 std::min(max_framerate_, requested_framerate));
asaperssonf7e294d2017-06-13 23:25:22 -07001703 GetAdaptCounter().DecrementFramerate(reason);
sprangc5d62e22017-04-02 23:53:04 -07001704 break;
asapersson13874762017-06-07 00:01:02 -07001705 }
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001706 case DegradationPreference::DISABLED:
asaperssonf7e294d2017-06-13 23:25:22 -07001707 return;
sprangc5d62e22017-04-02 23:53:04 -07001708 }
1709
asaperssond0de2952017-04-21 01:47:31 -07001710 last_adaptation_request_.emplace(adaptation_request);
1711
asapersson09f05612017-05-15 23:40:18 -07001712 UpdateAdaptationStats(reason);
1713
Mirko Bonadei675513b2017-11-09 11:09:25 +01001714 RTC_LOG(LS_INFO) << adapt_counter.ToString();
asapersson09f05612017-05-15 23:40:18 -07001715}
1716
Niels Möller213618e2018-07-24 09:29:58 +02001717// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
mflodmancc3d4422017-08-03 08:27:51 -07001718void VideoStreamEncoder::UpdateAdaptationStats(AdaptReason reason) {
asaperssond0de2952017-04-21 01:47:31 -07001719 switch (reason) {
asaperssond0de2952017-04-21 01:47:31 -07001720 case kCpu:
Niels Möller213618e2018-07-24 09:29:58 +02001721 encoder_stats_observer_->OnAdaptationChanged(
1722 VideoStreamEncoderObserver::AdaptationReason::kCpu,
1723 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asapersson09f05612017-05-15 23:40:18 -07001724 break;
1725 case kQuality:
Niels Möller213618e2018-07-24 09:29:58 +02001726 encoder_stats_observer_->OnAdaptationChanged(
1727 VideoStreamEncoderObserver::AdaptationReason::kQuality,
1728 GetActiveCounts(kCpu), GetActiveCounts(kQuality));
asaperssond0de2952017-04-21 01:47:31 -07001729 break;
1730 }
perkj26091b12016-09-01 01:17:40 -07001731}
1732
Niels Möller213618e2018-07-24 09:29:58 +02001733VideoStreamEncoderObserver::AdaptationSteps VideoStreamEncoder::GetActiveCounts(
mflodmancc3d4422017-08-03 08:27:51 -07001734 AdaptReason reason) {
Niels Möller213618e2018-07-24 09:29:58 +02001735 VideoStreamEncoderObserver::AdaptationSteps counts =
mflodmancc3d4422017-08-03 08:27:51 -07001736 GetConstAdaptCounter().Counts(reason);
asapersson09f05612017-05-15 23:40:18 -07001737 switch (reason) {
1738 case kCpu:
1739 if (!IsFramerateScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001740 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001741 if (!IsResolutionScalingEnabled(degradation_preference_))
Niels Möller213618e2018-07-24 09:29:58 +02001742 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001743 break;
1744 case kQuality:
1745 if (!IsFramerateScalingEnabled(degradation_preference_) ||
1746 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001747 counts.num_framerate_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001748 }
1749 if (!IsResolutionScalingEnabled(degradation_preference_) ||
1750 !quality_scaler_) {
Niels Möller213618e2018-07-24 09:29:58 +02001751 counts.num_resolution_reductions = absl::nullopt;
asapersson09f05612017-05-15 23:40:18 -07001752 }
1753 break;
sprangc5d62e22017-04-02 23:53:04 -07001754 }
asapersson09f05612017-05-15 23:40:18 -07001755 return counts;
sprangc5d62e22017-04-02 23:53:04 -07001756}
1757
mflodmancc3d4422017-08-03 08:27:51 -07001758VideoStreamEncoder::AdaptCounter& VideoStreamEncoder::GetAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001759 return adapt_counters_[degradation_preference_];
1760}
1761
mflodmancc3d4422017-08-03 08:27:51 -07001762const VideoStreamEncoder::AdaptCounter&
1763VideoStreamEncoder::GetConstAdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001764 return adapt_counters_[degradation_preference_];
1765}
1766
Erik Språng7ca375c2019-02-06 16:20:17 +01001767void VideoStreamEncoder::RunPostEncode(EncodedImage encoded_image,
Niels Möller6bb5ab92019-01-11 11:11:10 +01001768 int64_t time_sent_us,
Erik Språng7ca375c2019-02-06 16:20:17 +01001769 int temporal_index) {
Niels Möller6bb5ab92019-01-11 11:11:10 +01001770 if (!encoder_queue_.IsCurrent()) {
Erik Språng7ca375c2019-02-06 16:20:17 +01001771 encoder_queue_.PostTask(
1772 [this, encoded_image, time_sent_us, temporal_index] {
1773 RunPostEncode(encoded_image, time_sent_us, temporal_index);
1774 });
Niels Möller6bb5ab92019-01-11 11:11:10 +01001775 return;
1776 }
1777
1778 RTC_DCHECK_RUN_ON(&encoder_queue_);
Erik Språng7ca375c2019-02-06 16:20:17 +01001779
1780 absl::optional<int> encode_duration_us;
1781 if (encoded_image.timing_.flags != VideoSendTiming::kInvalid) {
1782 encode_duration_us =
1783 // TODO(nisse): Maybe use capture_time_ms_ rather than encode_start_ms_?
1784 rtc::kNumMicrosecsPerMillisec *
1785 (encoded_image.timing_.encode_finish_ms -
1786 encoded_image.timing_.encode_start_ms);
1787 }
1788
1789 // Run post encode tasks, such as overuse detection and frame rate/drop
1790 // stats for internal encoders.
1791 const size_t frame_size = encoded_image.size();
Niels Möller87e2d782019-03-07 10:18:23 +01001792 const bool keyframe =
1793 encoded_image._frameType == VideoFrameType::kVideoFrameKey;
Erik Språng7ca375c2019-02-06 16:20:17 +01001794
1795 if (frame_size > 0) {
1796 frame_dropper_.Fill(frame_size, !keyframe);
Niels Möller6bb5ab92019-01-11 11:11:10 +01001797 }
1798
Erik Språngd7329ca2019-02-21 21:19:53 +01001799 if (HasInternalSource()) {
Niels Möller6bb5ab92019-01-11 11:11:10 +01001800 // Update frame dropper after the fact for internal sources.
1801 input_framerate_.Update(1u, clock_->TimeInMilliseconds());
1802 frame_dropper_.Leak(GetInputFramerateFps());
1803 // Signal to encoder to drop next frame.
1804 if (frame_dropper_.DropFrame()) {
1805 pending_frame_drops_.fetch_add(1);
1806 }
1807 }
1808
Erik Språng7ca375c2019-02-06 16:20:17 +01001809 overuse_detector_->FrameSent(
1810 encoded_image.Timestamp(), time_sent_us,
1811 encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec,
1812 encode_duration_us);
1813 if (quality_scaler_ && encoded_image.qp_ >= 0)
Sebastian Janssonb6789402019-03-01 15:40:49 +01001814 quality_scaler_->ReportQp(encoded_image.qp_, time_sent_us);
Erik Språng7ca375c2019-02-06 16:20:17 +01001815 if (bitrate_adjuster_) {
1816 bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index);
1817 }
Niels Möller6bb5ab92019-01-11 11:11:10 +01001818}
1819
Erik Språngd7329ca2019-02-21 21:19:53 +01001820bool VideoStreamEncoder::HasInternalSource() const {
1821 // TODO(sprang): Checking both info from encoder and from encoder factory
1822 // until we have deprecated and removed the encoder factory info.
1823 return codec_info_.has_internal_source || encoder_info_.has_internal_source;
1824}
1825
Erik Språng6a7baa72019-02-26 18:31:00 +01001826void VideoStreamEncoder::ReleaseEncoder() {
1827 if (!encoder_ || !encoder_initialized_) {
1828 return;
1829 }
1830 encoder_->Release();
1831 encoder_initialized_ = false;
1832 TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release");
1833}
1834
asapersson09f05612017-05-15 23:40:18 -07001835// Class holding adaptation information.
mflodmancc3d4422017-08-03 08:27:51 -07001836VideoStreamEncoder::AdaptCounter::AdaptCounter() {
asapersson09f05612017-05-15 23:40:18 -07001837 fps_counters_.resize(kScaleReasonSize);
1838 resolution_counters_.resize(kScaleReasonSize);
asaperssonf7e294d2017-06-13 23:25:22 -07001839 static_assert(kScaleReasonSize == 2, "Update MoveCount.");
asapersson09f05612017-05-15 23:40:18 -07001840}
1841
mflodmancc3d4422017-08-03 08:27:51 -07001842VideoStreamEncoder::AdaptCounter::~AdaptCounter() {}
asapersson09f05612017-05-15 23:40:18 -07001843
mflodmancc3d4422017-08-03 08:27:51 -07001844std::string VideoStreamEncoder::AdaptCounter::ToString() const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001845 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001846 ss << "Downgrade counts: fps: {" << ToString(fps_counters_);
1847 ss << "}, resolution: {" << ToString(resolution_counters_) << "}";
Jonas Olsson84df1c72018-09-14 16:59:32 +02001848 return ss.Release();
asapersson09f05612017-05-15 23:40:18 -07001849}
1850
Niels Möller213618e2018-07-24 09:29:58 +02001851VideoStreamEncoderObserver::AdaptationSteps
1852VideoStreamEncoder::AdaptCounter::Counts(int reason) const {
1853 VideoStreamEncoderObserver::AdaptationSteps counts;
1854 counts.num_framerate_reductions = fps_counters_[reason];
1855 counts.num_resolution_reductions = resolution_counters_[reason];
asapersson09f05612017-05-15 23:40:18 -07001856 return counts;
1857}
1858
mflodmancc3d4422017-08-03 08:27:51 -07001859void VideoStreamEncoder::AdaptCounter::IncrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001860 ++(fps_counters_[reason]);
asapersson09f05612017-05-15 23:40:18 -07001861}
1862
mflodmancc3d4422017-08-03 08:27:51 -07001863void VideoStreamEncoder::AdaptCounter::IncrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001864 ++(resolution_counters_[reason]);
1865}
1866
mflodmancc3d4422017-08-03 08:27:51 -07001867void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001868 if (fps_counters_[reason] == 0) {
1869 // Balanced mode: Adapt up is in a different order, switch reason.
1870 // E.g. framerate adapt down: quality (2), framerate adapt up: cpu (3).
1871 // 1. Down resolution (cpu): res={quality:0,cpu:1}, fps={quality:0,cpu:0}
1872 // 2. Down fps (quality): res={quality:0,cpu:1}, fps={quality:1,cpu:0}
1873 // 3. Up fps (cpu): res={quality:1,cpu:0}, fps={quality:0,cpu:0}
1874 // 4. Up resolution (quality): res={quality:0,cpu:0}, fps={quality:0,cpu:0}
1875 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1876 RTC_DCHECK_GT(FramerateCount(), 0) << "Framerate not downgraded.";
1877 MoveCount(&resolution_counters_, reason);
1878 MoveCount(&fps_counters_, (reason + 1) % kScaleReasonSize);
1879 }
1880 --(fps_counters_[reason]);
1881 RTC_DCHECK_GE(fps_counters_[reason], 0);
1882}
1883
mflodmancc3d4422017-08-03 08:27:51 -07001884void VideoStreamEncoder::AdaptCounter::DecrementResolution(int reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001885 if (resolution_counters_[reason] == 0) {
1886 // Balanced mode: Adapt up is in a different order, switch reason.
1887 RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
1888 RTC_DCHECK_GT(ResolutionCount(), 0) << "Resolution not downgraded.";
1889 MoveCount(&fps_counters_, reason);
1890 MoveCount(&resolution_counters_, (reason + 1) % kScaleReasonSize);
1891 }
1892 --(resolution_counters_[reason]);
1893 RTC_DCHECK_GE(resolution_counters_[reason], 0);
1894}
1895
mflodmancc3d4422017-08-03 08:27:51 -07001896void VideoStreamEncoder::AdaptCounter::DecrementFramerate(int reason,
1897 int cur_fps) {
asaperssonf7e294d2017-06-13 23:25:22 -07001898 DecrementFramerate(reason);
1899 // Reset if at max fps (i.e. in case of fewer steps up than down).
1900 if (cur_fps == std::numeric_limits<int>::max())
1901 std::fill(fps_counters_.begin(), fps_counters_.end(), 0);
asapersson09f05612017-05-15 23:40:18 -07001902}
1903
mflodmancc3d4422017-08-03 08:27:51 -07001904int VideoStreamEncoder::AdaptCounter::FramerateCount() const {
asapersson09f05612017-05-15 23:40:18 -07001905 return Count(fps_counters_);
1906}
1907
mflodmancc3d4422017-08-03 08:27:51 -07001908int VideoStreamEncoder::AdaptCounter::ResolutionCount() const {
asapersson09f05612017-05-15 23:40:18 -07001909 return Count(resolution_counters_);
1910}
1911
mflodmancc3d4422017-08-03 08:27:51 -07001912int VideoStreamEncoder::AdaptCounter::FramerateCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001913 return fps_counters_[reason];
1914}
1915
mflodmancc3d4422017-08-03 08:27:51 -07001916int VideoStreamEncoder::AdaptCounter::ResolutionCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001917 return resolution_counters_[reason];
1918}
1919
mflodmancc3d4422017-08-03 08:27:51 -07001920int VideoStreamEncoder::AdaptCounter::TotalCount(int reason) const {
asapersson09f05612017-05-15 23:40:18 -07001921 return FramerateCount(reason) + ResolutionCount(reason);
1922}
1923
mflodmancc3d4422017-08-03 08:27:51 -07001924int VideoStreamEncoder::AdaptCounter::Count(
1925 const std::vector<int>& counters) const {
asapersson09f05612017-05-15 23:40:18 -07001926 return std::accumulate(counters.begin(), counters.end(), 0);
1927}
1928
mflodmancc3d4422017-08-03 08:27:51 -07001929void VideoStreamEncoder::AdaptCounter::MoveCount(std::vector<int>* counters,
1930 int from_reason) {
asaperssonf7e294d2017-06-13 23:25:22 -07001931 int to_reason = (from_reason + 1) % kScaleReasonSize;
1932 ++((*counters)[to_reason]);
1933 --((*counters)[from_reason]);
1934}
1935
mflodmancc3d4422017-08-03 08:27:51 -07001936std::string VideoStreamEncoder::AdaptCounter::ToString(
asapersson09f05612017-05-15 23:40:18 -07001937 const std::vector<int>& counters) const {
Jonas Olsson366a50c2018-09-06 13:41:30 +02001938 rtc::StringBuilder ss;
asapersson09f05612017-05-15 23:40:18 -07001939 for (size_t reason = 0; reason < kScaleReasonSize; ++reason) {
1940 ss << (reason ? " cpu" : "quality") << ":" << counters[reason];
sprangc5d62e22017-04-02 23:53:04 -07001941 }
Jonas Olsson84df1c72018-09-14 16:59:32 +02001942 return ss.Release();
sprangc5d62e22017-04-02 23:53:04 -07001943}
1944
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001945} // namespace webrtc