LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8 - screenshare_layers.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 204 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
      11             : 
      12             : #include <stdlib.h>
      13             : 
      14             : #include <algorithm>
      15             : 
      16             : #include "webrtc/base/checks.h"
      17             : #include "vpx/vpx_encoder.h"
      18             : #include "vpx/vp8cx.h"
      19             : #include "webrtc/modules/video_coding/include/video_codec_interface.h"
      20             : #include "webrtc/system_wrappers/include/clock.h"
      21             : #include "webrtc/system_wrappers/include/metrics.h"
      22             : 
      23             : namespace webrtc {
      24             : 
      25             : static const int kOneSecond90Khz = 90000;
      26             : static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5;
      27             : static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10;
      28             : static const int kQpDeltaThresholdForSync = 8;
      29             : 
      30             : const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
      31             : const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
      32             : 
      33             : constexpr int ScreenshareLayers::kMaxNumTemporalLayers;
      34             : 
      35             : // Since this is TL0 we only allow updating and predicting from the LAST
      36             : // reference frame.
      37             : const int ScreenshareLayers::kTl0Flags =
      38             :     VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF |
      39             :     VP8_EFLAG_NO_REF_ARF;
      40             : 
      41             : // Allow predicting from both TL0 and TL1.
      42             : const int ScreenshareLayers::kTl1Flags =
      43             :     VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
      44             : 
      45             : // Allow predicting from only TL0 to allow participants to switch to the high
      46             : // bitrate stream. This means predicting only from the LAST reference frame, but
      47             : // only updating GF to not corrupt TL0.
      48             : const int ScreenshareLayers::kTl1SyncFlags =
      49             :     VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF |
      50             :     VP8_EFLAG_NO_UPD_LAST;
      51             : 
      52             : // Always emit a frame with certain interval, even if bitrate targets have
      53             : // been exceeded.
      54             : const int ScreenshareLayers::kMaxFrameIntervalMs = 2000;
      55             : 
      56           0 : webrtc::TemporalLayers* ScreenshareTemporalLayersFactory::Create(
      57             :     int simulcast_id,
      58             :     int num_temporal_layers,
      59             :     uint8_t initial_tl0_pic_idx) const {
      60             :   webrtc::TemporalLayers* tl;
      61           0 :   if (simulcast_id == 0) {
      62           0 :     tl = new webrtc::ScreenshareLayers(num_temporal_layers, rand(),
      63           0 :                                        webrtc::Clock::GetRealTimeClock());
      64             :   } else {
      65           0 :     RealTimeTemporalLayersFactory rt_tl_factory;
      66           0 :     tl = rt_tl_factory.Create(simulcast_id, num_temporal_layers, rand());
      67             :   }
      68           0 :   if (listener_)
      69           0 :     listener_->OnTemporalLayersCreated(simulcast_id, tl);
      70           0 :   return tl;
      71             : }
      72             : 
      73           0 : ScreenshareLayers::ScreenshareLayers(int num_temporal_layers,
      74             :                                      uint8_t initial_tl0_pic_idx,
      75           0 :                                      Clock* clock)
      76             :     : clock_(clock),
      77             :       number_of_temporal_layers_(
      78           0 :           std::min(kMaxNumTemporalLayers, num_temporal_layers)),
      79             :       last_base_layer_sync_(false),
      80             :       tl0_pic_idx_(initial_tl0_pic_idx),
      81             :       active_layer_(-1),
      82             :       last_timestamp_(-1),
      83             :       last_sync_timestamp_(-1),
      84             :       last_emitted_tl0_timestamp_(-1),
      85             :       min_qp_(-1),
      86             :       max_qp_(-1),
      87             :       max_debt_bytes_(0),
      88             :       encode_framerate_(1000.0f, 1000.0f),  // 1 second window, second scale.
      89           0 :       bitrate_updated_(false) {
      90           0 :   RTC_CHECK_GT(number_of_temporal_layers_, 0);
      91           0 :   RTC_CHECK_LE(number_of_temporal_layers_, kMaxNumTemporalLayers);
      92           0 : }
      93             : 
      94           0 : ScreenshareLayers::~ScreenshareLayers() {
      95           0 :   UpdateHistograms();
      96           0 : }
      97             : 
      98           0 : int ScreenshareLayers::CurrentLayerId() const {
      99             :   // Codec does not use temporal layers for screenshare.
     100           0 :   return 0;
     101             : }
     102             : 
     103           0 : int ScreenshareLayers::EncodeFlags(uint32_t timestamp) {
     104           0 :   if (number_of_temporal_layers_ <= 1) {
     105             :     // No flags needed for 1 layer screenshare.
     106           0 :     return 0;
     107             :   }
     108             : 
     109           0 :   const int64_t now_ms = clock_->TimeInMilliseconds();
     110           0 :   if (target_framerate_.value_or(0) > 0 &&
     111           0 :       encode_framerate_.Rate(now_ms).value_or(0) > *target_framerate_) {
     112             :     // Max framerate exceeded, drop frame.
     113           0 :     return -1;
     114             :   }
     115             : 
     116           0 :   if (stats_.first_frame_time_ms_ == -1)
     117           0 :     stats_.first_frame_time_ms_ = now_ms;
     118             : 
     119           0 :   int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
     120           0 :   int flags = 0;
     121           0 :   if (active_layer_ == -1 ||
     122           0 :       layers_[active_layer_].state != TemporalLayer::State::kDropped) {
     123           0 :     if (last_emitted_tl0_timestamp_ != -1 &&
     124           0 :         (unwrapped_timestamp - last_emitted_tl0_timestamp_) / 90 >
     125             :             kMaxFrameIntervalMs) {
     126             :       // Too long time has passed since the last frame was emitted, cancel
     127             :       // enough debt to allow a single frame.
     128           0 :       layers_[0].debt_bytes_ = max_debt_bytes_ - 1;
     129             :     }
     130           0 :     if (layers_[0].debt_bytes_ > max_debt_bytes_) {
     131             :       // Must drop TL0, encode TL1 instead.
     132           0 :       if (layers_[1].debt_bytes_ > max_debt_bytes_) {
     133             :         // Must drop both TL0 and TL1.
     134           0 :         active_layer_ = -1;
     135             :       } else {
     136           0 :         active_layer_ = 1;
     137             :       }
     138             :     } else {
     139           0 :       active_layer_ = 0;
     140             :     }
     141             :   }
     142             : 
     143           0 :   switch (active_layer_) {
     144             :     case 0:
     145           0 :       flags = kTl0Flags;
     146           0 :       last_emitted_tl0_timestamp_ = unwrapped_timestamp;
     147           0 :       break;
     148             :     case 1:
     149           0 :       if (TimeToSync(unwrapped_timestamp)) {
     150           0 :         last_sync_timestamp_ = unwrapped_timestamp;
     151           0 :         flags = kTl1SyncFlags;
     152             :       } else {
     153           0 :         flags = kTl1Flags;
     154             :       }
     155           0 :       break;
     156             :     case -1:
     157           0 :       flags = -1;
     158           0 :       ++stats_.num_dropped_frames_;
     159           0 :       break;
     160             :     default:
     161           0 :       flags = -1;
     162           0 :       RTC_NOTREACHED();
     163             :   }
     164             : 
     165             :   int64_t ts_diff;
     166           0 :   if (last_timestamp_ == -1) {
     167           0 :     ts_diff = kOneSecond90Khz / capture_framerate_.value_or(*target_framerate_);
     168             :   } else {
     169           0 :     ts_diff = unwrapped_timestamp - last_timestamp_;
     170             :   }
     171             :   // Make sure both frame droppers leak out bits.
     172           0 :   layers_[0].UpdateDebt(ts_diff / 90);
     173           0 :   layers_[1].UpdateDebt(ts_diff / 90);
     174           0 :   last_timestamp_ = timestamp;
     175           0 :   return flags;
     176             : }
     177             : 
     178           0 : std::vector<uint32_t> ScreenshareLayers::OnRatesUpdated(int bitrate_kbps,
     179             :                                                         int max_bitrate_kbps,
     180             :                                                         int framerate) {
     181           0 :   RTC_DCHECK_GT(framerate, 0);
     182           0 :   if (!target_framerate_) {
     183             :     // First OnRatesUpdated() is called during construction, with the configured
     184             :     // targets as parameters.
     185           0 :     target_framerate_.emplace(framerate);
     186           0 :     capture_framerate_ = target_framerate_;
     187           0 :     bitrate_updated_ = true;
     188             :   } else {
     189           0 :     bitrate_updated_ =
     190           0 :         bitrate_kbps != static_cast<int>(layers_[0].target_rate_kbps_) ||
     191           0 :         max_bitrate_kbps != static_cast<int>(layers_[1].target_rate_kbps_) ||
     192           0 :         (capture_framerate_ &&
     193           0 :          framerate != static_cast<int>(*capture_framerate_));
     194           0 :     if (framerate < 0) {
     195           0 :       capture_framerate_.reset();
     196             :     } else {
     197           0 :       capture_framerate_.emplace(framerate);
     198             :     }
     199             :   }
     200             : 
     201           0 :   layers_[0].target_rate_kbps_ = bitrate_kbps;
     202           0 :   layers_[1].target_rate_kbps_ = max_bitrate_kbps;
     203             : 
     204           0 :   std::vector<uint32_t> allocation;
     205           0 :   allocation.push_back(bitrate_kbps);
     206           0 :   if (max_bitrate_kbps > bitrate_kbps)
     207           0 :     allocation.push_back(max_bitrate_kbps - bitrate_kbps);
     208           0 :   return allocation;
     209             : }
     210             : 
     211           0 : void ScreenshareLayers::FrameEncoded(unsigned int size,
     212             :                                      uint32_t timestamp,
     213             :                                      int qp) {
     214           0 :   if (size > 0)
     215           0 :     encode_framerate_.Update(1, clock_->TimeInMilliseconds());
     216             : 
     217           0 :   if (number_of_temporal_layers_ == 1)
     218           0 :     return;
     219             : 
     220           0 :   RTC_DCHECK_NE(-1, active_layer_);
     221           0 :   if (size == 0) {
     222           0 :     layers_[active_layer_].state = TemporalLayer::State::kDropped;
     223           0 :     ++stats_.num_overshoots_;
     224           0 :     return;
     225             :   }
     226             : 
     227           0 :   if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
     228           0 :     layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
     229             :   }
     230             : 
     231           0 :   if (qp != -1)
     232           0 :     layers_[active_layer_].last_qp = qp;
     233             : 
     234           0 :   if (active_layer_ == 0) {
     235           0 :     layers_[0].debt_bytes_ += size;
     236           0 :     layers_[1].debt_bytes_ += size;
     237           0 :     ++stats_.num_tl0_frames_;
     238           0 :     stats_.tl0_target_bitrate_sum_ += layers_[0].target_rate_kbps_;
     239           0 :     stats_.tl0_qp_sum_ += qp;
     240           0 :   } else if (active_layer_ == 1) {
     241           0 :     layers_[1].debt_bytes_ += size;
     242           0 :     ++stats_.num_tl1_frames_;
     243           0 :     stats_.tl1_target_bitrate_sum_ += layers_[1].target_rate_kbps_;
     244           0 :     stats_.tl1_qp_sum_ += qp;
     245             :   }
     246             : }
     247             : 
     248           0 : void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync,
     249             :                                               CodecSpecificInfoVP8* vp8_info,
     250             :                                               uint32_t timestamp) {
     251           0 :   int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp);
     252           0 :   if (number_of_temporal_layers_ == 1) {
     253           0 :     vp8_info->temporalIdx = kNoTemporalIdx;
     254           0 :     vp8_info->layerSync = false;
     255           0 :     vp8_info->tl0PicIdx = kNoTl0PicIdx;
     256             :   } else {
     257           0 :     RTC_DCHECK_NE(-1, active_layer_);
     258           0 :     vp8_info->temporalIdx = active_layer_;
     259           0 :     if (base_layer_sync) {
     260           0 :       vp8_info->temporalIdx = 0;
     261           0 :       last_sync_timestamp_ = unwrapped_timestamp;
     262           0 :     } else if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) {
     263             :       // Regardless of pattern the frame after a base layer sync will always
     264             :       // be a layer sync.
     265           0 :       last_sync_timestamp_ = unwrapped_timestamp;
     266             :     }
     267           0 :     vp8_info->layerSync = last_sync_timestamp_ != -1 &&
     268           0 :                           last_sync_timestamp_ == unwrapped_timestamp;
     269           0 :     if (vp8_info->temporalIdx == 0) {
     270           0 :       tl0_pic_idx_++;
     271             :     }
     272           0 :     last_base_layer_sync_ = base_layer_sync;
     273           0 :     vp8_info->tl0PicIdx = tl0_pic_idx_;
     274             :   }
     275           0 : }
     276             : 
     277           0 : bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
     278           0 :   RTC_DCHECK_EQ(1, active_layer_);
     279           0 :   RTC_DCHECK_NE(-1, layers_[0].last_qp);
     280           0 :   if (layers_[1].last_qp == -1) {
     281             :     // First frame in TL1 should only depend on TL0 since there are no
     282             :     // previous frames in TL1.
     283           0 :     return true;
     284             :   }
     285             : 
     286           0 :   RTC_DCHECK_NE(-1, last_sync_timestamp_);
     287           0 :   int64_t timestamp_diff = timestamp - last_sync_timestamp_;
     288           0 :   if (timestamp_diff > kMaxTimeBetweenSyncs) {
     289             :     // After a certain time, force a sync frame.
     290           0 :     return true;
     291           0 :   } else if (timestamp_diff < kMinTimeBetweenSyncs) {
     292             :     // If too soon from previous sync frame, don't issue a new one.
     293           0 :     return false;
     294             :   }
     295             :   // Issue a sync frame if difference in quality between TL0 and TL1 isn't too
     296             :   // large.
     297           0 :   if (layers_[0].last_qp - layers_[1].last_qp < kQpDeltaThresholdForSync)
     298           0 :     return true;
     299           0 :   return false;
     300             : }
     301             : 
     302           0 : uint32_t ScreenshareLayers::GetCodecTargetBitrateKbps() const {
     303           0 :   uint32_t target_bitrate_kbps = layers_[0].target_rate_kbps_;
     304             : 
     305           0 :   if (number_of_temporal_layers_ > 1) {
     306             :     // Calculate a codec target bitrate. This may be higher than TL0, gaining
     307             :     // quality at the expense of frame rate at TL0. Constraints:
     308             :     // - TL0 frame rate no less than framerate / kMaxTL0FpsReduction.
     309             :     // - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
     310           0 :     target_bitrate_kbps =
     311           0 :         std::min(layers_[0].target_rate_kbps_ * kMaxTL0FpsReduction,
     312           0 :                  layers_[1].target_rate_kbps_ / kAcceptableTargetOvershoot);
     313             :   }
     314             : 
     315           0 :   return std::max(layers_[0].target_rate_kbps_, target_bitrate_kbps);
     316             : }
     317             : 
     318           0 : bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
     319           0 :   bool cfg_updated = false;
     320           0 :   uint32_t target_bitrate_kbps = GetCodecTargetBitrateKbps();
     321           0 :   if (bitrate_updated_ || cfg->rc_target_bitrate != target_bitrate_kbps) {
     322           0 :     cfg->rc_target_bitrate = target_bitrate_kbps;
     323             : 
     324             :     // Don't reconfigure qp limits during quality boost frames.
     325           0 :     if (active_layer_ == -1 ||
     326           0 :         layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
     327           0 :       min_qp_ = cfg->rc_min_quantizer;
     328           0 :       max_qp_ = cfg->rc_max_quantizer;
     329             :       // After a dropped frame, a frame with max qp will be encoded and the
     330             :       // quality will then ramp up from there. To boost the speed of recovery,
     331             :       // encode the next frame with lower max qp. TL0 is the most important to
     332             :       // improve since the errors in this layer will propagate to TL1.
     333             :       // Currently, reduce max qp by 20% for TL0 and 15% for TL1.
     334           0 :       layers_[0].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
     335           0 :       layers_[1].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
     336             :     }
     337             : 
     338           0 :     if (capture_framerate_) {
     339             :       int avg_frame_size =
     340           0 :           (target_bitrate_kbps * 1000) / (8 * *capture_framerate_);
     341           0 :       max_debt_bytes_ = 4 * avg_frame_size;
     342             :     }
     343             : 
     344           0 :     bitrate_updated_ = false;
     345           0 :     cfg_updated = true;
     346             :   }
     347             : 
     348             :   // Don't try to update boosts state if not active yet.
     349           0 :   if (active_layer_ == -1)
     350           0 :     return cfg_updated;
     351             : 
     352           0 :   if (max_qp_ == -1 || number_of_temporal_layers_ <= 1)
     353           0 :     return cfg_updated;
     354             : 
     355             :   // If layer is in the quality boost state (following a dropped frame), update
     356             :   // the configuration with the adjusted (lower) qp and set the state back to
     357             :   // normal.
     358             :   unsigned int adjusted_max_qp;
     359           0 :   if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost &&
     360           0 :       layers_[active_layer_].enhanced_max_qp != -1) {
     361           0 :     adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
     362           0 :     layers_[active_layer_].state = TemporalLayer::State::kNormal;
     363             :   } else {
     364           0 :     if (max_qp_ == -1)
     365           0 :       return cfg_updated;
     366           0 :     adjusted_max_qp = max_qp_;  // Set the normal max qp.
     367             :   }
     368             : 
     369           0 :   if (adjusted_max_qp == cfg->rc_max_quantizer)
     370           0 :     return cfg_updated;
     371             : 
     372           0 :   cfg->rc_max_quantizer = adjusted_max_qp;
     373           0 :   cfg_updated = true;
     374             : 
     375           0 :   return cfg_updated;
     376             : }
     377             : 
     378           0 : void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
     379           0 :   uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
     380           0 :   if (debt_reduction_bytes >= debt_bytes_) {
     381           0 :     debt_bytes_ = 0;
     382             :   } else {
     383           0 :     debt_bytes_ -= debt_reduction_bytes;
     384             :   }
     385           0 : }
     386             : 
     387           0 : void ScreenshareLayers::UpdateHistograms() {
     388           0 :   if (stats_.first_frame_time_ms_ == -1)
     389           0 :     return;
     390             :   int64_t duration_sec =
     391           0 :       (clock_->TimeInMilliseconds() - stats_.first_frame_time_ms_ + 500) / 1000;
     392           0 :   if (duration_sec >= metrics::kMinRunTimeInSeconds) {
     393           0 :     RTC_HISTOGRAM_COUNTS_10000(
     394             :         "WebRTC.Video.Screenshare.Layer0.FrameRate",
     395             :         (stats_.num_tl0_frames_ + (duration_sec / 2)) / duration_sec);
     396           0 :     RTC_HISTOGRAM_COUNTS_10000(
     397             :         "WebRTC.Video.Screenshare.Layer1.FrameRate",
     398             :         (stats_.num_tl1_frames_ + (duration_sec / 2)) / duration_sec);
     399           0 :     int total_frames = stats_.num_tl0_frames_ + stats_.num_tl1_frames_;
     400           0 :     RTC_HISTOGRAM_COUNTS_10000(
     401             :         "WebRTC.Video.Screenshare.FramesPerDrop",
     402             :         (stats_.num_dropped_frames_ == 0 ? 0 : total_frames /
     403             :                                                    stats_.num_dropped_frames_));
     404           0 :     RTC_HISTOGRAM_COUNTS_10000(
     405             :         "WebRTC.Video.Screenshare.FramesPerOvershoot",
     406             :         (stats_.num_overshoots_ == 0 ? 0
     407             :                                      : total_frames / stats_.num_overshoots_));
     408           0 :     if (stats_.num_tl0_frames_ > 0) {
     409           0 :       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer0.Qp",
     410             :                                  stats_.tl0_qp_sum_ / stats_.num_tl0_frames_);
     411           0 :       RTC_HISTOGRAM_COUNTS_10000(
     412             :           "WebRTC.Video.Screenshare.Layer0.TargetBitrate",
     413             :           stats_.tl0_target_bitrate_sum_ / stats_.num_tl0_frames_);
     414             :     }
     415           0 :     if (stats_.num_tl1_frames_ > 0) {
     416           0 :       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.Layer1.Qp",
     417             :                                  stats_.tl1_qp_sum_ / stats_.num_tl1_frames_);
     418           0 :       RTC_HISTOGRAM_COUNTS_10000(
     419             :           "WebRTC.Video.Screenshare.Layer1.TargetBitrate",
     420             :           stats_.tl1_target_bitrate_sum_ / stats_.num_tl1_frames_);
     421             :     }
     422             :   }
     423             : }
     424             : 
     425             : }  // namespace webrtc

Generated by: LCOV version 1.13