blob: 9ee5ff0670d0e1a9dc57b45e9951de2cd769ba4c [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 <cstring>
#include <memory>
#include <vector>
#include "api/array_view.h"
#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "video/corruption_detection/video_frame_sampler.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.
constexpr int kDefaultScaledWidth = 4;
constexpr int kDefaultScaledHeight = 4;
constexpr double kDefaultStdDevGaussianBlur = 0.02;
#if GTEST_HAS_DEATH_TEST
// Defaults for blurring tests.
constexpr int kDefaultRow = 3;
constexpr int kDefaultColumn = 2;
constexpr double kDefaultStdDev = 1.12;
#endif // GTEST_HAS_DEATH_TEST
VideoFrame MakeDefaultFrame() {
// 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 VideoFrame::Builder()
.set_video_frame_buffer(I420Buffer::Copy(
kDefaultLumaWidth, kDefaultLumaHeight, kDefaultYContent,
kDefaultLumaWidth, kDefaultUContent, kDefaultChromaWidth,
kDefaultVContent, kDefaultChromaWidth))
.build();
}
VideoFrame MakeFrame(int width,
int height,
webrtc::ArrayView<const uint8_t> data) {
scoped_refptr<I420Buffer> buffer = I420Buffer::Create(width, height);
memcpy(buffer->MutableDataY(), data.data(), width * height);
return VideoFrame::Builder().set_video_frame_buffer(buffer).build();
}
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 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;
std::unique_ptr<VideoFrameSampler> sampler =
VideoFrameSampler::Create(MakeFrame(kWidth, kHeight, kData));
EXPECT_THAT(GetFilteredElement(*sampler, VideoFrameSampler::ChannelType::Y,
kRow, kColumn, kStdDev),
DoubleEq(126.45897447350468));
}
#if GTEST_HAS_DEATH_TEST
std::unique_ptr<VideoFrameSampler> MakeDefaultSampler() {
return VideoFrameSampler::Create(MakeDefaultFrame());
}
TEST(GaussianFilteringTest, ShouldCrashWhenRowIsNegative) {
EXPECT_DEATH(GetFilteredElement(*MakeDefaultSampler(),
VideoFrameSampler::ChannelType::Y, -1,
kDefaultColumn, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenRowIsOutOfRange) {
EXPECT_DEATH(GetFilteredElement(*MakeDefaultSampler(),
VideoFrameSampler::ChannelType::Y, 4,
kDefaultColumn, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenColumnIsNegative) {
EXPECT_DEATH(GetFilteredElement(*MakeDefaultSampler(),
VideoFrameSampler::ChannelType::Y,
kDefaultRow, -1, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenColumnIsOutOfRange) {
EXPECT_DEATH(GetFilteredElement(*MakeDefaultSampler(),
VideoFrameSampler::ChannelType::Y,
kDefaultRow, 4, kDefaultStdDev),
_);
}
TEST(GaussianFilteringTest, ShouldCrashWhenStdDevIsNegative) {
EXPECT_DEATH(GetFilteredElement(*MakeDefaultSampler(),
VideoFrameSampler::ChannelType::Y,
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);
std::unique_ptr<VideoFrameSampler> sampler =
VideoFrameSampler::Create(MakeFrame(kWidth, kHeight, data));
EXPECT_THAT(GetFilteredElement(*sampler, VideoFrameSampler::ChannelType::Y,
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,
ShouldReturnEmptyListGivenInvalidInputNoCoordinates) {
EXPECT_THAT(
GetSampleValuesForFrame(MakeDefaultFrame(), {}, kDefaultScaledWidth,
kDefaultScaledHeight, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputOutOfRangeCoordinates) {
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(MakeDefaultFrame(), kSampleCoordinates,
kDefaultScaledWidth, kDefaultScaledHeight,
kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputWidthZero) {
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(
GetSampleValuesForFrame(MakeDefaultFrame(), kDefaultSampleCoordinates, 0,
kDefaultScaledHeight, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputHeightZero) {
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(GetSampleValuesForFrame(
MakeDefaultFrame(), kDefaultSampleCoordinates,
kDefaultScaledWidth, 0, kDefaultStdDevGaussianBlur),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListGivenInvalidInputStdDevNegative) {
const std::vector<Coordinates> kDefaultSampleCoordinates =
MakeDefaultSampleCoordinates();
EXPECT_THAT(
GetSampleValuesForFrame(MakeDefaultFrame(), kDefaultSampleCoordinates,
kDefaultScaledWidth, kDefaultScaledHeight, -1.0),
IsEmpty());
}
TEST(HaltonFrameSamplerGaussianFilteringTest,
ShouldReturnEmptyListWhenUpscaling) {
EXPECT_THAT(GetSampleValuesForFrame(MakeDefaultFrame(),
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);
VideoFrame frame =
VideoFrame::Builder().set_video_frame_buffer(kI420Buffer).build();
// 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(frame, 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);
VideoFrame frame =
VideoFrame::Builder().set_video_frame_buffer(kI420Buffer).build();
// 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(frame, 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);
VideoFrame frame =
VideoFrame::Builder().set_video_frame_buffer(kI420Buffer).build();
// 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(frame, 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