blob: 17b1aed4d9b41ab6462cb2c79d1795e19bfdc9d2 [file] [log] [blame]
pbos@webrtc.org9115cde2014-12-09 10:36:40 +00001/* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +02002 *
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 */
pbos@webrtc.org9115cde2014-12-09 10:36:40 +00009
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020010#include "modules/video_coding/codecs/vp8/screenshare_layers.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000011
12#include <stdlib.h>
13
philipelcce46fc2015-12-21 03:04:49 -080014#include <algorithm>
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +020015#include <memory>
philipelcce46fc2015-12-21 03:04:49 -080016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/video_coding/include/video_codec_interface.h"
Elad Alon819661a2019-01-29 17:17:09 +010018#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
Ilya Nikolaevskiy58662912017-10-04 15:07:09 +020020#include "rtc_base/logging.h"
Sebastian Janssone64a6882019-03-01 18:04:07 +010021#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "system_wrappers/include/metrics.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000023
24namespace webrtc {
Erik Språng59021ba2018-10-03 11:05:16 +020025namespace {
Elad Alon411b49b2019-01-29 14:05:55 +010026using Buffer = Vp8FrameConfig::Buffer;
27using BufferFlags = Vp8FrameConfig::BufferFlags;
28
29constexpr BufferFlags kNone = Vp8FrameConfig::BufferFlags::kNone;
30constexpr BufferFlags kReference = Vp8FrameConfig::BufferFlags::kReference;
31constexpr BufferFlags kUpdate = Vp8FrameConfig::BufferFlags::kUpdate;
32constexpr BufferFlags kReferenceAndUpdate =
33 Vp8FrameConfig::BufferFlags::kReferenceAndUpdate;
34
35constexpr int kOneSecond90Khz = 90000;
36constexpr int kMinTimeBetweenSyncs = kOneSecond90Khz * 2;
37constexpr int kMaxTimeBetweenSyncs = kOneSecond90Khz * 4;
38constexpr int kQpDeltaThresholdForSync = 8;
39constexpr int kMinBitrateKbpsForQpBoost = 500;
Erik Språng59021ba2018-10-03 11:05:16 +020040} // namespace
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000041
sprang@webrtc.org70f74f32014-12-17 10:57:10 +000042const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
43const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
44
sprang429600d2017-01-26 06:12:26 -080045constexpr int ScreenshareLayers::kMaxNumTemporalLayers;
46
sprangafe1f742016-04-12 02:45:13 -070047// Always emit a frame with certain interval, even if bitrate targets have
sprang916170a2017-05-23 07:47:55 -070048// been exceeded. This prevents needless keyframe requests.
sprang6c4bbfa2017-05-30 10:08:23 -070049const int ScreenshareLayers::kMaxFrameIntervalMs = 2750;
sprangafe1f742016-04-12 02:45:13 -070050
Sebastian Janssone64a6882019-03-01 18:04:07 +010051ScreenshareLayers::ScreenshareLayers(int num_temporal_layers)
52 : number_of_temporal_layers_(
sprang429600d2017-01-26 06:12:26 -080053 std::min(kMaxNumTemporalLayers, num_temporal_layers)),
Erik Språng2c4c9142015-06-24 11:24:44 +020054 active_layer_(-1),
55 last_timestamp_(-1),
56 last_sync_timestamp_(-1),
sprangafe1f742016-04-12 02:45:13 -070057 last_emitted_tl0_timestamp_(-1),
Erik Språng27a457d2018-01-12 11:00:21 +010058 last_frame_time_ms_(-1),
Erik Språng2c4c9142015-06-24 11:24:44 +020059 min_qp_(-1),
60 max_qp_(-1),
61 max_debt_bytes_(0),
sprangac4a90d2016-12-28 05:58:07 -080062 encode_framerate_(1000.0f, 1000.0f), // 1 second window, second scale.
Erik Språng59021ba2018-10-03 11:05:16 +020063 bitrate_updated_(false),
64 checker_(TemporalLayersChecker::CreateTemporalLayersChecker(
Erik Språng4529fbc2018-10-12 10:30:31 +020065 Vp8TemporalLayersType::kBitrateDynamic,
Erik Språng59021ba2018-10-03 11:05:16 +020066 num_temporal_layers)) {
sprang429600d2017-01-26 06:12:26 -080067 RTC_CHECK_GT(number_of_temporal_layers_, 0);
68 RTC_CHECK_LE(number_of_temporal_layers_, kMaxNumTemporalLayers);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000069}
70
sprangb0fdfea2016-03-01 05:51:16 -080071ScreenshareLayers::~ScreenshareLayers() {
72 UpdateHistograms();
73}
74
Erik Språngfb2a66a2018-09-10 10:48:01 +020075bool ScreenshareLayers::SupportsEncoderFrameDropping() const {
76 // Frame dropping is handled internally by this class.
77 return false;
78}
79
Elad Alon411b49b2019-01-29 14:05:55 +010080Vp8FrameConfig ScreenshareLayers::UpdateLayerConfig(uint32_t timestamp) {
Erik Språng59021ba2018-10-03 11:05:16 +020081 auto it = pending_frame_configs_.find(timestamp);
82 if (it != pending_frame_configs_.end()) {
83 // Drop and re-encode, reuse the previous config.
84 return it->second;
85 }
86
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000087 if (number_of_temporal_layers_ <= 1) {
88 // No flags needed for 1 layer screenshare.
Peter Boström1436c832017-03-27 15:01:49 -040089 // TODO(pbos): Consider updating only last, and not all buffers.
Elad Alon411b49b2019-01-29 14:05:55 +010090 Vp8FrameConfig tl_config(kReferenceAndUpdate, kReferenceAndUpdate,
91 kReferenceAndUpdate);
Erik Språng59021ba2018-10-03 11:05:16 +020092 pending_frame_configs_[timestamp] = tl_config;
pbos51f083c2017-05-04 06:39:04 -070093 return tl_config;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000094 }
Erik Språng2c4c9142015-06-24 11:24:44 +020095
Sebastian Janssone64a6882019-03-01 18:04:07 +010096 const int64_t now_ms = rtc::TimeMillis();
sprangb0fdfea2016-03-01 05:51:16 -080097
Erik Språng2c4c9142015-06-24 11:24:44 +020098 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
sprang916170a2017-05-23 07:47:55 -070099 int64_t ts_diff;
100 if (last_timestamp_ == -1) {
101 ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
102 } else {
103 ts_diff = unwrapped_timestamp - last_timestamp_;
104 }
Erik Språng27a457d2018-01-12 11:00:21 +0100105
106 if (target_framerate_) {
107 // If input frame rate exceeds target frame rate, either over a one second
108 // averaging window, or if frame interval is below 90% of desired value,
109 // drop frame.
Erik Språng27a457d2018-01-12 11:00:21 +0100110 if (encode_framerate_.Rate(now_ms).value_or(0) > *target_framerate_)
Elad Alon411b49b2019-01-29 14:05:55 +0100111 return Vp8FrameConfig(kNone, kNone, kNone);
Erik Språng27a457d2018-01-12 11:00:21 +0100112
Erik Språngdb9e9d52018-01-22 09:23:11 -0800113 // Primarily check if frame interval is too short using frame timestamps,
114 // as if they are correct they won't be affected by queuing in webrtc.
115 const int64_t expected_frame_interval_90khz =
116 kOneSecond90Khz / *target_framerate_;
117 if (last_timestamp_ != -1 && ts_diff > 0) {
118 if (ts_diff < 85 * expected_frame_interval_90khz / 100) {
Elad Alon411b49b2019-01-29 14:05:55 +0100119 return Vp8FrameConfig(kNone, kNone, kNone);
Erik Språngdb9e9d52018-01-22 09:23:11 -0800120 }
121 } else {
122 // Timestamps looks off, use realtime clock here instead.
123 const int64_t expected_frame_interval_ms = 1000 / *target_framerate_;
124 if (last_frame_time_ms_ != -1 &&
125 now_ms - last_frame_time_ms_ <
126 (85 * expected_frame_interval_ms) / 100) {
Elad Alon411b49b2019-01-29 14:05:55 +0100127 return Vp8FrameConfig(kNone, kNone, kNone);
Erik Språngdb9e9d52018-01-22 09:23:11 -0800128 }
Erik Språng27a457d2018-01-12 11:00:21 +0100129 }
130 }
131
132 if (stats_.first_frame_time_ms_ == -1)
133 stats_.first_frame_time_ms_ = now_ms;
134
sprang916170a2017-05-23 07:47:55 -0700135 // Make sure both frame droppers leak out bits.
136 layers_[0].UpdateDebt(ts_diff / 90);
137 layers_[1].UpdateDebt(ts_diff / 90);
138 last_timestamp_ = timestamp;
Erik Språng27a457d2018-01-12 11:00:21 +0100139 last_frame_time_ms_ = now_ms;
sprang916170a2017-05-23 07:47:55 -0700140
141 TemporalLayerState layer_state = TemporalLayerState::kDrop;
142
Erik Språng2c4c9142015-06-24 11:24:44 +0200143 if (active_layer_ == -1 ||
144 layers_[active_layer_].state != TemporalLayer::State::kDropped) {
sprangafe1f742016-04-12 02:45:13 -0700145 if (last_emitted_tl0_timestamp_ != -1 &&
146 (unwrapped_timestamp - last_emitted_tl0_timestamp_) / 90 >
147 kMaxFrameIntervalMs) {
148 // Too long time has passed since the last frame was emitted, cancel
149 // enough debt to allow a single frame.
150 layers_[0].debt_bytes_ = max_debt_bytes_ - 1;
151 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200152 if (layers_[0].debt_bytes_ > max_debt_bytes_) {
153 // Must drop TL0, encode TL1 instead.
154 if (layers_[1].debt_bytes_ > max_debt_bytes_) {
155 // Must drop both TL0 and TL1.
156 active_layer_ = -1;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000157 } else {
Erik Språng2c4c9142015-06-24 11:24:44 +0200158 active_layer_ = 1;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000159 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200160 } else {
161 active_layer_ = 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000162 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000163 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200164
165 switch (active_layer_) {
166 case 0:
sprang916170a2017-05-23 07:47:55 -0700167 layer_state = TemporalLayerState::kTl0;
sprangafe1f742016-04-12 02:45:13 -0700168 last_emitted_tl0_timestamp_ = unwrapped_timestamp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200169 break;
170 case 1:
sprangf03ea042017-07-13 03:53:51 -0700171 if (layers_[1].state != TemporalLayer::State::kDropped) {
Erik Språngb75d6b82018-08-13 16:05:33 +0200172 if (TimeToSync(unwrapped_timestamp) ||
173 layers_[1].state == TemporalLayer::State::kKeyFrame) {
sprangf03ea042017-07-13 03:53:51 -0700174 last_sync_timestamp_ = unwrapped_timestamp;
175 layer_state = TemporalLayerState::kTl1Sync;
176 } else {
177 layer_state = TemporalLayerState::kTl1;
178 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200179 } else {
sprangf03ea042017-07-13 03:53:51 -0700180 layer_state = last_sync_timestamp_ == unwrapped_timestamp
181 ? TemporalLayerState::kTl1Sync
182 : TemporalLayerState::kTl1;
Erik Språng2c4c9142015-06-24 11:24:44 +0200183 }
184 break;
185 case -1:
sprang916170a2017-05-23 07:47:55 -0700186 layer_state = TemporalLayerState::kDrop;
sprangb0fdfea2016-03-01 05:51:16 -0800187 ++stats_.num_dropped_frames_;
Erik Språng2c4c9142015-06-24 11:24:44 +0200188 break;
189 default:
Erik Språng2c4c9142015-06-24 11:24:44 +0200190 RTC_NOTREACHED();
191 }
192
Elad Alon411b49b2019-01-29 14:05:55 +0100193 Vp8FrameConfig tl_config;
Peter Boström1436c832017-03-27 15:01:49 -0400194 // TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
195 // layers.
196 switch (layer_state) {
sprang916170a2017-05-23 07:47:55 -0700197 case TemporalLayerState::kDrop:
Elad Alon411b49b2019-01-29 14:05:55 +0100198 tl_config = Vp8FrameConfig(kNone, kNone, kNone);
pbos51f083c2017-05-04 06:39:04 -0700199 break;
sprang916170a2017-05-23 07:47:55 -0700200 case TemporalLayerState::kTl0:
Peter Boström1436c832017-03-27 15:01:49 -0400201 // TL0 only references and updates 'last'.
Elad Alon411b49b2019-01-29 14:05:55 +0100202 tl_config = Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700203 tl_config.packetizer_temporal_idx = 0;
pbos51f083c2017-05-04 06:39:04 -0700204 break;
sprang916170a2017-05-23 07:47:55 -0700205 case TemporalLayerState::kTl1:
Peter Boström1436c832017-03-27 15:01:49 -0400206 // TL1 references both 'last' and 'golden' but only updates 'golden'.
Elad Alon411b49b2019-01-29 14:05:55 +0100207 tl_config = Vp8FrameConfig(kReference, kReferenceAndUpdate, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700208 tl_config.packetizer_temporal_idx = 1;
pbos51f083c2017-05-04 06:39:04 -0700209 break;
sprang916170a2017-05-23 07:47:55 -0700210 case TemporalLayerState::kTl1Sync:
Peter Boström1436c832017-03-27 15:01:49 -0400211 // Predict from only TL0 to allow participants to switch to the high
212 // bitrate stream. Updates 'golden' so that TL1 can continue to refer to
213 // and update 'golden' from this point on.
Elad Alon411b49b2019-01-29 14:05:55 +0100214 tl_config = Vp8FrameConfig(kReference, kUpdate, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700215 tl_config.packetizer_temporal_idx = 1;
pbos51f083c2017-05-04 06:39:04 -0700216 break;
Peter Boström1436c832017-03-27 15:01:49 -0400217 }
pbos51f083c2017-05-04 06:39:04 -0700218
pbos1777c5f2017-07-19 17:04:02 -0700219 tl_config.layer_sync = layer_state == TemporalLayerState::kTl1Sync;
Erik Språng59021ba2018-10-03 11:05:16 +0200220 pending_frame_configs_[timestamp] = tl_config;
pbos51f083c2017-05-04 06:39:04 -0700221 return tl_config;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000222}
223
Erik Språngbb60a3a2018-03-19 18:25:10 +0100224void ScreenshareLayers::OnRatesUpdated(
225 const std::vector<uint32_t>& bitrates_bps,
226 int framerate_fps) {
227 RTC_DCHECK_GT(framerate_fps, 0);
228 RTC_DCHECK_GE(bitrates_bps.size(), 1);
229 RTC_DCHECK_LE(bitrates_bps.size(), 2);
230
231 // |bitrates_bps| uses individual rates per layer, but we want to use the
232 // accumulated rate here.
233 uint32_t tl0_kbps = bitrates_bps[0] / 1000;
234 uint32_t tl1_kbps = tl0_kbps;
235 if (bitrates_bps.size() > 1) {
236 tl1_kbps += bitrates_bps[1] / 1000;
237 }
238
sprangac4a90d2016-12-28 05:58:07 -0800239 if (!target_framerate_) {
Erik Språngbb60a3a2018-03-19 18:25:10 +0100240 // First OnRatesUpdated() is called during construction, with the
241 // configured targets as parameters.
242 target_framerate_ = framerate_fps;
sprang0ad0de62017-01-11 05:01:32 -0800243 capture_framerate_ = target_framerate_;
sprangac4a90d2016-12-28 05:58:07 -0800244 bitrate_updated_ = true;
245 } else {
Erik Språnge624d072018-04-11 16:47:27 +0200246 if ((capture_framerate_ &&
247 framerate_fps != static_cast<int>(*capture_framerate_)) ||
248 (tl0_kbps != layers_[0].target_rate_kbps_) ||
249 (tl1_kbps != layers_[1].target_rate_kbps_)) {
250 bitrate_updated_ = true;
251 }
Erik Språngbb60a3a2018-03-19 18:25:10 +0100252
253 if (framerate_fps < 0) {
sprang0ad0de62017-01-11 05:01:32 -0800254 capture_framerate_.reset();
sprangac4a90d2016-12-28 05:58:07 -0800255 } else {
Erik Språngbb60a3a2018-03-19 18:25:10 +0100256 capture_framerate_ = framerate_fps;
sprangac4a90d2016-12-28 05:58:07 -0800257 }
258 }
259
Erik Språngbb60a3a2018-03-19 18:25:10 +0100260 layers_[0].target_rate_kbps_ = tl0_kbps;
261 layers_[1].target_rate_kbps_ = tl1_kbps;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000262}
263
Erik Språng59021ba2018-10-03 11:05:16 +0200264void ScreenshareLayers::OnEncodeDone(uint32_t rtp_timestamp,
265 size_t size_bytes,
266 bool is_keyframe,
267 int qp,
philipel9df33532019-03-04 16:37:50 +0100268 CodecSpecificInfo* info) {
Erik Språng59021ba2018-10-03 11:05:16 +0200269 if (size_bytes == 0) {
Erik Språng2c4c9142015-06-24 11:24:44 +0200270 layers_[active_layer_].state = TemporalLayer::State::kDropped;
sprangb0fdfea2016-03-01 05:51:16 -0800271 ++stats_.num_overshoots_;
Erik Språng2c4c9142015-06-24 11:24:44 +0200272 return;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000273 }
sprangef7228c2015-08-05 02:01:29 -0700274
Elad Alon411b49b2019-01-29 14:05:55 +0100275 absl::optional<Vp8FrameConfig> frame_config;
Erik Språng59021ba2018-10-03 11:05:16 +0200276 auto it = pending_frame_configs_.find(rtp_timestamp);
277 if (it != pending_frame_configs_.end()) {
278 frame_config = it->second;
279 pending_frame_configs_.erase(it);
280
281 if (checker_) {
282 RTC_DCHECK(checker_->CheckTemporalConfig(is_keyframe, *frame_config));
283 }
284 }
285
philipel9df33532019-03-04 16:37:50 +0100286 CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
Erik Språng59021ba2018-10-03 11:05:16 +0200287 if (number_of_temporal_layers_ == 1) {
philipel9df33532019-03-04 16:37:50 +0100288 vp8_info.temporalIdx = kNoTemporalIdx;
289 vp8_info.layerSync = false;
Erik Språng59021ba2018-10-03 11:05:16 +0200290 } else {
291 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(rtp_timestamp);
292 if (frame_config) {
philipel9df33532019-03-04 16:37:50 +0100293 vp8_info.temporalIdx = frame_config->packetizer_temporal_idx;
294 vp8_info.layerSync = frame_config->layer_sync;
Erik Språng59021ba2018-10-03 11:05:16 +0200295 } else {
Elad Alon819661a2019-01-29 17:17:09 +0100296 RTC_DCHECK(is_keyframe);
Erik Språng59021ba2018-10-03 11:05:16 +0200297 }
Elad Alon819661a2019-01-29 17:17:09 +0100298
Erik Språng59021ba2018-10-03 11:05:16 +0200299 if (is_keyframe) {
philipel9df33532019-03-04 16:37:50 +0100300 vp8_info.temporalIdx = 0;
Erik Språng59021ba2018-10-03 11:05:16 +0200301 last_sync_timestamp_ = unwrapped_timestamp;
philipel9df33532019-03-04 16:37:50 +0100302 vp8_info.layerSync = true;
Erik Språng59021ba2018-10-03 11:05:16 +0200303 layers_[0].state = TemporalLayer::State::kKeyFrame;
304 layers_[1].state = TemporalLayer::State::kKeyFrame;
305 active_layer_ = 1;
philipel9df33532019-03-04 16:37:50 +0100306 info->template_structure =
307 GetTemplateStructure(number_of_temporal_layers_);
Erik Språng59021ba2018-10-03 11:05:16 +0200308 }
Elad Alon819661a2019-01-29 17:17:09 +0100309
philipel9df33532019-03-04 16:37:50 +0100310 vp8_info.useExplicitDependencies = true;
311 RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
312 RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
Elad Alon819661a2019-01-29 17:17:09 +0100313
314 // Note that |frame_config| is not derefernced if |is_keyframe|,
315 // meaning it's never dereferenced if the optional may be unset.
316 for (int i = 0; i < static_cast<int>(Buffer::kCount); ++i) {
317 if (!is_keyframe && frame_config->References(static_cast<Buffer>(i))) {
philipel9df33532019-03-04 16:37:50 +0100318 RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
Elad Alon819661a2019-01-29 17:17:09 +0100319 arraysize(CodecSpecificInfoVP8::referencedBuffers));
philipel9df33532019-03-04 16:37:50 +0100320 vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
Elad Alon819661a2019-01-29 17:17:09 +0100321 }
322
323 if (is_keyframe || frame_config->Updates(static_cast<Buffer>(i))) {
philipel9df33532019-03-04 16:37:50 +0100324 RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
Elad Alon819661a2019-01-29 17:17:09 +0100325 arraysize(CodecSpecificInfoVP8::updatedBuffers));
philipel9df33532019-03-04 16:37:50 +0100326 vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
Elad Alon819661a2019-01-29 17:17:09 +0100327 }
328 }
Erik Språng59021ba2018-10-03 11:05:16 +0200329 }
330
Sebastian Janssone64a6882019-03-01 18:04:07 +0100331 encode_framerate_.Update(1, rtc::TimeMillis());
Erik Språng59021ba2018-10-03 11:05:16 +0200332
333 if (number_of_temporal_layers_ == 1)
334 return;
335
336 RTC_DCHECK_NE(-1, active_layer_);
Erik Språng2c4c9142015-06-24 11:24:44 +0200337 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
338 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
339 }
340
341 if (qp != -1)
342 layers_[active_layer_].last_qp = qp;
343
344 if (active_layer_ == 0) {
Erik Språng59021ba2018-10-03 11:05:16 +0200345 layers_[0].debt_bytes_ += size_bytes;
346 layers_[1].debt_bytes_ += size_bytes;
sprangb0fdfea2016-03-01 05:51:16 -0800347 ++stats_.num_tl0_frames_;
348 stats_.tl0_target_bitrate_sum_ += layers_[0].target_rate_kbps_;
349 stats_.tl0_qp_sum_ += qp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200350 } else if (active_layer_ == 1) {
Erik Språng59021ba2018-10-03 11:05:16 +0200351 layers_[1].debt_bytes_ += size_bytes;
sprangb0fdfea2016-03-01 05:51:16 -0800352 ++stats_.num_tl1_frames_;
353 stats_.tl1_target_bitrate_sum_ += layers_[1].target_rate_kbps_;
354 stats_.tl1_qp_sum_ += qp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200355 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000356}
357
philipel9df33532019-03-04 16:37:50 +0100358TemplateStructure ScreenshareLayers::GetTemplateStructure(
359 int num_layers) const {
360 RTC_CHECK_LT(num_layers, 3);
361 RTC_CHECK_GT(num_layers, 0);
362
363 TemplateStructure template_structure;
364 template_structure.num_operating_points = num_layers;
365
366 using Builder = GenericFrameInfo::Builder;
367 switch (num_layers) {
368 case 1: {
369 template_structure.templates = {
370 Builder().T(0).Dtis("S").Build(),
371 Builder().T(0).Dtis("S").Fdiffs({1}).Build(),
372 };
373 return template_structure;
374 }
375 case 2: {
376 template_structure.templates = {
377 Builder().T(0).Dtis("SS").Build(),
378 Builder().T(0).Dtis("SS").Fdiffs({1}).Build(),
379 Builder().T(1).Dtis("-S").Fdiffs({1}).Build(),
380 };
381 return template_structure;
382 }
383 default:
384 RTC_NOTREACHED();
385 // To make the compiler happy!
386 return template_structure;
387 }
388}
389
Erik Språng2c4c9142015-06-24 11:24:44 +0200390bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
sprang2ddb8bd2016-02-04 03:59:52 -0800391 RTC_DCHECK_EQ(1, active_layer_);
henrikg91d6ede2015-09-17 00:24:34 -0700392 RTC_DCHECK_NE(-1, layers_[0].last_qp);
Erik Språng2c4c9142015-06-24 11:24:44 +0200393 if (layers_[1].last_qp == -1) {
394 // First frame in TL1 should only depend on TL0 since there are no
395 // previous frames in TL1.
396 return true;
397 }
398
henrikg91d6ede2015-09-17 00:24:34 -0700399 RTC_DCHECK_NE(-1, last_sync_timestamp_);
Erik Språng2c4c9142015-06-24 11:24:44 +0200400 int64_t timestamp_diff = timestamp - last_sync_timestamp_;
401 if (timestamp_diff > kMaxTimeBetweenSyncs) {
402 // After a certain time, force a sync frame.
403 return true;
404 } else if (timestamp_diff < kMinTimeBetweenSyncs) {
405 // If too soon from previous sync frame, don't issue a new one.
406 return false;
407 }
408 // Issue a sync frame if difference in quality between TL0 and TL1 isn't too
409 // large.
410 if (layers_[0].last_qp - layers_[1].last_qp < kQpDeltaThresholdForSync)
411 return true;
412 return false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000413}
414
sprangc7805db2016-11-25 08:09:43 -0800415uint32_t ScreenshareLayers::GetCodecTargetBitrateKbps() const {
416 uint32_t target_bitrate_kbps = layers_[0].target_rate_kbps_;
417
418 if (number_of_temporal_layers_ > 1) {
419 // Calculate a codec target bitrate. This may be higher than TL0, gaining
420 // quality at the expense of frame rate at TL0. Constraints:
421 // - TL0 frame rate no less than framerate / kMaxTL0FpsReduction.
422 // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
423 target_bitrate_kbps =
424 std::min(layers_[0].target_rate_kbps_ * kMaxTL0FpsReduction,
425 layers_[1].target_rate_kbps_ / kAcceptableTargetOvershoot);
426 }
427
428 return std::max(layers_[0].target_rate_kbps_, target_bitrate_kbps);
429}
430
Anders Carlssonbeabdcb2018-01-24 10:25:15 +0100431bool ScreenshareLayers::UpdateConfiguration(Vp8EncoderConfig* cfg) {
Erik Språngf1414702018-09-12 15:04:08 +0200432 if (min_qp_ == -1 || max_qp_ == -1) {
433 // Store the valid qp range. This must not change during the lifetime of
434 // this class.
435 min_qp_ = cfg->rc_min_quantizer;
436 max_qp_ = cfg->rc_max_quantizer;
437 }
438
Erik Språng08127a92016-11-16 16:41:30 +0100439 bool cfg_updated = false;
sprangc7805db2016-11-25 08:09:43 -0800440 uint32_t target_bitrate_kbps = GetCodecTargetBitrateKbps();
Erik Språng27a457d2018-01-12 11:00:21 +0100441
442 // TODO(sprang): We _really_ need to make an overhaul of this class. :(
443 // If we're dropping frames in order to meet a target framerate, adjust the
444 // bitrate assigned to the encoder so the total average bitrate is correct.
445 float encoder_config_bitrate_kbps = target_bitrate_kbps;
446 if (target_framerate_ && capture_framerate_ &&
447 *target_framerate_ < *capture_framerate_) {
448 encoder_config_bitrate_kbps *=
449 static_cast<float>(*capture_framerate_) / *target_framerate_;
450 }
451
452 if (bitrate_updated_ ||
453 cfg->rc_target_bitrate != encoder_config_bitrate_kbps) {
454 cfg->rc_target_bitrate = encoder_config_bitrate_kbps;
Erik Språng08127a92016-11-16 16:41:30 +0100455
456 // Don't reconfigure qp limits during quality boost frames.
457 if (active_layer_ == -1 ||
458 layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
Erik Språng08127a92016-11-16 16:41:30 +0100459 // After a dropped frame, a frame with max qp will be encoded and the
460 // quality will then ramp up from there. To boost the speed of recovery,
sprang916170a2017-05-23 07:47:55 -0700461 // encode the next frame with lower max qp, if there is sufficient
462 // bandwidth to do so without causing excessive delay.
463 // TL0 is the most important to improve since the errors in this layer
464 // will propagate to TL1.
Erik Språng08127a92016-11-16 16:41:30 +0100465 // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
sprang916170a2017-05-23 07:47:55 -0700466 if (layers_[1].target_rate_kbps_ >= kMinBitrateKbpsForQpBoost) {
467 layers_[0].enhanced_max_qp =
468 min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
469 layers_[1].enhanced_max_qp =
470 min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
471 } else {
472 layers_[0].enhanced_max_qp = -1;
473 layers_[1].enhanced_max_qp = -1;
474 }
Erik Språng08127a92016-11-16 16:41:30 +0100475 }
476
sprang0ad0de62017-01-11 05:01:32 -0800477 if (capture_framerate_) {
sprangac4a90d2016-12-28 05:58:07 -0800478 int avg_frame_size =
sprang0ad0de62017-01-11 05:01:32 -0800479 (target_bitrate_kbps * 1000) / (8 * *capture_framerate_);
sprang916170a2017-05-23 07:47:55 -0700480 // Allow max debt to be the size of a single optimal frame.
481 // TODO(sprang): Determine if this needs to be adjusted by some factor.
482 // (Lower values may cause more frame drops, higher may lead to queuing
483 // delays.)
484 max_debt_bytes_ = avg_frame_size;
Erik Språng08127a92016-11-16 16:41:30 +0100485 }
486
487 bitrate_updated_ = false;
488 cfg_updated = true;
489 }
490
491 // Don't try to update boosts state if not active yet.
492 if (active_layer_ == -1)
493 return cfg_updated;
494
sprangef7228c2015-08-05 02:01:29 -0700495 if (max_qp_ == -1 || number_of_temporal_layers_ <= 1)
Erik Språng08127a92016-11-16 16:41:30 +0100496 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200497
498 // If layer is in the quality boost state (following a dropped frame), update
499 // the configuration with the adjusted (lower) qp and set the state back to
500 // normal.
Erik Språngf1414702018-09-12 15:04:08 +0200501 unsigned int adjusted_max_qp = max_qp_; // Set the normal max qp.
502 if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost) {
503 if (layers_[active_layer_].enhanced_max_qp != -1) {
504 // Bitrate is high enough for quality boost, update max qp.
505 adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
506 }
507 // Regardless of qp, reset the boost state for the next frame.
Erik Språng2c4c9142015-06-24 11:24:44 +0200508 layers_[active_layer_].state = TemporalLayer::State::kNormal;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000509 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200510
511 if (adjusted_max_qp == cfg->rc_max_quantizer)
Erik Språng08127a92016-11-16 16:41:30 +0100512 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200513
514 cfg->rc_max_quantizer = adjusted_max_qp;
Erik Språng08127a92016-11-16 16:41:30 +0100515 cfg_updated = true;
sprangc7805db2016-11-25 08:09:43 -0800516
Erik Språng08127a92016-11-16 16:41:30 +0100517 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200518}
519
520void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
521 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
522 if (debt_reduction_bytes >= debt_bytes_) {
523 debt_bytes_ = 0;
524 } else {
525 debt_bytes_ -= debt_reduction_bytes;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000526 }
527}
sprang@webrtc.org70f74f32014-12-17 10:57:10 +0000528
sprangb0fdfea2016-03-01 05:51:16 -0800529void ScreenshareLayers::UpdateHistograms() {
530 if (stats_.first_frame_time_ms_ == -1)
531 return;
532 int64_t duration_sec =
Sebastian Janssone64a6882019-03-01 18:04:07 +0100533 (rtc::TimeMillis() - stats_.first_frame_time_ms_ + 500) / 1000;
sprangb0fdfea2016-03-01 05:51:16 -0800534 if (duration_sec >= metrics::kMinRunTimeInSeconds) {
535 RTC_HISTOGRAM_COUNTS_10000(
536 "WebRTC.Video.Screenshare.Layer0.FrameRate",
537 (stats_.num_tl0_frames_ + (duration_sec / 2)) / duration_sec);
538 RTC_HISTOGRAM_COUNTS_10000(
539 "WebRTC.Video.Screenshare.Layer1.FrameRate",
540 (stats_.num_tl1_frames_ + (duration_sec / 2)) / duration_sec);
541 int total_frames = stats_.num_tl0_frames_ + stats_.num_tl1_frames_;
asapersson58d992e2016-03-29 02:15:06 -0700542 RTC_HISTOGRAM_COUNTS_10000(
543 "WebRTC.Video.Screenshare.FramesPerDrop",
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +0200544 (stats_.num_dropped_frames_ == 0
545 ? 0
546 : total_frames / stats_.num_dropped_frames_));
asapersson58d992e2016-03-29 02:15:06 -0700547 RTC_HISTOGRAM_COUNTS_10000(
548 "WebRTC.Video.Screenshare.FramesPerOvershoot",
549 (stats_.num_overshoots_ == 0 ? 0
550 : total_frames / stats_.num_overshoots_));
sprangb0fdfea2016-03-01 05:51:16 -0800551 if (stats_.num_tl0_frames_ > 0) {
552 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer0.Qp",
553 stats_.tl0_qp_sum_ / stats_.num_tl0_frames_);
554 RTC_HISTOGRAM_COUNTS_10000(
555 "WebRTC.Video.Screenshare.Layer0.TargetBitrate",
556 stats_.tl0_target_bitrate_sum_ / stats_.num_tl0_frames_);
557 }
558 if (stats_.num_tl1_frames_ > 0) {
559 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer1.Qp",
560 stats_.tl1_qp_sum_ / stats_.num_tl1_frames_);
561 RTC_HISTOGRAM_COUNTS_10000(
562 "WebRTC.Video.Screenshare.Layer1.TargetBitrate",
563 stats_.tl1_target_bitrate_sum_ / stats_.num_tl1_frames_);
564 }
565 }
566}
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000567} // namespace webrtc