| Index: webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
|
| diff --git a/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc b/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
|
| index d535c617cd19ae1e028d4dddde655477ac61b1b4..ab1fea641617c7e8d1a96ea713b9b691d4dd22c9 100644
|
| --- a/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
|
| +++ b/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
|
| @@ -26,6 +26,7 @@ static const int kOneSecond90Khz = 90000;
|
| static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5;
|
| static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10;
|
| static const int kQpDeltaThresholdForSync = 8;
|
| +static const int kMinBitrateKbpsForQpBoost = 500;
|
|
|
| const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
|
| const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
|
| @@ -33,8 +34,8 @@ const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
|
| constexpr int ScreenshareLayers::kMaxNumTemporalLayers;
|
|
|
| // Always emit a frame with certain interval, even if bitrate targets have
|
| -// been exceeded.
|
| -const int ScreenshareLayers::kMaxFrameIntervalMs = 2000;
|
| +// been exceeded. This prevents needless keyframe requests.
|
| +const int ScreenshareLayers::kMaxFrameIntervalMs = 3000;
|
|
|
| webrtc::TemporalLayers* ScreenshareTemporalLayersFactory::Create(
|
| int simulcast_id,
|
| @@ -95,7 +96,7 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
| // TODO(pbos): Consider updating only last, and not all buffers.
|
| TemporalLayers::FrameConfig tl_config(
|
| kReferenceAndUpdate, kReferenceAndUpdate, kReferenceAndUpdate);
|
| - tl_config.pattern_idx = static_cast<int>(kTl1);
|
| + tl_config.pattern_idx = static_cast<int>(TemporalLayerState::kTl1);
|
| return tl_config;
|
| }
|
|
|
| @@ -110,7 +111,19 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
| stats_.first_frame_time_ms_ = now_ms;
|
|
|
| int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
|
| - TemporalLayerState layer_state = kDrop;
|
| + int64_t ts_diff;
|
| + if (last_timestamp_ == -1) {
|
| + ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
|
| + } else {
|
| + ts_diff = unwrapped_timestamp - last_timestamp_;
|
| + }
|
| + // Make sure both frame droppers leak out bits.
|
| + layers_[0].UpdateDebt(ts_diff / 90);
|
| + layers_[1].UpdateDebt(ts_diff / 90);
|
| + last_timestamp_ = timestamp;
|
| +
|
| + TemporalLayerState layer_state = TemporalLayerState::kDrop;
|
| +
|
| if (active_layer_ == -1 ||
|
| layers_[active_layer_].state != TemporalLayer::State::kDropped) {
|
| if (last_emitted_tl0_timestamp_ != -1 &&
|
| @@ -135,53 +148,43 @@ TemporalLayers::FrameConfig ScreenshareLayers::UpdateLayerConfig(
|
|
|
| switch (active_layer_) {
|
| case 0:
|
| - layer_state = kTl0;
|
| + layer_state = TemporalLayerState::kTl0;
|
| last_emitted_tl0_timestamp_ = unwrapped_timestamp;
|
| break;
|
| case 1:
|
| if (TimeToSync(unwrapped_timestamp)) {
|
| last_sync_timestamp_ = unwrapped_timestamp;
|
| - layer_state = kTl1Sync;
|
| + layer_state = TemporalLayerState::kTl1Sync;
|
| } else {
|
| - layer_state = kTl1;
|
| + layer_state = TemporalLayerState::kTl1;
|
| }
|
| break;
|
| case -1:
|
| - layer_state = kDrop;
|
| + layer_state = TemporalLayerState::kDrop;
|
| ++stats_.num_dropped_frames_;
|
| break;
|
| default:
|
| RTC_NOTREACHED();
|
| }
|
|
|
| - int64_t ts_diff;
|
| - if (last_timestamp_ == -1) {
|
| - ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
|
| - } else {
|
| - ts_diff = unwrapped_timestamp - last_timestamp_;
|
| - }
|
| - // Make sure both frame droppers leak out bits.
|
| - layers_[0].UpdateDebt(ts_diff / 90);
|
| - layers_[1].UpdateDebt(ts_diff / 90);
|
| - last_timestamp_ = timestamp;
|
| TemporalLayers::FrameConfig tl_config;
|
| // TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
|
| // layers.
|
| switch (layer_state) {
|
| - case kDrop:
|
| + case TemporalLayerState::kDrop:
|
| tl_config = TemporalLayers::FrameConfig(kNone, kNone, kNone);
|
| break;
|
| - case kTl0:
|
| + case TemporalLayerState::kTl0:
|
| // TL0 only references and updates 'last'.
|
| tl_config =
|
| TemporalLayers::FrameConfig(kReferenceAndUpdate, kNone, kNone);
|
| break;
|
| - case kTl1:
|
| + case TemporalLayerState::kTl1:
|
| // TL1 references both 'last' and 'golden' but only updates 'golden'.
|
| tl_config =
|
| TemporalLayers::FrameConfig(kReference, kReferenceAndUpdate, kNone);
|
| break;
|
| - case kTl1Sync:
|
| + case TemporalLayerState::kTl1Sync:
|
| // Predict from only TL0 to allow participants to switch to the high
|
| // bitrate stream. Updates 'golden' so that TL1 can continue to refer to
|
| // and update 'golden' from this point on.
|
| @@ -275,14 +278,14 @@ void ScreenshareLayers::PopulateCodecSpecific(
|
| TemporalLayerState layer_state =
|
| static_cast<TemporalLayerState>(tl_config.pattern_idx);
|
| switch (layer_state) {
|
| - case kDrop:
|
| + case TemporalLayerState::kDrop:
|
| RTC_NOTREACHED();
|
| break;
|
| - case kTl0:
|
| + case TemporalLayerState::kTl0:
|
| vp8_info->temporalIdx = 0;
|
| break;
|
| - case kTl1:
|
| - case kTl1Sync:
|
| + case TemporalLayerState::kTl1:
|
| + case TemporalLayerState::kTl1Sync:
|
| vp8_info->temporalIdx = 1;
|
| break;
|
| }
|
| @@ -358,17 +361,30 @@ bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
|
| max_qp_ = cfg->rc_max_quantizer;
|
| // After a dropped frame, a frame with max qp will be encoded and the
|
| // quality will then ramp up from there. To boost the speed of recovery,
|
| - // encode the next frame with lower max qp. TL0 is the most important to
|
| - // improve since the errors in this layer will propagate to TL1.
|
| + // encode the next frame with lower max qp, if there is sufficient
|
| + // bandwidth to do so without causing excessive delay.
|
| + // TL0 is the most important to improve since the errors in this layer
|
| + // will propagate to TL1.
|
| // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
|
| - layers_[0].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
|
| - layers_[1].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
|
| + if (layers_[1].target_rate_kbps_ >= kMinBitrateKbpsForQpBoost) {
|
| + layers_[0].enhanced_max_qp =
|
| + min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
|
| + layers_[1].enhanced_max_qp =
|
| + min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
|
| + } else {
|
| + layers_[0].enhanced_max_qp = -1;
|
| + layers_[1].enhanced_max_qp = -1;
|
| + }
|
| }
|
|
|
| if (capture_framerate_) {
|
| int avg_frame_size =
|
| (target_bitrate_kbps * 1000) / (8 * *capture_framerate_);
|
| - max_debt_bytes_ = 4 * avg_frame_size;
|
| + // Allow max debt to be the size of a single optimal frame.
|
| + // TODO(sprang): Determine if this needs to be adjusted by some factor.
|
| + // (Lower values may cause more frame drops, higher may lead to queuing
|
| + // delays.)
|
| + max_debt_bytes_ = avg_frame_size;
|
| }
|
|
|
| bitrate_updated_ = false;
|
| @@ -391,8 +407,6 @@ bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
|
| adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
|
| layers_[active_layer_].state = TemporalLayer::State::kNormal;
|
| } else {
|
| - if (max_qp_ == -1)
|
| - return cfg_updated;
|
| adjusted_max_qp = max_qp_; // Set the normal max qp.
|
| }
|
|
|
|
|