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}
This commit is contained in:
philipel 2024-06-25 12:05:29 +02:00 committed by WebRTC LUCI CQ
parent 889402ee1f
commit accef6ad5d
3 changed files with 96 additions and 8 deletions

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include <cstdint>
#include <limits>
#include <utility>
#include <vector>
@ -72,6 +73,16 @@ bool HasSps(const H26xPacketBuffer::Packet& packet) {
});
}
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 @@ bool HasVps(const H26xPacketBuffer::Packet& packet) {
} // 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 @@ H26xPacketBuffer::InsertResult H26xPacketBuffer::FindFrames(
// 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 @@ H26xPacketBuffer::InsertResult H26xPacketBuffer::FindFrames(
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;

View File

@ -72,6 +72,7 @@ class H26xPacketBuffer {
};
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 @@ class H26xPacketBuffer {
// 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

View File

@ -1043,6 +1043,72 @@ TEST(H26xPacketBufferTest, FullPacketBufferDoesNotBlockKeyframe) {
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);