rtp_frame_reference_finder_unittest.cc (10234B)
1 /* 2 * Copyright (c) 2016 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/video_coding/rtp_frame_reference_finder.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <map> 16 #include <memory> 17 #include <optional> 18 #include <set> 19 #include <utility> 20 21 #include "api/rtp_packet_infos.h" 22 #include "api/video/encoded_frame.h" 23 #include "api/video/encoded_image.h" 24 #include "api/video/video_codec_type.h" 25 #include "api/video/video_content_type.h" 26 #include "api/video/video_frame_type.h" 27 #include "api/video/video_rotation.h" 28 #include "api/video/video_timing.h" 29 #include "modules/rtp_rtcp/source/frame_object.h" 30 #include "modules/rtp_rtcp/source/rtp_video_header.h" 31 #include "rtc_base/random.h" 32 #include "test/gtest.h" 33 34 namespace webrtc { 35 36 namespace { 37 std::unique_ptr<RtpFrameObject> CreateFrame( 38 uint16_t seq_num_start, 39 uint16_t seq_num_end, 40 bool keyframe, 41 VideoCodecType codec, 42 const RTPVideoTypeHeader& video_type_header) { 43 RTPVideoHeader video_header; 44 video_header.frame_type = keyframe ? VideoFrameType::kVideoFrameKey 45 : VideoFrameType::kVideoFrameDelta; 46 video_header.video_type_header = video_type_header; 47 48 // clang-format off 49 return std::make_unique<RtpFrameObject>( 50 seq_num_start, 51 seq_num_end, 52 /*markerBit=*/true, 53 /*times_nacked=*/0, 54 /*first_packet_received_time=*/0, 55 /*last_packet_received_time=*/0, 56 /*rtp_timestamp=*/0, 57 /*ntp_time_ms=*/0, 58 VideoSendTiming(), 59 /*payload_type=*/0, 60 codec, 61 kVideoRotation_0, 62 VideoContentType::UNSPECIFIED, 63 video_header, 64 /*color_space=*/std::nullopt, 65 /*frame_instrumentation_data=*/std::nullopt, 66 RtpPacketInfos(), 67 EncodedImageBuffer::Create(/*size=*/0)); 68 // clang-format on 69 } 70 } // namespace 71 72 class TestRtpFrameReferenceFinder : public ::testing::Test { 73 protected: 74 TestRtpFrameReferenceFinder() 75 : rand_(0x8739211), 76 reference_finder_(std::make_unique<RtpFrameReferenceFinder>()), 77 frames_from_callback_(FrameComp()) {} 78 79 uint16_t Rand() { return rand_.Rand<uint16_t>(); } 80 81 void OnCompleteFrames(RtpFrameReferenceFinder::ReturnVector frames) { 82 for (auto& frame : frames) { 83 int64_t pid = frame->Id(); 84 uint16_t sidx = *frame->SpatialIndex(); 85 auto frame_it = frames_from_callback_.find(std::make_pair(pid, sidx)); 86 if (frame_it != frames_from_callback_.end()) { 87 ADD_FAILURE() << "Already received frame with (pid:sidx): (" << pid 88 << ":" << sidx << ")"; 89 return; 90 } 91 92 frames_from_callback_.insert( 93 std::make_pair(std::make_pair(pid, sidx), std::move(frame))); 94 } 95 } 96 97 void InsertGeneric(uint16_t seq_num_start, 98 uint16_t seq_num_end, 99 bool keyframe) { 100 std::unique_ptr<RtpFrameObject> frame = 101 CreateFrame(seq_num_start, seq_num_end, keyframe, kVideoCodecGeneric, 102 RTPVideoTypeHeader()); 103 104 OnCompleteFrames(reference_finder_->ManageFrame(std::move(frame))); 105 } 106 107 void InsertH264(uint16_t seq_num_start, uint16_t seq_num_end, bool keyframe) { 108 std::unique_ptr<RtpFrameObject> frame = 109 CreateFrame(seq_num_start, seq_num_end, keyframe, kVideoCodecH264, 110 RTPVideoTypeHeader()); 111 OnCompleteFrames(reference_finder_->ManageFrame(std::move(frame))); 112 } 113 114 void InsertPadding(uint16_t seq_num) { 115 OnCompleteFrames(reference_finder_->PaddingReceived(seq_num)); 116 } 117 118 // Check if a frame with picture id `pid` and spatial index `sidx` has been 119 // delivered from the packet buffer, and if so, if it has the references 120 // specified by `refs`. 121 template <typename... T> 122 void CheckReferences(int64_t picture_id_offset, 123 uint16_t sidx, 124 T... refs) const { 125 int64_t pid = picture_id_offset; 126 auto frame_it = frames_from_callback_.find(std::make_pair(pid, sidx)); 127 if (frame_it == frames_from_callback_.end()) { 128 ADD_FAILURE() << "Could not find frame with (pid:sidx): (" << pid << ":" 129 << sidx << ")"; 130 return; 131 } 132 133 std::set<int64_t> actual_refs; 134 for (uint8_t r = 0; r < frame_it->second->num_references; ++r) 135 actual_refs.insert(frame_it->second->references[r]); 136 137 std::set<int64_t> expected_refs; 138 RefsToSet(&expected_refs, refs...); 139 140 ASSERT_EQ(expected_refs, actual_refs); 141 } 142 143 template <typename... T> 144 void CheckReferencesGeneric(int64_t pid, T... refs) const { 145 CheckReferences(pid, 0, refs...); 146 } 147 148 template <typename... T> 149 void CheckReferencesH264(int64_t pid, T... refs) const { 150 CheckReferences(pid, 0, refs...); 151 } 152 153 template <typename... T> 154 void RefsToSet(std::set<int64_t>* m, int64_t ref, T... refs) const { 155 m->insert(ref); 156 RefsToSet(m, refs...); 157 } 158 159 void RefsToSet(std::set<int64_t>* /* m */) const {} 160 161 Random rand_; 162 std::unique_ptr<RtpFrameReferenceFinder> reference_finder_; 163 struct FrameComp { 164 bool operator()(const std::pair<int64_t, uint8_t> f1, 165 const std::pair<int64_t, uint8_t> f2) const { 166 if (f1.first == f2.first) 167 return f1.second < f2.second; 168 return f1.first < f2.first; 169 } 170 }; 171 std:: 172 map<std::pair<int64_t, uint8_t>, std::unique_ptr<EncodedFrame>, FrameComp> 173 frames_from_callback_; 174 }; 175 176 TEST_F(TestRtpFrameReferenceFinder, PaddingPackets) { 177 uint16_t sn = Rand(); 178 179 InsertGeneric(sn, sn, true); 180 InsertGeneric(sn + 2, sn + 2, false); 181 EXPECT_EQ(1UL, frames_from_callback_.size()); 182 InsertPadding(sn + 1); 183 EXPECT_EQ(2UL, frames_from_callback_.size()); 184 } 185 186 TEST_F(TestRtpFrameReferenceFinder, PaddingPacketsReordered) { 187 uint16_t sn = Rand(); 188 189 InsertGeneric(sn, sn, true); 190 InsertPadding(sn + 1); 191 InsertPadding(sn + 4); 192 InsertGeneric(sn + 2, sn + 3, false); 193 194 EXPECT_EQ(2UL, frames_from_callback_.size()); 195 CheckReferencesGeneric(sn); 196 CheckReferencesGeneric(sn + 3, sn + 0); 197 } 198 199 TEST_F(TestRtpFrameReferenceFinder, PaddingPacketsReorderedMultipleKeyframes) { 200 uint16_t sn = Rand(); 201 202 InsertGeneric(sn, sn, true); 203 InsertPadding(sn + 1); 204 InsertPadding(sn + 4); 205 InsertGeneric(sn + 2, sn + 3, false); 206 InsertGeneric(sn + 5, sn + 5, true); 207 InsertPadding(sn + 6); 208 InsertPadding(sn + 9); 209 InsertGeneric(sn + 7, sn + 8, false); 210 211 EXPECT_EQ(4UL, frames_from_callback_.size()); 212 } 213 214 TEST_F(TestRtpFrameReferenceFinder, AdvanceSavedKeyframe) { 215 uint16_t sn = Rand(); 216 217 InsertGeneric(sn, sn, true); 218 InsertGeneric(sn + 1, sn + 1, true); 219 InsertGeneric(sn + 2, sn + 10000, false); 220 InsertGeneric(sn + 10001, sn + 20000, false); 221 InsertGeneric(sn + 20001, sn + 30000, false); 222 InsertGeneric(sn + 30001, sn + 40000, false); 223 224 EXPECT_EQ(6UL, frames_from_callback_.size()); 225 } 226 227 TEST_F(TestRtpFrameReferenceFinder, ClearTo) { 228 uint16_t sn = Rand(); 229 230 InsertGeneric(sn, sn + 1, true); 231 InsertGeneric(sn + 4, sn + 5, false); // stashed 232 EXPECT_EQ(1UL, frames_from_callback_.size()); 233 234 InsertGeneric(sn + 6, sn + 7, true); // keyframe 235 EXPECT_EQ(2UL, frames_from_callback_.size()); 236 reference_finder_->ClearTo(sn + 7); 237 238 InsertGeneric(sn + 8, sn + 9, false); // first frame after keyframe. 239 EXPECT_EQ(3UL, frames_from_callback_.size()); 240 241 InsertGeneric(sn + 2, sn + 3, false); // late, cleared past this frame. 242 EXPECT_EQ(3UL, frames_from_callback_.size()); 243 } 244 245 TEST_F(TestRtpFrameReferenceFinder, H264KeyFrameReferences) { 246 uint16_t sn = Rand(); 247 InsertH264(sn, sn, true); 248 249 ASSERT_EQ(1UL, frames_from_callback_.size()); 250 CheckReferencesH264(sn); 251 } 252 253 TEST_F(TestRtpFrameReferenceFinder, H264SequenceNumberWrap) { 254 uint16_t sn = 0xFFFF; 255 256 InsertH264(sn - 1, sn - 1, true); 257 InsertH264(sn, sn, false); 258 InsertH264(sn + 1, sn + 1, false); 259 InsertH264(sn + 2, sn + 2, false); 260 261 ASSERT_EQ(4UL, frames_from_callback_.size()); 262 CheckReferencesH264(sn - 1); 263 CheckReferencesH264(sn, sn - 1); 264 CheckReferencesH264(sn + 1, sn); 265 CheckReferencesH264(sn + 2, sn + 1); 266 } 267 268 TEST_F(TestRtpFrameReferenceFinder, H264Frames) { 269 uint16_t sn = Rand(); 270 271 InsertH264(sn, sn, true); 272 InsertH264(sn + 1, sn + 1, false); 273 InsertH264(sn + 2, sn + 2, false); 274 InsertH264(sn + 3, sn + 3, false); 275 276 ASSERT_EQ(4UL, frames_from_callback_.size()); 277 CheckReferencesH264(sn); 278 CheckReferencesH264(sn + 1, sn); 279 CheckReferencesH264(sn + 2, sn + 1); 280 CheckReferencesH264(sn + 3, sn + 2); 281 } 282 283 TEST_F(TestRtpFrameReferenceFinder, H264Reordering) { 284 uint16_t sn = Rand(); 285 286 InsertH264(sn, sn, true); 287 InsertH264(sn + 1, sn + 1, false); 288 InsertH264(sn + 3, sn + 3, false); 289 InsertH264(sn + 2, sn + 2, false); 290 InsertH264(sn + 5, sn + 5, false); 291 InsertH264(sn + 6, sn + 6, false); 292 InsertH264(sn + 4, sn + 4, false); 293 294 ASSERT_EQ(7UL, frames_from_callback_.size()); 295 CheckReferencesH264(sn); 296 CheckReferencesH264(sn + 1, sn); 297 CheckReferencesH264(sn + 2, sn + 1); 298 CheckReferencesH264(sn + 3, sn + 2); 299 CheckReferencesH264(sn + 4, sn + 3); 300 CheckReferencesH264(sn + 5, sn + 4); 301 CheckReferencesH264(sn + 6, sn + 5); 302 } 303 304 TEST_F(TestRtpFrameReferenceFinder, H264SequenceNumberWrapMulti) { 305 uint16_t sn = 0xFFFF; 306 307 InsertH264(sn - 3, sn - 2, true); 308 InsertH264(sn - 1, sn + 1, false); 309 InsertH264(sn + 2, sn + 3, false); 310 InsertH264(sn + 4, sn + 7, false); 311 312 ASSERT_EQ(4UL, frames_from_callback_.size()); 313 CheckReferencesH264(sn - 2); 314 CheckReferencesH264(sn + 1, sn - 2); 315 CheckReferencesH264(sn + 3, sn + 1); 316 CheckReferencesH264(sn + 7, sn + 3); 317 } 318 319 TEST_F(TestRtpFrameReferenceFinder, Av1FrameNoDependencyDescriptor) { 320 uint16_t sn = 0xFFFF; 321 std::unique_ptr<RtpFrameObject> frame = 322 CreateFrame(/*seq_num_start=*/sn, /*seq_num_end=*/sn, /*keyframe=*/true, 323 kVideoCodecAV1, RTPVideoTypeHeader()); 324 325 OnCompleteFrames(reference_finder_->ManageFrame(std::move(frame))); 326 327 ASSERT_EQ(1UL, frames_from_callback_.size()); 328 CheckReferencesGeneric(sn); 329 } 330 331 } // namespace webrtc