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