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

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/modules/video_coding/media_optimization.h"
      12             : 
      13             : #include "webrtc/base/logging.h"
      14             : #include "webrtc/modules/video_coding/utility/frame_dropper.h"
      15             : #include "webrtc/system_wrappers/include/clock.h"
      16             : 
      17             : namespace webrtc {
      18             : namespace media_optimization {
      19             : 
      20             : struct MediaOptimization::EncodedFrameSample {
      21           0 :   EncodedFrameSample(size_t size_bytes,
      22             :                      uint32_t timestamp,
      23             :                      int64_t time_complete_ms)
      24           0 :       : size_bytes(size_bytes),
      25             :         timestamp(timestamp),
      26           0 :         time_complete_ms(time_complete_ms) {}
      27             : 
      28             :   size_t size_bytes;
      29             :   uint32_t timestamp;
      30             :   int64_t time_complete_ms;
      31             : };
      32             : 
      33           0 : MediaOptimization::MediaOptimization(Clock* clock)
      34             :     : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      35             :       clock_(clock),
      36             :       max_bit_rate_(0),
      37             :       codec_width_(0),
      38             :       codec_height_(0),
      39             :       user_frame_rate_(0),
      40           0 :       frame_dropper_(new FrameDropper),
      41             :       send_statistics_zero_encode_(0),
      42             :       max_payload_size_(1460),
      43             :       video_target_bitrate_(0),
      44             :       incoming_frame_rate_(0),
      45             :       encoded_frame_samples_(),
      46             :       avg_sent_bit_rate_bps_(0),
      47             :       avg_sent_framerate_(0),
      48             :       num_layers_(0),
      49           0 :       loadstate_(kLoadNormal) {
      50           0 :   memset(send_statistics_, 0, sizeof(send_statistics_));
      51           0 :   memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
      52           0 : }
      53             : 
      54           0 : MediaOptimization::~MediaOptimization(void) {
      55           0 : }
      56             : 
      57           0 : void MediaOptimization::Reset() {
      58           0 :   CriticalSectionScoped lock(crit_sect_.get());
      59           0 :   SetEncodingDataInternal(0, 0, 0, 0, 0, 1, 0, max_payload_size_);
      60           0 :   memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
      61           0 :   incoming_frame_rate_ = 0.0;
      62           0 :   frame_dropper_->Reset();
      63           0 :   frame_dropper_->SetRates(0, 0);
      64           0 :   send_statistics_zero_encode_ = 0;
      65           0 :   video_target_bitrate_ = 0;
      66           0 :   codec_width_ = 0;
      67           0 :   codec_height_ = 0;
      68           0 :   min_width_ = 0;
      69           0 :   min_height_ = 0;
      70           0 :   user_frame_rate_ = 0;
      71           0 :   encoded_frame_samples_.clear();
      72           0 :   avg_sent_bit_rate_bps_ = 0;
      73           0 :   num_layers_ = 1;
      74           0 : }
      75             : 
      76             : // Euclid's algorithm
      77             : // on arm, binary may be faster, but we do this rarely
      78           0 : static int GreatestCommonDenominator(int a, int b) {
      79           0 :   while (b != 0) {
      80           0 :     int t = b;
      81           0 :     b = a % b;
      82           0 :     a = t;
      83             :   }
      84           0 :   return a;
      85             : }
      86             : 
      87           0 : void MediaOptimization::SetEncodingData(int32_t max_bit_rate, // bps
      88             :                                         uint32_t target_bitrate, // bps
      89             :                                         uint16_t width,
      90             :                                         uint16_t height,
      91             :                                         uint32_t frame_rate, // fps*1000
      92             :                                         uint8_t  divisor,
      93             :                                         int num_layers,
      94             :                                         int32_t mtu) {
      95           0 :   CriticalSectionScoped lock(crit_sect_.get());
      96           0 :   SetEncodingDataInternal(max_bit_rate, target_bitrate, width,
      97           0 :                           height, num_layers, frame_rate, divisor, mtu);
      98           0 : }
      99             : 
     100           0 : void MediaOptimization::SetEncodingDataInternal(int32_t max_bit_rate, // bps
     101             :                                                 uint32_t target_bitrate, // bps
     102             :                                                 uint16_t width,
     103             :                                                 uint16_t height,
     104             :                                                 uint32_t frame_rate, // in fps*1000
     105             :                                                 uint8_t  divisor,
     106             :                                                 int num_layers,
     107             :                                                 int32_t mtu) {
     108             :   // Everything codec specific should be reset here since this means the codec
     109             :   // has changed.
     110             : 
     111           0 :   max_bit_rate_ = max_bit_rate;
     112           0 :   video_target_bitrate_ = target_bitrate;
     113           0 :   float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f;
     114           0 :   frame_dropper_->Reset();
     115           0 :   frame_dropper_->SetRates(target_bitrate_kbps, static_cast<float>(frame_rate) / 1000.0f);
     116           0 :   user_frame_rate_ = static_cast<float>(frame_rate) / 1000.0f;
     117           0 :   codec_width_ = width;
     118           0 :   codec_height_ = height;
     119           0 :   int gcd = GreatestCommonDenominator(codec_width_, codec_height_);
     120           0 :   min_width_ = gcd ? (codec_width_/gcd * divisor) : 0;
     121           0 :   min_height_ = gcd ? (codec_height_/gcd * divisor) : 0;
     122           0 :   num_layers_ = (num_layers <= 1) ? 1 : num_layers;  // Can also be zero.
     123           0 :   max_payload_size_ = mtu;
     124           0 : }
     125             : 
     126           0 : uint32_t MediaOptimization::SetTargetRates(uint32_t target_bitrate) {
     127           0 :   CriticalSectionScoped lock(crit_sect_.get());
     128           0 :   LOG(LS_INFO) << "SetTargetRates: " <<  target_bitrate << " bps ";
     129             : 
     130           0 :   video_target_bitrate_ = target_bitrate;
     131             : 
     132             :   // Cap target video bitrate to codec maximum.
     133           0 :   if (max_bit_rate_ > 0 && video_target_bitrate_ > max_bit_rate_) {
     134           0 :     video_target_bitrate_ = max_bit_rate_;
     135             :   }
     136             : 
     137             :   // Update encoding rates following protection settings.
     138             :   float target_video_bitrate_kbps =
     139           0 :       static_cast<float>(video_target_bitrate_) / 1000.0f;
     140           0 :   frame_dropper_->SetRates(target_video_bitrate_kbps, incoming_frame_rate_);
     141             : 
     142           0 :   return video_target_bitrate_;
     143             : }
     144             : 
     145           0 : uint32_t MediaOptimization::InputFrameRate() {
     146           0 :   CriticalSectionScoped lock(crit_sect_.get());
     147           0 :   return InputFrameRateInternal();
     148             : }
     149             : 
     150           0 : uint32_t MediaOptimization::InputFrameRateInternal() {
     151           0 :   ProcessIncomingFrameRate(clock_->TimeInMilliseconds());
     152           0 :   return uint32_t(incoming_frame_rate_ + 0.5f);
     153             : }
     154             : 
     155           0 : uint32_t MediaOptimization::SentFrameRate() {
     156           0 :   CriticalSectionScoped lock(crit_sect_.get());
     157           0 :   return SentFrameRateInternal();
     158             : }
     159             : 
     160           0 : uint32_t MediaOptimization::SentFrameRateInternal() {
     161           0 :   PurgeOldFrameSamples(clock_->TimeInMilliseconds());
     162           0 :   UpdateSentFramerate();
     163           0 :   return avg_sent_framerate_;
     164             : }
     165             : 
     166           0 : uint32_t MediaOptimization::SentBitRate() {
     167           0 :   CriticalSectionScoped lock(crit_sect_.get());
     168           0 :   const int64_t now_ms = clock_->TimeInMilliseconds();
     169           0 :   PurgeOldFrameSamples(now_ms);
     170           0 :   UpdateSentBitrate(now_ms);
     171           0 :   return avg_sent_bit_rate_bps_;
     172             : }
     173             : 
     174           0 : int32_t MediaOptimization::UpdateWithEncodedData(
     175             :     const EncodedImage& encoded_image) {
     176           0 :   size_t encoded_length = encoded_image._length;
     177           0 :   uint32_t timestamp = encoded_image._timeStamp;
     178           0 :   CriticalSectionScoped lock(crit_sect_.get());
     179           0 :   const int64_t now_ms = clock_->TimeInMilliseconds();
     180           0 :   PurgeOldFrameSamples(now_ms);
     181           0 :   if (encoded_frame_samples_.size() > 0 &&
     182           0 :       encoded_frame_samples_.back().timestamp == timestamp) {
     183             :     // Frames having the same timestamp are generated from the same input
     184             :     // frame. We don't want to double count them, but only increment the
     185             :     // size_bytes.
     186           0 :     encoded_frame_samples_.back().size_bytes += encoded_length;
     187           0 :     encoded_frame_samples_.back().time_complete_ms = now_ms;
     188             :   } else {
     189           0 :     encoded_frame_samples_.push_back(
     190           0 :         EncodedFrameSample(encoded_length, timestamp, now_ms));
     191             :   }
     192           0 :   UpdateSentBitrate(now_ms);
     193           0 :   UpdateSentFramerate();
     194           0 :   if (encoded_length > 0) {
     195           0 :     const bool delta_frame = encoded_image._frameType != kVideoFrameKey;
     196             :     // XXX TODO(jesup): if same_frame is true, we should be considering it a single
     197             :     // frame here.
     198           0 :     frame_dropper_->Fill(encoded_length, delta_frame);
     199             :   }
     200             : 
     201           0 :   return VCM_OK;
     202             : }
     203             : 
     204           0 : void MediaOptimization::EnableFrameDropper(bool enable) {
     205           0 :   CriticalSectionScoped lock(crit_sect_.get());
     206           0 :   frame_dropper_->Enable(enable);
     207           0 : }
     208             : 
     209           0 : bool MediaOptimization::DropFrame() {
     210           0 :   CriticalSectionScoped lock(crit_sect_.get());
     211           0 :   UpdateIncomingFrameRate();
     212             :   // Leak appropriate number of bytes.
     213           0 :   frame_dropper_->Leak((uint32_t)(InputFrameRateInternal() + 0.5f));
     214           0 :   return frame_dropper_->DropFrame();
     215             : }
     216             : 
     217           0 : void MediaOptimization::UpdateIncomingFrameRate() {
     218           0 :   int64_t now = clock_->TimeInMilliseconds();
     219           0 :   if (incoming_frame_times_[0] == 0) {
     220             :     // No shifting if this is the first time.
     221             :   } else {
     222             :     // Shift all times one step.
     223           0 :     for (int32_t i = (kFrameCountHistorySize - 2); i >= 0; i--) {
     224           0 :       incoming_frame_times_[i + 1] = incoming_frame_times_[i];
     225             :     }
     226             :   }
     227           0 :   incoming_frame_times_[0] = now;
     228           0 :   ProcessIncomingFrameRate(now);
     229           0 : }
     230             : 
     231           0 : void MediaOptimization::PurgeOldFrameSamples(int64_t now_ms) {
     232           0 :   while (!encoded_frame_samples_.empty()) {
     233           0 :     if (now_ms - encoded_frame_samples_.front().time_complete_ms >
     234             :         kBitrateAverageWinMs) {
     235           0 :       encoded_frame_samples_.pop_front();
     236             :     } else {
     237           0 :       break;
     238             :     }
     239             :   }
     240           0 : }
     241             : 
     242           0 : void MediaOptimization::UpdateSentBitrate(int64_t now_ms) {
     243           0 :   if (encoded_frame_samples_.empty()) {
     244           0 :     avg_sent_bit_rate_bps_ = 0;
     245           0 :     return;
     246             :   }
     247           0 :   size_t framesize_sum = 0;
     248           0 :   for (FrameSampleList::iterator it = encoded_frame_samples_.begin();
     249           0 :        it != encoded_frame_samples_.end(); ++it) {
     250           0 :     framesize_sum += it->size_bytes;
     251             :   }
     252             :   float denom = static_cast<float>(
     253           0 :       now_ms - encoded_frame_samples_.front().time_complete_ms);
     254           0 :   if (denom >= 1.0f) {
     255           0 :     avg_sent_bit_rate_bps_ =
     256           0 :         static_cast<uint32_t>(framesize_sum * 8.0f * 1000.0f / denom + 0.5f);
     257             :   } else {
     258           0 :     avg_sent_bit_rate_bps_ = framesize_sum * 8;
     259             :   }
     260             : }
     261             : 
     262           0 : void MediaOptimization::UpdateSentFramerate() {
     263           0 :   if (encoded_frame_samples_.size() <= 1) {
     264           0 :     avg_sent_framerate_ = encoded_frame_samples_.size();
     265           0 :     return;
     266             :   }
     267           0 :   int denom = encoded_frame_samples_.back().timestamp -
     268           0 :               encoded_frame_samples_.front().timestamp;
     269           0 :   if (denom > 0) {
     270           0 :     avg_sent_framerate_ =
     271           0 :         (90000 * (encoded_frame_samples_.size() - 1) + denom / 2) / denom;
     272             :   } else {
     273           0 :     avg_sent_framerate_ = encoded_frame_samples_.size();
     274             :   }
     275             : }
     276             : 
     277             : // Allowing VCM to keep track of incoming frame rate.
     278           0 : void MediaOptimization::ProcessIncomingFrameRate(int64_t now) {
     279           0 :   int32_t num = 0;
     280           0 :   int32_t nr_of_frames = 0;
     281           0 :   for (num = 1; num < (kFrameCountHistorySize - 1); ++num) {
     282           0 :     if (incoming_frame_times_[num] <= 0 ||
     283             :         // don't use data older than 2 s
     284           0 :         now - incoming_frame_times_[num] > kFrameHistoryWinMs) {
     285             :       break;
     286             :     } else {
     287           0 :       nr_of_frames++;
     288             :     }
     289             :   }
     290           0 :   if (num > 1) {
     291             :     const int64_t diff =
     292           0 :         incoming_frame_times_[0] - incoming_frame_times_[num - 1];
     293           0 :     incoming_frame_rate_ = 0.0;  // No frame rate estimate available.
     294           0 :     if (diff > 0) {
     295           0 :       incoming_frame_rate_ = nr_of_frames * 1000.0f / static_cast<float>(diff);
     296             :     }
     297             :   }
     298           0 : }
     299             : 
     300           0 : void MediaOptimization::SetCPULoadState(CPULoadState state) {
     301           0 :     CriticalSectionScoped lock(crit_sect_.get());
     302           0 :     loadstate_ = state;
     303           0 : }
     304             : 
     305             : }  // namespace media_optimization
     306             : }  // namespace webrtc

Generated by: LCOV version 1.13