blob: 4ee6b8f1277f4db78b43f910cd645125cba42b55 [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
perkj26091b12016-09-01 01:17:40 -070047// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
48// pipelining encoders better (multiple input frames before something comes
49// out). This should effectively turn off CPU adaptations for systems that
50// remotely cope with the load right now.
51CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
52 CpuOveruseOptions options;
53 if (full_overuse_time) {
54 options.low_encode_usage_threshold_percent = 150;
55 options.high_encode_usage_threshold_percent = 200;
56 }
57 return options;
58}
59
60} // namespace
61
Pera48ddb72016-09-29 11:48:50 +020062class ViEEncoder::ConfigureEncoderTask : public rtc::QueuedTask {
63 public:
64 ConfigureEncoderTask(ViEEncoder* vie_encoder,
65 VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -080066 size_t max_data_payload_length,
67 bool nack_enabled)
Pera48ddb72016-09-29 11:48:50 +020068 : vie_encoder_(vie_encoder),
69 config_(std::move(config)),
asapersson5f7226f2016-11-25 04:37:00 -080070 max_data_payload_length_(max_data_payload_length),
71 nack_enabled_(nack_enabled) {}
Pera48ddb72016-09-29 11:48:50 +020072
73 private:
74 bool Run() override {
asapersson5f7226f2016-11-25 04:37:00 -080075 vie_encoder_->ConfigureEncoderOnTaskQueue(
76 std::move(config_), max_data_payload_length_, nack_enabled_);
Pera48ddb72016-09-29 11:48:50 +020077 return true;
78 }
79
80 ViEEncoder* const vie_encoder_;
81 VideoEncoderConfig config_;
82 size_t max_data_payload_length_;
asapersson5f7226f2016-11-25 04:37:00 -080083 bool nack_enabled_;
Pera48ddb72016-09-29 11:48:50 +020084};
85
perkj26091b12016-09-01 01:17:40 -070086class ViEEncoder::EncodeTask : public rtc::QueuedTask {
87 public:
perkjd52063f2016-09-07 06:32:18 -070088 EncodeTask(const VideoFrame& frame,
89 ViEEncoder* vie_encoder,
nissee0e3bdf2017-01-18 02:16:20 -080090 int64_t time_when_posted_us,
asapersson6ffb67d2016-09-12 00:10:45 -070091 bool log_stats)
nissedf2ceb82016-12-15 06:29:53 -080092 : frame_(frame),
93 vie_encoder_(vie_encoder),
nissee0e3bdf2017-01-18 02:16:20 -080094 time_when_posted_us_(time_when_posted_us),
asapersson6ffb67d2016-09-12 00:10:45 -070095 log_stats_(log_stats) {
perkj26091b12016-09-01 01:17:40 -070096 ++vie_encoder_->posted_frames_waiting_for_encode_;
97 }
98
99 private:
100 bool Run() override {
asapersson6ffb67d2016-09-12 00:10:45 -0700101 RTC_DCHECK_RUN_ON(&vie_encoder_->encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700102 RTC_DCHECK_GT(vie_encoder_->posted_frames_waiting_for_encode_.Value(), 0);
perkj803d97f2016-11-01 11:45:46 -0700103 vie_encoder_->stats_proxy_->OnIncomingFrame(frame_.width(),
104 frame_.height());
asapersson6ffb67d2016-09-12 00:10:45 -0700105 ++vie_encoder_->captured_frame_count_;
perkj26091b12016-09-01 01:17:40 -0700106 if (--vie_encoder_->posted_frames_waiting_for_encode_ == 0) {
nissee0e3bdf2017-01-18 02:16:20 -0800107 vie_encoder_->EncodeVideoFrame(frame_, time_when_posted_us_);
perkj26091b12016-09-01 01:17:40 -0700108 } else {
109 // There is a newer frame in flight. Do not encode this frame.
110 LOG(LS_VERBOSE)
111 << "Incoming frame dropped due to that the encoder is blocked.";
asapersson6ffb67d2016-09-12 00:10:45 -0700112 ++vie_encoder_->dropped_frame_count_;
113 }
114 if (log_stats_) {
115 LOG(LS_INFO) << "Number of frames: captured "
116 << vie_encoder_->captured_frame_count_
117 << ", dropped (due to encoder blocked) "
118 << vie_encoder_->dropped_frame_count_ << ", interval_ms "
119 << kFrameLogIntervalMs;
120 vie_encoder_->captured_frame_count_ = 0;
121 vie_encoder_->dropped_frame_count_ = 0;
perkj26091b12016-09-01 01:17:40 -0700122 }
123 return true;
124 }
125 VideoFrame frame_;
perkjd52063f2016-09-07 06:32:18 -0700126 ViEEncoder* const vie_encoder_;
nissee0e3bdf2017-01-18 02:16:20 -0800127 const int64_t time_when_posted_us_;
asapersson6ffb67d2016-09-12 00:10:45 -0700128 const bool log_stats_;
perkj26091b12016-09-01 01:17:40 -0700129};
130
perkja49cbd32016-09-16 07:53:41 -0700131// VideoSourceProxy is responsible ensuring thread safety between calls to
perkj803d97f2016-11-01 11:45:46 -0700132// ViEEncoder::SetSource that will happen on libjingle's worker thread when a
perkja49cbd32016-09-16 07:53:41 -0700133// video capturer is connected to the encoder and the encoder task queue
134// (encoder_queue_) where the encoder reports its VideoSinkWants.
135class ViEEncoder::VideoSourceProxy {
136 public:
137 explicit VideoSourceProxy(ViEEncoder* vie_encoder)
perkj803d97f2016-11-01 11:45:46 -0700138 : vie_encoder_(vie_encoder),
sprangb1ca0732017-02-01 08:38:12 -0800139 degradation_preference_(DegradationPreference::kMaintainResolution),
perkj803d97f2016-11-01 11:45:46 -0700140 source_(nullptr) {}
perkja49cbd32016-09-16 07:53:41 -0700141
sprangb1ca0732017-02-01 08:38:12 -0800142 void SetSource(rtc::VideoSourceInterface<VideoFrame>* source,
143 const DegradationPreference& degradation_preference) {
perkj803d97f2016-11-01 11:45:46 -0700144 // Called on libjingle's worker thread.
perkja49cbd32016-09-16 07:53:41 -0700145 RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
146 rtc::VideoSourceInterface<VideoFrame>* old_source = nullptr;
perkj803d97f2016-11-01 11:45:46 -0700147 rtc::VideoSinkWants wants;
perkja49cbd32016-09-16 07:53:41 -0700148 {
149 rtc::CritScope lock(&crit_);
150 old_source = source_;
151 source_ = source;
perkj803d97f2016-11-01 11:45:46 -0700152 degradation_preference_ = degradation_preference;
153 wants = current_wants();
perkja49cbd32016-09-16 07:53:41 -0700154 }
155
156 if (old_source != source && old_source != nullptr) {
157 old_source->RemoveSink(vie_encoder_);
158 }
159
160 if (!source) {
161 return;
162 }
163
perkja49cbd32016-09-16 07:53:41 -0700164 source->AddOrUpdateSink(vie_encoder_, wants);
165 }
166
perkj803d97f2016-11-01 11:45:46 -0700167 void SetWantsRotationApplied(bool rotation_applied) {
168 rtc::CritScope lock(&crit_);
169 sink_wants_.rotation_applied = rotation_applied;
170 disabled_scaling_sink_wants_.rotation_applied = rotation_applied;
171 if (source_) {
172 source_->AddOrUpdateSink(vie_encoder_, current_wants());
173 }
174 }
175
176 void RequestResolutionLowerThan(int pixel_count) {
177 // Called on the encoder task queue.
178 rtc::CritScope lock(&crit_);
179 if (!IsResolutionScalingEnabledLocked()) {
180 // This can happen since |degradation_preference_| is set on
181 // libjingle's worker thread but the adaptation is done on the encoder
182 // task queue.
183 return;
184 }
185 // The input video frame size will have a resolution with less than or
186 // equal to |max_pixel_count| depending on how the source can scale the
187 // input frame size.
kthelgason5e13d412016-12-01 03:59:51 -0800188 const int pixels_wanted = (pixel_count * 3) / 5;
189 if (pixels_wanted < kMinPixelsPerFrame)
190 return;
191 sink_wants_.max_pixel_count = rtc::Optional<int>(pixels_wanted);
perkj803d97f2016-11-01 11:45:46 -0700192 sink_wants_.max_pixel_count_step_up = rtc::Optional<int>();
193 if (source_)
194 source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
195 }
196
197 void RequestHigherResolutionThan(int pixel_count) {
198 rtc::CritScope lock(&crit_);
199 if (!IsResolutionScalingEnabledLocked()) {
200 // This can happen since |degradation_preference_| is set on
201 // libjingle's worker thread but the adaptation is done on the encoder
sprangb1ca0732017-02-01 08:38:12 -0800202 // task queue.
perkj803d97f2016-11-01 11:45:46 -0700203 return;
204 }
205 // The input video frame size will have a resolution with "one step up"
206 // pixels than |max_pixel_count_step_up| where "one step up" depends on
207 // how the source can scale the input frame size.
208 sink_wants_.max_pixel_count = rtc::Optional<int>();
209 sink_wants_.max_pixel_count_step_up = rtc::Optional<int>(pixel_count);
210 if (source_)
211 source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
212 }
213
perkja49cbd32016-09-16 07:53:41 -0700214 private:
perkj803d97f2016-11-01 11:45:46 -0700215 bool IsResolutionScalingEnabledLocked() const
216 EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
217 return degradation_preference_ !=
sprangb1ca0732017-02-01 08:38:12 -0800218 DegradationPreference::kMaintainResolution;
perkj803d97f2016-11-01 11:45:46 -0700219 }
220
221 const rtc::VideoSinkWants& current_wants() const
222 EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
223 return IsResolutionScalingEnabledLocked() ? sink_wants_
224 : disabled_scaling_sink_wants_;
225 }
226
perkja49cbd32016-09-16 07:53:41 -0700227 rtc::CriticalSection crit_;
228 rtc::SequencedTaskChecker main_checker_;
perkj803d97f2016-11-01 11:45:46 -0700229 ViEEncoder* const vie_encoder_;
230 rtc::VideoSinkWants sink_wants_ GUARDED_BY(&crit_);
231 rtc::VideoSinkWants disabled_scaling_sink_wants_ GUARDED_BY(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800232 DegradationPreference degradation_preference_ GUARDED_BY(&crit_);
perkja49cbd32016-09-16 07:53:41 -0700233 rtc::VideoSourceInterface<VideoFrame>* source_ GUARDED_BY(&crit_);
234
235 RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
236};
237
mflodman0dbf0092015-10-19 08:12:12 -0700238ViEEncoder::ViEEncoder(uint32_t number_of_cores,
Peter Boström7083e112015-09-22 16:28:51 +0200239 SendStatisticsProxy* stats_proxy,
perkj26091b12016-09-01 01:17:40 -0700240 const VideoSendStream::Config::EncoderSettings& settings,
241 rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback,
perkj26091b12016-09-01 01:17:40 -0700242 EncodedFrameObserver* encoder_timing)
243 : shutdown_event_(true /* manual_reset */, false),
244 number_of_cores_(number_of_cores),
perkja49cbd32016-09-16 07:53:41 -0700245 source_proxy_(new VideoSourceProxy(this)),
Pera48ddb72016-09-29 11:48:50 +0200246 sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700247 settings_(settings),
Erik Språng08127a92016-11-16 16:41:30 +0100248 codec_type_(PayloadNameToCodecType(settings.payload_name)
249 .value_or(VideoCodecType::kVideoCodecUnknown)),
perkjf5b2e512016-07-05 08:34:04 -0700250 video_sender_(Clock::GetRealTimeClock(), this, this),
nissee0e3bdf2017-01-18 02:16:20 -0800251 overuse_detector_(GetCpuOveruseOptions(settings.full_overuse_time),
perkj26091b12016-09-01 01:17:40 -0700252 this,
253 encoder_timing,
254 stats_proxy),
Peter Boström7083e112015-09-22 16:28:51 +0200255 stats_proxy_(stats_proxy),
perkj26091b12016-09-01 01:17:40 -0700256 pre_encode_callback_(pre_encode_callback),
257 module_process_thread_(nullptr),
perkjfa10b552016-10-02 23:45:26 -0700258 pending_encoder_reconfiguration_(false),
perkj26091b12016-09-01 01:17:40 -0700259 encoder_start_bitrate_bps_(0),
Pera48ddb72016-09-29 11:48:50 +0200260 max_data_payload_length_(0),
asapersson5f7226f2016-11-25 04:37:00 -0800261 nack_enabled_(false),
pbos@webrtc.org143451d2015-03-18 14:40:03 +0000262 last_observed_bitrate_bps_(0),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000263 encoder_paused_and_dropped_frame_(false),
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000264 has_received_sli_(false),
265 picture_id_sli_(0),
266 has_received_rpsi_(false),
267 picture_id_rpsi_(0),
perkj26091b12016-09-01 01:17:40 -0700268 clock_(Clock::GetRealTimeClock()),
kthelgason0cd27ba2016-12-19 06:32:16 -0800269 scale_counter_(kScaleReasonSize, 0),
sprangb1ca0732017-02-01 08:38:12 -0800270 degradation_preference_(DegradationPreference::kMaintainResolution),
perkj26091b12016-09-01 01:17:40 -0700271 last_captured_timestamp_(0),
272 delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() -
273 clock_->TimeInMilliseconds()),
asapersson6ffb67d2016-09-12 00:10:45 -0700274 last_frame_log_ms_(clock_->TimeInMilliseconds()),
275 captured_frame_count_(0),
276 dropped_frame_count_(0),
sprang1a646ee2016-12-01 06:34:11 -0800277 bitrate_observer_(nullptr),
perkj26091b12016-09-01 01:17:40 -0700278 encoder_queue_("EncoderQueue") {
perkj803d97f2016-11-01 11:45:46 -0700279 encoder_queue_.PostTask([this] {
perkj26091b12016-09-01 01:17:40 -0700280 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj803d97f2016-11-01 11:45:46 -0700281 overuse_detector_.StartCheckForOveruse();
perkj26091b12016-09-01 01:17:40 -0700282 video_sender_.RegisterExternalEncoder(
283 settings_.encoder, settings_.payload_type, settings_.internal_source);
284 });
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000285}
286
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000287ViEEncoder::~ViEEncoder() {
perkja49cbd32016-09-16 07:53:41 -0700288 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700289 RTC_DCHECK(shutdown_event_.Wait(0))
290 << "Must call ::Stop() before destruction.";
291}
292
293void ViEEncoder::Stop() {
perkja49cbd32016-09-16 07:53:41 -0700294 RTC_DCHECK_RUN_ON(&thread_checker_);
sprangb1ca0732017-02-01 08:38:12 -0800295 source_proxy_->SetSource(nullptr, DegradationPreference());
perkja49cbd32016-09-16 07:53:41 -0700296 encoder_queue_.PostTask([this] {
297 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj803d97f2016-11-01 11:45:46 -0700298 overuse_detector_.StopCheckForOveruse();
Erik Språng08127a92016-11-16 16:41:30 +0100299 rate_allocator_.reset();
sprang1a646ee2016-12-01 06:34:11 -0800300 bitrate_observer_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700301 video_sender_.RegisterExternalEncoder(nullptr, settings_.payload_type,
302 false);
kthelgason876222f2016-11-29 01:44:11 -0800303 quality_scaler_ = nullptr;
perkja49cbd32016-09-16 07:53:41 -0700304 shutdown_event_.Set();
305 });
306
307 shutdown_event_.Wait(rtc::Event::kForever);
perkj26091b12016-09-01 01:17:40 -0700308}
309
310void ViEEncoder::RegisterProcessThread(ProcessThread* module_process_thread) {
perkja49cbd32016-09-16 07:53:41 -0700311 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj26091b12016-09-01 01:17:40 -0700312 RTC_DCHECK(!module_process_thread_);
313 module_process_thread_ = module_process_thread;
perkj26091b12016-09-01 01:17:40 -0700314 module_process_thread_->RegisterModule(&video_sender_);
315 module_process_thread_checker_.DetachFromThread();
316}
317
318void ViEEncoder::DeRegisterProcessThread() {
perkja49cbd32016-09-16 07:53:41 -0700319 RTC_DCHECK_RUN_ON(&thread_checker_);
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200320 module_process_thread_->DeRegisterModule(&video_sender_);
asapersson@webrtc.org96dc6852014-11-03 14:40:38 +0000321}
322
sprang1a646ee2016-12-01 06:34:11 -0800323void ViEEncoder::SetBitrateObserver(
324 VideoBitrateAllocationObserver* bitrate_observer) {
325 RTC_DCHECK_RUN_ON(&thread_checker_);
326 encoder_queue_.PostTask([this, bitrate_observer] {
327 RTC_DCHECK_RUN_ON(&encoder_queue_);
328 RTC_DCHECK(!bitrate_observer_);
329 bitrate_observer_ = bitrate_observer;
330 });
331}
332
perkj803d97f2016-11-01 11:45:46 -0700333void ViEEncoder::SetSource(
334 rtc::VideoSourceInterface<VideoFrame>* source,
335 const VideoSendStream::DegradationPreference& degradation_preference) {
perkja49cbd32016-09-16 07:53:41 -0700336 RTC_DCHECK_RUN_ON(&thread_checker_);
perkj803d97f2016-11-01 11:45:46 -0700337 source_proxy_->SetSource(source, degradation_preference);
338 encoder_queue_.PostTask([this, degradation_preference] {
339 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800340
341 degradation_preference_ = degradation_preference;
minyue35fc2aa2017-02-01 03:14:00 -0800342 stats_proxy_->SetResolutionRestrictionStats(
sprangb1ca0732017-02-01 08:38:12 -0800343 degradation_preference !=
344 VideoSendStream::DegradationPreference::kMaintainResolution,
345 scale_counter_[kCpu] > 0, scale_counter_[kQuality]);
perkj803d97f2016-11-01 11:45:46 -0700346 });
perkja49cbd32016-09-16 07:53:41 -0700347}
348
perkj803d97f2016-11-01 11:45:46 -0700349void ViEEncoder::SetSink(EncoderSink* sink, bool rotation_applied) {
350 source_proxy_->SetWantsRotationApplied(rotation_applied);
perkj26091b12016-09-01 01:17:40 -0700351 encoder_queue_.PostTask([this, sink] {
352 RTC_DCHECK_RUN_ON(&encoder_queue_);
353 sink_ = sink;
354 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000355}
356
perkj26091b12016-09-01 01:17:40 -0700357void ViEEncoder::SetStartBitrate(int start_bitrate_bps) {
358 encoder_queue_.PostTask([this, start_bitrate_bps] {
359 RTC_DCHECK_RUN_ON(&encoder_queue_);
360 encoder_start_bitrate_bps_ = start_bitrate_bps;
361 });
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000362}
Peter Boström00b9d212016-05-19 16:59:03 +0200363
Per512ecb32016-09-23 15:52:06 +0200364void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -0800365 size_t max_data_payload_length,
366 bool nack_enabled) {
Pera48ddb72016-09-29 11:48:50 +0200367 encoder_queue_.PostTask(
368 std::unique_ptr<rtc::QueuedTask>(new ConfigureEncoderTask(
asapersson5f7226f2016-11-25 04:37:00 -0800369 this, std::move(config), max_data_payload_length, nack_enabled)));
perkj26091b12016-09-01 01:17:40 -0700370}
371
Pera48ddb72016-09-29 11:48:50 +0200372void ViEEncoder::ConfigureEncoderOnTaskQueue(VideoEncoderConfig config,
asapersson5f7226f2016-11-25 04:37:00 -0800373 size_t max_data_payload_length,
374 bool nack_enabled) {
perkj26091b12016-09-01 01:17:40 -0700375 RTC_DCHECK_RUN_ON(&encoder_queue_);
perkj26091b12016-09-01 01:17:40 -0700376 RTC_DCHECK(sink_);
perkjfa10b552016-10-02 23:45:26 -0700377 LOG(LS_INFO) << "ConfigureEncoder requested.";
Pera48ddb72016-09-29 11:48:50 +0200378
379 max_data_payload_length_ = max_data_payload_length;
asapersson5f7226f2016-11-25 04:37:00 -0800380 nack_enabled_ = nack_enabled;
Pera48ddb72016-09-29 11:48:50 +0200381 encoder_config_ = std::move(config);
perkjfa10b552016-10-02 23:45:26 -0700382 pending_encoder_reconfiguration_ = true;
Pera48ddb72016-09-29 11:48:50 +0200383
perkjfa10b552016-10-02 23:45:26 -0700384 // Reconfigure the encoder now if the encoder has an internal source or
Per21d45d22016-10-30 21:37:57 +0100385 // if the frame resolution is known. Otherwise, the reconfiguration is
386 // deferred until the next frame to minimize the number of reconfigurations.
387 // The codec configuration depends on incoming video frame size.
388 if (last_frame_info_) {
389 ReconfigureEncoder();
390 } else if (settings_.internal_source) {
391 last_frame_info_ = rtc::Optional<VideoFrameInfo>(
392 VideoFrameInfo(176, 144, kVideoRotation_0, false));
perkjfa10b552016-10-02 23:45:26 -0700393 ReconfigureEncoder();
394 }
395}
perkj26091b12016-09-01 01:17:40 -0700396
perkjfa10b552016-10-02 23:45:26 -0700397void ViEEncoder::ReconfigureEncoder() {
398 RTC_DCHECK_RUN_ON(&encoder_queue_);
399 RTC_DCHECK(pending_encoder_reconfiguration_);
400 std::vector<VideoStream> streams =
401 encoder_config_.video_stream_factory->CreateEncoderStreams(
402 last_frame_info_->width, last_frame_info_->height, encoder_config_);
perkj26091b12016-09-01 01:17:40 -0700403
Erik Språng08127a92016-11-16 16:41:30 +0100404 VideoCodec codec;
405 if (!VideoCodecInitializer::SetupCodec(encoder_config_, settings_, streams,
asapersson5f7226f2016-11-25 04:37:00 -0800406 nack_enabled_, &codec,
407 &rate_allocator_)) {
Erik Språng08127a92016-11-16 16:41:30 +0100408 LOG(LS_ERROR) << "Failed to create encoder configuration.";
409 }
perkjfa10b552016-10-02 23:45:26 -0700410
411 codec.startBitrate =
412 std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
413 codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);
414 codec.expect_encode_from_texture = last_frame_info_->is_texture;
Stefan Holmere5904162015-03-26 11:11:06 +0100415
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200416 bool success = video_sender_.RegisterSendCodec(
perkjfa10b552016-10-02 23:45:26 -0700417 &codec, number_of_cores_,
418 static_cast<uint32_t>(max_data_payload_length_)) == VCM_OK;
Peter Boström905f8e72016-03-02 16:59:56 +0100419 if (!success) {
420 LOG(LS_ERROR) << "Failed to configure encoder.";
421 RTC_DCHECK(success);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000422 }
Peter Boström905f8e72016-03-02 16:59:56 +0100423
sprang1a646ee2016-12-01 06:34:11 -0800424 video_sender_.UpdateChannelParemeters(rate_allocator_.get(),
425 bitrate_observer_);
426
Peter Boströma03785e2016-03-03 11:36:18 +0100427 if (stats_proxy_) {
Erik Språng08127a92016-11-16 16:41:30 +0100428 int framerate = stats_proxy_->GetSendFrameRate();
429 if (framerate == 0)
430 framerate = codec.maxFramerate;
431 stats_proxy_->OnEncoderReconfigured(
432 encoder_config_, rate_allocator_->GetPreferredBitrateBps(framerate));
Peter Boströma03785e2016-03-03 11:36:18 +0100433 }
Per512ecb32016-09-23 15:52:06 +0200434
perkjfa10b552016-10-02 23:45:26 -0700435 pending_encoder_reconfiguration_ = false;
Erik Språng08127a92016-11-16 16:41:30 +0100436
Pera48ddb72016-09-29 11:48:50 +0200437 sink_->OnEncoderConfigurationChanged(
perkjfa10b552016-10-02 23:45:26 -0700438 std::move(streams), encoder_config_.min_transmit_bitrate_bps);
kthelgason876222f2016-11-29 01:44:11 -0800439
440 const auto scaling_settings = settings_.encoder->GetScalingSettings();
sprangb1ca0732017-02-01 08:38:12 -0800441 if (degradation_preference_ != DegradationPreference::kMaintainResolution &&
442 scaling_settings.enabled) {
kthelgason876222f2016-11-29 01:44:11 -0800443 if (scaling_settings.thresholds) {
444 quality_scaler_.reset(
445 new QualityScaler(this, *(scaling_settings.thresholds)));
446 } else {
447 quality_scaler_.reset(new QualityScaler(this, codec_type_));
448 }
449 } else {
450 quality_scaler_.reset(nullptr);
minyue35fc2aa2017-02-01 03:14:00 -0800451 stats_proxy_->SetResolutionRestrictionStats(
452 false, scale_counter_[kCpu] > 0, scale_counter_[kQuality]);
kthelgason876222f2016-11-29 01:44:11 -0800453 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000454}
455
perkja49cbd32016-09-16 07:53:41 -0700456void ViEEncoder::OnFrame(const VideoFrame& video_frame) {
perkj26091b12016-09-01 01:17:40 -0700457 RTC_DCHECK_RUNS_SERIALIZED(&incoming_frame_race_checker_);
perkj26091b12016-09-01 01:17:40 -0700458 VideoFrame incoming_frame = video_frame;
459
460 // Local time in webrtc time base.
nisse1c0dea82017-01-30 02:43:18 -0800461 int64_t current_time_us = clock_->TimeInMicroseconds();
462 int64_t current_time_ms = current_time_us / rtc::kNumMicrosecsPerMillisec;
463 // TODO(nisse): This always overrides the incoming timestamp. Don't
464 // do that, trust the frame source.
465 incoming_frame.set_timestamp_us(current_time_us);
perkj26091b12016-09-01 01:17:40 -0700466
467 // Capture time may come from clock with an offset and drift from clock_.
468 int64_t capture_ntp_time_ms;
nisse891419f2017-01-12 10:02:22 -0800469 if (video_frame.ntp_time_ms() > 0) {
perkj26091b12016-09-01 01:17:40 -0700470 capture_ntp_time_ms = video_frame.ntp_time_ms();
471 } else if (video_frame.render_time_ms() != 0) {
472 capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
473 } else {
nisse1c0dea82017-01-30 02:43:18 -0800474 capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
perkj26091b12016-09-01 01:17:40 -0700475 }
476 incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);
477
478 // Convert NTP time, in ms, to RTP timestamp.
479 const int kMsToRtpTimestamp = 90;
480 incoming_frame.set_timestamp(
481 kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));
482
483 if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
484 // We don't allow the same capture time for two frames, drop this one.
485 LOG(LS_WARNING) << "Same/old NTP timestamp ("
486 << incoming_frame.ntp_time_ms()
487 << " <= " << last_captured_timestamp_
488 << ") for incoming frame. Dropping.";
489 return;
490 }
491
asapersson6ffb67d2016-09-12 00:10:45 -0700492 bool log_stats = false;
nisse1c0dea82017-01-30 02:43:18 -0800493 if (current_time_ms - last_frame_log_ms_ > kFrameLogIntervalMs) {
494 last_frame_log_ms_ = current_time_ms;
asapersson6ffb67d2016-09-12 00:10:45 -0700495 log_stats = true;
496 }
497
perkj26091b12016-09-01 01:17:40 -0700498 last_captured_timestamp_ = incoming_frame.ntp_time_ms();
asapersson6ffb67d2016-09-12 00:10:45 -0700499 encoder_queue_.PostTask(std::unique_ptr<rtc::QueuedTask>(new EncodeTask(
nissee0e3bdf2017-01-18 02:16:20 -0800500 incoming_frame, this, rtc::TimeMicros(), log_stats)));
perkj26091b12016-09-01 01:17:40 -0700501}
502
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000503bool ViEEncoder::EncoderPaused() const {
perkj26091b12016-09-01 01:17:40 -0700504 RTC_DCHECK_RUN_ON(&encoder_queue_);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000505 // Pause video if paused by caller or as long as the network is down or the
506 // pacer queue has grown too large in buffered mode.
perkj57c21f92016-06-17 07:27:16 -0700507 // If the pacer queue has grown too large or the network is down,
perkjfea93092016-05-14 00:58:48 -0700508 // last_observed_bitrate_bps_ will be 0.
perkj26091b12016-09-01 01:17:40 -0700509 return last_observed_bitrate_bps_ == 0;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000510}
511
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000512void ViEEncoder::TraceFrameDropStart() {
perkj26091b12016-09-01 01:17:40 -0700513 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000514 // Start trace event only on the first frame after encoder is paused.
515 if (!encoder_paused_and_dropped_frame_) {
516 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
517 }
518 encoder_paused_and_dropped_frame_ = true;
519 return;
520}
521
522void ViEEncoder::TraceFrameDropEnd() {
perkj26091b12016-09-01 01:17:40 -0700523 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000524 // End trace event on first frame after encoder resumes, if frame was dropped.
525 if (encoder_paused_and_dropped_frame_) {
526 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
527 }
528 encoder_paused_and_dropped_frame_ = false;
529}
530
perkjd52063f2016-09-07 06:32:18 -0700531void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
nissee0e3bdf2017-01-18 02:16:20 -0800532 int64_t time_when_posted_us) {
perkj26091b12016-09-01 01:17:40 -0700533 RTC_DCHECK_RUN_ON(&encoder_queue_);
kthelgason876222f2016-11-29 01:44:11 -0800534
perkj26091b12016-09-01 01:17:40 -0700535 if (pre_encode_callback_)
536 pre_encode_callback_->OnFrame(video_frame);
537
Per21d45d22016-10-30 21:37:57 +0100538 if (!last_frame_info_ || video_frame.width() != last_frame_info_->width ||
perkjfa10b552016-10-02 23:45:26 -0700539 video_frame.height() != last_frame_info_->height ||
540 video_frame.rotation() != last_frame_info_->rotation ||
541 video_frame.is_texture() != last_frame_info_->is_texture) {
542 pending_encoder_reconfiguration_ = true;
543 last_frame_info_ = rtc::Optional<VideoFrameInfo>(
544 VideoFrameInfo(video_frame.width(), video_frame.height(),
545 video_frame.rotation(), video_frame.is_texture()));
546 LOG(LS_INFO) << "Video frame parameters changed: dimensions="
547 << last_frame_info_->width << "x" << last_frame_info_->height
548 << ", rotation=" << last_frame_info_->rotation
549 << ", texture=" << last_frame_info_->is_texture;
550 }
551
sprang57c2fff2017-01-16 06:24:02 -0800552 int64_t now_ms = clock_->TimeInMilliseconds();
perkjfa10b552016-10-02 23:45:26 -0700553 if (pending_encoder_reconfiguration_) {
554 ReconfigureEncoder();
sprang57c2fff2017-01-16 06:24:02 -0800555 } else if (!last_parameters_update_ms_ ||
556 now_ms - *last_parameters_update_ms_ >=
557 vcm::VCMProcessTimer::kDefaultProcessIntervalMs) {
558 video_sender_.UpdateChannelParemeters(rate_allocator_.get(),
559 bitrate_observer_);
perkjfa10b552016-10-02 23:45:26 -0700560 }
sprang57c2fff2017-01-16 06:24:02 -0800561 last_parameters_update_ms_.emplace(now_ms);
perkjfa10b552016-10-02 23:45:26 -0700562
perkj26091b12016-09-01 01:17:40 -0700563 if (EncoderPaused()) {
564 TraceFrameDropStart();
565 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000566 }
perkj26091b12016-09-01 01:17:40 -0700567 TraceFrameDropEnd();
niklase@google.com470e71d2011-07-07 08:21:25 +0000568
Magnus Jedvert26679d62015-04-07 14:07:41 +0200569 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +0000570 "Encode");
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +0000571
nissee0e3bdf2017-01-18 02:16:20 -0800572 overuse_detector_.FrameCaptured(video_frame, time_when_posted_us);
perkjd52063f2016-09-07 06:32:18 -0700573
Pera48ddb72016-09-29 11:48:50 +0200574 if (codec_type_ == webrtc::kVideoCodecVP8) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000575 webrtc::CodecSpecificInfo codec_specific_info;
576 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
perkj26091b12016-09-01 01:17:40 -0700577
hta527d3472016-11-16 23:23:04 -0800578 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI = has_received_rpsi_;
579 codec_specific_info.codecSpecific.VP8.hasReceivedSLI = has_received_sli_;
580 codec_specific_info.codecSpecific.VP8.pictureIdRPSI = picture_id_rpsi_;
581 codec_specific_info.codecSpecific.VP8.pictureIdSLI = picture_id_sli_;
582 has_received_sli_ = false;
583 has_received_rpsi_ = false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000584
hta527d3472016-11-16 23:23:04 -0800585 video_sender_.AddVideoFrame(video_frame, &codec_specific_info);
586 return;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000587 }
perkjfa10b552016-10-02 23:45:26 -0700588 video_sender_.AddVideoFrame(video_frame, nullptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000589}
niklase@google.com470e71d2011-07-07 08:21:25 +0000590
Peter Boström233bfd22016-01-18 20:23:40 +0100591void ViEEncoder::SendKeyFrame() {
perkj26091b12016-09-01 01:17:40 -0700592 if (!encoder_queue_.IsCurrent()) {
593 encoder_queue_.PostTask([this] { SendKeyFrame(); });
594 return;
595 }
596 RTC_DCHECK_RUN_ON(&encoder_queue_);
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200597 video_sender_.IntraFrameRequest(0);
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000598}
599
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700600EncodedImageCallback::Result ViEEncoder::OnEncodedImage(
601 const EncodedImage& encoded_image,
602 const CodecSpecificInfo* codec_specific_info,
603 const RTPFragmentationHeader* fragmentation) {
perkj26091b12016-09-01 01:17:40 -0700604 // Encoded is called on whatever thread the real encoder implementation run
605 // on. In the case of hardware encoders, there might be several encoders
606 // running in parallel on different threads.
kthelgason0cd27ba2016-12-19 06:32:16 -0800607 if (stats_proxy_)
kjellander02b3d272016-04-20 05:05:54 -0700608 stats_proxy_->OnSendEncodedImage(encoded_image, codec_specific_info);
sprang3911c262016-04-15 01:24:14 -0700609
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700610 EncodedImageCallback::Result result =
611 sink_->OnEncodedImage(encoded_image, codec_specific_info, fragmentation);
perkjbc75d972016-05-02 06:31:25 -0700612
nissee0e3bdf2017-01-18 02:16:20 -0800613 int64_t time_sent_us = rtc::TimeMicros();
perkjd52063f2016-09-07 06:32:18 -0700614 uint32_t timestamp = encoded_image._timeStamp;
kthelgason876222f2016-11-29 01:44:11 -0800615 const int qp = encoded_image.qp_;
nissee0e3bdf2017-01-18 02:16:20 -0800616 encoder_queue_.PostTask([this, timestamp, time_sent_us, qp] {
perkjd52063f2016-09-07 06:32:18 -0700617 RTC_DCHECK_RUN_ON(&encoder_queue_);
nissee0e3bdf2017-01-18 02:16:20 -0800618 overuse_detector_.FrameSent(timestamp, time_sent_us);
kthelgason876222f2016-11-29 01:44:11 -0800619 if (quality_scaler_)
620 quality_scaler_->ReportQP(qp);
perkjd52063f2016-09-07 06:32:18 -0700621 });
perkj803d97f2016-11-01 11:45:46 -0700622
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700623 return result;
Peter Boströmb7d9a972015-12-18 16:01:11 +0100624}
625
kthelgason876222f2016-11-29 01:44:11 -0800626void ViEEncoder::OnDroppedFrame() {
627 encoder_queue_.PostTask([this] {
628 RTC_DCHECK_RUN_ON(&encoder_queue_);
629 if (quality_scaler_)
630 quality_scaler_->ReportDroppedFrame();
631 });
632}
633
perkj275afc52016-09-01 00:21:16 -0700634void ViEEncoder::SendStatistics(uint32_t bit_rate, uint32_t frame_rate) {
perkj26091b12016-09-01 01:17:40 -0700635 RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread());
Peter Boström7083e112015-09-22 16:28:51 +0200636 if (stats_proxy_)
perkj275afc52016-09-01 00:21:16 -0700637 stats_proxy_->OnEncoderStatsUpdate(frame_rate, bit_rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000638}
639
perkj600246e2016-05-04 11:26:51 -0700640void ViEEncoder::OnReceivedSLI(uint8_t picture_id) {
perkj26091b12016-09-01 01:17:40 -0700641 if (!encoder_queue_.IsCurrent()) {
642 encoder_queue_.PostTask([this, picture_id] { OnReceivedSLI(picture_id); });
643 return;
644 }
645 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000646 picture_id_sli_ = picture_id;
647 has_received_sli_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000648}
649
perkj600246e2016-05-04 11:26:51 -0700650void ViEEncoder::OnReceivedRPSI(uint64_t picture_id) {
perkj26091b12016-09-01 01:17:40 -0700651 if (!encoder_queue_.IsCurrent()) {
652 encoder_queue_.PostTask([this, picture_id] { OnReceivedRPSI(picture_id); });
653 return;
654 }
655 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000656 picture_id_rpsi_ = picture_id;
657 has_received_rpsi_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000658}
659
perkj600246e2016-05-04 11:26:51 -0700660void ViEEncoder::OnReceivedIntraFrameRequest(size_t stream_index) {
perkj26091b12016-09-01 01:17:40 -0700661 if (!encoder_queue_.IsCurrent()) {
662 encoder_queue_.PostTask(
663 [this, stream_index] { OnReceivedIntraFrameRequest(stream_index); });
664 return;
665 }
666 RTC_DCHECK_RUN_ON(&encoder_queue_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000667 // Key frame request from remote side, signal to VCM.
justinlin@chromium.org7bfb3a32013-05-13 22:59:00 +0000668 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
perkj600246e2016-05-04 11:26:51 -0700669 video_sender_.IntraFrameRequest(stream_index);
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000670}
671
mflodman86aabb22016-03-11 15:44:32 +0100672void ViEEncoder::OnBitrateUpdated(uint32_t bitrate_bps,
stefan@webrtc.orgedeea912014-12-08 19:46:23 +0000673 uint8_t fraction_lost,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000674 int64_t round_trip_time_ms) {
perkj26091b12016-09-01 01:17:40 -0700675 if (!encoder_queue_.IsCurrent()) {
676 encoder_queue_.PostTask(
677 [this, bitrate_bps, fraction_lost, round_trip_time_ms] {
678 OnBitrateUpdated(bitrate_bps, fraction_lost, round_trip_time_ms);
679 });
680 return;
681 }
682 RTC_DCHECK_RUN_ON(&encoder_queue_);
683 RTC_DCHECK(sink_) << "sink_ must be set before the encoder is active.";
684
perkjec81bcd2016-05-11 06:01:13 -0700685 LOG(LS_VERBOSE) << "OnBitrateUpdated, bitrate " << bitrate_bps
mflodman8602a3d2015-05-20 15:54:42 -0700686 << " packet loss " << static_cast<int>(fraction_lost)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000687 << " rtt " << round_trip_time_ms;
perkj26091b12016-09-01 01:17:40 -0700688
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200689 video_sender_.SetChannelParameters(bitrate_bps, fraction_lost,
sprang1a646ee2016-12-01 06:34:11 -0800690 round_trip_time_ms, rate_allocator_.get(),
691 bitrate_observer_);
perkj26091b12016-09-01 01:17:40 -0700692
693 encoder_start_bitrate_bps_ =
694 bitrate_bps != 0 ? bitrate_bps : encoder_start_bitrate_bps_;
mflodman101f2502016-06-09 17:21:19 +0200695 bool video_is_suspended = bitrate_bps == 0;
Erik Språng08127a92016-11-16 16:41:30 +0100696 bool video_suspension_changed = video_is_suspended != EncoderPaused();
perkj26091b12016-09-01 01:17:40 -0700697 last_observed_bitrate_bps_ = bitrate_bps;
Peter Boströmd153a372015-11-10 15:27:12 +0000698
mflodman101f2502016-06-09 17:21:19 +0200699 if (stats_proxy_ && video_suspension_changed) {
mflodman522739c2016-06-22 17:42:30 +0200700 LOG(LS_INFO) << "Video suspend state changed to: "
701 << (video_is_suspended ? "suspended" : "not suspended");
Peter Boström7083e112015-09-22 16:28:51 +0200702 stats_proxy_->OnSuspendChange(video_is_suspended);
mflodman101f2502016-06-09 17:21:19 +0200703 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000704}
705
sprangb1ca0732017-02-01 08:38:12 -0800706void ViEEncoder::AdaptDown(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -0700707 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800708 if (degradation_preference_ != DegradationPreference::kBalanced)
perkj803d97f2016-11-01 11:45:46 -0700709 return;
perkj803d97f2016-11-01 11:45:46 -0700710 // Request lower resolution if the current resolution is lower than last time
711 // we asked for the resolution to be lowered.
kthelgason93f16d72017-01-16 06:15:23 -0800712 int current_pixel_count =
713 last_frame_info_ ? last_frame_info_->pixel_count() : 0;
kthelgason876222f2016-11-29 01:44:11 -0800714 if (max_pixel_count_ && current_pixel_count >= *max_pixel_count_)
715 return;
716 switch (reason) {
717 case kQuality:
kthelgason0cd27ba2016-12-19 06:32:16 -0800718 stats_proxy_->OnQualityRestrictedResolutionChanged(
719 scale_counter_[reason] + 1);
kthelgason876222f2016-11-29 01:44:11 -0800720 break;
721 case kCpu:
722 if (scale_counter_[reason] >= kMaxCpuDowngrades)
723 return;
724 // Update stats accordingly.
725 stats_proxy_->OnCpuRestrictedResolutionChanged(true);
726 break;
727 }
728 max_pixel_count_ = rtc::Optional<int>(current_pixel_count);
729 max_pixel_count_step_up_ = rtc::Optional<int>();
730 ++scale_counter_[reason];
731 source_proxy_->RequestResolutionLowerThan(current_pixel_count);
732 LOG(LS_INFO) << "Scaling down resolution.";
733 for (size_t i = 0; i < kScaleReasonSize; ++i) {
734 LOG(LS_INFO) << "Scaled " << scale_counter_[i]
kthelgason93f16d72017-01-16 06:15:23 -0800735 << " times for reason: " << (i ? "cpu" : "quality");
perkj803d97f2016-11-01 11:45:46 -0700736 }
perkj26091b12016-09-01 01:17:40 -0700737}
738
sprangb1ca0732017-02-01 08:38:12 -0800739void ViEEncoder::AdaptUp(AdaptReason reason) {
perkjd52063f2016-09-07 06:32:18 -0700740 RTC_DCHECK_RUN_ON(&encoder_queue_);
sprangb1ca0732017-02-01 08:38:12 -0800741 if (scale_counter_[reason] == 0 ||
742 degradation_preference_ != DegradationPreference::kBalanced) {
perkj803d97f2016-11-01 11:45:46 -0700743 return;
sprangb1ca0732017-02-01 08:38:12 -0800744 }
kthelgason876222f2016-11-29 01:44:11 -0800745 // Only scale if resolution is higher than last time
746 // we requested higher resolution.
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 (current_pixel_count <= max_pixel_count_step_up_.value_or(0))
750 return;
751 switch (reason) {
752 case kQuality:
753 stats_proxy_->OnQualityRestrictedResolutionChanged(
kthelgason0cd27ba2016-12-19 06:32:16 -0800754 scale_counter_[reason] - 1);
kthelgason876222f2016-11-29 01:44:11 -0800755 break;
756 case kCpu:
757 // Update stats accordingly.
758 stats_proxy_->OnCpuRestrictedResolutionChanged(scale_counter_[reason] >
759 1);
760 break;
761 }
762 max_pixel_count_ = rtc::Optional<int>();
763 max_pixel_count_step_up_ = rtc::Optional<int>(current_pixel_count);
764 --scale_counter_[reason];
765 source_proxy_->RequestHigherResolutionThan(current_pixel_count);
766 LOG(LS_INFO) << "Scaling up resolution.";
767 for (size_t i = 0; i < kScaleReasonSize; ++i) {
768 LOG(LS_INFO) << "Scaled " << scale_counter_[i]
kthelgason7e70fe22016-12-16 03:46:48 -0800769 << " times for reason: " << (i ? "cpu" : "quality");
perkj803d97f2016-11-01 11:45:46 -0700770 }
perkj26091b12016-09-01 01:17:40 -0700771}
772
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000773} // namespace webrtc