blob: 444c0ccc90f749eb59f4d747b93af0eb0fb5be8f [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"
18#include "rtc_base/checks.h"
Ilya Nikolaevskiy58662912017-10-04 15:07:09 +020019#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "system_wrappers/include/clock.h"
21#include "system_wrappers/include/metrics.h"
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +020022#include "vpx/vp8cx.h"
23#include "vpx/vpx_encoder.h"
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000024
25namespace webrtc {
26
Erik Språng2c4c9142015-06-24 11:24:44 +020027static const int kOneSecond90Khz = 90000;
Erik Språng13044c12017-10-05 12:20:36 +020028static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 2;
29static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 4;
Erik Språng2c4c9142015-06-24 11:24:44 +020030static const int kQpDeltaThresholdForSync = 8;
sprang916170a2017-05-23 07:47:55 -070031static const int kMinBitrateKbpsForQpBoost = 500;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000032
sprang@webrtc.org70f74f32014-12-17 10:57:10 +000033const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
34const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
35
sprang429600d2017-01-26 06:12:26 -080036constexpr int ScreenshareLayers::kMaxNumTemporalLayers;
37
sprangafe1f742016-04-12 02:45:13 -070038// Always emit a frame with certain interval, even if bitrate targets have
sprang916170a2017-05-23 07:47:55 -070039// been exceeded. This prevents needless keyframe requests.
sprang6c4bbfa2017-05-30 10:08:23 -070040const int ScreenshareLayers::kMaxFrameIntervalMs = 2750;
sprangafe1f742016-04-12 02:45:13 -070041
Erik Språng08127a92016-11-16 16:41:30 +010042webrtc::TemporalLayers* ScreenshareTemporalLayersFactory::Create(
43 int simulcast_id,
44 int num_temporal_layers,
45 uint8_t initial_tl0_pic_idx) const {
sprang429600d2017-01-26 06:12:26 -080046 webrtc::TemporalLayers* tl;
47 if (simulcast_id == 0) {
48 tl = new webrtc::ScreenshareLayers(num_temporal_layers, rand(),
49 webrtc::Clock::GetRealTimeClock());
50 } else {
sprang5271ea62017-03-01 01:58:17 -080051 TemporalLayersFactory rt_tl_factory;
sprang429600d2017-01-26 06:12:26 -080052 tl = rt_tl_factory.Create(simulcast_id, num_temporal_layers, rand());
53 }
Erik Språng08127a92016-11-16 16:41:30 +010054 if (listener_)
55 listener_->OnTemporalLayersCreated(simulcast_id, tl);
56 return tl;
57}
58
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +020059std::unique_ptr<webrtc::TemporalLayersChecker>
60ScreenshareTemporalLayersFactory::CreateChecker(
61 int simulcast_id,
62 int temporal_layers,
63 uint8_t initial_tl0_pic_idx) const {
64 webrtc::TemporalLayersChecker* tlc;
65 if (simulcast_id == 0) {
Ilya Nikolaevskiy58662912017-10-04 15:07:09 +020066 tlc =
67 new webrtc::TemporalLayersChecker(temporal_layers, initial_tl0_pic_idx);
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +020068 } else {
69 TemporalLayersFactory rt_tl_factory;
70 return rt_tl_factory.CreateChecker(simulcast_id, temporal_layers,
71 initial_tl0_pic_idx);
72 }
73 return std::unique_ptr<webrtc::TemporalLayersChecker>(tlc);
74}
75
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000076ScreenshareLayers::ScreenshareLayers(int num_temporal_layers,
sprangb0fdfea2016-03-01 05:51:16 -080077 uint8_t initial_tl0_pic_idx,
78 Clock* clock)
79 : clock_(clock),
sprang429600d2017-01-26 06:12:26 -080080 number_of_temporal_layers_(
81 std::min(kMaxNumTemporalLayers, num_temporal_layers)),
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000082 last_base_layer_sync_(false),
83 tl0_pic_idx_(initial_tl0_pic_idx),
Erik Språng2c4c9142015-06-24 11:24:44 +020084 active_layer_(-1),
85 last_timestamp_(-1),
86 last_sync_timestamp_(-1),
sprangafe1f742016-04-12 02:45:13 -070087 last_emitted_tl0_timestamp_(-1),
Erik Språng27a457d2018-01-12 11:00:21 +010088 last_frame_time_ms_(-1),
Erik Språng2c4c9142015-06-24 11:24:44 +020089 min_qp_(-1),
90 max_qp_(-1),
91 max_debt_bytes_(0),
sprangac4a90d2016-12-28 05:58:07 -080092 encode_framerate_(1000.0f, 1000.0f), // 1 second window, second scale.
Erik Språng08127a92016-11-16 16:41:30 +010093 bitrate_updated_(false) {
sprang429600d2017-01-26 06:12:26 -080094 RTC_CHECK_GT(number_of_temporal_layers_, 0);
95 RTC_CHECK_LE(number_of_temporal_layers_, kMaxNumTemporalLayers);
pbos@webrtc.org9115cde2014-12-09 10:36:40 +000096}
97
sprangb0fdfea2016-03-01 05:51:16 -080098ScreenshareLayers::~ScreenshareLayers() {
99 UpdateHistograms();
100}
101
brandtr080830c2017-05-03 03:25:53 -0700102uint8_t ScreenshareLayers::Tl0PicIdx() const {
103 return tl0_pic_idx_;
104}
105
pbos18ad1d42017-05-04 05:04:46 -0700106TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
107 uint32_t timestamp) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000108 if (number_of_temporal_layers_ <= 1) {
109 // No flags needed for 1 layer screenshare.
Peter Boström1436c832017-03-27 15:01:49 -0400110 // TODO(pbos): Consider updating only last, and not all buffers.
pbos51f083c2017-05-04 06:39:04 -0700111 TemporalLayers::FrameConfig tl_config(
112 kReferenceAndUpdate, kReferenceAndUpdate, kReferenceAndUpdate);
pbos51f083c2017-05-04 06:39:04 -0700113 return tl_config;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000114 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200115
sprangac4a90d2016-12-28 05:58:07 -0800116 const int64_t now_ms = clock_->TimeInMilliseconds();
sprangb0fdfea2016-03-01 05:51:16 -0800117
Erik Språng2c4c9142015-06-24 11:24:44 +0200118 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
sprang916170a2017-05-23 07:47:55 -0700119 int64_t ts_diff;
120 if (last_timestamp_ == -1) {
121 ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
122 } else {
123 ts_diff = unwrapped_timestamp - last_timestamp_;
124 }
Erik Språng27a457d2018-01-12 11:00:21 +0100125
126 if (target_framerate_) {
127 // If input frame rate exceeds target frame rate, either over a one second
128 // averaging window, or if frame interval is below 90% of desired value,
129 // drop frame.
130 // Use real-time clock rather than timestamps, in case there is a
131 // discontinuity in the timestamps sequence.
132 if (encode_framerate_.Rate(now_ms).value_or(0) > *target_framerate_)
133 return TemporalLayers::FrameConfig(kNone, kNone, kNone);
134
135 int64_t expected_frame_interval_ms = 1000 / *target_framerate_;
136 if (last_frame_time_ms_ != -1 &&
137 now_ms - last_frame_time_ms_ < (9 * expected_frame_interval_ms) / 10) {
138 return TemporalLayers::FrameConfig(kNone, kNone, kNone);
139 }
140 }
141
142 if (stats_.first_frame_time_ms_ == -1)
143 stats_.first_frame_time_ms_ = now_ms;
144
sprang916170a2017-05-23 07:47:55 -0700145 // Make sure both frame droppers leak out bits.
146 layers_[0].UpdateDebt(ts_diff / 90);
147 layers_[1].UpdateDebt(ts_diff / 90);
148 last_timestamp_ = timestamp;
Erik Språng27a457d2018-01-12 11:00:21 +0100149 last_frame_time_ms_ = now_ms;
sprang916170a2017-05-23 07:47:55 -0700150
151 TemporalLayerState layer_state = TemporalLayerState::kDrop;
152
Erik Språng2c4c9142015-06-24 11:24:44 +0200153 if (active_layer_ == -1 ||
154 layers_[active_layer_].state != TemporalLayer::State::kDropped) {
sprangafe1f742016-04-12 02:45:13 -0700155 if (last_emitted_tl0_timestamp_ != -1 &&
156 (unwrapped_timestamp - last_emitted_tl0_timestamp_) / 90 >
157 kMaxFrameIntervalMs) {
158 // Too long time has passed since the last frame was emitted, cancel
159 // enough debt to allow a single frame.
160 layers_[0].debt_bytes_ = max_debt_bytes_ - 1;
161 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200162 if (layers_[0].debt_bytes_ > max_debt_bytes_) {
163 // Must drop TL0, encode TL1 instead.
164 if (layers_[1].debt_bytes_ > max_debt_bytes_) {
165 // Must drop both TL0 and TL1.
166 active_layer_ = -1;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000167 } else {
Erik Språng2c4c9142015-06-24 11:24:44 +0200168 active_layer_ = 1;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000169 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200170 } else {
171 active_layer_ = 0;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000172 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000173 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200174
175 switch (active_layer_) {
176 case 0:
sprang916170a2017-05-23 07:47:55 -0700177 layer_state = TemporalLayerState::kTl0;
sprangafe1f742016-04-12 02:45:13 -0700178 last_emitted_tl0_timestamp_ = unwrapped_timestamp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200179 break;
180 case 1:
sprangf03ea042017-07-13 03:53:51 -0700181 if (layers_[1].state != TemporalLayer::State::kDropped) {
182 if (TimeToSync(unwrapped_timestamp)) {
183 last_sync_timestamp_ = unwrapped_timestamp;
184 layer_state = TemporalLayerState::kTl1Sync;
185 } else {
186 layer_state = TemporalLayerState::kTl1;
187 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200188 } else {
sprangf03ea042017-07-13 03:53:51 -0700189 layer_state = last_sync_timestamp_ == unwrapped_timestamp
190 ? TemporalLayerState::kTl1Sync
191 : TemporalLayerState::kTl1;
Erik Språng2c4c9142015-06-24 11:24:44 +0200192 }
193 break;
194 case -1:
sprang916170a2017-05-23 07:47:55 -0700195 layer_state = TemporalLayerState::kDrop;
sprangb0fdfea2016-03-01 05:51:16 -0800196 ++stats_.num_dropped_frames_;
Erik Språng2c4c9142015-06-24 11:24:44 +0200197 break;
198 default:
Erik Språng2c4c9142015-06-24 11:24:44 +0200199 RTC_NOTREACHED();
200 }
201
pbos51f083c2017-05-04 06:39:04 -0700202 TemporalLayers::FrameConfig tl_config;
Peter Boström1436c832017-03-27 15:01:49 -0400203 // TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
204 // layers.
205 switch (layer_state) {
sprang916170a2017-05-23 07:47:55 -0700206 case TemporalLayerState::kDrop:
pbos51f083c2017-05-04 06:39:04 -0700207 tl_config = TemporalLayers::FrameConfig(kNone, kNone, kNone);
208 break;
sprang916170a2017-05-23 07:47:55 -0700209 case TemporalLayerState::kTl0:
Peter Boström1436c832017-03-27 15:01:49 -0400210 // TL0 only references and updates 'last'.
pbos51f083c2017-05-04 06:39:04 -0700211 tl_config =
212 TemporalLayers::FrameConfig(kReferenceAndUpdate, kNone, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700213 tl_config.packetizer_temporal_idx = 0;
pbos51f083c2017-05-04 06:39:04 -0700214 break;
sprang916170a2017-05-23 07:47:55 -0700215 case TemporalLayerState::kTl1:
Peter Boström1436c832017-03-27 15:01:49 -0400216 // TL1 references both 'last' and 'golden' but only updates 'golden'.
pbos51f083c2017-05-04 06:39:04 -0700217 tl_config =
218 TemporalLayers::FrameConfig(kReference, kReferenceAndUpdate, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700219 tl_config.packetizer_temporal_idx = 1;
pbos51f083c2017-05-04 06:39:04 -0700220 break;
sprang916170a2017-05-23 07:47:55 -0700221 case TemporalLayerState::kTl1Sync:
Peter Boström1436c832017-03-27 15:01:49 -0400222 // Predict from only TL0 to allow participants to switch to the high
223 // bitrate stream. Updates 'golden' so that TL1 can continue to refer to
224 // and update 'golden' from this point on.
pbos51f083c2017-05-04 06:39:04 -0700225 tl_config = TemporalLayers::FrameConfig(kReference, kUpdate, kNone);
pbos1777c5f2017-07-19 17:04:02 -0700226 tl_config.packetizer_temporal_idx = 1;
pbos51f083c2017-05-04 06:39:04 -0700227 break;
Peter Boström1436c832017-03-27 15:01:49 -0400228 }
pbos51f083c2017-05-04 06:39:04 -0700229
pbos1777c5f2017-07-19 17:04:02 -0700230 tl_config.layer_sync = layer_state == TemporalLayerState::kTl1Sync;
pbos51f083c2017-05-04 06:39:04 -0700231 return tl_config;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000232}
233
Erik Språng08127a92016-11-16 16:41:30 +0100234std::vector<uint32_t> ScreenshareLayers::OnRatesUpdated(int bitrate_kbps,
235 int max_bitrate_kbps,
236 int framerate) {
sprangac4a90d2016-12-28 05:58:07 -0800237 RTC_DCHECK_GT(framerate, 0);
238 if (!target_framerate_) {
239 // First OnRatesUpdated() is called during construction, with the configured
240 // targets as parameters.
241 target_framerate_.emplace(framerate);
sprang0ad0de62017-01-11 05:01:32 -0800242 capture_framerate_ = target_framerate_;
sprangac4a90d2016-12-28 05:58:07 -0800243 bitrate_updated_ = true;
244 } else {
245 bitrate_updated_ =
246 bitrate_kbps != static_cast<int>(layers_[0].target_rate_kbps_) ||
247 max_bitrate_kbps != static_cast<int>(layers_[1].target_rate_kbps_) ||
sprang0ad0de62017-01-11 05:01:32 -0800248 (capture_framerate_ &&
249 framerate != static_cast<int>(*capture_framerate_));
sprangac4a90d2016-12-28 05:58:07 -0800250 if (framerate < 0) {
sprang0ad0de62017-01-11 05:01:32 -0800251 capture_framerate_.reset();
sprangac4a90d2016-12-28 05:58:07 -0800252 } else {
sprang0ad0de62017-01-11 05:01:32 -0800253 capture_framerate_.emplace(framerate);
sprangac4a90d2016-12-28 05:58:07 -0800254 }
255 }
256
Erik Språng2c4c9142015-06-24 11:24:44 +0200257 layers_[0].target_rate_kbps_ = bitrate_kbps;
258 layers_[1].target_rate_kbps_ = max_bitrate_kbps;
pbos@webrtc.org89042902015-03-20 12:49:38 +0000259
Erik Språng08127a92016-11-16 16:41:30 +0100260 std::vector<uint32_t> allocation;
261 allocation.push_back(bitrate_kbps);
262 if (max_bitrate_kbps > bitrate_kbps)
263 allocation.push_back(max_bitrate_kbps - bitrate_kbps);
264 return allocation;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000265}
266
Peter Boström1436c832017-03-27 15:01:49 -0400267void ScreenshareLayers::FrameEncoded(unsigned int size, int qp) {
sprangac4a90d2016-12-28 05:58:07 -0800268 if (size > 0)
269 encode_framerate_.Update(1, clock_->TimeInMilliseconds());
270
sprang2ddb8bd2016-02-04 03:59:52 -0800271 if (number_of_temporal_layers_ == 1)
272 return;
273
274 RTC_DCHECK_NE(-1, active_layer_);
Erik Språng2c4c9142015-06-24 11:24:44 +0200275 if (size == 0) {
276 layers_[active_layer_].state = TemporalLayer::State::kDropped;
sprangb0fdfea2016-03-01 05:51:16 -0800277 ++stats_.num_overshoots_;
Erik Språng2c4c9142015-06-24 11:24:44 +0200278 return;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000279 }
sprangef7228c2015-08-05 02:01:29 -0700280
Erik Språng2c4c9142015-06-24 11:24:44 +0200281 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
282 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
283 }
284
285 if (qp != -1)
286 layers_[active_layer_].last_qp = qp;
287
288 if (active_layer_ == 0) {
289 layers_[0].debt_bytes_ += size;
290 layers_[1].debt_bytes_ += size;
sprangb0fdfea2016-03-01 05:51:16 -0800291 ++stats_.num_tl0_frames_;
292 stats_.tl0_target_bitrate_sum_ += layers_[0].target_rate_kbps_;
293 stats_.tl0_qp_sum_ += qp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200294 } else if (active_layer_ == 1) {
295 layers_[1].debt_bytes_ += size;
sprangb0fdfea2016-03-01 05:51:16 -0800296 ++stats_.num_tl1_frames_;
297 stats_.tl1_target_bitrate_sum_ += layers_[1].target_rate_kbps_;
298 stats_.tl1_qp_sum_ += qp;
Erik Språng2c4c9142015-06-24 11:24:44 +0200299 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000300}
301
pbos18ad1d42017-05-04 05:04:46 -0700302void ScreenshareLayers::PopulateCodecSpecific(
303 bool frame_is_keyframe,
304 const TemporalLayers::FrameConfig& tl_config,
305 CodecSpecificInfoVP8* vp8_info,
306 uint32_t timestamp) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000307 if (number_of_temporal_layers_ == 1) {
308 vp8_info->temporalIdx = kNoTemporalIdx;
309 vp8_info->layerSync = false;
310 vp8_info->tl0PicIdx = kNoTl0PicIdx;
311 } else {
pbos1777c5f2017-07-19 17:04:02 -0700312 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
313 vp8_info->temporalIdx = tl_config.packetizer_temporal_idx;
314 vp8_info->layerSync = tl_config.layer_sync;
Peter Boström1436c832017-03-27 15:01:49 -0400315 if (frame_is_keyframe) {
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000316 vp8_info->temporalIdx = 0;
Erik Språng2c4c9142015-06-24 11:24:44 +0200317 last_sync_timestamp_ = unwrapped_timestamp;
pbos1777c5f2017-07-19 17:04:02 -0700318 vp8_info->layerSync = true;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000319 } else if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) {
320 // Regardless of pattern the frame after a base layer sync will always
321 // be a layer sync.
Erik Språng2c4c9142015-06-24 11:24:44 +0200322 last_sync_timestamp_ = unwrapped_timestamp;
pbos1777c5f2017-07-19 17:04:02 -0700323 vp8_info->layerSync = true;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000324 }
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000325 if (vp8_info->temporalIdx == 0) {
326 tl0_pic_idx_++;
327 }
Peter Boström1436c832017-03-27 15:01:49 -0400328 last_base_layer_sync_ = frame_is_keyframe;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000329 vp8_info->tl0PicIdx = tl0_pic_idx_;
330 }
331}
332
Erik Språng2c4c9142015-06-24 11:24:44 +0200333bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
sprang2ddb8bd2016-02-04 03:59:52 -0800334 RTC_DCHECK_EQ(1, active_layer_);
henrikg91d6ede2015-09-17 00:24:34 -0700335 RTC_DCHECK_NE(-1, layers_[0].last_qp);
Erik Språng2c4c9142015-06-24 11:24:44 +0200336 if (layers_[1].last_qp == -1) {
337 // First frame in TL1 should only depend on TL0 since there are no
338 // previous frames in TL1.
339 return true;
340 }
341
henrikg91d6ede2015-09-17 00:24:34 -0700342 RTC_DCHECK_NE(-1, last_sync_timestamp_);
Erik Språng2c4c9142015-06-24 11:24:44 +0200343 int64_t timestamp_diff = timestamp - last_sync_timestamp_;
344 if (timestamp_diff > kMaxTimeBetweenSyncs) {
345 // After a certain time, force a sync frame.
346 return true;
347 } else if (timestamp_diff < kMinTimeBetweenSyncs) {
348 // If too soon from previous sync frame, don't issue a new one.
349 return false;
350 }
351 // Issue a sync frame if difference in quality between TL0 and TL1 isn't too
352 // large.
353 if (layers_[0].last_qp - layers_[1].last_qp < kQpDeltaThresholdForSync)
354 return true;
355 return false;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000356}
357
sprangc7805db2016-11-25 08:09:43 -0800358uint32_t ScreenshareLayers::GetCodecTargetBitrateKbps() const {
359 uint32_t target_bitrate_kbps = layers_[0].target_rate_kbps_;
360
361 if (number_of_temporal_layers_ > 1) {
362 // Calculate a codec target bitrate. This may be higher than TL0, gaining
363 // quality at the expense of frame rate at TL0. Constraints:
364 // - TL0 frame rate no less than framerate / kMaxTL0FpsReduction.
365 // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
366 target_bitrate_kbps =
367 std::min(layers_[0].target_rate_kbps_ * kMaxTL0FpsReduction,
368 layers_[1].target_rate_kbps_ / kAcceptableTargetOvershoot);
369 }
370
371 return std::max(layers_[0].target_rate_kbps_, target_bitrate_kbps);
372}
373
Erik Språng2c4c9142015-06-24 11:24:44 +0200374bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
Erik Språng08127a92016-11-16 16:41:30 +0100375 bool cfg_updated = false;
sprangc7805db2016-11-25 08:09:43 -0800376 uint32_t target_bitrate_kbps = GetCodecTargetBitrateKbps();
Erik Språng27a457d2018-01-12 11:00:21 +0100377
378 // TODO(sprang): We _really_ need to make an overhaul of this class. :(
379 // If we're dropping frames in order to meet a target framerate, adjust the
380 // bitrate assigned to the encoder so the total average bitrate is correct.
381 float encoder_config_bitrate_kbps = target_bitrate_kbps;
382 if (target_framerate_ && capture_framerate_ &&
383 *target_framerate_ < *capture_framerate_) {
384 encoder_config_bitrate_kbps *=
385 static_cast<float>(*capture_framerate_) / *target_framerate_;
386 }
387
388 if (bitrate_updated_ ||
389 cfg->rc_target_bitrate != encoder_config_bitrate_kbps) {
390 cfg->rc_target_bitrate = encoder_config_bitrate_kbps;
Erik Språng08127a92016-11-16 16:41:30 +0100391
392 // Don't reconfigure qp limits during quality boost frames.
393 if (active_layer_ == -1 ||
394 layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
395 min_qp_ = cfg->rc_min_quantizer;
396 max_qp_ = cfg->rc_max_quantizer;
397 // After a dropped frame, a frame with max qp will be encoded and the
398 // quality will then ramp up from there. To boost the speed of recovery,
sprang916170a2017-05-23 07:47:55 -0700399 // encode the next frame with lower max qp, if there is sufficient
400 // bandwidth to do so without causing excessive delay.
401 // TL0 is the most important to improve since the errors in this layer
402 // will propagate to TL1.
Erik Språng08127a92016-11-16 16:41:30 +0100403 // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
sprang916170a2017-05-23 07:47:55 -0700404 if (layers_[1].target_rate_kbps_ >= kMinBitrateKbpsForQpBoost) {
405 layers_[0].enhanced_max_qp =
406 min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
407 layers_[1].enhanced_max_qp =
408 min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
409 } else {
410 layers_[0].enhanced_max_qp = -1;
411 layers_[1].enhanced_max_qp = -1;
412 }
Erik Språng08127a92016-11-16 16:41:30 +0100413 }
414
sprang0ad0de62017-01-11 05:01:32 -0800415 if (capture_framerate_) {
sprangac4a90d2016-12-28 05:58:07 -0800416 int avg_frame_size =
sprang0ad0de62017-01-11 05:01:32 -0800417 (target_bitrate_kbps * 1000) / (8 * *capture_framerate_);
sprang916170a2017-05-23 07:47:55 -0700418 // Allow max debt to be the size of a single optimal frame.
419 // TODO(sprang): Determine if this needs to be adjusted by some factor.
420 // (Lower values may cause more frame drops, higher may lead to queuing
421 // delays.)
422 max_debt_bytes_ = avg_frame_size;
Erik Språng08127a92016-11-16 16:41:30 +0100423 }
424
425 bitrate_updated_ = false;
426 cfg_updated = true;
427 }
428
429 // Don't try to update boosts state if not active yet.
430 if (active_layer_ == -1)
431 return cfg_updated;
432
sprangef7228c2015-08-05 02:01:29 -0700433 if (max_qp_ == -1 || number_of_temporal_layers_ <= 1)
Erik Språng08127a92016-11-16 16:41:30 +0100434 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200435
436 // If layer is in the quality boost state (following a dropped frame), update
437 // the configuration with the adjusted (lower) qp and set the state back to
438 // normal.
439 unsigned int adjusted_max_qp;
440 if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost &&
441 layers_[active_layer_].enhanced_max_qp != -1) {
442 adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
443 layers_[active_layer_].state = TemporalLayer::State::kNormal;
444 } else {
Erik Språng2c4c9142015-06-24 11:24:44 +0200445 adjusted_max_qp = max_qp_; // Set the normal max qp.
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000446 }
Erik Språng2c4c9142015-06-24 11:24:44 +0200447
448 if (adjusted_max_qp == cfg->rc_max_quantizer)
Erik Språng08127a92016-11-16 16:41:30 +0100449 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200450
451 cfg->rc_max_quantizer = adjusted_max_qp;
Erik Språng08127a92016-11-16 16:41:30 +0100452 cfg_updated = true;
sprangc7805db2016-11-25 08:09:43 -0800453
Erik Språng08127a92016-11-16 16:41:30 +0100454 return cfg_updated;
Erik Språng2c4c9142015-06-24 11:24:44 +0200455}
456
457void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
458 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
459 if (debt_reduction_bytes >= debt_bytes_) {
460 debt_bytes_ = 0;
461 } else {
462 debt_bytes_ -= debt_reduction_bytes;
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000463 }
464}
sprang@webrtc.org70f74f32014-12-17 10:57:10 +0000465
sprangb0fdfea2016-03-01 05:51:16 -0800466void ScreenshareLayers::UpdateHistograms() {
467 if (stats_.first_frame_time_ms_ == -1)
468 return;
469 int64_t duration_sec =
470 (clock_->TimeInMilliseconds() - stats_.first_frame_time_ms_ + 500) / 1000;
471 if (duration_sec >= metrics::kMinRunTimeInSeconds) {
472 RTC_HISTOGRAM_COUNTS_10000(
473 "WebRTC.Video.Screenshare.Layer0.FrameRate",
474 (stats_.num_tl0_frames_ + (duration_sec / 2)) / duration_sec);
475 RTC_HISTOGRAM_COUNTS_10000(
476 "WebRTC.Video.Screenshare.Layer1.FrameRate",
477 (stats_.num_tl1_frames_ + (duration_sec / 2)) / duration_sec);
478 int total_frames = stats_.num_tl0_frames_ + stats_.num_tl1_frames_;
asapersson58d992e2016-03-29 02:15:06 -0700479 RTC_HISTOGRAM_COUNTS_10000(
480 "WebRTC.Video.Screenshare.FramesPerDrop",
Ilya Nikolaevskiybf352982017-10-02 10:08:25 +0200481 (stats_.num_dropped_frames_ == 0
482 ? 0
483 : total_frames / stats_.num_dropped_frames_));
asapersson58d992e2016-03-29 02:15:06 -0700484 RTC_HISTOGRAM_COUNTS_10000(
485 "WebRTC.Video.Screenshare.FramesPerOvershoot",
486 (stats_.num_overshoots_ == 0 ? 0
487 : total_frames / stats_.num_overshoots_));
sprangb0fdfea2016-03-01 05:51:16 -0800488 if (stats_.num_tl0_frames_ > 0) {
489 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer0.Qp",
490 stats_.tl0_qp_sum_ / stats_.num_tl0_frames_);
491 RTC_HISTOGRAM_COUNTS_10000(
492 "WebRTC.Video.Screenshare.Layer0.TargetBitrate",
493 stats_.tl0_target_bitrate_sum_ / stats_.num_tl0_frames_);
494 }
495 if (stats_.num_tl1_frames_ > 0) {
496 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer1.Qp",
497 stats_.tl1_qp_sum_ / stats_.num_tl1_frames_);
498 RTC_HISTOGRAM_COUNTS_10000(
499 "WebRTC.Video.Screenshare.Layer1.TargetBitrate",
500 stats_.tl1_target_bitrate_sum_ / stats_.num_tl1_frames_);
501 }
502 }
503}
pbos@webrtc.org9115cde2014-12-09 10:36:40 +0000504} // namespace webrtc