diff --git a/common_video/corruption_detection_converters.cc b/common_video/corruption_detection_converters.cc index 74e978dd23..ad35b2506d 100644 --- a/common_video/corruption_detection_converters.cc +++ b/common_video/corruption_detection_converters.cc @@ -11,6 +11,7 @@ #include "common_video/corruption_detection_converters.h" #include +#include #include "common_video/corruption_detection_message.h" #include "common_video/frame_instrumentation_data.h" @@ -20,6 +21,30 @@ namespace webrtc { namespace { +int GetFullSequenceIndex(int previous_sequence_index, + int sequence_index_update, + bool update_the_most_significant_bits) { + RTC_CHECK_GE(previous_sequence_index, 0) + << "previous_sequence_index must not be negative"; + RTC_CHECK_LE(previous_sequence_index, 0x7FFF) + << "previous_sequence_index must be at most 15 bits"; + RTC_CHECK_GE(sequence_index_update, 0) + << "sequence_index_update must not be negative"; + RTC_CHECK_LE(sequence_index_update, 0b0111'1111) + << "sequence_index_update must be at most 7 bits"; + if (update_the_most_significant_bits) { + // Reset LSB. + return sequence_index_update << 7; + } + int upper_bits = previous_sequence_index & 0b0011'1111'1000'0000; + if (sequence_index_update < (previous_sequence_index & 0b0111'1111)) { + // Assume one and only one wraparound has happened. + upper_bits += 0b1000'0000; + } + // Replace the lowest bits with the bits from the update. + return upper_bits + sequence_index_update; +} + int GetSequenceIndexForMessage(int sequence_index, bool communicate_upper_bits) { return communicate_upper_bits ? (sequence_index >> 7) @@ -28,6 +53,31 @@ int GetSequenceIndexForMessage(int sequence_index, } // namespace +std::optional +ConvertCorruptionDetectionMessageToFrameInstrumentationData( + const CorruptionDetectionMessage& message, + int previous_sequence_index) { + if (previous_sequence_index < 0) { + return std::nullopt; + } + if (message.sample_values().empty()) { + return std::nullopt; + } + int full_sequence_index = GetFullSequenceIndex( + previous_sequence_index, message.sequence_index(), + message.interpret_sequence_index_as_most_significant_bits()); + std::vector sample_values(message.sample_values().cbegin(), + message.sample_values().cend()); + return FrameInstrumentationData{ + .sequence_index = full_sequence_index, + .communicate_upper_bits = + message.interpret_sequence_index_as_most_significant_bits(), + .std_dev = message.std_dev(), + .luma_error_threshold = message.luma_error_threshold(), + .chroma_error_threshold = message.chroma_error_threshold(), + .sample_values = sample_values}; +} + std::optional ConvertFrameInstrumentationDataToCorruptionDetectionMessage( const FrameInstrumentationData& data) { diff --git a/common_video/corruption_detection_converters.h b/common_video/corruption_detection_converters.h index 7387fee437..a8c864071e 100644 --- a/common_video/corruption_detection_converters.h +++ b/common_video/corruption_detection_converters.h @@ -18,6 +18,10 @@ namespace webrtc { +std::optional +ConvertCorruptionDetectionMessageToFrameInstrumentationData( + const CorruptionDetectionMessage& message, + int previous_sequence_index); std::optional ConvertFrameInstrumentationDataToCorruptionDetectionMessage( const FrameInstrumentationData& frame_instrumentation_data); diff --git a/common_video/corruption_detection_converters_unittest.cc b/common_video/corruption_detection_converters_unittest.cc index eccd5f8160..a4b717fde7 100644 --- a/common_video/corruption_detection_converters_unittest.cc +++ b/common_video/corruption_detection_converters_unittest.cc @@ -11,6 +11,7 @@ #include "common_video/corruption_detection_converters.h" #include +#include #include "common_video/corruption_detection_message.h" #include "common_video/frame_instrumentation_data.h" @@ -23,7 +24,8 @@ namespace { using ::testing::_; using ::testing::ElementsAre; -TEST(CorruptionDetectionConvertersTest, ConvertsValidData) { +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, + ConvertsValidData) { FrameInstrumentationData data = {.sequence_index = 1, .communicate_upper_bits = false, .std_dev = 1.0, @@ -42,7 +44,7 @@ TEST(CorruptionDetectionConvertersTest, ConvertsValidData) { EXPECT_THAT(message->sample_values(), ElementsAre(1.0, 2.0, 3.0, 4.0, 5.0)); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenSequenceIndexIsNegative) { FrameInstrumentationData data = {.sequence_index = -1, .communicate_upper_bits = false, @@ -56,7 +58,7 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenSequenceIndexIsTooLarge) { // Sequence index must be at max 14 bits. FrameInstrumentationData data = {.sequence_index = 0x4000, @@ -71,7 +73,7 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenThereAreNoSampleValues) { // FrameInstrumentationData must by definition have at least one sample value. FrameInstrumentationData data = {.sequence_index = 1, @@ -86,7 +88,7 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenNotSpecifyingSampleValues) { FrameInstrumentationData data = {.sequence_index = 1, .communicate_upper_bits = false, @@ -99,7 +101,7 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ConvertsSequenceIndexWhenSetToUseUpperBits) { FrameInstrumentationData data = {.sequence_index = 0b0000'0110'0000'0101, .communicate_upper_bits = true, @@ -119,7 +121,7 @@ TEST(CorruptionDetectionConvertersTest, EXPECT_THAT(message->sample_values(), ElementsAre(1.0, 2.0, 3.0, 4.0, 5.0)); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest, ConvertsSequenceIndexWhenSetToUseLowerBits) { FrameInstrumentationData data = {.sequence_index = 0b0000'0110'0000'0101, .communicate_upper_bits = false, @@ -139,7 +141,8 @@ TEST(CorruptionDetectionConvertersTest, EXPECT_THAT(message->sample_values(), ElementsAre(1.0, 2.0, 3.0, 4.0, 5.0)); } -TEST(CorruptionDetectionConvertersTest, ConvertsValidSyncData) { +TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest, + ConvertsValidSyncData) { FrameInstrumentationSyncData data = {.sequence_index = 1, .communicate_upper_bits = true}; @@ -151,7 +154,8 @@ TEST(CorruptionDetectionConvertersTest, ConvertsValidSyncData) { } #if GTEST_HAS_DEATH_TEST -TEST(CorruptionDetectionConvertersTest, FailsWhenSetToNotCommunicateUpperBits) { +TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest, + FailsWhenSetToNotCommunicateUpperBits) { FrameInstrumentationSyncData data = {.sequence_index = 1, .communicate_upper_bits = false}; @@ -160,7 +164,7 @@ TEST(CorruptionDetectionConvertersTest, FailsWhenSetToNotCommunicateUpperBits) { } #endif // GTEST_HAS_DEATH_TEST -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenSyncSequenceIndexIsNegative) { FrameInstrumentationSyncData data = {.sequence_index = -1, .communicate_upper_bits = true}; @@ -170,7 +174,7 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } -TEST(CorruptionDetectionConvertersTest, +TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest, ReturnsNulloptWhenSyncSequenceIndexIsTooLarge) { FrameInstrumentationSyncData data = {.sequence_index = 0x4000, .communicate_upper_bits = true}; @@ -180,5 +184,123 @@ TEST(CorruptionDetectionConvertersTest, ASSERT_FALSE(message.has_value()); } +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + FailWhenPreviousSequenceIndexIsNegative) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + EXPECT_FALSE( + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, -1) + .has_value()); +} + +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + FailWhenNoSampleValuesAreProvided) { + std::optional message = + CorruptionDetectionMessage::Builder().Build(); + ASSERT_TRUE(message.has_value()); + + EXPECT_FALSE( + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 0) + .has_value()); +} + +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + IgnorePreviousSequenceIndexWhenSetToUpdateTheMostSignificantBits) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSequenceIndex(11) + .WithInterpretSequenceIndexAsMostSignificantBits(true) + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + std::optional data = + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 12); + + ASSERT_TRUE(data.has_value()); + EXPECT_EQ(data->sequence_index, 0b0101'1000'0000); +} + +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + UseMessageSequenceIndexWhenHigherThanPrevious) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSequenceIndex(11) + .WithInterpretSequenceIndexAsMostSignificantBits(false) + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + std::optional data = + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 0); + + ASSERT_TRUE(data.has_value()); + EXPECT_EQ(data->sequence_index, 11); +} + +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + IncreaseThePreviousIdxUntilLsbsAreEqualToTheUpdateWhenTheUpdateIsLsbs) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSequenceIndex(11) + .WithInterpretSequenceIndexAsMostSignificantBits(false) + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + std::optional data = + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, + 1 + 128); + + ASSERT_TRUE(data.has_value()); + EXPECT_EQ(data->sequence_index, 11 + 128); +} + +TEST(CorruptionDetectionMessageToFrameInstrumentationData, + IgnoreIndexUpdateWhenTheLowerBitsSuppliedAreTheSameAsInThePreviousIndex) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSequenceIndex(11) + .WithInterpretSequenceIndexAsMostSignificantBits(false) + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + std::optional data = + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, + 11 + 128); + + ASSERT_TRUE(data.has_value()); + EXPECT_EQ(data->sequence_index, 11 + 128); +} + +TEST( + CorruptionDetectionMessageToFrameInstrumentationData, + IncreaseTheMsbsByOneAndSetTheMessagesLsbWhenMessageLsbIsLowerThanPrevious) { + std::vector sample_values = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::optional message = + CorruptionDetectionMessage::Builder() + .WithSequenceIndex(11) + .WithInterpretSequenceIndexAsMostSignificantBits(false) + .WithSampleValues(sample_values) + .Build(); + ASSERT_TRUE(message.has_value()); + + std::optional data = + ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 12); + + ASSERT_TRUE(data.has_value()); + EXPECT_EQ(data->sequence_index, 11 + 128); +} + } // namespace } // namespace webrtc