blob: 3fd899c912dc90d099d4a545094a046f10454e8c [file] [log] [blame]
/*
* 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_frame_sampler.h"
#include <cstdint>
#include <vector>
#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::_;
using ::testing::AllOf;
using ::testing::DoubleEq;
using ::testing::DoubleNear;
using ::testing::ElementsAre;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::Not;
using Coordinates = HaltonFrameSampler::Coordinates;
// Defaults for sampling tests.
const int kDefaultScaledWidth = 4;
const int kDefaultScaledHeight = 4;
const double kDefaultStdDevGaussianBlur = 0.02;
#if GTEST_HAS_DEATH_TEST
// Defaults for blurring tests.
const int kDefaultWidth = 4;
const int kDefaultHeight = 4;
const int kDefaultStride = 4;
const uint8_t kDefaultData[kDefaultWidth * kDefaultHeight] = {
20, 196, 250, 115, 139, 39, 99, 197, 21, 166, 254, 28, 227, 54, 64, 46};
const int kDefaultRow = 3;
const int kDefaultColumn = 2;
const double kDefaultStdDev = 1.12;
#endif // GTEST_HAS_DEATH_TEST
scoped_refptr<I420Buffer> MakeDefaultI420FrameBuffer() {
// Create an I420 frame of size 4x4.
const int kDefaultLumaWidth = 4;
const int kDefaultLumaHeight = 4;
const int kDefaultChromaWidth = 2;
const uint8_t kDefaultYContent[16] = {20, 196, 250, 115, 139, 39, 99, 197,
21, 166, 254, 28, 227, 54, 64, 46};
const uint8_t kDefaultUContent[4] = {156, 203, 36, 128};
const uint8_t kDefaultVContent[4] = {112, 2, 0, 24};
return I420Buffer::Copy(kDefaultLumaWidth, kDefaultLumaHeight,
kDefaultYContent, kDefaultLumaWidth, kDefaultUContent,
kDefaultChromaWidth, kDefaultVContent,
kDefaultChromaWidth);
}
std::vector<Coordinates> MakeDefaultSampleCoordinates() {
// Coordinates in all planes.
return {{.row = 0.2, .column = 0.7},
{.row = 0.5, .column = 0.9},
{.row = 0.3, .column = 0.7},
{.row = 0.8, .column = 0.4}};
}
TEST(GaussianFilteringTest, ShouldReturnFilteredValueWhenInputIsValid) {
const int kWidth = 8;
const int kHeight = 8;
const int kStride = 8;
const uint8_t kData[kWidth * kHeight] = {
219, 38, 75, 13, 77, 22, 108, 5, //
199, 105, 237, 3, 194, 63, 200, 95, //
116, 21, 224, 21, 79, 210, 138, 3, //
130, 156, 139, 176, 1, 134, 191, 61, //
123, 59, 34, 237, 223, 162, 113, 108, //
146, 210, 214, 110, 50, 205, 135, 18, //
51, 198, 63, 69, 70, 117, 180, 126, //
244, 250, 194, 195, 85, 24, 25, 224};
// Chosing the point in the middle so all pixels are used.
const int kRow = 3;
const int kColumn = 3;
// Resulting in a filter size of 3 pixels.
const double kStdDev = 1;
EXPECT_THAT(GetFilteredElement(kWidth, kHeight, kStride, kData, kRow, kColumn,
kStdDev),
DoubleEq(126.45897447350468));
}
#if GTEST_HAS_DEATH_TEST
TEST(GaussianFilteringTest, ShouldCrashWhenRowIsNegative) {
EXPECT_DEATH(
GetFilteredElement(kDefaultWidth, kDefaultHeight, kDefaultStride,
kDefaultData, -1, kDefaultColumn, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenRowIsOutOfRange) {
EXPECT_DEATH(
GetFilteredElement(kDefaultWidth, 4, kDefaultStride, kDefaultData, 4,
kDefaultColumn, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenColumnIsNegative) {
EXPECT_DEATH(
GetFilteredElement(kDefaultWidth, kDefaultHeight, kDefaultStride,
kDefaultData, kDefaultRow, -1, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenColumnIsOutOfRange) {
EXPECT_DEATH(GetFilteredElement(4, kDefaultHeight, kDefaultStride,
kDefaultData, kDefaultRow, 4, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenStrideIsSmallerThanWidth) {
EXPECT_DEATH(GetFilteredElement(4, kDefaultHeight, 3, kDefaultData,
kDefaultRow, kDefaultColumn, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenStdDevIsNegative) {
EXPECT_DEATH(
GetFilteredElement(kDefaultWidth, kDefaultHeight, kDefaultStride,
kDefaultData, kDefaultRow, kDefaultColumn, -1.0),
_);
}
TEST(GaussianFilteringTest, RoundingErrorsShouldNotHappen) {
// These values should force a rounding error.
constexpr int kWidth = 128;
constexpr int kHeight = 128;
constexpr double kStdDev = 40;
const std::vector<uint8_t> data(kWidth * kHeight, 255);
EXPECT_THAT(GetFilteredElement(kWidth, kHeight, kHeight, data.data(),
kWidth / 2, kHeight / 2, kStdDev),
255);
}
TEST(HaltonFrameSamplerTest, FrameIsNotSampledWhenTimestampsAreEqual) {
HaltonFrameSampler halton_frame_sampler;
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0, /*num_samples=*/1),
Not(IsEmpty()));
EXPECT_DEATH(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0, /*num_samples=*/1),
_);
}
#endif // GTEST_HAS_DEATH_TEST
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputNoFrameBuffer) {
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(GetSampleValuesForFrame(nullptr, kDefaultSampleCoordinates,
kDefaultScaledWidth, kDefaultScaledHeight,
kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputNoCoordinates) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
EXPECT_THAT(
GetSampleValuesForFrame(kDefaultI420Buffer, {}, kDefaultScaledWidth,
kDefaultScaledHeight, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputOutOfRangeCoordinates) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
const std::vector<Coordinates> kSampleCoordinates = {
{.row = 0.2, .column = 0.7},
{.row = 0.5, .column = 1.0},
{.row = 0.3, .column = 0.7},
{.row = 0.8, .column = 0.4}};
EXPECT_THAT(GetSampleValuesForFrame(kDefaultI420Buffer, kSampleCoordinates,
kDefaultScaledWidth, kDefaultScaledHeight,
kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputWidthZero) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(
GetSampleValuesForFrame(kDefaultI420Buffer, kDefaultSampleCoordinates, 0,
kDefaultScaledHeight, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputHeightZero) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(GetSampleValuesForFrame(
kDefaultI420Buffer, kDefaultSampleCoordinates,
kDefaultScaledWidth, 0, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputStdDevNegative) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(
GetSampleValuesForFrame(kDefaultI420Buffer, kDefaultSampleCoordinates,
kDefaultScaledWidth, kDefaultScaledHeight, -1.0),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListWhenUpscaling) {
const scoped_refptr<I420Buffer> kDefaultI420Buffer =
MakeDefaultI420FrameBuffer();
EXPECT_THAT(GetSampleValuesForFrame(kDefaultI420Buffer,
MakeDefaultSampleCoordinates(),
/*scaled_width=*/8, /*scaled_height=*/8,
kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnGivenValueWhenNoScalingOrFilteringIsDefined) {
// 4x4 i420 frame data.
const int kLumaWidth = 4;
const int kLumaHeight = 4;
const int kChromaWidth = 2;
const uint8_t kYContent[16] = {20, 196, 250, 115, 139, 39, 99, 197,
21, 166, 254, 28, 227, 54, 64, 46};
const uint8_t kUContent[4] = {156, 203, 36, 128};
const uint8_t kVContent[4] = {112, 2, 0, 24};
const scoped_refptr<I420Buffer> kI420Buffer =
I420Buffer::Copy(kLumaWidth, kLumaHeight, kYContent, kLumaWidth,
kUContent, kChromaWidth, kVContent, kChromaWidth);
// Coordinates in all planes.
const std::vector<Coordinates> kSampleCoordinates = {
{.row = 0.2, .column = 0.7},
{.row = 0.5, .column = 0.9},
{.row = 0.3, .column = 0.7},
{.row = 0.8, .column = 0.4}};
// No scaling.
const int kScaledWidth = kLumaWidth;
const int kScaledHeight = kLumaHeight;
// No filtering.
const double kStdDevGaussianBlur = 0.02;
EXPECT_THAT(
GetSampleValuesForFrame(kI420Buffer, kSampleCoordinates, kScaledWidth,
kScaledHeight, kStdDevGaussianBlur),
ElementsAre(AllOf(Field(&FilteredSample::value, DoubleEq(156.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(2.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(36.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(64.0)),
Field(&FilteredSample::plane, ImagePlane::kLuma))));
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldScaleTheFrameWhenScalingIsRequested) {
// 4x4 i420 frame data.
const int kLumaWidth = 4;
const int kLumaHeight = 4;
const int kChromaWidth = 2;
const uint8_t kYContent[16] = {20, 196, 250, 115, 139, 39, 99, 197,
21, 166, 254, 28, 227, 54, 64, 46};
const uint8_t kUContent[4] = {156, 203, 36, 128};
const uint8_t kVContent[4] = {112, 2, 0, 24};
const scoped_refptr<I420Buffer> kI420Buffer =
I420Buffer::Copy(kLumaWidth, kLumaHeight, kYContent, kLumaWidth,
kUContent, kChromaWidth, kVContent, kChromaWidth);
// Coordinates in all planes.
const std::vector<Coordinates> kSampleCoordinates = {
{.row = 0.2, .column = 0.7},
{.row = 0.5, .column = 0.9},
{.row = 0.3, .column = 0.7},
{.row = 0.8, .column = 0.4}};
// With scaling.
const int kScaledWidth = 2;
const int kScaledHeight = 2;
// No filtering.
const double kStdDevGaussianBlur = 0.02;
EXPECT_THAT(
GetSampleValuesForFrame(kI420Buffer, kSampleCoordinates, kScaledWidth,
kScaledHeight, kStdDevGaussianBlur),
ElementsAre(AllOf(Field(&FilteredSample::value, DoubleEq(131.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(35.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(131.0)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(98.0)),
Field(&FilteredSample::plane, ImagePlane::kLuma))));
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnFilteredValuesWhenFilteringIsRequested) {
// 8x8 i420 frame data.
const int kLumaWidth = 8;
const int kLumaHeight = 8;
const int kChromaWidth = 4;
const uint8_t kYContent[kLumaWidth * kLumaHeight] = {
219, 38, 75, 13, 77, 22, 108, 5, //
199, 105, 237, 3, 194, 63, 200, 95, //
116, 21, 224, 21, 79, 210, 138, 3, //
130, 156, 139, 176, 1, 134, 191, 61, //
123, 59, 34, 237, 223, 162, 113, 108, //
146, 210, 214, 110, 50, 205, 135, 18, //
51, 198, 63, 69, 70, 117, 180, 126, //
244, 250, 194, 195, 85, 24, 25, 224};
const uint8_t kUContent[16] = {
219, 38, 75, 13, 77, 22, 108, 5, //
199, 105, 237, 3, 194, 63, 200, 95,
};
const uint8_t kVContent[16] = {
123, 59, 34, 237, 223, 162, 113, 108, //
51, 198, 63, 69, 70, 117, 180, 126,
};
const scoped_refptr<I420Buffer> kI420Buffer =
I420Buffer::Copy(kLumaWidth, kLumaHeight, kYContent, kLumaWidth,
kUContent, kChromaWidth, kVContent, kChromaWidth);
// Coordinates in all (YUV) planes.
const std::vector<Coordinates> kSampleCoordinates = {
{.row = 0.2, .column = 0.7},
{.row = 0.5, .column = 0.9},
{.row = 0.3, .column = 0.7},
{.row = 0.8, .column = 0.4}};
// No scaling.
const int kScaledWidth = kLumaWidth;
const int kScaledHeight = kLumaHeight;
// With filtering (kernel size 3x3 minimum required).
const double kStdDevGaussianBlur = 1;
EXPECT_THAT(
GetSampleValuesForFrame(kI420Buffer, kSampleCoordinates, kScaledWidth,
kScaledHeight, kStdDevGaussianBlur),
ElementsAre(
AllOf(Field(&FilteredSample::value, DoubleEq(114.6804322931639)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(109.66816384377159)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(133.7339472739954)),
Field(&FilteredSample::plane, ImagePlane::kChroma)),
AllOf(Field(&FilteredSample::value, DoubleEq(104.43135638243807)),
Field(&FilteredSample::plane, ImagePlane::kLuma))));
}
TEST(HaltonFrameSamplerTest, CoordinatesFollowsHaltonSequence) {
HaltonFrameSampler halton_frame_sampler;
const int kNumSamples = 1;
EXPECT_THAT(halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(0.0)),
Field(&Coordinates::column, DoubleEq(0.0)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 2)),
Field(&Coordinates::column, DoubleEq(1.0 / 3)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 4)),
Field(&Coordinates::column, DoubleEq(2.0 / 3)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(3.0 / 4)),
Field(&Coordinates::column, DoubleEq(1.0 / 9)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 8)),
Field(&Coordinates::column, DoubleEq(4.0 / 9)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(5.0 / 8)),
Field(&Coordinates::column, DoubleEq(7.0 / 9)))));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(kNumSamples),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(3.0 / 8)),
Field(&Coordinates::column, DoubleEq(2.0 / 9)))));
}
TEST(HaltonFrameSamplerTest, GeneratesMultipleSamplesWhenRequested) {
HaltonFrameSampler halton_frame_sampler;
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(3),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(0.0)),
Field(&Coordinates::column, DoubleEq(0.0))),
AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 2)),
Field(&Coordinates::column, DoubleEq(1.0 / 3))),
AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 4)),
Field(&Coordinates::column, DoubleEq(2.0 / 3)))));
}
TEST(HaltonFrameSamplerTest, ShouldChangeIndexWhenRequestedTo) {
HaltonFrameSampler halton_frame_sampler;
halton_frame_sampler.SetCurrentIndex(1);
EXPECT_EQ(halton_frame_sampler.GetCurrentIndex(), 1);
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrame(1),
ElementsAre(AllOf(Field(&Coordinates::row, DoubleEq(1.0 / 2)),
Field(&Coordinates::column, DoubleEq(1.0 / 3)))));
}
TEST(HaltonFrameSamplerTest, FirstFrameIsSampled) {
HaltonFrameSampler halton_frame_sampler;
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0, /*num_samples=*/1),
Not(IsEmpty()));
}
TEST(HaltonFrameSamplerTest,
DeltaFrameFollowingSampledFrameWithTooShortTimeDeltaIsNotSampled) {
HaltonFrameSampler halton_frame_sampler;
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0, /*num_samples=*/1);
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/1, /*num_samples=*/1),
IsEmpty());
}
TEST(HaltonFrameSamplerTest,
DeltaFramesAreSampledBasedOnHowManyFramesHasPassedSinceLastSampledFrame) {
HaltonFrameSampler halton_frame_sampler;
uint32_t rtp_timestamp = 0;
const int kNumSamples = 1;
// The number of frames between each sample is defined as
// 33 - mod(number_of_sampled_frames, 8)
// so the following gets get coverage for [26, 33] two times.
for (int iterations = 0; iterations < 2; ++iterations) {
for (int num_sampled_frames = 0; num_sampled_frames < 8;
++num_sampled_frames) {
EXPECT_THAT(halton_frame_sampler
.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, rtp_timestamp, kNumSamples),
Not(IsEmpty()));
++rtp_timestamp;
for (int num_unsampled_frames = 1;
num_unsampled_frames < 33 - num_sampled_frames;
++num_unsampled_frames) {
EXPECT_THAT(halton_frame_sampler
.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, rtp_timestamp, kNumSamples),
IsEmpty());
++rtp_timestamp;
}
}
}
}
TEST(HaltonFrameSamplerTest, KeyFrameIsSampled) {
HaltonFrameSampler halton_frame_sampler;
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0, /*num_samples=*/1),
Not(IsEmpty()));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/true, /*rtp_timestamp=*/1, /*num_samples=*/1),
Not(IsEmpty()));
}
TEST(HaltonFrameSamplerTest,
SampleFramesWhenEnoughTimeHasPassedSinceLastSampledFrame) {
HaltonFrameSampler halton_frame_sampler;
const uint32_t kRtpTimestamp = 0;
const int kNumSamples = 1;
const uint32_t kSufficientDuration = 90'000;
const uint32_t kTooShortDuration = 1;
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, kRtpTimestamp, kNumSamples);
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, kRtpTimestamp + kSufficientDuration,
kNumSamples),
Not(IsEmpty()));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false,
kRtpTimestamp + kSufficientDuration + kTooShortDuration, kNumSamples),
IsEmpty());
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, kRtpTimestamp + 2 * kSufficientDuration,
kNumSamples),
Not(IsEmpty()));
}
TEST(HaltonFrameSamplerTest,
FrameIsNotSampledWhenTooShortTimeHasPassedSinceLastSampledFrame) {
HaltonFrameSampler halton_frame_sampler;
const uint32_t kRtpTimestamp = 0;
const uint32_t kTooShortDuration = 90'000 - 1;
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, kRtpTimestamp, /*num_samples=*/1);
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, kRtpTimestamp + kTooShortDuration,
/*num_samples=*/1),
IsEmpty());
}
TEST(HaltonFrameSamplerTest,
SampleFramesWhenEnoughTimeWithWraparoundHasPassedSinceLastSampledFrame) {
HaltonFrameSampler halton_frame_sampler;
// Time delta = 90'000.
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0xFFFE'A071,
/*num_samples=*/1),
Not(IsEmpty()));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/1, /*num_samples=*/1),
Not(IsEmpty()));
}
TEST(
HaltonFrameSamplerTest,
FrameIsNotSampledWhenTooShortTimeDeltaWithWraparoundSinceLastSampledFrame) {
HaltonFrameSampler halton_frame_sampler;
// Time delta = 89'999.
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/0xFFFE'A072,
/*num_samples=*/1),
Not(IsEmpty()));
EXPECT_THAT(
halton_frame_sampler.GetSampleCoordinatesForFrameIfFrameShouldBeSampled(
/*is_key_frame=*/false, /*rtp_timestamp=*/1, /*num_samples=*/1),
IsEmpty());
}
} // namespace
} // namespace webrtc