blob: d4b7cf9c423f7b6a859695650aaf37759bec6a2f [file]
/*
* Copyright 2025 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 "api/video/corruption_detection/frame_instrumentation_data_reader.h"
#include <optional>
#include <vector>
#include "api/transport/rtp/corruption_detection_message.h"
#include "api/video/corruption_detection/frame_instrumentation_data.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::ElementsAre;
using ::testing::Eq;
namespace webrtc {
TEST(FrameInstrumentationDataReaderTest, AcceptsMsbFromStart) {
FrameInstrumentationDataReader reader;
std::optional<FrameInstrumentationData> data = reader.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(1)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build());
EXPECT_TRUE(data.has_value());
EXPECT_THAT(data->sequence_index(), Eq(1 << 7));
}
TEST(FrameInstrumentationDataReaderTest, RejectsLsbFromStart) {
FrameInstrumentationDataReader reader;
std::optional<FrameInstrumentationData> data = reader.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(1)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build());
EXPECT_FALSE(data.has_value());
}
TEST(FrameInstrumentationDataReaderTest,
IgnorePreviousSequenceIndexWhenSetToUpdateTheMostSignificantBits) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_TRUE(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
.has_value());
// New absolute value 12 << 7 take precedence.
std::optional<FrameInstrumentationData> data = reader.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(12)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build());
ASSERT_TRUE(data.has_value());
EXPECT_THAT(data->sequence_index(), Eq(12 << 7));
}
TEST(FrameInstrumentationDataReaderTest,
UseMessageSequenceIndexWhenHigherThanPrevious) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_TRUE(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
.has_value());
std::optional<FrameInstrumentationData> data = reader.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(12)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build());
ASSERT_TRUE(data.has_value());
EXPECT_EQ(data->sequence_index(), (11 << 7) + 12);
}
TEST(FrameInstrumentationDataReaderTest, HandlesMsbRollOver) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
->sequence_index(),
Eq(11 << 7));
// Bump index by 100.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(100)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq((11 << 7) + 100));
// Bumping it again so that LSB = 1, MSB should increment to 12.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(1)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq((12 << 7) + 1));
}
TEST(FrameInstrumentationDataReaderTest,
IgnoreIndexUpdateWhenTheLowerBitsSuppliedAreTheSameAsInThePreviousIndex) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
->sequence_index(),
Eq(11 << 7));
// LSB = 0, meaning it's the same sequence again - no increment.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq(11 << 7));
}
TEST(FrameInstrumentationDataReaderTest, MaximumRollover) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
->sequence_index(),
Eq(11 << 7));
// Bump index by 1.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(1)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq((11 << 7) + 1));
// Setting the LSB to one lower than current => maximum +127 jump.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq(12 << 7));
}
TEST(FrameInstrumentationDataReaderTest, RolloverWithSamples) {
FrameInstrumentationDataReader reader;
// Prime with sequence index 11 << 7.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build())
->sequence_index(),
Eq(11 << 7));
// Bump index by one, but include 4 samples values, which count as index too.
std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0};
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(1)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.WithSampleValues(sample_values)
.Build())
->sequence_index(),
Eq((11 << 7) + 1));
// Set the LSB to 4, which is one less than the previous seen sequence, this
// counts as a wraparound.
EXPECT_THAT(
reader
.ParseMessage(
*CorruptionDetectionMessage::Builder()
.WithSequenceIndex(4)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.Build())
->sequence_index(),
Eq((12 << 7) + 4));
}
TEST(FrameInstrumentationDataReaderTest, ConvertAllFields) {
std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
std::optional<CorruptionDetectionMessage> message =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(11)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.WithStdDev(1.2)
.WithLumaErrorThreshold(10)
.WithChromaErrorThreshold(10)
.WithSampleValues(sample_values)
.Build();
ASSERT_TRUE(message.has_value());
FrameInstrumentationDataReader reader;
std::optional<FrameInstrumentationData> data = reader.ParseMessage(*message);
ASSERT_TRUE(data.has_value());
EXPECT_EQ(data->sequence_index(), 11 << 7);
EXPECT_NEAR(data->std_dev(), 1.2, 0.024); // ~2%
EXPECT_EQ(data->luma_error_threshold(), 10);
EXPECT_EQ(data->chroma_error_threshold(), 10);
EXPECT_THAT(data->sample_values(), ElementsAre(1.0, 2.0, 3.0, 4.0, 5.0));
}
} // namespace webrtc