tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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