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