mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
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:
parent
a1ead6f2ab
commit
26341990a1
10 changed files with 229 additions and 161 deletions
|
@ -240,8 +240,6 @@ rtc_source_set("video_coding_utility") {
|
|||
"utility/framerate_controller.h",
|
||||
"utility/ivf_file_writer.cc",
|
||||
"utility/ivf_file_writer.h",
|
||||
"utility/moving_average.cc",
|
||||
"utility/moving_average.h",
|
||||
"utility/quality_scaler.cc",
|
||||
"utility/quality_scaler.h",
|
||||
"utility/simulcast_rate_allocator.cc",
|
||||
|
@ -858,7 +856,6 @@ if (rtc_include_tests) {
|
|||
"utility/frame_dropper_unittest.cc",
|
||||
"utility/framerate_controller_unittest.cc",
|
||||
"utility/ivf_file_writer_unittest.cc",
|
||||
"utility/moving_average_unittest.cc",
|
||||
"utility/quality_scaler_unittest.cc",
|
||||
"utility/simulcast_rate_allocator_unittest.cc",
|
||||
"video_codec_initializer_unittest.cc",
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
|
@ -173,8 +173,8 @@ void QualityScaler::CheckQp() {
|
|||
// If we have not observed at least this many frames we can't make a good
|
||||
// scaling decision.
|
||||
const size_t frames = config_.use_all_drop_reasons
|
||||
? framedrop_percent_all_.size()
|
||||
: framedrop_percent_media_opt_.size();
|
||||
? framedrop_percent_all_.Size()
|
||||
: framedrop_percent_media_opt_.Size();
|
||||
if (frames < kMinFramesNeededToScale) {
|
||||
observed_enough_frames_ = false;
|
||||
return;
|
||||
|
@ -183,8 +183,9 @@ void QualityScaler::CheckQp() {
|
|||
|
||||
// Check if we should scale down due to high frame drop.
|
||||
const absl::optional<int> drop_rate =
|
||||
config_.use_all_drop_reasons ? framedrop_percent_all_.GetAverage()
|
||||
: framedrop_percent_media_opt_.GetAverage();
|
||||
config_.use_all_drop_reasons
|
||||
? framedrop_percent_all_.GetAverageRoundedDown()
|
||||
: framedrop_percent_media_opt_.GetAverageRoundedDown();
|
||||
if (drop_rate && *drop_rate >= kFramedropPercentThreshold) {
|
||||
RTC_LOG(LS_INFO) << "Reporting high QP, framedrop percent " << *drop_rate;
|
||||
ReportQpHigh();
|
||||
|
@ -192,11 +193,12 @@ void QualityScaler::CheckQp() {
|
|||
}
|
||||
|
||||
// Check if we should scale up or down based on QP.
|
||||
const absl::optional<int> avg_qp_high = qp_smoother_high_
|
||||
? qp_smoother_high_->GetAvg()
|
||||
: average_qp_.GetAverage();
|
||||
const absl::optional<int> avg_qp_high =
|
||||
qp_smoother_high_ ? qp_smoother_high_->GetAvg()
|
||||
: average_qp_.GetAverageRoundedDown();
|
||||
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) {
|
||||
RTC_LOG(LS_INFO) << "Checking average QP " << *avg_qp_high << " ("
|
||||
<< *avg_qp_low << ").";
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include "absl/types/optional.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#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/numerics/moving_average.h"
|
||||
#include "rtc_base/sequenced_task_checker.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
@ -79,9 +79,10 @@ class QualityScaler {
|
|||
const VideoEncoder::QpThresholds thresholds_;
|
||||
const int64_t sampling_period_ms_;
|
||||
bool fast_rampup_ RTC_GUARDED_BY(&task_checker_);
|
||||
MovingAverage average_qp_ RTC_GUARDED_BY(&task_checker_);
|
||||
MovingAverage framedrop_percent_media_opt_ RTC_GUARDED_BY(&task_checker_);
|
||||
MovingAverage framedrop_percent_all_ RTC_GUARDED_BY(&task_checker_);
|
||||
rtc::MovingAverage average_qp_ RTC_GUARDED_BY(&task_checker_);
|
||||
rtc::MovingAverage framedrop_percent_media_opt_
|
||||
RTC_GUARDED_BY(&task_checker_);
|
||||
rtc::MovingAverage framedrop_percent_all_ RTC_GUARDED_BY(&task_checker_);
|
||||
|
||||
// Used by QualityScalingExperiment.
|
||||
const bool experiment_enabled_;
|
||||
|
|
|
@ -68,7 +68,7 @@ rtc_source_set("compile_assert_c") {
|
|||
}
|
||||
|
||||
# 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.
|
||||
rtc_source_set("rtc_base_approved") {
|
||||
visibility = [ "*" ]
|
||||
|
@ -656,6 +656,8 @@ rtc_static_library("rtc_numerics") {
|
|||
sources = [
|
||||
"numerics/exp_filter.cc",
|
||||
"numerics/exp_filter.h",
|
||||
"numerics/moving_average.cc",
|
||||
"numerics/moving_average.h",
|
||||
"numerics/moving_median_filter.h",
|
||||
"numerics/percentile_filter.h",
|
||||
"numerics/sequence_number_util.h",
|
||||
|
@ -1211,6 +1213,7 @@ if (rtc_include_tests) {
|
|||
|
||||
sources = [
|
||||
"numerics/exp_filter_unittest.cc",
|
||||
"numerics/moving_average_unittest.cc",
|
||||
"numerics/moving_median_filter_unittest.cc",
|
||||
"numerics/percentile_filter_unittest.cc",
|
||||
"numerics/sequence_number_util_unittest.cc",
|
||||
|
|
60
rtc_base/numerics/moving_average.cc
Normal file
60
rtc_base/numerics/moving_average.cc
Normal 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
|
63
rtc_base/numerics/moving_average.h
Normal file
63
rtc_base/numerics/moving_average.h
Normal 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_
|
87
rtc_base/numerics/moving_average_unittest.cc
Normal file
87
rtc_base/numerics/moving_average_unittest.cc
Normal 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
|
Loading…
Reference in a new issue