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);