Add MovingMedianFilter to rtc_base/numerics

This class will be used for filtering remote clock offset in rtp streams.
It is a separate wrapper around PercentileFilter because it will be used
in that form in several places.

Bug: webrtc:8468
Change-Id: If1f6c38ac1ffa02232c1aed5512b92878b1c346a
Reviewed-on: https://webrtc-review.googlesource.com/17841
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20531}
This commit is contained in:
Ilya Nikolaevskiy
2017-11-01 14:01:00 +01:00
committed by Commit Bot
parent 37651993ed
commit b968575017
3 changed files with 122 additions and 0 deletions

View File

@ -402,6 +402,7 @@ 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_median_filter.h",
"numerics/percentile_filter.h", "numerics/percentile_filter.h",
"numerics/sequence_number_util.h", "numerics/sequence_number_util.h",
] ]
@ -997,6 +998,7 @@ if (rtc_include_tests) {
} }
sources = [ sources = [
"numerics/exp_filter_unittest.cc", "numerics/exp_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,69 @@
/*
* Copyright (c) 2017 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_MEDIAN_FILTER_H_
#define RTC_BASE_NUMERICS_MOVING_MEDIAN_FILTER_H_
#include <list>
#include "rtc_base/checks.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/numerics/percentile_filter.h"
namespace webrtc {
// Class to efficiently get moving median filter from a stream of samples.
template <typename T>
class MovingMedianFilter {
public:
// Construct filter. |window_size| is how many latest samples are stored and
// used to take median. |window_size| must be positive.
explicit MovingMedianFilter(size_t window_size);
// Insert a new sample.
void Insert(const T& value);
// Get median over the latest window.
T GetFilteredValue() const;
private:
PercentileFilter<T> percentile_filter_;
std::list<T> samples_;
size_t samples_stored_;
const size_t window_size_;
RTC_DISALLOW_COPY_AND_ASSIGN(MovingMedianFilter);
};
template <typename T>
MovingMedianFilter<T>::MovingMedianFilter(size_t window_size)
: percentile_filter_(0.5f), samples_stored_(0), window_size_(window_size) {
RTC_CHECK_GT(window_size, 0);
}
template <typename T>
void MovingMedianFilter<T>::Insert(const T& value) {
percentile_filter_.Insert(value);
samples_.emplace_back(value);
++samples_stored_;
if (samples_stored_ > window_size_) {
percentile_filter_.Erase(samples_.front());
samples_.pop_front();
--samples_stored_;
}
}
template <typename T>
T MovingMedianFilter<T>::GetFilteredValue() const {
return percentile_filter_.GetPercentileValue();
}
} // namespace webrtc
#endif // RTC_BASE_NUMERICS_MOVING_MEDIAN_FILTER_H_

View File

@ -0,0 +1,51 @@
/*
* Copyright 2017 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_median_filter.h"
#include "test/gtest.h"
namespace webrtc {
TEST(MovingMedianFilterTest, ProcessesNoSamples) {
MovingMedianFilter<int> filter(2);
EXPECT_EQ(0, filter.GetFilteredValue());
}
TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow5) {
MovingMedianFilter<int> filter(5);
const int64_t kSamples[5] = {1, 5, 2, 3, 4};
const int64_t kExpectedFilteredValues[5] = {1, 1, 2, 2, 3};
for (int i = 0; i < 5; ++i) {
filter.Insert(kSamples[i]);
EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue());
}
}
TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow3) {
MovingMedianFilter<int> filter(3);
const int64_t kSamples[5] = {1, 5, 2, 3, 4};
const int64_t kExpectedFilteredValues[5] = {1, 1, 2, 3, 3};
for (int i = 0; i < 5; ++i) {
filter.Insert(kSamples[i]);
EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue());
}
}
TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow1) {
MovingMedianFilter<int> filter(1);
const int64_t kSamples[5] = {1, 5, 2, 3, 4};
const int64_t kExpectedFilteredValues[5] = {1, 5, 2, 3, 4};
for (int i = 0; i < 5; ++i) {
filter.Insert(kSamples[i]);
EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue());
}
}
} // namespace webrtc