Allow for reordering around IRAPs.

Bug: webrtc:41480904
Change-Id: I16fb4466bff8a0c192467332413205cb9958674e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/355482
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42537}
diff --git a/modules/video_coding/h26x_packet_buffer.cc b/modules/video_coding/h26x_packet_buffer.cc
index 3770edb..e6e7441 100644
--- a/modules/video_coding/h26x_packet_buffer.cc
+++ b/modules/video_coding/h26x_packet_buffer.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 #include <cstdint>
+#include <limits>
 #include <utility>
 #include <vector>
 
@@ -72,6 +73,16 @@
   });
 }
 
+int64_t* GetContinuousSequence(rtc::ArrayView<int64_t> last_continuous,
+                               int64_t unwrapped_seq_num) {
+  for (int64_t& last : last_continuous) {
+    if (unwrapped_seq_num - 1 == last) {
+      return &last;
+    }
+  }
+  return nullptr;
+}
+
 #ifdef RTC_ENABLE_H265
 bool HasVps(const H26xPacketBuffer::Packet& packet) {
   std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices(
@@ -88,7 +99,9 @@
 }  // namespace
 
 H26xPacketBuffer::H26xPacketBuffer(bool h264_idr_only_keyframes_allowed)
-    : h264_idr_only_keyframes_allowed_(h264_idr_only_keyframes_allowed) {}
+    : h264_idr_only_keyframes_allowed_(h264_idr_only_keyframes_allowed) {
+  last_continuous_in_sequence_.fill(std::numeric_limits<int64_t>::min());
+}
 
 H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPacket(
     std::unique_ptr<Packet> packet) {
@@ -138,18 +151,25 @@
 
   // Check if the packet is continuous or the beginning of a new coded video
   // sequence.
-  if (unwrapped_seq_num - 1 != last_continuous_unwrapped_seq_num_) {
-    if (unwrapped_seq_num <= last_continuous_unwrapped_seq_num_ ||
-        !BeginningOfStream(*packet)) {
+  int64_t* last_continuous_unwrapped_seq_num =
+      GetContinuousSequence(last_continuous_in_sequence_, unwrapped_seq_num);
+  if (last_continuous_unwrapped_seq_num == nullptr) {
+    if (!BeginningOfStream(*packet)) {
       return result;
     }
 
-    last_continuous_unwrapped_seq_num_ = unwrapped_seq_num;
+    last_continuous_in_sequence_[last_continuous_in_sequence_index_] =
+        unwrapped_seq_num;
+    last_continuous_unwrapped_seq_num =
+        &last_continuous_in_sequence_[last_continuous_in_sequence_index_];
+    last_continuous_in_sequence_index_ =
+        (last_continuous_in_sequence_index_ + 1) %
+        last_continuous_in_sequence_.size();
   }
 
   for (int64_t seq_num = unwrapped_seq_num;
        seq_num < unwrapped_seq_num + kBufferSize;) {
-    RTC_DCHECK_GE(seq_num, *last_continuous_unwrapped_seq_num_);
+    RTC_DCHECK_GE(seq_num, *last_continuous_unwrapped_seq_num);
 
     // Packets that were never assembled into a completed frame will stay in
     // the 'buffer_'. Check that the `packet` sequence number match the expected
@@ -158,7 +178,7 @@
       return result;
     }
 
-    last_continuous_unwrapped_seq_num_ = seq_num;
+    *last_continuous_unwrapped_seq_num = seq_num;
     // Last packet of the frame, try to assemble the frame.
     if (packet->marker_bit) {
       uint32_t rtp_timestamp = packet->timestamp;
diff --git a/modules/video_coding/h26x_packet_buffer.h b/modules/video_coding/h26x_packet_buffer.h
index ef6d0db..3576e6e 100644
--- a/modules/video_coding/h26x_packet_buffer.h
+++ b/modules/video_coding/h26x_packet_buffer.h
@@ -72,6 +72,7 @@
   };
 
   static constexpr int kBufferSize = 2048;
+  static constexpr int kNumTrackedSequences = 5;
 
   std::unique_ptr<Packet>& GetPacket(int64_t unwrapped_seq_num);
   bool BeginningOfStream(const Packet& packet) const;
@@ -91,7 +92,8 @@
   // Indicates whether IDR frames without SPS and PPS are allowed.
   const bool h264_idr_only_keyframes_allowed_;
   std::array<std::unique_ptr<Packet>, kBufferSize> buffer_;
-  absl::optional<int64_t> last_continuous_unwrapped_seq_num_;
+  std::array<int64_t, kNumTrackedSequences> last_continuous_in_sequence_;
+  int64_t last_continuous_in_sequence_index_ = 0;
   SeqNumUnwrapper<uint16_t> seq_num_unwrapper_;
 
   // Map from pps_pic_parameter_set_id to the PPS payload associated with this
diff --git a/modules/video_coding/h26x_packet_buffer_unittest.cc b/modules/video_coding/h26x_packet_buffer_unittest.cc
index 50f35f3..3ceccd9 100644
--- a/modules/video_coding/h26x_packet_buffer_unittest.cc
+++ b/modules/video_coding/h26x_packet_buffer_unittest.cc
@@ -1043,6 +1043,72 @@
               SizeIs(1));
 }
 
+TEST(H26xPacketBufferTest, AssembleFrameAfterReordering) {
+  H26xPacketBuffer packet_buffer(/*h264_allow_idr_only_keyframes=*/false);
+
+  EXPECT_THAT(packet_buffer
+                  .InsertPacket(H264Packet(kH264StapA)
+                                    .Sps()
+                                    .Pps()
+                                    .Idr()
+                                    .SeqNum(2)
+                                    .Time(2)
+                                    .Marker()
+                                    .Build())
+                  .packets,
+              SizeIs(1));
+
+  EXPECT_THAT(packet_buffer
+                  .InsertPacket(H264Packet(kH264SingleNalu)
+                                    .Slice()
+                                    .SeqNum(1)
+                                    .Time(1)
+                                    .Marker()
+                                    .Build())
+                  .packets,
+              IsEmpty());
+
+  EXPECT_THAT(packet_buffer
+                  .InsertPacket(H264Packet(kH264StapA)
+                                    .Sps()
+                                    .Pps()
+                                    .Idr()
+                                    .SeqNum(0)
+                                    .Time(0)
+                                    .Marker()
+                                    .Build())
+                  .packets,
+              SizeIs(2));
+}
+
+TEST(H26xPacketBufferTest, AssembleFrameAfterLoss) {
+  H26xPacketBuffer packet_buffer(/*h264_allow_idr_only_keyframes=*/false);
+
+  EXPECT_THAT(packet_buffer
+                  .InsertPacket(H264Packet(kH264StapA)
+                                    .Sps()
+                                    .Pps()
+                                    .Idr()
+                                    .SeqNum(0)
+                                    .Time(0)
+                                    .Marker()
+                                    .Build())
+                  .packets,
+              SizeIs(1));
+
+  EXPECT_THAT(packet_buffer
+                  .InsertPacket(H264Packet(kH264StapA)
+                                    .Sps()
+                                    .Pps()
+                                    .Idr()
+                                    .SeqNum(2)
+                                    .Time(2)
+                                    .Marker()
+                                    .Build())
+                  .packets,
+              SizeIs(1));
+}
+
 #ifdef RTC_ENABLE_H265
 TEST(H26xPacketBufferTest, H265VpsSpsPpsIdrIsKeyframe) {
   H26xPacketBuffer packet_buffer(/*allow_idr_only_keyframes=*/false);