rtp_packetizer_av1_unittest.cc (15005B)
1 /* 2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/rtp_rtcp/source/rtp_packetizer_av1.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <initializer_list> 16 #include <utility> 17 #include <vector> 18 19 #include "api/array_view.h" 20 #include "api/scoped_refptr.h" 21 #include "api/video/encoded_image.h" 22 #include "api/video/video_frame_type.h" 23 #include "modules/rtp_rtcp/source/rtp_format.h" 24 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" 25 #include "modules/rtp_rtcp/source/rtp_packetizer_av1_test_helper.h" 26 #include "modules/rtp_rtcp/source/video_rtp_depacketizer_av1.h" 27 #include "test/gmock.h" 28 #include "test/gtest.h" 29 30 namespace webrtc { 31 namespace { 32 33 using ::testing::Each; 34 using ::testing::ElementsAre; 35 using ::testing::ElementsAreArray; 36 using ::testing::Le; 37 using ::testing::SizeIs; 38 39 constexpr uint8_t kNewCodedVideoSequenceBit = 0b00'00'1000; 40 41 // Wrapper around rtp_packet to make it look like container of payload bytes. 42 struct RtpPayload { 43 using value_type = ArrayView<const uint8_t>::value_type; 44 using const_iterator = ArrayView<const uint8_t>::const_iterator; 45 46 RtpPayload() : rtp_packet(/*extensions=*/nullptr) {} 47 RtpPayload& operator=(RtpPayload&&) = default; 48 RtpPayload(RtpPayload&&) = default; 49 50 const_iterator begin() const { return rtp_packet.payload().begin(); } 51 const_iterator end() const { return rtp_packet.payload().end(); } 52 const uint8_t* data() const { return rtp_packet.payload().data(); } 53 size_t size() const { return rtp_packet.payload().size(); } 54 55 uint8_t aggregation_header() const { return rtp_packet.payload()[0]; } 56 57 RtpPacketToSend rtp_packet; 58 }; 59 60 // Wrapper around frame pointer to make it look like container of bytes with 61 // nullptr frame look like empty container. 62 class Av1Frame { 63 public: 64 using value_type = uint8_t; 65 using const_iterator = const uint8_t*; 66 67 explicit Av1Frame(scoped_refptr<EncodedImageBuffer> frame) 68 : frame_(std::move(frame)) {} 69 70 const_iterator begin() const { return frame_ ? frame_->data() : nullptr; } 71 const_iterator end() const { 72 return frame_ ? (frame_->data() + frame_->size()) : nullptr; 73 } 74 75 private: 76 scoped_refptr<EncodedImageBuffer> frame_; 77 }; 78 79 std::vector<RtpPayload> Packetize( 80 ArrayView<const uint8_t> payload, 81 RtpPacketizer::PayloadSizeLimits limits, 82 VideoFrameType frame_type = VideoFrameType::kVideoFrameDelta, 83 bool is_last_frame_in_picture = true) { 84 // Run code under test. 85 RtpPacketizerAv1 packetizer(payload, limits, frame_type, 86 is_last_frame_in_picture); 87 // Convert result into structure that is easier to run expectation against. 88 std::vector<RtpPayload> result(packetizer.NumPackets()); 89 for (RtpPayload& rtp_payload : result) { 90 EXPECT_TRUE(packetizer.NextPacket(&rtp_payload.rtp_packet)); 91 } 92 return result; 93 } 94 95 Av1Frame ReassembleFrame(ArrayView<const RtpPayload> rtp_payloads) { 96 std::vector<ArrayView<const uint8_t>> payloads(rtp_payloads.size()); 97 for (size_t i = 0; i < rtp_payloads.size(); ++i) { 98 payloads[i] = rtp_payloads[i]; 99 } 100 return Av1Frame(VideoRtpDepacketizerAv1().AssembleFrame(payloads)); 101 } 102 103 TEST(RtpPacketizerAv1Test, EmptyPayload) { 104 RtpPacketizer::PayloadSizeLimits limits; 105 RtpPacketizerAv1 packetizer({}, limits, VideoFrameType::kVideoFrameKey, true); 106 EXPECT_EQ(packetizer.NumPackets(), 0u); 107 } 108 109 TEST(RtpPacketizerAv1Test, PacketizeOneObuWithoutSizeAndExtension) { 110 auto kFrame = BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) 111 .WithoutSize() 112 .WithPayload({1, 2, 3, 4, 5, 6, 7})}); 113 EXPECT_THAT(Packetize(kFrame, {}), 114 ElementsAre(ElementsAre(0b00'01'0000, // aggregation header 115 kAv1ObuTypeFrame, 1, 2, 3, 4, 5, 6, 7))); 116 } 117 118 TEST(RtpPacketizerAv1Test, PacketizeOneObuWithoutSizeWithExtension) { 119 auto kFrame = BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) 120 .WithoutSize() 121 .WithExtension(kAv1ObuExtensionS1T1) 122 .WithPayload({2, 3, 4, 5, 6, 7})}); 123 EXPECT_THAT( 124 Packetize(kFrame, {}), 125 ElementsAre(ElementsAre(0b00'01'0000, // aggregation header 126 kAv1ObuTypeFrame | kAv1ObuExtensionPresentBit, 127 kAv1ObuExtensionS1T1, 2, 3, 4, 5, 6, 7))); 128 } 129 130 TEST(RtpPacketizerAv1Test, RemovesObuSizeFieldWithoutExtension) { 131 auto kFrame = BuildAv1Frame( 132 {Av1Obu(kAv1ObuTypeFrame).WithPayload({11, 12, 13, 14, 15, 16, 17})}); 133 EXPECT_THAT( 134 Packetize(kFrame, {}), 135 ElementsAre(ElementsAre(0b00'01'0000, // aggregation header 136 kAv1ObuTypeFrame, 11, 12, 13, 14, 15, 16, 17))); 137 } 138 139 TEST(RtpPacketizerAv1Test, RemovesObuSizeFieldWithExtension) { 140 auto kFrame = BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) 141 .WithExtension(kAv1ObuExtensionS1T1) 142 .WithPayload({1, 2, 3, 4, 5, 6, 7})}); 143 EXPECT_THAT( 144 Packetize(kFrame, {}), 145 ElementsAre(ElementsAre(0b00'01'0000, // aggregation header 146 kAv1ObuTypeFrame | kAv1ObuExtensionPresentBit, 147 kAv1ObuExtensionS1T1, 1, 2, 3, 4, 5, 6, 7))); 148 } 149 150 TEST(RtpPacketizerAv1Test, OmitsSizeForLastObuWhenThreeObusFitsIntoThePacket) { 151 auto kFrame = BuildAv1Frame( 152 {Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({1, 2, 3, 4, 5, 6}), 153 Av1Obu(kAv1ObuTypeMetadata).WithPayload({11, 12, 13, 14}), 154 Av1Obu(kAv1ObuTypeFrame).WithPayload({21, 22, 23, 24, 25, 26})}); 155 EXPECT_THAT(Packetize(kFrame, {}), 156 ElementsAre(ElementsAre( 157 0b00'11'0000, // aggregation header 158 7, kAv1ObuTypeSequenceHeader, 1, 2, 3, 4, 5, 6, // 159 5, kAv1ObuTypeMetadata, 11, 12, 13, 14, // 160 kAv1ObuTypeFrame, 21, 22, 23, 24, 25, 26))); 161 } 162 163 TEST(RtpPacketizerAv1Test, UseSizeForAllObusWhenFourObusFitsIntoThePacket) { 164 auto kFrame = BuildAv1Frame( 165 {Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({1, 2, 3, 4, 5, 6}), 166 Av1Obu(kAv1ObuTypeMetadata).WithPayload({11, 12, 13, 14}), 167 Av1Obu(kAv1ObuTypeFrameHeader).WithPayload({21, 22, 23}), 168 Av1Obu(kAv1ObuTypeTileGroup).WithPayload({31, 32, 33, 34, 35, 36})}); 169 EXPECT_THAT(Packetize(kFrame, {}), 170 ElementsAre(ElementsAre( 171 0b00'00'0000, // aggregation header 172 7, kAv1ObuTypeSequenceHeader, 1, 2, 3, 4, 5, 6, // 173 5, kAv1ObuTypeMetadata, 11, 12, 13, 14, // 174 4, kAv1ObuTypeFrameHeader, 21, 22, 23, // 175 7, kAv1ObuTypeTileGroup, 31, 32, 33, 34, 35, 36))); 176 } 177 178 TEST(RtpPacketizerAv1Test, DiscardsTemporalDelimiterAndTileListObu) { 179 auto kFrame = BuildAv1Frame( 180 {Av1Obu(kAv1ObuTypeTemporalDelimiter), Av1Obu(kAv1ObuTypeMetadata), 181 Av1Obu(kAv1ObuTypeTileList).WithPayload({1, 2, 3, 4, 5, 6}), 182 Av1Obu(kAv1ObuTypeFrameHeader).WithPayload({21, 22, 23}), 183 Av1Obu(kAv1ObuTypeTileGroup).WithPayload({31, 32, 33, 34, 35, 36})}); 184 185 EXPECT_THAT( 186 Packetize(kFrame, {}), 187 ElementsAre(ElementsAre(0b00'11'0000, // aggregation header 188 1, 189 kAv1ObuTypeMetadata, // 190 4, kAv1ObuTypeFrameHeader, 21, 22, 191 23, // 192 kAv1ObuTypeTileGroup, 31, 32, 33, 34, 35, 36))); 193 } 194 195 TEST(RtpPacketizerAv1Test, SplitTwoObusIntoTwoPacketForceSplitObuHeader) { 196 // Craft expected payloads so that there is only one way to split original 197 // frame into two packets. 198 const uint8_t kExpectPayload1[6] = { 199 0b01'10'0000, // aggregation_header 200 3, 201 kAv1ObuTypeFrameHeader | kAv1ObuExtensionPresentBit, 202 kAv1ObuExtensionS1T1, 203 21, // 204 kAv1ObuTypeTileGroup | kAv1ObuExtensionPresentBit}; 205 const uint8_t kExpectPayload2[6] = {0b10'01'0000, // aggregation_header 206 kAv1ObuExtensionS1T1, 11, 12, 13, 14}; 207 auto kFrame = BuildAv1Frame({Av1Obu(kAv1ObuTypeFrameHeader) 208 .WithExtension(kAv1ObuExtensionS1T1) 209 .WithPayload({21}), 210 Av1Obu(kAv1ObuTypeTileGroup) 211 .WithExtension(kAv1ObuExtensionS1T1) 212 .WithPayload({11, 12, 13, 14})}); 213 214 RtpPacketizer::PayloadSizeLimits limits; 215 limits.max_payload_len = 6; 216 auto payloads = Packetize(kFrame, limits); 217 EXPECT_THAT(payloads, ElementsAre(ElementsAreArray(kExpectPayload1), 218 ElementsAreArray(kExpectPayload2))); 219 } 220 221 TEST(RtpPacketizerAv1Test, 222 SetsNbitAtTheFirstPacketOfAKeyFrameWithSequenceHeader) { 223 auto kFrame = BuildAv1Frame( 224 {Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({1, 2, 3, 4, 5, 6, 7})}); 225 RtpPacketizer::PayloadSizeLimits limits; 226 limits.max_payload_len = 6; 227 auto packets = Packetize(kFrame, limits, VideoFrameType::kVideoFrameKey); 228 ASSERT_THAT(packets, SizeIs(2)); 229 EXPECT_TRUE(packets[0].aggregation_header() & kNewCodedVideoSequenceBit); 230 EXPECT_FALSE(packets[1].aggregation_header() & kNewCodedVideoSequenceBit); 231 } 232 233 TEST(RtpPacketizerAv1Test, 234 DoesntSetNbitAtThePacketsOfAKeyFrameWithoutSequenceHeader) { 235 auto kFrame = BuildAv1Frame( 236 {Av1Obu(kAv1ObuTypeFrame).WithPayload({1, 2, 3, 4, 5, 6, 7})}); 237 RtpPacketizer::PayloadSizeLimits limits; 238 limits.max_payload_len = 6; 239 auto packets = Packetize(kFrame, limits, VideoFrameType::kVideoFrameKey); 240 ASSERT_THAT(packets, SizeIs(2)); 241 EXPECT_FALSE(packets[0].aggregation_header() & kNewCodedVideoSequenceBit); 242 EXPECT_FALSE(packets[1].aggregation_header() & kNewCodedVideoSequenceBit); 243 } 244 245 TEST(RtpPacketizerAv1Test, DoesntSetNbitAtThePacketsOfADeltaFrame) { 246 // Even when that delta frame starts with a (redundant) sequence header. 247 auto kFrame = BuildAv1Frame( 248 {Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({1, 2, 3, 4, 5, 6, 7})}); 249 RtpPacketizer::PayloadSizeLimits limits; 250 limits.max_payload_len = 6; 251 auto packets = Packetize(kFrame, limits, VideoFrameType::kVideoFrameDelta); 252 ASSERT_THAT(packets, SizeIs(2)); 253 EXPECT_FALSE(packets[0].aggregation_header() & kNewCodedVideoSequenceBit); 254 EXPECT_FALSE(packets[1].aggregation_header() & kNewCodedVideoSequenceBit); 255 } 256 257 // There are multiple valid reasonable ways to split payload into multiple 258 // packets, do not validate current choice, instead use RtpDepacketizer 259 // to validate frame is reconstracted to the same one. Note: since 260 // RtpDepacketizer always inserts obu_size fields in the output, use frame where 261 // each obu has obu_size fields for more streight forward validation. 262 TEST(RtpPacketizerAv1Test, SplitSingleObuIntoTwoPackets) { 263 auto kFrame = 264 BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) 265 .WithPayload({11, 12, 13, 14, 15, 16, 17, 18, 19})}); 266 267 RtpPacketizer::PayloadSizeLimits limits; 268 limits.max_payload_len = 8; 269 auto payloads = Packetize(kFrame, limits); 270 EXPECT_THAT(payloads, ElementsAre(SizeIs(Le(8u)), SizeIs(Le(8u)))); 271 272 // Use RtpDepacketizer to validate the split. 273 EXPECT_THAT(ReassembleFrame(payloads), ElementsAreArray(kFrame)); 274 } 275 276 TEST(RtpPacketizerAv1Test, SplitSingleObuIntoManyPackets) { 277 auto kFrame = BuildAv1Frame( 278 {Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(1200, 27))}); 279 280 RtpPacketizer::PayloadSizeLimits limits; 281 limits.max_payload_len = 100; 282 auto payloads = Packetize(kFrame, limits); 283 EXPECT_THAT(payloads, SizeIs(13u)); 284 EXPECT_THAT(payloads, Each(SizeIs(Le(100u)))); 285 286 // Use RtpDepacketizer to validate the split. 287 EXPECT_THAT(ReassembleFrame(payloads), ElementsAreArray(kFrame)); 288 } 289 290 TEST(RtpPacketizerAv1Test, SetMarkerBitForLastPacketInEndOfPictureFrame) { 291 auto kFrame = BuildAv1Frame( 292 {Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(200, 27))}); 293 294 RtpPacketizer::PayloadSizeLimits limits; 295 limits.max_payload_len = 100; 296 auto payloads = Packetize(kFrame, limits, VideoFrameType::kVideoFrameDelta, 297 /*is_last_frame_in_picture=*/true); 298 ASSERT_THAT(payloads, SizeIs(3u)); 299 EXPECT_FALSE(payloads[0].rtp_packet.Marker()); 300 EXPECT_FALSE(payloads[1].rtp_packet.Marker()); 301 EXPECT_TRUE(payloads[2].rtp_packet.Marker()); 302 } 303 304 TEST(RtpPacketizerAv1Test, DoesntSetMarkerBitForPacketsNotInEndOfPictureFrame) { 305 auto kFrame = BuildAv1Frame( 306 {Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(200, 27))}); 307 308 RtpPacketizer::PayloadSizeLimits limits; 309 limits.max_payload_len = 100; 310 auto payloads = Packetize(kFrame, limits, VideoFrameType::kVideoFrameDelta, 311 /*is_last_frame_in_picture=*/false); 312 ASSERT_THAT(payloads, SizeIs(3u)); 313 EXPECT_FALSE(payloads[0].rtp_packet.Marker()); 314 EXPECT_FALSE(payloads[1].rtp_packet.Marker()); 315 EXPECT_FALSE(payloads[2].rtp_packet.Marker()); 316 } 317 318 TEST(RtpPacketizerAv1Test, SplitTwoObusIntoTwoPackets) { 319 // 2nd OBU is too large to fit into one packet, so its head would be in the 320 // same packet as the 1st OBU. 321 auto kFrame = BuildAv1Frame( 322 {Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({11, 12}), 323 Av1Obu(kAv1ObuTypeFrame).WithPayload({1, 2, 3, 4, 5, 6, 7, 8, 9})}); 324 325 RtpPacketizer::PayloadSizeLimits limits; 326 limits.max_payload_len = 8; 327 auto payloads = Packetize(kFrame, limits); 328 EXPECT_THAT(payloads, ElementsAre(SizeIs(Le(8u)), SizeIs(Le(8u)))); 329 330 // Use RtpDepacketizer to validate the split. 331 EXPECT_THAT(ReassembleFrame(payloads), ElementsAreArray(kFrame)); 332 } 333 334 TEST(RtpPacketizerAv1Test, 335 SplitSingleObuIntoTwoPacketsBecauseOfSinglePacketLimit) { 336 auto kFrame = 337 BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) 338 .WithPayload({11, 12, 13, 14, 15, 16, 17, 18, 19})}); 339 RtpPacketizer::PayloadSizeLimits limits; 340 limits.max_payload_len = 10; 341 limits.single_packet_reduction_len = 8; 342 auto payloads = Packetize(kFrame, limits); 343 EXPECT_THAT(payloads, ElementsAre(SizeIs(Le(10u)), SizeIs(Le(10u)))); 344 345 EXPECT_THAT(ReassembleFrame(payloads), ElementsAreArray(kFrame)); 346 } 347 348 TEST(RtpPacketizerAv1TestEven, EvenDistribution) { 349 auto kFrame = BuildAv1Frame({ 350 Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(1206, 0)), 351 Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(1476, 0)), 352 Av1Obu(kAv1ObuTypeFrame).WithPayload(std::vector<uint8_t>(1431, 0)), 353 }); 354 EXPECT_THAT(Packetize(kFrame, {}), ElementsAre(SizeIs(1032), SizeIs(1032), 355 SizeIs(1032), SizeIs(1028))); 356 } 357 358 } // namespace 359 } // namespace webrtc