1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2 *
3 * Use of this source code is governed by a BSD-style license
4 * that can be found in the LICENSE file in the root of the source
5 * tree. An additional intellectual property rights grant can be found
6 * in the file PATENTS. All contributing project authors may
7 * be found in the AUTHORS file in the root of the source tree.
8 */
9
10 #include "modules/video_coding/codecs/vp8/screenshare_layers.h"
11
12 #include <stdlib.h>
13
14 #include <algorithm>
15 #include <memory>
16
17 #include "modules/video_coding/include/video_codec_interface.h"
18 #include "rtc_base/arraysize.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/time_utils.h"
22 #include "system_wrappers/include/metrics.h"
23
24 namespace webrtc {
25 namespace {
26 using BufferFlags = Vp8FrameConfig::BufferFlags;
27
28 constexpr BufferFlags kNone = Vp8FrameConfig::BufferFlags::kNone;
29 constexpr BufferFlags kReference = Vp8FrameConfig::BufferFlags::kReference;
30 constexpr BufferFlags kUpdate = Vp8FrameConfig::BufferFlags::kUpdate;
31 constexpr BufferFlags kReferenceAndUpdate =
32 Vp8FrameConfig::BufferFlags::kReferenceAndUpdate;
33
34 constexpr int kOneSecond90Khz = 90000;
35 constexpr int kMinTimeBetweenSyncs = kOneSecond90Khz * 2;
36 constexpr int kMaxTimeBetweenSyncs = kOneSecond90Khz * 4;
37 constexpr int kQpDeltaThresholdForSync = 8;
38 constexpr int kMinBitrateKbpsForQpBoost = 500;
39 constexpr auto kSwitch = DecodeTargetIndication::kSwitch;
40 } // namespace
41
42 const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
43 const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
44
45 constexpr int ScreenshareLayers::kMaxNumTemporalLayers;
46
47 // Always emit a frame with certain interval, even if bitrate targets have
48 // been exceeded. This prevents needless keyframe requests.
49 const int ScreenshareLayers::kMaxFrameIntervalMs = 2750;
50
ScreenshareLayers(int num_temporal_layers)51 ScreenshareLayers::ScreenshareLayers(int num_temporal_layers)
52 : number_of_temporal_layers_(
53 std::min(kMaxNumTemporalLayers, num_temporal_layers)),
54 active_layer_(-1),
55 last_timestamp_(-1),
56 last_sync_timestamp_(-1),
57 last_emitted_tl0_timestamp_(-1),
58 last_frame_time_ms_(-1),
59 max_debt_bytes_(0),
60 encode_framerate_(1000.0f, 1000.0f), // 1 second window, second scale.
61 bitrate_updated_(false),
62 checker_(TemporalLayersChecker::CreateTemporalLayersChecker(
63 Vp8TemporalLayersType::kBitrateDynamic,
64 num_temporal_layers)) {
65 RTC_CHECK_GT(number_of_temporal_layers_, 0);
66 RTC_CHECK_LE(number_of_temporal_layers_, kMaxNumTemporalLayers);
67 }
68
~ScreenshareLayers()69 ScreenshareLayers::~ScreenshareLayers() {
70 UpdateHistograms();
71 }
72
SetQpLimits(size_t stream_index,int min_qp,int max_qp)73 void ScreenshareLayers::SetQpLimits(size_t stream_index,
74 int min_qp,
75 int max_qp) {
76 RTC_DCHECK_LT(stream_index, StreamCount());
77 // 0 < min_qp <= max_qp
78 RTC_DCHECK_LT(0, min_qp);
79 RTC_DCHECK_LE(min_qp, max_qp);
80
81 RTC_DCHECK_EQ(min_qp_.has_value(), max_qp_.has_value());
82 if (!min_qp_.has_value()) {
83 min_qp_ = min_qp;
84 max_qp_ = max_qp;
85 } else {
86 RTC_DCHECK_EQ(min_qp, min_qp_.value());
87 RTC_DCHECK_EQ(max_qp, max_qp_.value());
88 }
89 }
90
StreamCount() const91 size_t ScreenshareLayers::StreamCount() const {
92 return 1;
93 }
94
SupportsEncoderFrameDropping(size_t stream_index) const95 bool ScreenshareLayers::SupportsEncoderFrameDropping(
96 size_t stream_index) const {
97 RTC_DCHECK_LT(stream_index, StreamCount());
98 // Frame dropping is handled internally by this class.
99 return false;
100 }
101
NextFrameConfig(size_t stream_index,uint32_t timestamp)102 Vp8FrameConfig ScreenshareLayers::NextFrameConfig(size_t stream_index,
103 uint32_t timestamp) {
104 RTC_DCHECK_LT(stream_index, StreamCount());
105
106 auto it = pending_frame_configs_.find(timestamp);
107 if (it != pending_frame_configs_.end()) {
108 // Drop and re-encode, reuse the previous config.
109 return it->second.frame_config;
110 }
111
112 if (number_of_temporal_layers_ <= 1) {
113 // No flags needed for 1 layer screenshare.
114 // TODO(pbos): Consider updating only last, and not all buffers.
115 DependencyInfo dependency_info{
116 "S", {kReferenceAndUpdate, kReferenceAndUpdate, kReferenceAndUpdate}};
117 pending_frame_configs_[timestamp] = dependency_info;
118 return dependency_info.frame_config;
119 }
120
121 const int64_t now_ms = rtc::TimeMillis();
122
123 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
124 int64_t ts_diff;
125 if (last_timestamp_ == -1) {
126 ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
127 } else {
128 ts_diff = unwrapped_timestamp - last_timestamp_;
129 }
130
131 if (target_framerate_) {
132 // If input frame rate exceeds target frame rate, either over a one second
133 // averaging window, or if frame interval is below 90% of desired value,
134 // drop frame.
135 if (encode_framerate_.Rate(now_ms).value_or(0) > *target_framerate_)
136 return Vp8FrameConfig(kNone, kNone, kNone);
137
138 // Primarily check if frame interval is too short using frame timestamps,
139 // as if they are correct they won't be affected by queuing in webrtc.
140 const int64_t expected_frame_interval_90khz =
141 kOneSecond90Khz / *target_framerate_;
142 if (last_timestamp_ != -1 && ts_diff > 0) {
143 if (ts_diff < 85 * expected_frame_interval_90khz / 100) {
144 return Vp8FrameConfig(kNone, kNone, kNone);
145 }
146 } else {
147 // Timestamps looks off, use realtime clock here instead.
148 const int64_t expected_frame_interval_ms = 1000 / *target_framerate_;
149 if (last_frame_time_ms_ != -1 &&
150 now_ms - last_frame_time_ms_ <
151 (85 * expected_frame_interval_ms) / 100) {
152 return Vp8FrameConfig(kNone, kNone, kNone);
153 }
154 }
155 }
156
157 if (stats_.first_frame_time_ms_ == -1)
158 stats_.first_frame_time_ms_ = now_ms;
159
160 // Make sure both frame droppers leak out bits.
161 layers_[0].UpdateDebt(ts_diff / 90);
162 layers_[1].UpdateDebt(ts_diff / 90);
163 last_timestamp_ = timestamp;
164 last_frame_time_ms_ = now_ms;
165
166 TemporalLayerState layer_state = TemporalLayerState::kDrop;
167
168 if (active_layer_ == -1 ||
169 layers_[active_layer_].state != TemporalLayer::State::kDropped) {
170 if (last_emitted_tl0_timestamp_ != -1 &&
171 (unwrapped_timestamp - last_emitted_tl0_timestamp_) / 90 >
172 kMaxFrameIntervalMs) {
173 // Too long time has passed since the last frame was emitted, cancel
174 // enough debt to allow a single frame.
175 layers_[0].debt_bytes_ = max_debt_bytes_ - 1;
176 }
177 if (layers_[0].debt_bytes_ > max_debt_bytes_) {
178 // Must drop TL0, encode TL1 instead.
179 if (layers_[1].debt_bytes_ > max_debt_bytes_) {
180 // Must drop both TL0 and TL1.
181 active_layer_ = -1;
182 } else {
183 active_layer_ = 1;
184 }
185 } else {
186 active_layer_ = 0;
187 }
188 }
189
190 switch (active_layer_) {
191 case 0:
192 layer_state = TemporalLayerState::kTl0;
193 last_emitted_tl0_timestamp_ = unwrapped_timestamp;
194 break;
195 case 1:
196 if (layers_[1].state != TemporalLayer::State::kDropped) {
197 if (TimeToSync(unwrapped_timestamp) ||
198 layers_[1].state == TemporalLayer::State::kKeyFrame) {
199 last_sync_timestamp_ = unwrapped_timestamp;
200 layer_state = TemporalLayerState::kTl1Sync;
201 } else {
202 layer_state = TemporalLayerState::kTl1;
203 }
204 } else {
205 layer_state = last_sync_timestamp_ == unwrapped_timestamp
206 ? TemporalLayerState::kTl1Sync
207 : TemporalLayerState::kTl1;
208 }
209 break;
210 case -1:
211 layer_state = TemporalLayerState::kDrop;
212 ++stats_.num_dropped_frames_;
213 break;
214 default:
215 RTC_NOTREACHED();
216 }
217
218 DependencyInfo dependency_info;
219 // TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
220 // layers.
221 switch (layer_state) {
222 case TemporalLayerState::kDrop:
223 dependency_info = {"", {kNone, kNone, kNone}};
224 break;
225 case TemporalLayerState::kTl0:
226 // TL0 only references and updates 'last'.
227 dependency_info = {"SS", {kReferenceAndUpdate, kNone, kNone}};
228 dependency_info.frame_config.packetizer_temporal_idx = 0;
229 break;
230 case TemporalLayerState::kTl1:
231 // TL1 references both 'last' and 'golden' but only updates 'golden'.
232 dependency_info = {"-R", {kReference, kReferenceAndUpdate, kNone}};
233 dependency_info.frame_config.packetizer_temporal_idx = 1;
234 break;
235 case TemporalLayerState::kTl1Sync:
236 // Predict from only TL0 to allow participants to switch to the high
237 // bitrate stream. Updates 'golden' so that TL1 can continue to refer to
238 // and update 'golden' from this point on.
239 dependency_info = {"-S", {kReference, kUpdate, kNone}};
240 dependency_info.frame_config.packetizer_temporal_idx = 1;
241 dependency_info.frame_config.layer_sync = true;
242 break;
243 }
244
245 pending_frame_configs_[timestamp] = dependency_info;
246 return dependency_info.frame_config;
247 }
248
OnRatesUpdated(size_t stream_index,const std::vector<uint32_t> & bitrates_bps,int framerate_fps)249 void ScreenshareLayers::OnRatesUpdated(
250 size_t stream_index,
251 const std::vector<uint32_t>& bitrates_bps,
252 int framerate_fps) {
253 RTC_DCHECK_LT(stream_index, StreamCount());
254 RTC_DCHECK_GT(framerate_fps, 0);
255 RTC_DCHECK_GE(bitrates_bps.size(), 1);
256 RTC_DCHECK_LE(bitrates_bps.size(), 2);
257
258 // |bitrates_bps| uses individual rates per layer, but we want to use the
259 // accumulated rate here.
260 uint32_t tl0_kbps = bitrates_bps[0] / 1000;
261 uint32_t tl1_kbps = tl0_kbps;
262 if (bitrates_bps.size() > 1) {
263 tl1_kbps += bitrates_bps[1] / 1000;
264 }
265
266 if (!target_framerate_) {
267 // First OnRatesUpdated() is called during construction, with the
268 // configured targets as parameters.
269 target_framerate_ = framerate_fps;
270 capture_framerate_ = target_framerate_;
271 bitrate_updated_ = true;
272 } else {
273 if ((capture_framerate_ &&
274 framerate_fps != static_cast<int>(*capture_framerate_)) ||
275 (tl0_kbps != layers_[0].target_rate_kbps_) ||
276 (tl1_kbps != layers_[1].target_rate_kbps_)) {
277 bitrate_updated_ = true;
278 }
279
280 if (framerate_fps < 0) {
281 capture_framerate_.reset();
282 } else {
283 capture_framerate_ = framerate_fps;
284 }
285 }
286
287 layers_[0].target_rate_kbps_ = tl0_kbps;
288 layers_[1].target_rate_kbps_ = tl1_kbps;
289 }
290
OnEncodeDone(size_t stream_index,uint32_t rtp_timestamp,size_t size_bytes,bool is_keyframe,int qp,CodecSpecificInfo * info)291 void ScreenshareLayers::OnEncodeDone(size_t stream_index,
292 uint32_t rtp_timestamp,
293 size_t size_bytes,
294 bool is_keyframe,
295 int qp,
296 CodecSpecificInfo* info) {
297 RTC_DCHECK_LT(stream_index, StreamCount());
298
299 if (size_bytes == 0) {
300 RTC_LOG(LS_WARNING) << "Empty frame; treating as dropped.";
301 OnFrameDropped(stream_index, rtp_timestamp);
302 return;
303 }
304
305 absl::optional<DependencyInfo> dependency_info;
306 auto it = pending_frame_configs_.find(rtp_timestamp);
307 if (it != pending_frame_configs_.end()) {
308 dependency_info = it->second;
309 pending_frame_configs_.erase(it);
310
311 if (checker_) {
312 RTC_DCHECK(checker_->CheckTemporalConfig(is_keyframe,
313 dependency_info->frame_config));
314 }
315 }
316
317 CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
318 GenericFrameInfo& generic_frame_info = info->generic_frame_info.emplace();
319
320 if (number_of_temporal_layers_ == 1) {
321 vp8_info.temporalIdx = kNoTemporalIdx;
322 vp8_info.layerSync = false;
323 generic_frame_info.decode_target_indications = {kSwitch};
324 generic_frame_info.encoder_buffers.emplace_back(
325 0, /*referenced=*/!is_keyframe, /*updated=*/true);
326 } else {
327 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(rtp_timestamp);
328 if (dependency_info) {
329 vp8_info.temporalIdx =
330 dependency_info->frame_config.packetizer_temporal_idx;
331 vp8_info.layerSync = dependency_info->frame_config.layer_sync;
332 generic_frame_info.decode_target_indications =
333 dependency_info->decode_target_indications;
334 } else {
335 RTC_DCHECK(is_keyframe);
336 }
337
338 if (is_keyframe) {
339 vp8_info.temporalIdx = 0;
340 last_sync_timestamp_ = unwrapped_timestamp;
341 vp8_info.layerSync = true;
342 layers_[0].state = TemporalLayer::State::kKeyFrame;
343 layers_[1].state = TemporalLayer::State::kKeyFrame;
344 active_layer_ = 1;
345 info->template_structure =
346 GetTemplateStructure(number_of_temporal_layers_);
347 generic_frame_info.decode_target_indications = {kSwitch, kSwitch};
348 } else if (active_layer_ >= 0 && layers_[active_layer_].state ==
349 TemporalLayer::State::kKeyFrame) {
350 layers_[active_layer_].state = TemporalLayer::State::kNormal;
351 }
352
353 vp8_info.useExplicitDependencies = true;
354 RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
355 RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
356
357 // Note that |frame_config| is not derefernced if |is_keyframe|,
358 // meaning it's never dereferenced if the optional may be unset.
359 for (int i = 0; i < static_cast<int>(Vp8FrameConfig::Buffer::kCount); ++i) {
360 bool references = false;
361 bool updates = is_keyframe;
362 if (!is_keyframe && dependency_info->frame_config.References(
363 static_cast<Vp8FrameConfig::Buffer>(i))) {
364 RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
365 arraysize(CodecSpecificInfoVP8::referencedBuffers));
366 references = true;
367 vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
368 }
369
370 if (is_keyframe || dependency_info->frame_config.Updates(
371 static_cast<Vp8FrameConfig::Buffer>(i))) {
372 RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
373 arraysize(CodecSpecificInfoVP8::updatedBuffers));
374 updates = true;
375 vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
376 }
377
378 if (references || updates)
379 generic_frame_info.encoder_buffers.emplace_back(i, references, updates);
380 }
381 }
382
383 encode_framerate_.Update(1, rtc::TimeMillis());
384
385 if (number_of_temporal_layers_ == 1)
386 return;
387
388 RTC_DCHECK_NE(-1, active_layer_);
389 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
390 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
391 }
392
393 if (qp != -1)
394 layers_[active_layer_].last_qp = qp;
395
396 if (active_layer_ == 0) {
397 layers_[0].debt_bytes_ += size_bytes;
398 layers_[1].debt_bytes_ += size_bytes;
399 ++stats_.num_tl0_frames_;
400 stats_.tl0_target_bitrate_sum_ += layers_[0].target_rate_kbps_;
401 stats_.tl0_qp_sum_ += qp;
402 } else if (active_layer_ == 1) {
403 layers_[1].debt_bytes_ += size_bytes;
404 ++stats_.num_tl1_frames_;
405 stats_.tl1_target_bitrate_sum_ += layers_[1].target_rate_kbps_;
406 stats_.tl1_qp_sum_ += qp;
407 }
408 }
409
OnFrameDropped(size_t stream_index,uint32_t rtp_timestamp)410 void ScreenshareLayers::OnFrameDropped(size_t stream_index,
411 uint32_t rtp_timestamp) {
412 layers_[active_layer_].state = TemporalLayer::State::kDropped;
413 ++stats_.num_overshoots_;
414 }
415
OnPacketLossRateUpdate(float packet_loss_rate)416 void ScreenshareLayers::OnPacketLossRateUpdate(float packet_loss_rate) {}
417
OnRttUpdate(int64_t rtt_ms)418 void ScreenshareLayers::OnRttUpdate(int64_t rtt_ms) {}
419
OnLossNotification(const VideoEncoder::LossNotification & loss_notification)420 void ScreenshareLayers::OnLossNotification(
421 const VideoEncoder::LossNotification& loss_notification) {}
422
GetTemplateStructure(int num_layers) const423 FrameDependencyStructure ScreenshareLayers::GetTemplateStructure(
424 int num_layers) const {
425 RTC_CHECK_LT(num_layers, 3);
426 RTC_CHECK_GT(num_layers, 0);
427
428 FrameDependencyStructure template_structure;
429 template_structure.num_decode_targets = num_layers;
430
431 switch (num_layers) {
432 case 1: {
433 template_structure.templates.resize(2);
434 template_structure.templates[0].T(0).Dtis("S");
435 template_structure.templates[1].T(0).Dtis("S").FrameDiffs({1});
436 return template_structure;
437 }
438 case 2: {
439 template_structure.templates.resize(3);
440 template_structure.templates[0].T(0).Dtis("SS");
441 template_structure.templates[1].T(0).Dtis("SS").FrameDiffs({1});
442 template_structure.templates[2].T(1).Dtis("-S").FrameDiffs({1});
443 return template_structure;
444 }
445 default:
446 RTC_NOTREACHED();
447 // To make the compiler happy!
448 return template_structure;
449 }
450 }
451
TimeToSync(int64_t timestamp) const452 bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
453 RTC_DCHECK_EQ(1, active_layer_);
454 RTC_DCHECK_NE(-1, layers_[0].last_qp);
455 if (layers_[1].last_qp == -1) {
456 // First frame in TL1 should only depend on TL0 since there are no
457 // previous frames in TL1.
458 return true;
459 }
460
461 RTC_DCHECK_NE(-1, last_sync_timestamp_);
462 int64_t timestamp_diff = timestamp - last_sync_timestamp_;
463 if (timestamp_diff > kMaxTimeBetweenSyncs) {
464 // After a certain time, force a sync frame.
465 return true;
466 } else if (timestamp_diff < kMinTimeBetweenSyncs) {
467 // If too soon from previous sync frame, don't issue a new one.
468 return false;
469 }
470 // Issue a sync frame if difference in quality between TL0 and TL1 isn't too
471 // large.
472 if (layers_[0].last_qp - layers_[1].last_qp < kQpDeltaThresholdForSync)
473 return true;
474 return false;
475 }
476
GetCodecTargetBitrateKbps() const477 uint32_t ScreenshareLayers::GetCodecTargetBitrateKbps() const {
478 uint32_t target_bitrate_kbps = layers_[0].target_rate_kbps_;
479
480 if (number_of_temporal_layers_ > 1) {
481 // Calculate a codec target bitrate. This may be higher than TL0, gaining
482 // quality at the expense of frame rate at TL0. Constraints:
483 // - TL0 frame rate no less than framerate / kMaxTL0FpsReduction.
484 // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
485 target_bitrate_kbps =
486 std::min(layers_[0].target_rate_kbps_ * kMaxTL0FpsReduction,
487 layers_[1].target_rate_kbps_ / kAcceptableTargetOvershoot);
488 }
489
490 return std::max(layers_[0].target_rate_kbps_, target_bitrate_kbps);
491 }
492
UpdateConfiguration(size_t stream_index)493 Vp8EncoderConfig ScreenshareLayers::UpdateConfiguration(size_t stream_index) {
494 RTC_DCHECK_LT(stream_index, StreamCount());
495 RTC_DCHECK(min_qp_.has_value());
496 RTC_DCHECK(max_qp_.has_value());
497
498 const uint32_t target_bitrate_kbps = GetCodecTargetBitrateKbps();
499
500 // TODO(sprang): We _really_ need to make an overhaul of this class. :(
501 // If we're dropping frames in order to meet a target framerate, adjust the
502 // bitrate assigned to the encoder so the total average bitrate is correct.
503 float encoder_config_bitrate_kbps = target_bitrate_kbps;
504 if (target_framerate_ && capture_framerate_ &&
505 *target_framerate_ < *capture_framerate_) {
506 encoder_config_bitrate_kbps *=
507 static_cast<float>(*capture_framerate_) / *target_framerate_;
508 }
509
510 if (bitrate_updated_ ||
511 encoder_config_.rc_target_bitrate !=
512 absl::make_optional(encoder_config_bitrate_kbps)) {
513 encoder_config_.rc_target_bitrate = encoder_config_bitrate_kbps;
514
515 // Don't reconfigure qp limits during quality boost frames.
516 if (active_layer_ == -1 ||
517 layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
518 const int min_qp = min_qp_.value();
519 const int max_qp = max_qp_.value();
520
521 // After a dropped frame, a frame with max qp will be encoded and the
522 // quality will then ramp up from there. To boost the speed of recovery,
523 // encode the next frame with lower max qp, if there is sufficient
524 // bandwidth to do so without causing excessive delay.
525 // TL0 is the most important to improve since the errors in this layer
526 // will propagate to TL1.
527 // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
528 if (layers_[1].target_rate_kbps_ >= kMinBitrateKbpsForQpBoost) {
529 layers_[0].enhanced_max_qp = min_qp + (((max_qp - min_qp) * 80) / 100);
530 layers_[1].enhanced_max_qp = min_qp + (((max_qp - min_qp) * 85) / 100);
531 } else {
532 layers_[0].enhanced_max_qp = -1;
533 layers_[1].enhanced_max_qp = -1;
534 }
535 }
536
537 if (capture_framerate_) {
538 int avg_frame_size =
539 (target_bitrate_kbps * 1000) / (8 * *capture_framerate_);
540 // Allow max debt to be the size of a single optimal frame.
541 // TODO(sprang): Determine if this needs to be adjusted by some factor.
542 // (Lower values may cause more frame drops, higher may lead to queuing
543 // delays.)
544 max_debt_bytes_ = avg_frame_size;
545 }
546
547 bitrate_updated_ = false;
548 }
549
550 // Don't try to update boosts state if not active yet.
551 if (active_layer_ == -1)
552 return encoder_config_;
553
554 if (number_of_temporal_layers_ <= 1)
555 return encoder_config_;
556
557 // If layer is in the quality boost state (following a dropped frame), update
558 // the configuration with the adjusted (lower) qp and set the state back to
559 // normal.
560 unsigned int adjusted_max_qp = max_qp_.value(); // Set the normal max qp.
561 if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost) {
562 if (layers_[active_layer_].enhanced_max_qp != -1) {
563 // Bitrate is high enough for quality boost, update max qp.
564 adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
565 }
566 // Regardless of qp, reset the boost state for the next frame.
567 layers_[active_layer_].state = TemporalLayer::State::kNormal;
568 }
569 encoder_config_.rc_max_quantizer = adjusted_max_qp;
570
571 return encoder_config_;
572 }
573
UpdateDebt(int64_t delta_ms)574 void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
575 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
576 if (debt_reduction_bytes >= debt_bytes_) {
577 debt_bytes_ = 0;
578 } else {
579 debt_bytes_ -= debt_reduction_bytes;
580 }
581 }
582
UpdateHistograms()583 void ScreenshareLayers::UpdateHistograms() {
584 if (stats_.first_frame_time_ms_ == -1)
585 return;
586 int64_t duration_sec =
587 (rtc::TimeMillis() - stats_.first_frame_time_ms_ + 500) / 1000;
588 if (duration_sec >= metrics::kMinRunTimeInSeconds) {
589 RTC_HISTOGRAM_COUNTS_10000(
590 "WebRTC.Video.Screenshare.Layer0.FrameRate",
591 (stats_.num_tl0_frames_ + (duration_sec / 2)) / duration_sec);
592 RTC_HISTOGRAM_COUNTS_10000(
593 "WebRTC.Video.Screenshare.Layer1.FrameRate",
594 (stats_.num_tl1_frames_ + (duration_sec / 2)) / duration_sec);
595 int total_frames = stats_.num_tl0_frames_ + stats_.num_tl1_frames_;
596 RTC_HISTOGRAM_COUNTS_10000(
597 "WebRTC.Video.Screenshare.FramesPerDrop",
598 (stats_.num_dropped_frames_ == 0
599 ? 0
600 : total_frames / stats_.num_dropped_frames_));
601 RTC_HISTOGRAM_COUNTS_10000(
602 "WebRTC.Video.Screenshare.FramesPerOvershoot",
603 (stats_.num_overshoots_ == 0 ? 0
604 : total_frames / stats_.num_overshoots_));
605 if (stats_.num_tl0_frames_ > 0) {
606 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer0.Qp",
607 stats_.tl0_qp_sum_ / stats_.num_tl0_frames_);
608 RTC_HISTOGRAM_COUNTS_10000(
609 "WebRTC.Video.Screenshare.Layer0.TargetBitrate",
610 stats_.tl0_target_bitrate_sum_ / stats_.num_tl0_frames_);
611 }
612 if (stats_.num_tl1_frames_ > 0) {
613 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer1.Qp",
614 stats_.tl1_qp_sum_ / stats_.num_tl1_frames_);
615 RTC_HISTOGRAM_COUNTS_10000(
616 "WebRTC.Video.Screenshare.Layer1.TargetBitrate",
617 stats_.tl1_target_bitrate_sum_ / stats_.num_tl1_frames_);
618 }
619 }
620 }
621 } // namespace webrtc
622