blob: a8d0500eb5d968867f988b20698613a39cca1189 [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
Peter Boström7623ce42015-12-09 12:13:30 +010011#include "webrtc/video/vie_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>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
niklase@google.com470e71d2011-07-07 08:21:25 +000016
kthelgason0cd27ba2016-12-19 06:32:16 -080017#include "webrtc/base/arraysize.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000018#include "webrtc/base/checks.h"
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.h"
tommie4f96502015-10-20 23:00:48 -070020#include "webrtc/base/trace_event.h"
Niels Möllerd28db7f2016-05-10 16:31:47 +020021#include "webrtc/base/timeutils.h"
sprang1a646ee2016-12-01 06:34:11 -080022#include "webrtc/common_video/include/video_bitrate_allocator.h"
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010023#include "webrtc/modules/pacing/paced_sender.h"
Erik Språng08127a92016-11-16 16:41:30 +010024#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
sprangb1ca0732017-02-01 08:38:12 -080025#include "webrtc/modules/video_coding/include/video_codec_initializer.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010026#include "webrtc/modules/video_coding/include/video_coding.h"
27#include "webrtc/modules/video_coding/include/video_coding_defines.h"
Peter Boströme4499152016-02-05 11:13:28 +010028#include "webrtc/video/overuse_frame_detector.h"
pbos@webrtc.org273a4142014-12-01 15:23:21 +000029#include "webrtc/video/send_statistics_proxy.h"
Peter Boströme4499152016-02-05 11:13:28 +010030#include "webrtc/video_frame.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000031namespace webrtc {
32
perkj26091b12016-09-01 01:17:40 -070033namespace {
sprangb1ca0732017-02-01 08:38:12 -080034using DegradationPreference = VideoSendStream::DegradationPreference;
35
asapersson6ffb67d2016-09-12 00:10:45 -070036// Time interval for logging frame counts.
37const int64_t kFrameLogIntervalMs = 60000;
kthelgason5e13d412016-12-01 03:59:51 -080038// We will never ask for a resolution lower than this.
kthelgason33ce8892016-12-09 03:53:59 -080039#if defined(WEBRTC_ANDROID)
40// TODO(kthelgason): Lower this limit when better testing
41// on MediaCodec and fallback implementations are in place.
42const int kMinPixelsPerFrame = 320 * 180;
43#else
kthelgason5e13d412016-12-01 03:59:51 -080044const int kMinPixelsPerFrame = 120 * 90;
kthelgason33ce8892016-12-09 03:53:59 -080045#endif
perkj26091b12016-09-01 01:17:40 -070046
kthelgason2bc68642017-02-07 07:02:22 -080047// The maximum number of frames to drop at beginning of stream
48// to try and achieve desired bitrate.
49const int kMaxInitialFramedrop = 4;
50
perkj26091b12016-09-01 01:17:40 -070051// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
52// pipelining encoders better (multiple input frames before something comes
53// out). This should effectively turn off CPU adaptations for systems that
54// remotely cope with the load right now.
55CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
56 CpuOveruseOptions options;
57 if (full_overuse_time) {
58 options.low_encode_usage_threshold_percent = 150;
59 options.high_encode_usage_threshold_percent = 200;
60 }
61 return options;
62}
63
kthelgason2bc68642017-02-07 07:02:22 -080064uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) {
65 if (kbps > 0) {
66 if (kbps < 300 /* qvga */) {
67 return 320 * 240;
68 } else if (kbps < 500 /* vga */) {
69 return 640 * 480;
70 }
71 }
72 return std::numeric_limits<uint32_t>::max();
73}
74
perkj26091b12016-09-01 01:17:40 -070075} // namespace
76
Pera48ddb72016-09-29 11:48:50 +020077class ViEEncoder::ConfigureEncoderTask : public rtc::QueuedTask {
78 public:
79 ConfigureEncoderTask(ViEEncoder* vie_encoder,
80 VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -080081 size_t max_data_payload_length,
82 bool nack_enabled)
Pera48ddb72016-09-29 11:48:50 +020083 : vie_encoder_(vie_encoder),
84 config_(std::move(config)),
asapersson5f7226f2016-11-25 04:37:00 -080085 max_data_payload_length_(max_data_payload_length),
86 nack_enabled_(nack_enabled) {}
Pera48ddb72016-09-29 11:48:50 +020087
88 private:
89 bool Run() override {
asapersson5f7226f2016-11-25 04:37:00 -080090 vie_encoder_->ConfigureEncoderOnTaskQueue(
91 std::move(config_), max_data_payload_length_, nack_enabled_);
Pera48ddb72016-09-29 11:48:50 +020092 return true;
93 }
94
95 ViEEncoder* const vie_encoder_;
96 VideoEncoderConfig config_;
97 size_t max_data_payload_length_;
asapersson5f7226f2016-11-25 04:37:00 -080098 bool nack_enabled_;
Pera48ddb72016-09-29 11:48:50 +020099};
100
perkj26091b12016-09-01 01:17:40 -0700101class ViEEncoder::EncodeTask : public rtc::QueuedTask {
102 public:
perkjd52063f2016-09-07 06:32:18 -0700103 EncodeTask(const VideoFrame& frame,
104 ViEEncoder* vie_encoder,
nissee0e3bdf2017-01-18 02:16:20 -0800105 int64_t time_when_posted_us,
asapersson6ffb67d2016-09-12 00:10:45 -0700106 bool log_stats)
nissedf2ceb82016-12-15 06:29:53 -0800107 : frame_(frame),
108 vie_encoder_(vie_encoder),
nissee0e3bdf2017-01-18 02:16:20 -0800109 time_when_posted_us_(time_when_posted_us),
asapersson6ffb67d2016-09-12 00:10:45 -0700110 log_stats_(log_stats) {
perkj26091b12016-09-01 01:17:40 -0700111 ++vie_encoder_->posted_frames_waiting_for_encode_;
112 }
113
114 private:
115 bool Run() override {
asapersson6ffb67d2016-09-12 00:10:45 -0700116 RTC_DCHECK_RUN_ON(&vie_encoder_->encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700117 RTC_DCHECK_GT(vie_encoder_->posted_frames_waiting_for_encode_.Value(), 0);
perkj803d97f2016-11-01 11:45:46 -0700118 vie_encoder_->stats_proxy_->OnIncomingFrame(frame_.width(),
119 frame_.height());
asapersson6ffb67d2016-09-12 00:10:45 -0700120 ++vie_encoder_->captured_frame_count_;
perkj26091b12016-09-01 01:17:40 -0700121 if (--vie_encoder_->posted_frames_waiting_for_encode_ == 0) {
nissee0e3bdf2017-01-18 02:16:20 -0800122 vie_encoder_->EncodeVideoFrame(frame_, time_when_posted_us_);
perkj26091b12016-09-01 01:17:40 -0700123 } else {
124 // There is a newer frame in flight. Do not encode this frame.
125 LOG(LS_VERBOSE)
126 << "Incoming frame dropped due to that the encoder is blocked.";
asapersson6ffb67d2016-09-12 00:10:45 -0700127 ++vie_encoder_->dropped_frame_count_;
128 }
129 if (log_stats_) {
130 LOG(LS_INFO) << "Number of frames: captured "
131 << vie_encoder_->captured_frame_count_
132 << ", dropped (due to encoder blocked) "
133 << vie_encoder_->dropped_frame_count_ << ", interval_ms "
134 << kFrameLogIntervalMs;
135 vie_encoder_->captured_frame_count_ = 0;
136 vie_encoder_->dropped_frame_count_ = 0;
perkj26091b12016-09-01 01:17:40 -0700137 }
138 return true;
139 }
140 VideoFrame frame_;
perkjd52063f2016-09-07 06:32:18 -0700141 ViEEncoder* const vie_encoder_;
nissee0e3bdf2017-01-18 02:16:20 -0800142 const int64_t time_when_posted_us_;
asapersson6ffb67d2016-09-12 00:10:45 -0700143 const bool log_stats_;
perkj26091b12016-09-01 01:17:40 -0700144};
145
perkja49cbd32016-09-16 07:53:41 -0700146// VideoSourceProxy is responsible ensuring thread safety between calls to
perkj803d97f2016-11-01 11:45:46 -0700147// ViEEncoder::SetSource that will happen on libjingle's worker thread when a
perkja49cbd32016-09-16 07:53:41 -0700148// video capturer is connected to the encoder and the encoder task queue
149// (encoder_queue_) where the encoder reports its VideoSinkWants.
150class ViEEncoder::VideoSourceProxy {
151 public:
152 explicit VideoSourceProxy(ViEEncoder* vie_encoder)
perkj803d97f2016-11-01 11:45:46 -0700153 : vie_encoder_(vie_encoder),
sprangb1ca0732017-02-01 08:38:12 -0800154 degradation_preference_(DegradationPreference::kMaintainResolution),
perkj803d97f2016-11-01 11:45:46 -0700155 source_(nullptr) {}
perkja49cbd32016-09-16 07:53:41 -0700156
sprangb1ca0732017-02-01 08:38:12 -0800157 void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
158 const DegradationPreference& degradation_preference) {
perkj803d97f2016-11-01 11:45:46 -0700159 // Called on libjingle's worker thread.
perkja49cbd32016-09-16 07:53:41 -0700160 RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
161 rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr;
perkj803d97f2016-11-01 11:45:46 -0700162 rtc::VideoSinkWants wants;
perkja49cbd32016-09-16 07:53:41 -0700163 {
164 rtc::CritScope lock(&crit_);
165 old_source = source_;
166 source_ = source;
perkj803d97f2016-11-01 11:45:46 -0700167 degradation_preference_ = degradation_preference;
168 wants = current_wants();
perkja49cbd32016-09-16 07:53:41 -0700169 }
170
171 if (old_source != source && old_source != nullptr) {
172 old_source->RemoveSink(vie_encoder_);
173 }
174
175 if (!source) {
176 return;
177 }
178
perkja49cbd32016-09-16 07:53:41 -0700179 source->AddOrUpdateSink(vie_encoder_, wants);
180 }
181
perkj803d97f2016-11-01 11:45:46 -0700182 void SetWantsRotationApplied(bool rotation_applied) {
183 rtc::CritScope lock(&crit_);
184 sink_wants_.rotation_applied = rotation_applied;
185 disabled_scaling_sink_wants_.rotation_applied = rotation_applied;
186 if (source_) {
187 source_->AddOrUpdateSink(vie_encoder_, current_wants());
188 }
189 }
190
191 void RequestResolutionLowerThan(int pixel_count) {
192 // Called on the encoder task queue.
193 rtc::CritScope lock(&crit_);
194 if (!IsResolutionScalingEnabledLocked()) {
195 // This can happen since |degradation_preference_| is set on
196 // libjingle's worker thread but the adaptation is done on the encoder
197 // task queue.
198 return;
199 }
200 // The input video frame size will have a resolution with less than or
201 // equal to |max_pixel_count| depending on how the source can scale the
202 // input frame size.
kthelgason5e13d412016-12-01 03:59:51 -0800203 const int pixels_wanted = (pixel_count * 3) / 5;
204 if (pixels_wanted < kMinPixelsPerFrame)
205 return;
206 sink_wants_.max_pixel_count = rtc::Optional<int>(pixels_wanted);
perkj803d97f2016-11-01 11:45:46 -0700207 sink_wants_.max_pixel_count_step_up = rtc::Optional<int>();
208 if (source_)
209 source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
210 }
211
212 void RequestHigherResolutionThan(int pixel_count) {
213 rtc::CritScope lock(&crit_);
214 if (!IsResolutionScalingEnabledLocked()) {
215 // This can happen since |degradation_preference_| is set on
216 // libjingle's worker thread but the adaptation is done on the encoder
sprangb1ca0732017-02-01 08:38:12 -0800217 // task queue.
perkj803d97f2016-11-01 11:45:46 -0700218 return;
219 }
220 // The input video frame size will have a resolution with "one step up"
221 // pixels than |max_pixel_count_step_up| where "one step up" depends on
222 // how the source can scale the input frame size.
223 sink_wants_.max_pixel_count = rtc::Optional<int>();
224 sink_wants_.max_pixel_count_step_up = rtc::Optional<int>(pixel_count);
225 if (source_)
226 source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
227 }
228
perkja49cbd32016-09-16 07:53:41 -0700229 private:
perkj803d97f2016-11-01 11:45:46 -0700230 bool IsResolutionScalingEnabledLocked() const
231 EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
232 return degradation_preference_ !=
sprangb1ca0732017-02-01 08:38:12 -0800233 DegradationPreference::kMaintainResolution;
perkj803d97f2016-11-01 11:45:46 -0700234 }
235
236 const rtc::VideoSinkWants& current_wants() const
237 EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
238 return IsResolutionScalingEnabledLocked() ? sink_wants_
239 : disabled_scaling_sink_wants_;
240 }
241
perkja49cbd32016-09-16 07:53:41 -0700242 rtc::CriticalSection crit_;
243 rtc::SequencedTaskChecker main_checker_;
perkj803d97f2016-11-01 11:45:46 -0700244 ViEEncoder* const vie_encoder_;
245 rtc::VideoSinkWants sink_wants_ GUARDED_BY(&crit_);
246 rtc::VideoSinkWants disabled_scaling_sink_wants_ GUARDED_BY(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800247 DegradationPreference degradation_preference_ GUARDED_BY(&crit_);
perkja49cbd32016-09-16 07:53:41 -0700248 rtc::VideoSourceInterface<VideoFrame>* source_ GUARDED_BY(&crit_);
249
250 RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
251};
252
mflodman0dbf0092015-10-19 08:12:12 -0700253ViEEncoder::ViEEncoder(uint32_t number_of_cores,
Peter Boström7083e112015-09-22 16:28:51 +0200254 SendStatisticsProxy* stats_proxy,
perkj26091b12016-09-01 01:17:40 -0700255 const VideoSendStream::Config::EncoderSettings& settings,
256 rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback,
perkj26091b12016-09-01 01:17:40 -0700257 EncodedFrameObserver* encoder_timing)
258 : shutdown_event_(true /* manual_reset */, false),
259 number_of_cores_(number_of_cores),
kthelgason2bc68642017-02-07 07:02:22 -0800260 initial_rampup_(0),
perkja49cbd32016-09-16 07:53:41 -0700261 source_proxy_(new VideoSourceProxy(this)),
Pera48ddb72016-09-29 11:48:50 +0200262 sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700263 settings_(settings),
Erik Språng08127a92016-11-16 16:41:30 +0100264 codec_type_(PayloadNameToCodecType(settings.payload_name)
265 .value_or(VideoCodecType::kVideoCodecUnknown)),
perkjf5b2e512016-07-05 08:34:04 -0700266 video_sender_(Clock::GetRealTimeClock(), this, this),
nissee0e3bdf2017-01-18 02:16:20 -0800267 overuse_detector_(GetCpuOveruseOptions(settings.full_overuse_time),
perkj26091b12016-09-01 01:17:40 -0700268 this,
269 encoder_timing,
270 stats_proxy),
Peter Boström7083e112015-09-22 16:28:51 +0200271 stats_proxy_(stats_proxy),
perkj26091b12016-09-01 01:17:40 -0700272 pre_encode_callback_(pre_encode_callback),
273 module_process_thread_(nullptr),
perkjfa10b552016-10-02 23:45:26 -0700274 pending_encoder_reconfiguration_(false),
perkj26091b12016-09-01 01:17:40 -0700275 encoder_start_bitrate_bps_(0),
Pera48ddb72016-09-29 11:48:50 +0200276 max_data_payload_length_(0),
asapersson5f7226f2016-11-25 04:37:00 -0800277 nack_enabled_(false),
pbos@webrtc.org143451d2015-03-18 14:40:03 +0000278 last_observed_bitrate_bps_(0),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000279 encoder_paused_and_dropped_frame_(false),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000280 has_received_sli_(false),
281 picture_id_sli_(0),
282 has_received_rpsi_(false),
283 picture_id_rpsi_(0),
perkj26091b12016-09-01 01:17:40 -0700284 clock_(Clock::GetRealTimeClock()),
kthelgason0cd27ba2016-12-19 06:32:16 -0800285 scale_counter_(kScaleReasonSize, 0),
sprangb1ca0732017-02-01 08:38:12 -0800286 degradation_preference_(DegradationPreference::kMaintainResolution),
perkj26091b12016-09-01 01:17:40 -0700287 last_captured_timestamp_(0),
288 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
289 clock_->TimeInMilliseconds()),
asapersson6ffb67d2016-09-12 00:10:45 -0700290 last_frame_log_ms_(clock_->TimeInMilliseconds()),
291 captured_frame_count_(0),
292 dropped_frame_count_(0),
sprang1a646ee2016-12-01 06:34:11 -0800293 bitrate_observer_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700294 encoder_queue_("EncoderQueue") {
perkj803d97f2016-11-01 11:45:46 -0700295 encoder_queue_.PostTask([this] {
perkj26091b12016-09-01 01:17:40 -0700296 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj803d97f2016-11-01 11:45:46 -0700297 overuse_detector_.StartCheckForOveruse();
perkj26091b12016-09-01 01:17:40 -0700298 video_sender_.RegisterExternalEncoder(
299 settings_.encoder, settings_.payload_type, settings_.internal_source);
300 });
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000301}
302
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000303ViEEncoder::~ViEEncoder() {
perkja49cbd32016-09-16 07:53:41 -0700304 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700305 RTC_DCHECK(shutdown_event_.Wait(0))
306 << "Must call ::Stop() before destruction.";
307}
308
309void ViEEncoder::Stop() {
perkja49cbd32016-09-16 07:53:41 -0700310 RTC_DCHECK_RUN_ON(&thread_checker_);
sprangb1ca0732017-02-01 08:38:12 -0800311 source_proxy_->SetSource(nullptr, DegradationPreference());
perkja49cbd32016-09-16 07:53:41 -0700312 encoder_queue_.PostTask([this] {
313 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj803d97f2016-11-01 11:45:46 -0700314 overuse_detector_.StopCheckForOveruse();
Erik Språng08127a92016-11-16 16:41:30 +0100315 rate_allocator_.reset();
sprang1a646ee2016-12-01 06:34:11 -0800316 bitrate_observer_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700317 video_sender_.RegisterExternalEncoder(nullptr, settings_.payload_type,
318 false);
kthelgason876222f2016-11-29 01:44:11 -0800319 quality_scaler_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700320 shutdown_event_.Set();
321 });
322
323 shutdown_event_.Wait(rtc::Event::kForever);
perkj26091b12016-09-01 01:17:40 -0700324}
325
326void ViEEncoder::RegisterProcessThread(ProcessThread* module_process_thread) {
perkja49cbd32016-09-16 07:53:41 -0700327 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700328 RTC_DCHECK(!module_process_thread_);
329 module_process_thread_ = module_process_thread;
perkj26091b12016-09-01 01:17:40 -0700330 module_process_thread_->RegisterModule(&video_sender_);
331 module_process_thread_checker_.DetachFromThread();
332}
333
334void ViEEncoder::DeRegisterProcessThread() {
perkja49cbd32016-09-16 07:53:41 -0700335 RTC_DCHECK_RUN_ON(&thread_checker_);
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200336 module_process_thread_->DeRegisterModule(&video_sender_);
asapersson@webrtc.org96dc6852014-11-03 14:40:38 +0000337}
338
sprang1a646ee2016-12-01 06:34:11 -0800339void ViEEncoder::SetBitrateObserver(
340 VideoBitrateAllocationObserver* bitrate_observer) {
341 RTC_DCHECK_RUN_ON(&thread_checker_);
342 encoder_queue_.PostTask([this, bitrate_observer] {
343 RTC_DCHECK_RUN_ON(&encoder_queue_);
344 RTC_DCHECK(!bitrate_observer_);
345 bitrate_observer_ = bitrate_observer;
346 });
347}
348
perkj803d97f2016-11-01 11:45:46 -0700349void ViEEncoder::SetSource(
350 rtc::VideoSourceInterface<VideoFrame>* source,
351 const VideoSendStream::DegradationPreference& degradation_preference) {
perkja49cbd32016-09-16 07:53:41 -0700352 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj803d97f2016-11-01 11:45:46 -0700353 source_proxy_->SetSource(source, degradation_preference);
354 encoder_queue_.PostTask([this, degradation_preference] {
355 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800356
357 degradation_preference_ = degradation_preference;
kthelgason2bc68642017-02-07 07:02:22 -0800358 initial_rampup_ =
359 degradation_preference_ != DegradationPreference::kMaintainResolution
360 ? 0
361 : kMaxInitialFramedrop;
362 ConfigureQualityScaler();
perkj803d97f2016-11-01 11:45:46 -0700363 });
perkja49cbd32016-09-16 07:53:41 -0700364}
365
perkj803d97f2016-11-01 11:45:46 -0700366void ViEEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
367 source_proxy_->SetWantsRotationApplied(rotation_applied);
perkj26091b12016-09-01 01:17:40 -0700368 encoder_queue_.PostTask([this, sink] {
369 RTC_DCHECK_RUN_ON(&encoder_queue_);
370 sink_ = sink;
371 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000372}
373
perkj26091b12016-09-01 01:17:40 -0700374void ViEEncoder::SetStartBitrate(int start_bitrate_bps) {
375 encoder_queue_.PostTask([this, start_bitrate_bps] {
376 RTC_DCHECK_RUN_ON(&encoder_queue_);
377 encoder_start_bitrate_bps_ = start_bitrate_bps;
378 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000379}
Peter Boström00b9d212016-05-19 16:59:03 +0200380
Per512ecb32016-09-23 15:52:06 +0200381void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -0800382 size_t max_data_payload_length,
383 bool nack_enabled) {
Pera48ddb72016-09-29 11:48:50 +0200384 encoder_queue_.PostTask(
385 std::unique_ptr<rtc::QueuedTask>(new ConfigureEncoderTask(
asapersson5f7226f2016-11-25 04:37:00 -0800386 this, std::move(config), max_data_payload_length, nack_enabled)));
perkj26091b12016-09-01 01:17:40 -0700387}
388
Pera48ddb72016-09-29 11:48:50 +0200389void ViEEncoder::ConfigureEncoderOnTaskQueue(VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -0800390 size_t max_data_payload_length,
391 bool nack_enabled) {
perkj26091b12016-09-01 01:17:40 -0700392 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700393 RTC_DCHECK(sink_);
perkjfa10b552016-10-02 23:45:26 -0700394 LOG(LS_INFO) << "ConfigureEncoder requested.";
Pera48ddb72016-09-29 11:48:50 +0200395
396 max_data_payload_length_ = max_data_payload_length;
asapersson5f7226f2016-11-25 04:37:00 -0800397 nack_enabled_ = nack_enabled;
Pera48ddb72016-09-29 11:48:50 +0200398 encoder_config_ = std::move(config);
perkjfa10b552016-10-02 23:45:26 -0700399 pending_encoder_reconfiguration_ = true;
Pera48ddb72016-09-29 11:48:50 +0200400
perkjfa10b552016-10-02 23:45:26 -0700401 // Reconfigure the encoder now if the encoder has an internal source or
Per21d45d22016-10-30 21:37:57 +0100402 // if the frame resolution is known. Otherwise, the reconfiguration is
403 // deferred until the next frame to minimize the number of reconfigurations.
404 // The codec configuration depends on incoming video frame size.
405 if (last_frame_info_) {
406 ReconfigureEncoder();
407 } else if (settings_.internal_source) {
408 last_frame_info_ = rtc::Optional<VideoFrameInfo>(
409 VideoFrameInfo(176, 144, kVideoRotation_0, false));
perkjfa10b552016-10-02 23:45:26 -0700410 ReconfigureEncoder();
411 }
412}
perkj26091b12016-09-01 01:17:40 -0700413
perkjfa10b552016-10-02 23:45:26 -0700414void ViEEncoder::ReconfigureEncoder() {
415 RTC_DCHECK_RUN_ON(&encoder_queue_);
416 RTC_DCHECK(pending_encoder_reconfiguration_);
417 std::vector<VideoStream> streams =
418 encoder_config_.video_stream_factory->CreateEncoderStreams(
419 last_frame_info_->width, last_frame_info_->height, encoder_config_);
perkj26091b12016-09-01 01:17:40 -0700420
Erik Språng08127a92016-11-16 16:41:30 +0100421 VideoCodec codec;
422 if (!VideoCodecInitializer::SetupCodec(encoder_config_, settings_, streams,
asapersson5f7226f2016-11-25 04:37:00 -0800423 nack_enabled_, &codec,
424 &rate_allocator_)) {
Erik Språng08127a92016-11-16 16:41:30 +0100425 LOG(LS_ERROR) << "Failed to create encoder configuration.";
426 }
perkjfa10b552016-10-02 23:45:26 -0700427
428 codec.startBitrate =
429 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
430 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
431 codec.expect_encode_from_texture = last_frame_info_->is_texture;
Stefan Holmere5904162015-03-26 11:11:06 +0100432
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200433 bool success = video_sender_.RegisterSendCodec(
perkjfa10b552016-10-02 23:45:26 -0700434 &codec, number_of_cores_,
435 static_cast<uint32_t>(max_data_payload_length_)) == VCM_OK;
Peter Boström905f8e72016-03-02 16:59:56 +0100436 if (!success) {
437 LOG(LS_ERROR) << "Failed to configure encoder.";
438 RTC_DCHECK(success);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000439 }
Peter Boström905f8e72016-03-02 16:59:56 +0100440
sprang1a646ee2016-12-01 06:34:11 -0800441 video_sender_.UpdateChannelParemeters(rate_allocator_.get(),
442 bitrate_observer_);
443
Peter Boströma03785e2016-03-03 11:36:18 +0100444 if (stats_proxy_) {
Erik Språng08127a92016-11-16 16:41:30 +0100445 int framerate = stats_proxy_->GetSendFrameRate();
446 if (framerate == 0)
447 framerate = codec.maxFramerate;
448 stats_proxy_->OnEncoderReconfigured(
449 encoder_config_, rate_allocator_->GetPreferredBitrateBps(framerate));
Peter Boströma03785e2016-03-03 11:36:18 +0100450 }
Per512ecb32016-09-23 15:52:06 +0200451
perkjfa10b552016-10-02 23:45:26 -0700452 pending_encoder_reconfiguration_ = false;
Erik Språng08127a92016-11-16 16:41:30 +0100453
Pera48ddb72016-09-29 11:48:50 +0200454 sink_->OnEncoderConfigurationChanged(
perkjfa10b552016-10-02 23:45:26 -0700455 std::move(streams), encoder_config_.min_transmit_bitrate_bps);
kthelgason876222f2016-11-29 01:44:11 -0800456
kthelgason2bc68642017-02-07 07:02:22 -0800457 ConfigureQualityScaler();
458}
459
460void ViEEncoder::ConfigureQualityScaler() {
461 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800462 const auto scaling_settings = settings_.encoder->GetScalingSettings();
kthelgason2bc68642017-02-07 07:02:22 -0800463 const bool degradation_preference_allows_scaling =
464 degradation_preference_ != DegradationPreference::kMaintainResolution;
465 if (degradation_preference_allows_scaling && scaling_settings.enabled) {
466 // Drop frames and scale down until desired quality is achieved.
kthelgason876222f2016-11-29 01:44:11 -0800467 if (scaling_settings.thresholds) {
468 quality_scaler_.reset(
469 new QualityScaler(this, *(scaling_settings.thresholds)));
470 } else {
471 quality_scaler_.reset(new QualityScaler(this, codec_type_));
472 }
473 } else {
474 quality_scaler_.reset(nullptr);
475 }
kthelgason2bc68642017-02-07 07:02:22 -0800476 stats_proxy_->SetResolutionRestrictionStats(
477 degradation_preference_allows_scaling, scale_counter_[kCpu] > 0,
478 scale_counter_[kQuality]);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000479}
480
perkja49cbd32016-09-16 07:53:41 -0700481void ViEEncoder::OnFrame(const VideoFrame& video_frame) {
perkj26091b12016-09-01 01:17:40 -0700482 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_);
perkj26091b12016-09-01 01:17:40 -0700483 VideoFrame incoming_frame = video_frame;
484
485 // Local time in webrtc time base.
nisse1c0dea82017-01-30 02:43:18 -0800486 int64_t current_time_us = clock_->TimeInMicroseconds();
487 int64_t current_time_ms = current_time_us / rtc::kNumMicrosecsPerMillisec;
488 // TODO(nisse): This always overrides the incoming timestamp. Don't
489 // do that, trust the frame source.
490 incoming_frame.set_timestamp_us(current_time_us);
perkj26091b12016-09-01 01:17:40 -0700491
492 // Capture time may come from clock with an offset and drift from clock_.
493 int64_t capture_ntp_time_ms;
nisse891419f2017-01-12 10:02:22 -0800494 if (video_frame.ntp_time_ms() > 0) {
perkj26091b12016-09-01 01:17:40 -0700495 capture_ntp_time_ms = video_frame.ntp_time_ms();
496 } else if (video_frame.render_time_ms() != 0) {
497 capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
498 } else {
nisse1c0dea82017-01-30 02:43:18 -0800499 capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
perkj26091b12016-09-01 01:17:40 -0700500 }
501 incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
502
503 // Convert NTP time, in ms, to RTP timestamp.
504 const int kMsToRtpTimestamp = 90;
505 incoming_frame.set_timestamp(
506 kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
507
508 if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
509 // We don't allow the same capture time for two frames, drop this one.
510 LOG(LS_WARNING) << "Same/old NTP timestamp ("
511 << incoming_frame.ntp_time_ms()
512 << " <= " << last_captured_timestamp_
513 << ") for incoming frame. Dropping.";
514 return;
515 }
516
asapersson6ffb67d2016-09-12 00:10:45 -0700517 bool log_stats = false;
nisse1c0dea82017-01-30 02:43:18 -0800518 if (current_time_ms - last_frame_log_ms_ > kFrameLogIntervalMs) {
519 last_frame_log_ms_ = current_time_ms;
asapersson6ffb67d2016-09-12 00:10:45 -0700520 log_stats = true;
521 }
522
perkj26091b12016-09-01 01:17:40 -0700523 last_captured_timestamp_ = incoming_frame.ntp_time_ms();
asapersson6ffb67d2016-09-12 00:10:45 -0700524 encoder_queue_.PostTask(std::unique_ptr<rtc::QueuedTask>(new EncodeTask(
nissee0e3bdf2017-01-18 02:16:20 -0800525 incoming_frame, this, rtc::TimeMicros(), log_stats)));
perkj26091b12016-09-01 01:17:40 -0700526}
527
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000528bool ViEEncoder::EncoderPaused() const {
perkj26091b12016-09-01 01:17:40 -0700529 RTC_DCHECK_RUN_ON(&encoder_queue_);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000530 // Pause video if paused by caller or as long as the network is down or the
531 // pacer queue has grown too large in buffered mode.
perkj57c21f92016-06-17 07:27:16 -0700532 // If the pacer queue has grown too large or the network is down,
perkjfea93092016-05-14 00:58:48 -0700533 // last_observed_bitrate_bps_ will be 0.
perkj26091b12016-09-01 01:17:40 -0700534 return last_observed_bitrate_bps_ == 0;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000535}
536
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000537void ViEEncoder::TraceFrameDropStart() {
perkj26091b12016-09-01 01:17:40 -0700538 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000539 // Start trace event only on the first frame after encoder is paused.
540 if (!encoder_paused_and_dropped_frame_) {
541 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
542 }
543 encoder_paused_and_dropped_frame_ = true;
544 return;
545}
546
547void ViEEncoder::TraceFrameDropEnd() {
perkj26091b12016-09-01 01:17:40 -0700548 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000549 // End trace event on first frame after encoder resumes, if frame was dropped.
550 if (encoder_paused_and_dropped_frame_) {
551 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
552 }
553 encoder_paused_and_dropped_frame_ = false;
554}
555
perkjd52063f2016-09-07 06:32:18 -0700556void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
nissee0e3bdf2017-01-18 02:16:20 -0800557 int64_t time_when_posted_us) {
perkj26091b12016-09-01 01:17:40 -0700558 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800559
perkj26091b12016-09-01 01:17:40 -0700560 if (pre_encode_callback_)
561 pre_encode_callback_->OnFrame(video_frame);
562
Per21d45d22016-10-30 21:37:57 +0100563 if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
perkjfa10b552016-10-02 23:45:26 -0700564 video_frame.height() != last_frame_info_->height ||
565 video_frame.rotation() != last_frame_info_->rotation ||
566 video_frame.is_texture() != last_frame_info_->is_texture) {
567 pending_encoder_reconfiguration_ = true;
568 last_frame_info_ = rtc::Optional<VideoFrameInfo>(
569 VideoFrameInfo(video_frame.width(), video_frame.height(),
570 video_frame.rotation(), video_frame.is_texture()));
571 LOG(LS_INFO) << "Video frame parameters changed: dimensions="
572 << last_frame_info_->width << "x" << last_frame_info_->height
573 << ", rotation=" << last_frame_info_->rotation
574 << ", texture=" << last_frame_info_->is_texture;
575 }
576
kthelgason2bc68642017-02-07 07:02:22 -0800577 if (initial_rampup_ < kMaxInitialFramedrop &&
578 video_frame.size() >
579 MaximumFrameSizeForBitrate(encoder_start_bitrate_bps_ / 1000)) {
580 LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
581 AdaptDown(kQuality);
582 ++initial_rampup_;
583 return;
584 }
585 initial_rampup_ = kMaxInitialFramedrop;
586
sprang57c2fff2017-01-16 06:24:02 -0800587 int64_t now_ms = clock_->TimeInMilliseconds();
perkjfa10b552016-10-02 23:45:26 -0700588 if (pending_encoder_reconfiguration_) {
589 ReconfigureEncoder();
sprang57c2fff2017-01-16 06:24:02 -0800590 } else if (!last_parameters_update_ms_ ||
591 now_ms - *last_parameters_update_ms_ >=
592 vcm::VCMProcessTimer::kDefaultProcessIntervalMs) {
593 video_sender_.UpdateChannelParemeters(rate_allocator_.get(),
594 bitrate_observer_);
perkjfa10b552016-10-02 23:45:26 -0700595 }
sprang57c2fff2017-01-16 06:24:02 -0800596 last_parameters_update_ms_.emplace(now_ms);
perkjfa10b552016-10-02 23:45:26 -0700597
perkj26091b12016-09-01 01:17:40 -0700598 if (EncoderPaused()) {
599 TraceFrameDropStart();
600 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000601 }
perkj26091b12016-09-01 01:17:40 -0700602 TraceFrameDropEnd();
niklase@google.com470e71d2011-07-07 08:21:25 +0000603
Magnus Jedvert26679d62015-04-07 14:07:41 +0200604 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +0000605 "Encode");
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +0000606
nissee0e3bdf2017-01-18 02:16:20 -0800607 overuse_detector_.FrameCaptured(video_frame, time_when_posted_us);
perkjd52063f2016-09-07 06:32:18 -0700608
Pera48ddb72016-09-29 11:48:50 +0200609 if (codec_type_ == webrtc::kVideoCodecVP8) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000610 webrtc::CodecSpecificInfo codec_specific_info;
611 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
perkj26091b12016-09-01 01:17:40 -0700612
hta527d3472016-11-16 23:23:04 -0800613 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI = has_received_rpsi_;
614 codec_specific_info.codecSpecific.VP8.hasReceivedSLI = has_received_sli_;
615 codec_specific_info.codecSpecific.VP8.pictureIdRPSI = picture_id_rpsi_;
616 codec_specific_info.codecSpecific.VP8.pictureIdSLI = picture_id_sli_;
617 has_received_sli_ = false;
618 has_received_rpsi_ = false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000619
hta527d3472016-11-16 23:23:04 -0800620 video_sender_.AddVideoFrame(video_frame, &codec_specific_info);
621 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000622 }
perkjfa10b552016-10-02 23:45:26 -0700623 video_sender_.AddVideoFrame(video_frame, nullptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000624}
niklase@google.com470e71d2011-07-07 08:21:25 +0000625
Peter Boström233bfd22016-01-18 20:23:40 +0100626void ViEEncoder::SendKeyFrame() {
perkj26091b12016-09-01 01:17:40 -0700627 if (!encoder_queue_.IsCurrent()) {
628 encoder_queue_.PostTask([this] { SendKeyFrame(); });
629 return;
630 }
631 RTC_DCHECK_RUN_ON(&encoder_queue_);
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200632 video_sender_.IntraFrameRequest(0);
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000633}
634
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700635EncodedImageCallback::Result ViEEncoder::OnEncodedImage(
636 const EncodedImage& encoded_image,
637 const CodecSpecificInfo* codec_specific_info,
638 const RTPFragmentationHeader* fragmentation) {
perkj26091b12016-09-01 01:17:40 -0700639 // Encoded is called on whatever thread the real encoder implementation run
640 // on. In the case of hardware encoders, there might be several encoders
641 // running in parallel on different threads.
kthelgason0cd27ba2016-12-19 06:32:16 -0800642 if (stats_proxy_)
kjellander02b3d272016-04-20 05:05:54 -0700643 stats_proxy_->OnSendEncodedImage(encoded_image, codec_specific_info);
sprang3911c262016-04-15 01:24:14 -0700644
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700645 EncodedImageCallback::Result result =
646 sink_->OnEncodedImage(encoded_image, codec_specific_info, fragmentation);
perkjbc75d972016-05-02 06:31:25 -0700647
nissee0e3bdf2017-01-18 02:16:20 -0800648 int64_t time_sent_us = rtc::TimeMicros();
perkjd52063f2016-09-07 06:32:18 -0700649 uint32_t timestamp = encoded_image._timeStamp;
kthelgason876222f2016-11-29 01:44:11 -0800650 const int qp = encoded_image.qp_;
nissee0e3bdf2017-01-18 02:16:20 -0800651 encoder_queue_.PostTask([this, timestamp, time_sent_us, qp] {
perkjd52063f2016-09-07 06:32:18 -0700652 RTC_DCHECK_RUN_ON(&encoder_queue_);
nissee0e3bdf2017-01-18 02:16:20 -0800653 overuse_detector_.FrameSent(timestamp, time_sent_us);
kthelgason876222f2016-11-29 01:44:11 -0800654 if (quality_scaler_)
655 quality_scaler_->ReportQP(qp);
perkjd52063f2016-09-07 06:32:18 -0700656 });
perkj803d97f2016-11-01 11:45:46 -0700657
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700658 return result;
Peter Boströmb7d9a972015-12-18 16:01:11 +0100659}
660
kthelgason876222f2016-11-29 01:44:11 -0800661void ViEEncoder::OnDroppedFrame() {
662 encoder_queue_.PostTask([this] {
663 RTC_DCHECK_RUN_ON(&encoder_queue_);
664 if (quality_scaler_)
665 quality_scaler_->ReportDroppedFrame();
666 });
667}
668
perkj275afc52016-09-01 00:21:16 -0700669void ViEEncoder::SendStatistics(uint32_t bit_rate, uint32_t frame_rate) {
perkj26091b12016-09-01 01:17:40 -0700670 RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread());
Peter Boström7083e112015-09-22 16:28:51 +0200671 if (stats_proxy_)
perkj275afc52016-09-01 00:21:16 -0700672 stats_proxy_->OnEncoderStatsUpdate(frame_rate, bit_rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000673}
674
perkj600246e2016-05-04 11:26:51 -0700675void ViEEncoder::OnReceivedSLI(uint8_t picture_id) {
perkj26091b12016-09-01 01:17:40 -0700676 if (!encoder_queue_.IsCurrent()) {
677 encoder_queue_.PostTask([this, picture_id] { OnReceivedSLI(picture_id); });
678 return;
679 }
680 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000681 picture_id_sli_ = picture_id;
682 has_received_sli_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000683}
684
perkj600246e2016-05-04 11:26:51 -0700685void ViEEncoder::OnReceivedRPSI(uint64_t picture_id) {
perkj26091b12016-09-01 01:17:40 -0700686 if (!encoder_queue_.IsCurrent()) {
687 encoder_queue_.PostTask([this, picture_id] { OnReceivedRPSI(picture_id); });
688 return;
689 }
690 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000691 picture_id_rpsi_ = picture_id;
692 has_received_rpsi_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000693}
694
perkj600246e2016-05-04 11:26:51 -0700695void ViEEncoder::OnReceivedIntraFrameRequest(size_t stream_index) {
perkj26091b12016-09-01 01:17:40 -0700696 if (!encoder_queue_.IsCurrent()) {
697 encoder_queue_.PostTask(
698 [this, stream_index] { OnReceivedIntraFrameRequest(stream_index); });
699 return;
700 }
701 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000702 // Key frame request from remote side, signal to VCM.
justinlin@chromium.org7bfb3a32013-05-13 22:59:00 +0000703 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
perkj600246e2016-05-04 11:26:51 -0700704 video_sender_.IntraFrameRequest(stream_index);
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000705}
706
mflodman86aabb22016-03-11 15:44:32 +0100707void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps,
stefan@webrtc.orgedeea912014-12-08 19:46:23 +0000708 uint8_t fraction_lost,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000709 int64_t round_trip_time_ms) {
perkj26091b12016-09-01 01:17:40 -0700710 if (!encoder_queue_.IsCurrent()) {
711 encoder_queue_.PostTask(
712 [this, bitrate_bps, fraction_lost, round_trip_time_ms] {
713 OnBitrateUpdated(bitrate_bps, fraction_lost, round_trip_time_ms);
714 });
715 return;
716 }
717 RTC_DCHECK_RUN_ON(&encoder_queue_);
718 RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
719
perkjec81bcd2016-05-11 06:01:13 -0700720 LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << bitrate_bps
mflodman8602a3d2015-05-20 15:54:42 -0700721 << " packet loss " << static_cast<int>(fraction_lost)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000722 << " rtt " << round_trip_time_ms;
perkj26091b12016-09-01 01:17:40 -0700723
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200724 video_sender_.SetChannelParameters(bitrate_bps, fraction_lost,
sprang1a646ee2016-12-01 06:34:11 -0800725 round_trip_time_ms, rate_allocator_.get(),
726 bitrate_observer_);
perkj26091b12016-09-01 01:17:40 -0700727
728 encoder_start_bitrate_bps_ =
729 bitrate_bps != 0 ? bitrate_bps : encoder_start_bitrate_bps_;
mflodman101f2502016-06-09 17:21:19 +0200730 bool video_is_suspended = bitrate_bps == 0;
Erik Språng08127a92016-11-16 16:41:30 +0100731 bool video_suspension_changed = video_is_suspended != EncoderPaused();
perkj26091b12016-09-01 01:17:40 -0700732 last_observed_bitrate_bps_ = bitrate_bps;
Peter Boströmd153a372015-11-10 15:27:12 +0000733
mflodman101f2502016-06-09 17:21:19 +0200734 if (stats_proxy_ && video_suspension_changed) {
mflodman522739c2016-06-22 17:42:30 +0200735 LOG(LS_INFO) << "Video suspend state changed to: "
736 << (video_is_suspended ? "suspended" : "not suspended");
Peter Boström7083e112015-09-22 16:28:51 +0200737 stats_proxy_->OnSuspendChange(video_is_suspended);
mflodman101f2502016-06-09 17:21:19 +0200738 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000739}
740
sprangb1ca0732017-02-01 08:38:12 -0800741void ViEEncoder::AdaptDown(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -0700742 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800743 if (degradation_preference_ != DegradationPreference::kBalanced)
perkj803d97f2016-11-01 11:45:46 -0700744 return;
perkj803d97f2016-11-01 11:45:46 -0700745 // Request lower resolution if the current resolution is lower than last time
746 // we asked for the resolution to be lowered.
kthelgason93f16d72017-01-16 06:15:23 -0800747 int current_pixel_count =
748 last_frame_info_ ? last_frame_info_->pixel_count() : 0;
kthelgason876222f2016-11-29 01:44:11 -0800749 if (max_pixel_count_ && current_pixel_count >= *max_pixel_count_)
750 return;
751 switch (reason) {
752 case kQuality:
kthelgason0cd27ba2016-12-19 06:32:16 -0800753 stats_proxy_->OnQualityRestrictedResolutionChanged(
754 scale_counter_[reason] + 1);
kthelgason876222f2016-11-29 01:44:11 -0800755 break;
756 case kCpu:
757 if (scale_counter_[reason] >= kMaxCpuDowngrades)
758 return;
759 // Update stats accordingly.
760 stats_proxy_->OnCpuRestrictedResolutionChanged(true);
761 break;
762 }
763 max_pixel_count_ = rtc::Optional<int>(current_pixel_count);
764 max_pixel_count_step_up_ = rtc::Optional<int>();
765 ++scale_counter_[reason];
766 source_proxy_->RequestResolutionLowerThan(current_pixel_count);
767 LOG(LS_INFO) << "Scaling down resolution.";
768 for (size_t i = 0; i < kScaleReasonSize; ++i) {
769 LOG(LS_INFO) << "Scaled " << scale_counter_[i]
kthelgason93f16d72017-01-16 06:15:23 -0800770 << " times for reason: " << (i ? "cpu" : "quality");
perkj803d97f2016-11-01 11:45:46 -0700771 }
perkj26091b12016-09-01 01:17:40 -0700772}
773
sprangb1ca0732017-02-01 08:38:12 -0800774void ViEEncoder::AdaptUp(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -0700775 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800776 if (scale_counter_[reason] == 0 ||
777 degradation_preference_ != DegradationPreference::kBalanced) {
perkj803d97f2016-11-01 11:45:46 -0700778 return;
sprangb1ca0732017-02-01 08:38:12 -0800779 }
kthelgason876222f2016-11-29 01:44:11 -0800780 // Only scale if resolution is higher than last time
781 // we requested higher resolution.
kthelgason93f16d72017-01-16 06:15:23 -0800782 int current_pixel_count =
783 last_frame_info_ ? last_frame_info_->pixel_count() : 0;
kthelgason876222f2016-11-29 01:44:11 -0800784 if (current_pixel_count <= max_pixel_count_step_up_.value_or(0))
785 return;
786 switch (reason) {
787 case kQuality:
788 stats_proxy_->OnQualityRestrictedResolutionChanged(
kthelgason0cd27ba2016-12-19 06:32:16 -0800789 scale_counter_[reason] - 1);
kthelgason876222f2016-11-29 01:44:11 -0800790 break;
791 case kCpu:
792 // Update stats accordingly.
793 stats_proxy_->OnCpuRestrictedResolutionChanged(scale_counter_[reason] >
794 1);
795 break;
796 }
797 max_pixel_count_ = rtc::Optional<int>();
798 max_pixel_count_step_up_ = rtc::Optional<int>(current_pixel_count);
799 --scale_counter_[reason];
800 source_proxy_->RequestHigherResolutionThan(current_pixel_count);
801 LOG(LS_INFO) << "Scaling up resolution.";
802 for (size_t i = 0; i < kScaleReasonSize; ++i) {
803 LOG(LS_INFO) << "Scaled " << scale_counter_[i]
kthelgason7e70fe22016-12-16 03:46:48 -0800804 << " times for reason: " << (i ? "cpu" : "quality");
perkj803d97f2016-11-01 11:45:46 -0700805 }
perkj26091b12016-09-01 01:17:40 -0700806}
807
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000808} // namespace webrtc