Add converter from CorruptionDetectionMessage To FrameInstrumentationData

Bug: webrtc:358039777
Change-Id: I041b9a84e1f93d7e7a3d31b8f0f33c94eeca76a6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/363700
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Auto-Submit: Fanny Linderborg <linderborg@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43081}
diff --git a/common_video/corruption_detection_converters.cc b/common_video/corruption_detection_converters.cc
index 74e978d..ad35b25 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 <optional>
+#include <vector>
 
 #include "common_video/corruption_detection_message.h"
 #include "common_video/frame_instrumentation_data.h"
@@ -20,6 +21,30 @@
 
 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 @@
 
 }  // namespace
 
+std::optional<FrameInstrumentationData>
+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<double> 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<CorruptionDetectionMessage>
 ConvertFrameInstrumentationDataToCorruptionDetectionMessage(
     const FrameInstrumentationData& data) {
diff --git a/common_video/corruption_detection_converters.h b/common_video/corruption_detection_converters.h
index 7387fee..a8c8640 100644
--- a/common_video/corruption_detection_converters.h
+++ b/common_video/corruption_detection_converters.h
@@ -18,6 +18,10 @@
 
 namespace webrtc {
 
+std::optional<FrameInstrumentationData>
+ConvertCorruptionDetectionMessageToFrameInstrumentationData(
+    const CorruptionDetectionMessage& message,
+    int previous_sequence_index);
 std::optional<CorruptionDetectionMessage>
 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 eccd5f8..a4b717f 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 <optional>
+#include <vector>
 
 #include "common_video/corruption_detection_message.h"
 #include "common_video/frame_instrumentation_data.h"
@@ -23,7 +24,8 @@
 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 @@
   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 @@
   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 @@
   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 @@
   ASSERT_FALSE(message.has_value());
 }
 
-TEST(CorruptionDetectionConvertersTest,
+TEST(FrameInstrumentationDataToCorruptionDetectionMessageTest,
      ReturnsNulloptWhenNotSpecifyingSampleValues) {
   FrameInstrumentationData data = {.sequence_index = 1,
                                    .communicate_upper_bits = false,
@@ -99,7 +101,7 @@
   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 @@
   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 @@
   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 @@
 }
 
 #if GTEST_HAS_DEATH_TEST
-TEST(CorruptionDetectionConvertersTest, FailsWhenSetToNotCommunicateUpperBits) {
+TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest,
+     FailsWhenSetToNotCommunicateUpperBits) {
   FrameInstrumentationSyncData data = {.sequence_index = 1,
                                        .communicate_upper_bits = false};
 
@@ -160,7 +164,7 @@
 }
 #endif  // GTEST_HAS_DEATH_TEST
 
-TEST(CorruptionDetectionConvertersTest,
+TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest,
      ReturnsNulloptWhenSyncSequenceIndexIsNegative) {
   FrameInstrumentationSyncData data = {.sequence_index = -1,
                                        .communicate_upper_bits = true};
@@ -170,7 +174,7 @@
   ASSERT_FALSE(message.has_value());
 }
 
-TEST(CorruptionDetectionConvertersTest,
+TEST(FrameInstrumentationSyncDataToCorruptionDetectionMessageTest,
      ReturnsNulloptWhenSyncSequenceIndexIsTooLarge) {
   FrameInstrumentationSyncData data = {.sequence_index = 0x4000,
                                        .communicate_upper_bits = true};
@@ -180,5 +184,123 @@
   ASSERT_FALSE(message.has_value());
 }
 
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     FailWhenPreviousSequenceIndexIsNegative) {
+  std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder()
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  EXPECT_FALSE(
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, -1)
+          .has_value());
+}
+
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     FailWhenNoSampleValuesAreProvided) {
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder().Build();
+  ASSERT_TRUE(message.has_value());
+
+  EXPECT_FALSE(
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 0)
+          .has_value());
+}
+
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     IgnorePreviousSequenceIndexWhenSetToUpdateTheMostSignificantBits) {
+  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)
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  std::optional<FrameInstrumentationData> data =
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 12);
+
+  ASSERT_TRUE(data.has_value());
+  EXPECT_EQ(data->sequence_index, 0b0101'1000'0000);
+}
+
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     UseMessageSequenceIndexWhenHigherThanPrevious) {
+  std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder()
+          .WithSequenceIndex(11)
+          .WithInterpretSequenceIndexAsMostSignificantBits(false)
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  std::optional<FrameInstrumentationData> data =
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 0);
+
+  ASSERT_TRUE(data.has_value());
+  EXPECT_EQ(data->sequence_index, 11);
+}
+
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     IncreaseThePreviousIdxUntilLsbsAreEqualToTheUpdateWhenTheUpdateIsLsbs) {
+  std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder()
+          .WithSequenceIndex(11)
+          .WithInterpretSequenceIndexAsMostSignificantBits(false)
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  std::optional<FrameInstrumentationData> data =
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message,
+                                                                  1 + 128);
+
+  ASSERT_TRUE(data.has_value());
+  EXPECT_EQ(data->sequence_index, 11 + 128);
+}
+
+TEST(CorruptionDetectionMessageToFrameInstrumentationData,
+     IgnoreIndexUpdateWhenTheLowerBitsSuppliedAreTheSameAsInThePreviousIndex) {
+  std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder()
+          .WithSequenceIndex(11)
+          .WithInterpretSequenceIndexAsMostSignificantBits(false)
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  std::optional<FrameInstrumentationData> data =
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message,
+                                                                  11 + 128);
+
+  ASSERT_TRUE(data.has_value());
+  EXPECT_EQ(data->sequence_index, 11 + 128);
+}
+
+TEST(
+    CorruptionDetectionMessageToFrameInstrumentationData,
+    IncreaseTheMsbsByOneAndSetTheMessagesLsbWhenMessageLsbIsLowerThanPrevious) {
+  std::vector<double> sample_values = {1.0, 2.0, 3.0, 4.0, 5.0};
+  std::optional<CorruptionDetectionMessage> message =
+      CorruptionDetectionMessage::Builder()
+          .WithSequenceIndex(11)
+          .WithInterpretSequenceIndexAsMostSignificantBits(false)
+          .WithSampleValues(sample_values)
+          .Build();
+  ASSERT_TRUE(message.has_value());
+
+  std::optional<FrameInstrumentationData> data =
+      ConvertCorruptionDetectionMessageToFrameInstrumentationData(*message, 12);
+
+  ASSERT_TRUE(data.has_value());
+  EXPECT_EQ(data->sequence_index, 11 + 128);
+}
+
 }  // namespace
 }  // namespace webrtc