diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc index e0b831e72b..f8d6776c12 100644 --- a/call/rtp_payload_params.cc +++ b/call/rtp_payload_params.cc @@ -36,6 +36,7 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info, absl::optional spatial_index, RTPVideoHeader* rtp) { rtp->codec = info.codecType; + rtp->is_last_frame_in_picture = info.end_of_picture; switch (info.codecType) { case kVideoCodecVP8: { auto& vp8_header = rtp->video_type_header.emplace(); diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 7703a6bf0f..7550b70f69 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -54,8 +54,9 @@ std::unique_ptr RtpPacketizer::Create( return std::make_unique(payload, limits, vp9); } case kVideoCodecAV1: - return std::make_unique(payload, limits, - rtp_video_header.frame_type); + return std::make_unique( + payload, limits, rtp_video_header.frame_type, + rtp_video_header.is_last_frame_in_picture); default: { return std::make_unique(payload, limits, rtp_video_header); diff --git a/modules/rtp_rtcp/source/rtp_packetizer_av1.cc b/modules/rtp_rtcp/source/rtp_packetizer_av1.cc index 909b1289ed..4408beed31 100644 --- a/modules/rtp_rtcp/source/rtp_packetizer_av1.cc +++ b/modules/rtp_rtcp/source/rtp_packetizer_av1.cc @@ -88,10 +88,12 @@ int MaxFragmentSize(int remaining_bytes) { RtpPacketizerAv1::RtpPacketizerAv1(rtc::ArrayView payload, RtpPacketizer::PayloadSizeLimits limits, - VideoFrameType frame_type) + VideoFrameType frame_type, + bool is_last_frame_in_picture) : frame_type_(frame_type), obus_(ParseObus(payload)), - packets_(Packetize(obus_, limits)) {} + packets_(Packetize(obus_, limits)), + is_last_frame_in_picture_(is_last_frame_in_picture) {} std::vector RtpPacketizerAv1::ParseObus( rtc::ArrayView payload) { @@ -414,11 +416,8 @@ bool RtpPacketizerAv1::NextPacket(RtpPacketToSend* packet) { kAggregationHeaderSize + next_packet.packet_size); ++packet_index_; - if (packet_index_ == packets_.size()) { - // TODO(danilchap): To support spatial scalability pass and use information - // if this frame is the last in the temporal unit. - packet->SetMarker(true); - } + bool is_last_packet_in_frame = packet_index_ == packets_.size(); + packet->SetMarker(is_last_packet_in_frame && is_last_frame_in_picture_); return true; } diff --git a/modules/rtp_rtcp/source/rtp_packetizer_av1.h b/modules/rtp_rtcp/source/rtp_packetizer_av1.h index 79fa6e02f9..520e746eac 100644 --- a/modules/rtp_rtcp/source/rtp_packetizer_av1.h +++ b/modules/rtp_rtcp/source/rtp_packetizer_av1.h @@ -26,7 +26,8 @@ class RtpPacketizerAv1 : public RtpPacketizer { public: RtpPacketizerAv1(rtc::ArrayView payload, PayloadSizeLimits limits, - VideoFrameType frame_type); + VideoFrameType frame_type, + bool is_last_frame_in_picture); ~RtpPacketizerAv1() override = default; size_t NumPackets() const override { return packets_.size() - packet_index_; } @@ -63,6 +64,7 @@ class RtpPacketizerAv1 : public RtpPacketizer { const VideoFrameType frame_type_; const std::vector obus_; const std::vector packets_; + const bool is_last_frame_in_picture_; size_t packet_index_ = 0; }; diff --git a/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc b/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc index 0529e98129..84d2b35bc6 100644 --- a/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc @@ -88,9 +88,11 @@ class Av1Frame { std::vector Packetize( rtc::ArrayView payload, RtpPacketizer::PayloadSizeLimits limits, - VideoFrameType frame_type = VideoFrameType::kVideoFrameDelta) { + VideoFrameType frame_type = VideoFrameType::kVideoFrameDelta, + bool is_last_frame_in_picture = true) { // Run code under test. - RtpPacketizerAv1 packetizer(payload, limits, frame_type); + RtpPacketizerAv1 packetizer(payload, limits, frame_type, + is_last_frame_in_picture); // Convert result into structure that is easier to run expectation against. std::vector result(packetizer.NumPackets()); for (RtpPayload& rtp_payload : result) { @@ -332,6 +334,34 @@ TEST(RtpPacketizerAv1Test, SplitSingleObuIntoManyPackets) { EXPECT_THAT(ReassembleFrame(payloads), ElementsAreArray(kFrame)); } +TEST(RtpPacketizerAv1Test, SetMarkerBitForLastPacketInEndOfPictureFrame) { + auto kFrame = BuildAv1Frame( + {Obu(kObuTypeFrame).WithPayload(std::vector(200, 27))}); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 100; + auto payloads = Packetize(kFrame, limits, VideoFrameType::kVideoFrameDelta, + /*is_last_frame_in_picture=*/true); + ASSERT_THAT(payloads, SizeIs(3u)); + EXPECT_FALSE(payloads[0].rtp_packet.Marker()); + EXPECT_FALSE(payloads[1].rtp_packet.Marker()); + EXPECT_TRUE(payloads[2].rtp_packet.Marker()); +} + +TEST(RtpPacketizerAv1Test, DoesntSetMarkerBitForPacketsNotInEndOfPictureFrame) { + auto kFrame = BuildAv1Frame( + {Obu(kObuTypeFrame).WithPayload(std::vector(200, 27))}); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 100; + auto payloads = Packetize(kFrame, limits, VideoFrameType::kVideoFrameDelta, + /*is_last_frame_in_picture=*/false); + ASSERT_THAT(payloads, SizeIs(3u)); + EXPECT_FALSE(payloads[0].rtp_packet.Marker()); + EXPECT_FALSE(payloads[1].rtp_packet.Marker()); + EXPECT_FALSE(payloads[2].rtp_packet.Marker()); +} + TEST(RtpPacketizerAv1Test, SplitTwoObusIntoTwoPackets) { // 2nd OBU is too large to fit into one packet, so its head would be in the // same packet as the 1st OBU. diff --git a/modules/rtp_rtcp/source/rtp_video_header.h b/modules/rtp_rtcp/source/rtp_video_header.h index ca3415587d..8a2fcba939 100644 --- a/modules/rtp_rtcp/source/rtp_video_header.h +++ b/modules/rtp_rtcp/source/rtp_video_header.h @@ -70,6 +70,7 @@ struct RTPVideoHeader { VideoContentType content_type = VideoContentType::UNSPECIFIED; bool is_first_packet_in_frame = false; bool is_last_packet_in_frame = false; + bool is_last_frame_in_picture = true; uint8_t simulcastIdx = 0; VideoCodecType codec = VideoCodecType::kVideoCodecGeneric; diff --git a/test/fuzzers/rtp_packetizer_av1_fuzzer.cc b/test/fuzzers/rtp_packetizer_av1_fuzzer.cc index 5277c10f4b..e5550c1279 100644 --- a/test/fuzzers/rtp_packetizer_av1_fuzzer.cc +++ b/test/fuzzers/rtp_packetizer_av1_fuzzer.cc @@ -35,7 +35,8 @@ void FuzzOneInput(const uint8_t* data, size_t size) { // Main function under test: RtpPacketizerAv1's constructor. RtpPacketizerAv1 packetizer(fuzz_input.ReadByteArray(fuzz_input.BytesLeft()), - limits, frame_type); + limits, frame_type, + /*is_last_frame_in_picture=*/true); size_t num_packets = packetizer.NumPackets(); if (num_packets == 0) {