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:

committed by
Commit Bot

parent
37651993ed
commit
b968575017
@ -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",
|
||||||
]
|
]
|
||||||
|
69
rtc_base/numerics/moving_median_filter.h
Normal file
69
rtc_base/numerics/moving_median_filter.h
Normal 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_
|
51
rtc_base/numerics/moving_median_filter_unittest.cc
Normal file
51
rtc_base/numerics/moving_median_filter_unittest.cc
Normal 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
|
Reference in New Issue
Block a user