Fix wraparound issue in FrameInstrumentationGenerator.
This prevents an RTC_CHECK from triggering if the sequence index
wraparound happens on a delta frame.
Bug: webrtc:440978611, chromium:440989756
Change-Id: I4d893687391e87a0d2a8476d0db70153b0e8a768
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/406100
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Fanny Linderborg <linderborg@webrtc.org>
Auto-Submit: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45426}
diff --git a/video/corruption_detection/frame_instrumentation_generator.cc b/video/corruption_detection/frame_instrumentation_generator.cc
index be02930..160f9fb 100644
--- a/video/corruption_detection/frame_instrumentation_generator.cc
+++ b/video/corruption_detection/frame_instrumentation_generator.cc
@@ -140,17 +140,17 @@
}
int sequence_index = contexts_[layer_id].frame_sampler.GetCurrentIndex();
- if (is_key_frame) {
+ if (is_key_frame && ((sequence_index & 0b0111'1111) != 0)) {
// Increase until all the last 7 bits are zeroes.
- // If this would overflow to 15 bits, reset to 0.
- if (sequence_index > 0b0011'1111'1000'0000) {
- sequence_index = 0;
- } else if ((sequence_index & 0b0111'1111) != 0) {
- // Last 7 bits are not all zeroes.
- sequence_index >>= 7;
- sequence_index += 1;
- sequence_index <<= 7;
- }
+ sequence_index >>= 7;
+ sequence_index += 1;
+ sequence_index <<= 7;
+ contexts_[layer_id].frame_sampler.SetCurrentIndex(sequence_index);
+ }
+
+ if (sequence_index >= (1 << 14)) {
+ // Overflow of 14 bit counter, reset to 0.
+ sequence_index = 0;
contexts_[layer_id].frame_sampler.SetCurrentIndex(sequence_index);
}
diff --git a/video/corruption_detection/frame_instrumentation_generator_unittest.cc b/video/corruption_detection/frame_instrumentation_generator_unittest.cc
index 0cf2975..264c801 100644
--- a/video/corruption_detection/frame_instrumentation_generator_unittest.cc
+++ b/video/corruption_detection/frame_instrumentation_generator_unittest.cc
@@ -581,6 +581,54 @@
EXPECT_EQ(data1->sequence_index(), 0b0000'1000'0000);
EXPECT_EQ(data2->sequence_index(), 0b0001'0000'0000);
}
+TEST(FrameInstrumentationGeneratorTest,
+ SequenceIndexThatWouldOverflowTo15BitsIncreasesCorrectlyAtNewDeltaFrame) {
+ FrameInstrumentationGenerator generator(VideoCodecType::kVideoCodecVP8);
+ generator.OnCapturedFrame(
+ VideoFrame::Builder()
+ .set_video_frame_buffer(MakeI420FrameBufferWithDifferentPixelValues())
+ .set_rtp_timestamp(1)
+ .build());
+ EncodedImage encoded_image;
+ encoded_image.SetRtpTimestamp(1);
+ encoded_image.SetFrameType(VideoFrameType::kVideoFrameDelta);
+ encoded_image.qp_ = 10;
+ encoded_image._encodedWidth = kDefaultScaledWidth;
+ encoded_image._encodedHeight = kDefaultScaledHeight;
+ encoded_image.SetSimulcastIndex(0);
+
+ constexpr int kMaxSequenceIndex = 0b11'1111'1111'1111;
+
+ generator.SetHaltonSequenceIndex(kMaxSequenceIndex,
+ generator.GetLayerId(encoded_image));
+ std::optional<FrameInstrumentationData> data =
+ generator.OnEncodedImage(encoded_image);
+
+ ASSERT_TRUE(data.has_value());
+ EXPECT_EQ(data->sequence_index(), kMaxSequenceIndex);
+
+ // Loop until we get a new delta frame.
+ bool has_found_delta_frame = false;
+ for (int i = 0; i < 34; ++i) {
+ generator.OnCapturedFrame(
+ VideoFrame::Builder()
+ .set_video_frame_buffer(
+ MakeI420FrameBufferWithDifferentPixelValues())
+ .set_rtp_timestamp(i + 2)
+ .build());
+
+ encoded_image.SetRtpTimestamp(i + 2);
+
+ std::optional<FrameInstrumentationData> frame_instrumentation_data =
+ generator.OnEncodedImage(encoded_image);
+ if (frame_instrumentation_data.has_value()) {
+ has_found_delta_frame = true;
+ EXPECT_EQ(frame_instrumentation_data->sequence_index(), 0);
+ break;
+ }
+ }
+ EXPECT_TRUE(has_found_delta_frame);
+}
TEST(FrameInstrumentationGeneratorTest, GetterAndSetterOperatesAsExpected) {
FrameInstrumentationGenerator generator(VideoCodecType::kVideoCodecVP8);