Home | History | Annotate | Download | only in utility
      1 /*
      2  *  Copyright (c) 2014 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/utility/quality_scaler.h"
     12 
     13 namespace webrtc {
     14 
     15 static const int kMinFps = 10;
     16 static const int kMeasureSeconds = 5;
     17 static const int kFramedropPercentThreshold = 60;
     18 static const int kLowQpThresholdDenominator = 3;
     19 
     20 QualityScaler::QualityScaler()
     21     : num_samples_(0), low_qp_threshold_(-1), downscale_shift_(0) {
     22 }
     23 
     24 void QualityScaler::Init(int max_qp) {
     25   ClearSamples();
     26   downscale_shift_ = 0;
     27   low_qp_threshold_ = max_qp / kLowQpThresholdDenominator ;
     28 }
     29 
     30 void QualityScaler::ReportFramerate(int framerate) {
     31   num_samples_ = static_cast<size_t>(
     32       kMeasureSeconds * (framerate < kMinFps ? kMinFps : framerate));
     33 }
     34 
     35 void QualityScaler::ReportEncodedFrame(int qp) {
     36   average_qp_.AddSample(qp);
     37   framedrop_percent_.AddSample(0);
     38 }
     39 
     40 void QualityScaler::ReportDroppedFrame() {
     41   framedrop_percent_.AddSample(100);
     42 }
     43 
     44 QualityScaler::Resolution QualityScaler::GetScaledResolution(
     45     const I420VideoFrame& frame) {
     46   // Both of these should be set through InitEncode -> Should be set by now.
     47   assert(low_qp_threshold_ >= 0);
     48   assert(num_samples_ > 0);
     49   // Update scale factor.
     50   int avg;
     51   if (framedrop_percent_.GetAverage(num_samples_, &avg) &&
     52       avg >= kFramedropPercentThreshold) {
     53     AdjustScale(false);
     54   } else if (average_qp_.GetAverage(num_samples_, &avg) &&
     55              avg <= low_qp_threshold_) {
     56     AdjustScale(true);
     57   }
     58 
     59   Resolution res;
     60   res.width = frame.width();
     61   res.height = frame.height();
     62 
     63   assert(downscale_shift_ >= 0);
     64   for (int shift = downscale_shift_;
     65        shift > 0 && res.width > 1 && res.height > 1;
     66        --shift) {
     67     res.width >>= 1;
     68     res.height >>= 1;
     69   }
     70 
     71   return res;
     72 }
     73 
     74 const I420VideoFrame& QualityScaler::GetScaledFrame(
     75     const I420VideoFrame& frame) {
     76   Resolution res = GetScaledResolution(frame);
     77   if (res.width == frame.width())
     78     return frame;
     79 
     80   scaler_.Set(frame.width(),
     81               frame.height(),
     82               res.width,
     83               res.height,
     84               kI420,
     85               kI420,
     86               kScaleBox);
     87   if (scaler_.Scale(frame, &scaled_frame_) != 0)
     88     return frame;
     89 
     90   scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms());
     91   scaled_frame_.set_timestamp(frame.timestamp());
     92   scaled_frame_.set_render_time_ms(frame.render_time_ms());
     93 
     94   return scaled_frame_;
     95 }
     96 
     97 QualityScaler::MovingAverage::MovingAverage() : sum_(0) {
     98 }
     99 
    100 void QualityScaler::MovingAverage::AddSample(int sample) {
    101   samples_.push_back(sample);
    102   sum_ += sample;
    103 }
    104 
    105 bool QualityScaler::MovingAverage::GetAverage(size_t num_samples, int* avg) {
    106   assert(num_samples > 0);
    107   if (num_samples > samples_.size())
    108     return false;
    109 
    110   // Remove old samples.
    111   while (num_samples < samples_.size()) {
    112     sum_ -= samples_.front();
    113     samples_.pop_front();
    114   }
    115 
    116   *avg = sum_ / static_cast<int>(num_samples);
    117   return true;
    118 }
    119 
    120 void QualityScaler::MovingAverage::Reset() {
    121   sum_ = 0;
    122   samples_.clear();
    123 }
    124 
    125 void QualityScaler::ClearSamples() {
    126   average_qp_.Reset();
    127   framedrop_percent_.Reset();
    128 }
    129 
    130 void QualityScaler::AdjustScale(bool up) {
    131   downscale_shift_ += up ? -1 : 1;
    132   if (downscale_shift_ < 0)
    133     downscale_shift_ = 0;
    134   ClearSamples();
    135 }
    136 
    137 }  // namespace webrtc
    138