1 /*
2  *  Copyright (c) 2016 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 "video/quality_threshold.h"
12 
13 #include "rtc_base/checks.h"
14 
15 namespace webrtc {
16 
QualityThreshold(int low_threshold,int high_threshold,float fraction,int max_measurements)17 QualityThreshold::QualityThreshold(int low_threshold,
18                                    int high_threshold,
19                                    float fraction,
20                                    int max_measurements)
21     : buffer_(new int[max_measurements]),
22       max_measurements_(max_measurements),
23       fraction_(fraction),
24       low_threshold_(low_threshold),
25       high_threshold_(high_threshold),
26       until_full_(max_measurements),
27       next_index_(0),
28       sum_(0),
29       count_low_(0),
30       count_high_(0),
31       num_high_states_(0),
32       num_certain_states_(0) {
33   RTC_CHECK_GT(fraction, 0.5f);
34   RTC_CHECK_GT(max_measurements, 1);
35   RTC_CHECK_LT(low_threshold, high_threshold);
36 }
37 
38 QualityThreshold::~QualityThreshold() = default;
39 
AddMeasurement(int measurement)40 void QualityThreshold::AddMeasurement(int measurement) {
41   int prev_val = until_full_ > 0 ? 0 : buffer_[next_index_];
42   buffer_[next_index_] = measurement;
43   next_index_ = (next_index_ + 1) % max_measurements_;
44 
45   sum_ += measurement - prev_val;
46 
47   if (until_full_ == 0) {
48     if (prev_val <= low_threshold_) {
49       --count_low_;
50     } else if (prev_val >= high_threshold_) {
51       --count_high_;
52     }
53   }
54 
55   if (measurement <= low_threshold_) {
56     ++count_low_;
57   } else if (measurement >= high_threshold_) {
58     ++count_high_;
59   }
60 
61   float sufficient_majority = fraction_ * max_measurements_;
62   if (count_high_ >= sufficient_majority) {
63     is_high_ = true;
64   } else if (count_low_ >= sufficient_majority) {
65     is_high_ = false;
66   }
67 
68   if (until_full_ > 0)
69     --until_full_;
70 
71   if (is_high_) {
72     if (*is_high_)
73       ++num_high_states_;
74     ++num_certain_states_;
75   }
76 }
77 
IsHigh() const78 absl::optional<bool> QualityThreshold::IsHigh() const {
79   return is_high_;
80 }
81 
CalculateVariance() const82 absl::optional<double> QualityThreshold::CalculateVariance() const {
83   if (until_full_ > 0) {
84     return absl::nullopt;
85   }
86 
87   double variance = 0;
88   double mean = static_cast<double>(sum_) / max_measurements_;
89   for (int i = 0; i < max_measurements_; ++i) {
90     variance += (buffer_[i] - mean) * (buffer_[i] - mean);
91   }
92   return variance / (max_measurements_ - 1);
93 }
94 
FractionHigh(int min_required_samples) const95 absl::optional<double> QualityThreshold::FractionHigh(
96     int min_required_samples) const {
97   RTC_DCHECK_GT(min_required_samples, 0);
98   if (num_certain_states_ < min_required_samples)
99     return absl::nullopt;
100 
101   return static_cast<double>(num_high_states_) / num_certain_states_;
102 }
103 
104 }  // namespace webrtc
105