Move MovingAverage to rtc_base/numerics and update it.

This utility class is needed in rtcp_rtp. Instead of reimplementing it
again, the existing class is moved to rtc_base, cleaned from unused
features and extended as required for the new usage.

Bug: webrtc:9914
Change-Id: I3b0d83d08d8fa5e1384b4721a93c6a90781948fd
Reviewed-on: https://webrtc-review.googlesource.com/c/109081
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25498}
This commit is contained in:
Ilya Nikolaevskiy 2018-11-05 12:55:18 +01:00 committed by Commit Bot
parent a1ead6f2ab
commit 26341990a1
10 changed files with 229 additions and 161 deletions

View file

@ -240,8 +240,6 @@ rtc_source_set("video_coding_utility") {
"utility/framerate_controller.h", "utility/framerate_controller.h",
"utility/ivf_file_writer.cc", "utility/ivf_file_writer.cc",
"utility/ivf_file_writer.h", "utility/ivf_file_writer.h",
"utility/moving_average.cc",
"utility/moving_average.h",
"utility/quality_scaler.cc", "utility/quality_scaler.cc",
"utility/quality_scaler.h", "utility/quality_scaler.h",
"utility/simulcast_rate_allocator.cc", "utility/simulcast_rate_allocator.cc",
@ -858,7 +856,6 @@ if (rtc_include_tests) {
"utility/frame_dropper_unittest.cc", "utility/frame_dropper_unittest.cc",
"utility/framerate_controller_unittest.cc", "utility/framerate_controller_unittest.cc",
"utility/ivf_file_writer_unittest.cc", "utility/ivf_file_writer_unittest.cc",
"utility/moving_average_unittest.cc",
"utility/quality_scaler_unittest.cc", "utility/quality_scaler_unittest.cc",
"utility/simulcast_rate_allocator_unittest.cc", "utility/simulcast_rate_allocator_unittest.cc",
"video_codec_initializer_unittest.cc", "video_codec_initializer_unittest.cc",

View file

@ -1,47 +0,0 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/utility/moving_average.h"
#include <algorithm>
namespace webrtc {
MovingAverage::MovingAverage(size_t s) : sum_history_(s + 1, 0) {}
MovingAverage::~MovingAverage() = default;
void MovingAverage::AddSample(int sample) {
count_++;
sum_ += sample;
sum_history_[count_ % sum_history_.size()] = sum_;
}
absl::optional<int> MovingAverage::GetAverage() const {
return GetAverage(size());
}
absl::optional<int> MovingAverage::GetAverage(size_t num_samples) const {
if (num_samples > size() || num_samples == 0)
return absl::nullopt;
int sum = sum_ - sum_history_[(count_ - num_samples) % sum_history_.size()];
return sum / static_cast<int>(num_samples);
}
void MovingAverage::Reset() {
count_ = 0;
sum_ = 0;
std::fill(sum_history_.begin(), sum_history_.end(), 0);
}
size_t MovingAverage::size() const {
return std::min(count_, sum_history_.size() - 1);
}
} // namespace webrtc

View file

@ -1,36 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_VIDEO_CODING_UTILITY_MOVING_AVERAGE_H_
#define MODULES_VIDEO_CODING_UTILITY_MOVING_AVERAGE_H_
#include <vector>
#include "absl/types/optional.h"
namespace webrtc {
class MovingAverage {
public:
explicit MovingAverage(size_t s);
~MovingAverage();
void AddSample(int sample);
absl::optional<int> GetAverage() const;
absl::optional<int> GetAverage(size_t num_samples) const;
void Reset();
size_t size() const;
private:
size_t count_ = 0;
int sum_ = 0;
std::vector<int> sum_history_;
};
} // namespace webrtc
#endif // MODULES_VIDEO_CODING_UTILITY_MOVING_AVERAGE_H_

View file

@ -1,62 +0,0 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/utility/moving_average.h"
#include "test/gtest.h"
TEST(MovingAverageTest, EmptyAverage) {
webrtc::MovingAverage moving_average(1);
EXPECT_EQ(0u, moving_average.size());
EXPECT_FALSE(moving_average.GetAverage(0));
}
// Test single value.
TEST(MovingAverageTest, OneElement) {
webrtc::MovingAverage moving_average(1);
moving_average.AddSample(3);
EXPECT_EQ(1u, moving_average.size());
EXPECT_EQ(3, *moving_average.GetAverage());
EXPECT_EQ(3, *moving_average.GetAverage(1));
EXPECT_FALSE(moving_average.GetAverage(2));
}
TEST(MovingAverageTest, GetAverage) {
webrtc::MovingAverage moving_average(1024);
moving_average.AddSample(1);
moving_average.AddSample(1);
moving_average.AddSample(3);
moving_average.AddSample(3);
EXPECT_EQ(*moving_average.GetAverage(4), 2);
EXPECT_EQ(*moving_average.GetAverage(2), 3);
EXPECT_FALSE(moving_average.GetAverage(0));
}
TEST(MovingAverageTest, Reset) {
webrtc::MovingAverage moving_average(5);
moving_average.AddSample(1);
EXPECT_EQ(1, *moving_average.GetAverage(1));
moving_average.Reset();
EXPECT_FALSE(moving_average.GetAverage(1));
EXPECT_FALSE(moving_average.GetAverage(6));
}
TEST(MovingAverageTest, ManySamples) {
webrtc::MovingAverage moving_average(10);
for (int i = 1; i < 11; i++) {
moving_average.AddSample(i);
}
EXPECT_EQ(*moving_average.GetAverage(), 5);
moving_average.Reset();
for (int i = 1; i < 2001; i++) {
moving_average.AddSample(i);
}
EXPECT_EQ(*moving_average.GetAverage(), 1995);
}

View file

@ -173,8 +173,8 @@ void QualityScaler::CheckQp() {
// If we have not observed at least this many frames we can't make a good // If we have not observed at least this many frames we can't make a good
// scaling decision. // scaling decision.
const size_t frames = config_.use_all_drop_reasons const size_t frames = config_.use_all_drop_reasons
? framedrop_percent_all_.size() ? framedrop_percent_all_.Size()
: framedrop_percent_media_opt_.size(); : framedrop_percent_media_opt_.Size();
if (frames < kMinFramesNeededToScale) { if (frames < kMinFramesNeededToScale) {
observed_enough_frames_ = false; observed_enough_frames_ = false;
return; return;
@ -183,8 +183,9 @@ void QualityScaler::CheckQp() {
// Check if we should scale down due to high frame drop. // Check if we should scale down due to high frame drop.
const absl::optional<int> drop_rate = const absl::optional<int> drop_rate =
config_.use_all_drop_reasons ? framedrop_percent_all_.GetAverage() config_.use_all_drop_reasons
: framedrop_percent_media_opt_.GetAverage(); ? framedrop_percent_all_.GetAverageRoundedDown()
: framedrop_percent_media_opt_.GetAverageRoundedDown();
if (drop_rate && *drop_rate >= kFramedropPercentThreshold) { if (drop_rate && *drop_rate >= kFramedropPercentThreshold) {
RTC_LOG(LS_INFO) << "Reporting high QP, framedrop percent " << *drop_rate; RTC_LOG(LS_INFO) << "Reporting high QP, framedrop percent " << *drop_rate;
ReportQpHigh(); ReportQpHigh();
@ -192,11 +193,12 @@ void QualityScaler::CheckQp() {
} }
// Check if we should scale up or down based on QP. // Check if we should scale up or down based on QP.
const absl::optional<int> avg_qp_high = qp_smoother_high_ const absl::optional<int> avg_qp_high =
? qp_smoother_high_->GetAvg() qp_smoother_high_ ? qp_smoother_high_->GetAvg()
: average_qp_.GetAverage(); : average_qp_.GetAverageRoundedDown();
const absl::optional<int> avg_qp_low = const absl::optional<int> avg_qp_low =
qp_smoother_low_ ? qp_smoother_low_->GetAvg() : average_qp_.GetAverage(); qp_smoother_low_ ? qp_smoother_low_->GetAvg()
: average_qp_.GetAverageRoundedDown();
if (avg_qp_high && avg_qp_low) { if (avg_qp_high && avg_qp_low) {
RTC_LOG(LS_INFO) << "Checking average QP " << *avg_qp_high << " (" RTC_LOG(LS_INFO) << "Checking average QP " << *avg_qp_high << " ("
<< *avg_qp_low << ")."; << *avg_qp_low << ").";

View file

@ -17,8 +17,8 @@
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "common_types.h" // NOLINT(build/include) #include "common_types.h" // NOLINT(build/include)
#include "modules/video_coding/utility/moving_average.h"
#include "rtc_base/experiments/quality_scaling_experiment.h" #include "rtc_base/experiments/quality_scaling_experiment.h"
#include "rtc_base/numerics/moving_average.h"
#include "rtc_base/sequenced_task_checker.h" #include "rtc_base/sequenced_task_checker.h"
namespace webrtc { namespace webrtc {
@ -79,9 +79,10 @@ class QualityScaler {
const VideoEncoder::QpThresholds thresholds_; const VideoEncoder::QpThresholds thresholds_;
const int64_t sampling_period_ms_; const int64_t sampling_period_ms_;
bool fast_rampup_ RTC_GUARDED_BY(&task_checker_); bool fast_rampup_ RTC_GUARDED_BY(&task_checker_);
MovingAverage average_qp_ RTC_GUARDED_BY(&task_checker_); rtc::MovingAverage average_qp_ RTC_GUARDED_BY(&task_checker_);
MovingAverage framedrop_percent_media_opt_ RTC_GUARDED_BY(&task_checker_); rtc::MovingAverage framedrop_percent_media_opt_
MovingAverage framedrop_percent_all_ RTC_GUARDED_BY(&task_checker_); RTC_GUARDED_BY(&task_checker_);
rtc::MovingAverage framedrop_percent_all_ RTC_GUARDED_BY(&task_checker_);
// Used by QualityScalingExperiment. // Used by QualityScalingExperiment.
const bool experiment_enabled_; const bool experiment_enabled_;

View file

@ -68,7 +68,7 @@ rtc_source_set("compile_assert_c") {
} }
# The subset of rtc_base approved for use outside of libjingle. # The subset of rtc_base approved for use outside of libjingle.
# TODO(bugs.webrtc.org/9838): Create small and focues build targets and remove # TODO(bugs.webrtc.org/9838): Create small and focused build targets and remove
# the old concept of rtc_base and rtc_base_approved. # the old concept of rtc_base and rtc_base_approved.
rtc_source_set("rtc_base_approved") { rtc_source_set("rtc_base_approved") {
visibility = [ "*" ] visibility = [ "*" ]
@ -656,6 +656,8 @@ rtc_static_library("rtc_numerics") {
sources = [ sources = [
"numerics/exp_filter.cc", "numerics/exp_filter.cc",
"numerics/exp_filter.h", "numerics/exp_filter.h",
"numerics/moving_average.cc",
"numerics/moving_average.h",
"numerics/moving_median_filter.h", "numerics/moving_median_filter.h",
"numerics/percentile_filter.h", "numerics/percentile_filter.h",
"numerics/sequence_number_util.h", "numerics/sequence_number_util.h",
@ -1211,6 +1213,7 @@ if (rtc_include_tests) {
sources = [ sources = [
"numerics/exp_filter_unittest.cc", "numerics/exp_filter_unittest.cc",
"numerics/moving_average_unittest.cc",
"numerics/moving_median_filter_unittest.cc", "numerics/moving_median_filter_unittest.cc",
"numerics/percentile_filter_unittest.cc", "numerics/percentile_filter_unittest.cc",
"numerics/sequence_number_util_unittest.cc", "numerics/sequence_number_util_unittest.cc",

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/numerics/moving_average.h"
#include <algorithm>
#include "rtc_base/checks.h"
namespace rtc {
MovingAverage::MovingAverage(size_t window_size) : history_(window_size, 0) {
// Limit window size to avoid overflow.
RTC_DCHECK_LE(window_size, (int64_t{1} << 32) - 1);
}
MovingAverage::~MovingAverage() = default;
void MovingAverage::AddSample(int sample) {
count_++;
size_t index = count_ % history_.size();
if (count_ > history_.size())
sum_ -= history_[index];
sum_ += sample;
history_[index] = sample;
}
absl::optional<int> MovingAverage::GetAverageRoundedDown() const {
if (count_ == 0)
return absl::nullopt;
return sum_ / Size();
}
absl::optional<int> MovingAverage::GetAverageRoundedToClosest() const {
if (count_ == 0)
return absl::nullopt;
return (sum_ + Size() / 2) / Size();
}
absl::optional<double> MovingAverage::GetUnroundedAverage() const {
if (count_ == 0)
return absl::nullopt;
return sum_ / static_cast<double>(Size());
}
void MovingAverage::Reset() {
count_ = 0;
sum_ = 0;
}
size_t MovingAverage::Size() const {
return std::min(count_, history_.size());
}
} // namespace rtc

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_NUMERICS_MOVING_AVERAGE_H_
#define RTC_BASE_NUMERICS_MOVING_AVERAGE_H_
#include <vector>
#include "absl/types/optional.h"
namespace rtc {
// Calculates average over fixed size window. If there are less than window
// size elements, calculates average of all inserted so far elements.
//
class MovingAverage {
public:
// Maximum supported window size is 2^32 - 1.
explicit MovingAverage(size_t window_size);
~MovingAverage();
// MovingAverage is neither copyable nor movable.
MovingAverage(const MovingAverage&) = delete;
MovingAverage& operator=(const MovingAverage&) = delete;
// Adds new sample. If the window is full, the oldest element is pushed out.
void AddSample(int sample);
// Returns rounded down average of last |window_size| elements or all
// elements if there are not enough of them. Returns nullopt if there were
// no elements added.
absl::optional<int> GetAverageRoundedDown() const;
// Same as above but rounded to the closest integer.
absl::optional<int> GetAverageRoundedToClosest() const;
// Returns unrounded average over the window.
absl::optional<double> GetUnroundedAverage() const;
// Resets to the initial state before any elements were added.
void Reset();
// Returns number of elements in the window.
size_t Size() const;
private:
// Total number of samples added to the class since last reset.
size_t count_ = 0;
// Sum of the samples in the moving window.
int64_t sum_ = 0;
// Circular buffer for all the samples in the moving window.
// Size is always |window_size|
std::vector<int> history_;
};
} // namespace rtc
#endif // RTC_BASE_NUMERICS_MOVING_AVERAGE_H_

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/numerics/moving_average.h"
#include "test/gtest.h"
namespace test {
TEST(MovingAverageTest, EmptyAverage) {
rtc::MovingAverage moving_average(1);
EXPECT_EQ(0u, moving_average.Size());
EXPECT_EQ(absl::nullopt, moving_average.GetAverageRoundedDown());
}
// Test single value.
TEST(MovingAverageTest, OneElement) {
rtc::MovingAverage moving_average(1);
moving_average.AddSample(3);
EXPECT_EQ(1u, moving_average.Size());
EXPECT_EQ(3, *moving_average.GetAverageRoundedDown());
}
TEST(MovingAverageTest, GetAverage) {
rtc::MovingAverage moving_average(1024);
moving_average.AddSample(1);
moving_average.AddSample(1);
moving_average.AddSample(3);
moving_average.AddSample(3);
EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 2);
EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 2);
}
TEST(MovingAverageTest, GetAverageRoundedDownRounds) {
rtc::MovingAverage moving_average(1024);
moving_average.AddSample(1);
moving_average.AddSample(2);
moving_average.AddSample(2);
moving_average.AddSample(2);
EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 1);
}
TEST(MovingAverageTest, GetAverageRoundedToClosestRounds) {
rtc::MovingAverage moving_average(1024);
moving_average.AddSample(1);
moving_average.AddSample(2);
moving_average.AddSample(2);
moving_average.AddSample(2);
EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 2);
}
TEST(MovingAverageTest, Reset) {
rtc::MovingAverage moving_average(5);
moving_average.AddSample(1);
EXPECT_EQ(1, *moving_average.GetAverageRoundedDown());
EXPECT_EQ(1, *moving_average.GetAverageRoundedToClosest());
moving_average.Reset();
EXPECT_FALSE(moving_average.GetAverageRoundedDown());
moving_average.AddSample(10);
EXPECT_EQ(10, *moving_average.GetAverageRoundedDown());
EXPECT_EQ(10, *moving_average.GetAverageRoundedToClosest());
}
TEST(MovingAverageTest, ManySamples) {
rtc::MovingAverage moving_average(10);
for (int i = 1; i < 11; i++) {
moving_average.AddSample(i);
}
EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 5);
EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 6);
for (int i = 1; i < 2001; i++) {
moving_average.AddSample(i);
}
EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 1995);
EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 1996);
}
} // namespace test