From c2a82417e9a9716d2ee1bdb113bb73272b609351 Mon Sep 17 00:00:00 2001 From: Fanny Linderborg Date: Fri, 9 Aug 2024 13:49:29 +0200 Subject: [PATCH] Add support for the Halton sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: b/358039777 Change-Id: Id191d584e22cf82384a5d16ed355f41c0bb32b7b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358981 Reviewed-by: Erik Språng Commit-Queue: Fanny Linderborg Cr-Commit-Position: refs/heads/main@{#42764} --- video/BUILD.gn | 1 + video/corruption_detection/BUILD.gn | 34 +++++++++ video/corruption_detection/halton_sequence.cc | 66 +++++++++++++++++ video/corruption_detection/halton_sequence.h | 48 ++++++++++++ .../halton_sequence_unittest.cc | 73 +++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 video/corruption_detection/BUILD.gn create mode 100644 video/corruption_detection/halton_sequence.cc create mode 100644 video/corruption_detection/halton_sequence.h create mode 100644 video/corruption_detection/halton_sequence_unittest.cc diff --git a/video/BUILD.gn b/video/BUILD.gn index a23d4bb6ce..77b453e077 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -959,6 +959,7 @@ if (rtc_include_tests) { "config:encoder_config", "config:streams_config", "config:video_config_tests", + "corruption_detection:corruption_detection_tests", "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/functional:any_invocable", "//third_party/abseil-cpp/absl/memory", diff --git a/video/corruption_detection/BUILD.gn b/video/corruption_detection/BUILD.gn new file mode 100644 index 0000000000..879639dc91 --- /dev/null +++ b/video/corruption_detection/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright 2024 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. + +import("../../webrtc.gni") + +rtc_library("halton_sequence") { + sources = [ + "halton_sequence.cc", + "halton_sequence.h", + ] + deps = [ "../../rtc_base:checks" ] +} + +if (rtc_include_tests) { + rtc_library("halton_sequence_unittest") { + testonly = true + sources = [ "halton_sequence_unittest.cc" ] + deps = [ + ":halton_sequence", + "../../test/:test_support", + ] + } + + rtc_library("corruption_detection_tests") { + testonly = true + sources = [] + deps = [ ":halton_sequence_unittest" ] + } +} diff --git a/video/corruption_detection/halton_sequence.cc b/video/corruption_detection/halton_sequence.cc new file mode 100644 index 0000000000..e977e903bc --- /dev/null +++ b/video/corruption_detection/halton_sequence.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2024 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 "video/corruption_detection/halton_sequence.h" + +#include +#include + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { + +static constexpr int kMaxDimensions = 5; +const int kBases[kMaxDimensions] = {2, 3, 5, 7, 11}; + +double GetVanDerCorputSequenceElement(int sequence_idx, int base) { + if (sequence_idx < 0 || base < 2) { + sequence_idx = 0; + base = 2; + } + double element = 0.0; + double positional_value = 1.0; + int left = sequence_idx; + while (left > 0) { + positional_value /= base; + element += positional_value * (left % base); + left /= base; + } + return element; +} + +} // namespace + +HaltonSequence::HaltonSequence(int num_dimensions) + : num_dimensions_(num_dimensions), current_idx_(0) { + RTC_CHECK_GE(num_dimensions_, 1) + << "num_dimensions must be >= 1. Will be set to 1."; + RTC_CHECK_LE(num_dimensions_, kMaxDimensions) + << "num_dimensions must be <= " << kMaxDimensions << ". Will be set to " + << kMaxDimensions << "."; + num_dimensions_ = std::clamp(num_dimensions_, 1, kMaxDimensions); +} + +std::vector HaltonSequence::GetNext() { + std::vector point = {}; + point.reserve(num_dimensions_); + for (int i = 0; i < num_dimensions_; ++i) { + point.push_back(GetVanDerCorputSequenceElement(current_idx_, kBases[i])); + } + ++current_idx_; + return point; +} + +void HaltonSequence::Reset() { + HaltonSequence::current_idx_ = 0; +} + +} // namespace webrtc diff --git a/video/corruption_detection/halton_sequence.h b/video/corruption_detection/halton_sequence.h new file mode 100644 index 0000000000..fea7971cb2 --- /dev/null +++ b/video/corruption_detection/halton_sequence.h @@ -0,0 +1,48 @@ +/* + * Copyright 2024 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 VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_ +#define VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_ + +#include + +namespace webrtc { + +// Generates the Halton sequence: a low discrepancy sequence of doubles in the +// half-open interval [0,1). See https://en.wikipedia.org/wiki/Halton_sequence +// for information on how the sequence is constructed. +class HaltonSequence { + public: + // Creates a sequence in `num_dimensions` number of dimensions. Possible + // values are [1, 5]. + explicit HaltonSequence(int num_dimensions); + // Creates a default sequence in a single dimension. + HaltonSequence() = default; + HaltonSequence(const HaltonSequence&) = default; + HaltonSequence(HaltonSequence&&) = default; + HaltonSequence& operator=(const HaltonSequence&) = default; + HaltonSequence& operator=(HaltonSequence&&) = default; + ~HaltonSequence() = default; + + // Gets the next point in the sequence where each value is in the half-open + // interval [0,1). + std::vector GetNext(); + int GetCurrentIndex() const { return current_idx_; } + void SetCurrentIndex(int idx) { current_idx_ = idx; } + void Reset(); + + private: + int num_dimensions_ = 1; + int current_idx_ = 0; +}; + +} // namespace webrtc + +#endif // VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_ diff --git a/video/corruption_detection/halton_sequence_unittest.cc b/video/corruption_detection/halton_sequence_unittest.cc new file mode 100644 index 0000000000..9eedb800f4 --- /dev/null +++ b/video/corruption_detection/halton_sequence_unittest.cc @@ -0,0 +1,73 @@ +/* + * Copyright 2024 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 "video/corruption_detection/halton_sequence.h" + +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::DoubleEq; +using ::testing::ElementsAre; + +TEST(HaltonSequenceTest, ShouldGenerateBase2SequenceByDefault) { + HaltonSequence halton_sequence; + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 2))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 4))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 4))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 8))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(5.0 / 8))); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 8))); +} + +TEST(HaltonSequenceTest, + ShouldGenerateBase2Base3SequencesWhenCreatedAs2Dimensional) { + HaltonSequence halton_sequence(2); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(0.0), DoubleEq(0.0))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(1.0 / 2), DoubleEq(1.0 / 3))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(1.0 / 4), DoubleEq(2.0 / 3))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(3.0 / 4), DoubleEq(1.0 / 9))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(1.0 / 8), DoubleEq(4.0 / 9))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(5.0 / 8), DoubleEq(7.0 / 9))); + EXPECT_THAT(halton_sequence.GetNext(), + ElementsAre(DoubleEq(3.0 / 8), DoubleEq(2.0 / 9))); +} + +TEST(HaltonSequenceTest, ShouldRestartSequenceWhenResetIsCalled) { + HaltonSequence halton_sequence; + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0))); + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 1); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 2))); + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 2); + halton_sequence.Reset(); + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0))); +} + +TEST(HaltonSequenceTest, ShouldSetCurrentIndexWhenSetCurrentIndexIsCalled) { + HaltonSequence halton_sequence; + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0); + halton_sequence.SetCurrentIndex(3); + EXPECT_THAT(halton_sequence.GetCurrentIndex(), 3); + EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 4))); +} + +} // namespace +} // namespace webrtc