| /* | 
 |  *  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 "common_video/corruption_detection_converters.h" | 
 |  | 
 | #include <optional> | 
 | #include <vector> | 
 |  | 
 | #include "api/transport/rtp/corruption_detection_message.h" | 
 | #include "common_video/frame_instrumentation_data.h" | 
 | #include "rtc_base/checks.h" | 
 |  | 
 | 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) | 
 |                                 : (sequence_index & 0b0111'1111); | 
 | } | 
 |  | 
 | }  // 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<FrameInstrumentationSyncData> | 
 | ConvertCorruptionDetectionMessageToFrameInstrumentationSyncData( | 
 |     const CorruptionDetectionMessage& message, | 
 |     int previous_sequence_index) { | 
 |   if (previous_sequence_index < 0) { | 
 |     return std::nullopt; | 
 |   } | 
 |   if (!message.sample_values().empty()) { | 
 |     return std::nullopt; | 
 |   } | 
 |   if (!message.interpret_sequence_index_as_most_significant_bits()) { | 
 |     return std::nullopt; | 
 |   } | 
 |   return FrameInstrumentationSyncData{ | 
 |       .sequence_index = GetFullSequenceIndex( | 
 |           previous_sequence_index, message.sequence_index(), | 
 |           /*update_the_most_significant_bits=*/true), | 
 |       .communicate_upper_bits = true}; | 
 | } | 
 |  | 
 | std::optional<CorruptionDetectionMessage> | 
 | ConvertFrameInstrumentationDataToCorruptionDetectionMessage( | 
 |     const FrameInstrumentationData& data) { | 
 |   if (data.sequence_index < 0 || data.sequence_index > 0b0011'1111'1111'1111) { | 
 |     return std::nullopt; | 
 |   } | 
 |   // Frame instrumentation data must have sample values. | 
 |   if (data.sample_values.empty()) { | 
 |     return std::nullopt; | 
 |   } | 
 |   return CorruptionDetectionMessage::Builder() | 
 |       .WithSequenceIndex(GetSequenceIndexForMessage( | 
 |           data.sequence_index, data.communicate_upper_bits)) | 
 |       .WithInterpretSequenceIndexAsMostSignificantBits( | 
 |           data.communicate_upper_bits) | 
 |       .WithStdDev(data.std_dev) | 
 |       .WithLumaErrorThreshold(data.luma_error_threshold) | 
 |       .WithChromaErrorThreshold(data.chroma_error_threshold) | 
 |       .WithSampleValues(data.sample_values) | 
 |       .Build(); | 
 | } | 
 |  | 
 | std::optional<CorruptionDetectionMessage> | 
 | ConvertFrameInstrumentationSyncDataToCorruptionDetectionMessage( | 
 |     const FrameInstrumentationSyncData& data) { | 
 |   RTC_DCHECK(data.communicate_upper_bits) | 
 |       << "FrameInstrumentationSyncData data must always send the upper bits."; | 
 |  | 
 |   if (data.sequence_index < 0 || data.sequence_index > 0b0011'1111'1111'1111) { | 
 |     return std::nullopt; | 
 |   } | 
 |   return CorruptionDetectionMessage::Builder() | 
 |       .WithSequenceIndex(GetSequenceIndexForMessage( | 
 |           data.sequence_index, data.communicate_upper_bits)) | 
 |       .WithInterpretSequenceIndexAsMostSignificantBits(true) | 
 |       .Build(); | 
 | } | 
 |  | 
 | }  // namespace webrtc |