tor-browser

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

rtp_packetizer_h265_unittest.cc (29480B)


      1 /*
      2 *  Copyright (c) 2023 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_h265.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <cstring>
     16 #include <initializer_list>
     17 #include <vector>
     18 
     19 #include "absl/algorithm/container.h"
     20 #include "api/array_view.h"
     21 #include "common_video/h265/h265_common.h"
     22 #include "modules/rtp_rtcp/source/rtp_format.h"
     23 #include "modules/rtp_rtcp/source/rtp_packet_h265_common.h"
     24 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
     25 #include "rtc_base/buffer.h"
     26 #include "rtc_base/checks.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::Eq;
     37 using ::testing::SizeIs;
     38 
     39 constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
     40 constexpr size_t kMaxPayloadSizeBytes = 1200;
     41 constexpr size_t kH265LengthFieldSizeBytes = 2;
     42 constexpr RtpPacketizer::PayloadSizeLimits kNoLimits;
     43 
     44 constexpr size_t kFuHeaderSizeBytes =
     45    kH265FuHeaderSizeBytes + kH265PayloadHeaderSizeBytes;
     46 
     47 struct NalUnitHeader {
     48  uint8_t forbidden_zero_bit = 0;
     49  uint8_t nal_unit_type = 0;
     50  uint8_t nuh_layer_id = 0;
     51  uint8_t nuh_temporal_id_plus1 = 0;
     52 };
     53 
     54 // Creates Buffer that looks like nal unit of given header and size.
     55 Buffer GenerateNalUnit(NalUnitHeader header, size_t size) {
     56  RTC_CHECK_GT(size, 0);
     57  Buffer buffer(size);
     58  buffer[0] = (header.nal_unit_type << 1) | (header.nuh_layer_id >> 5);
     59  buffer[1] = (header.nuh_layer_id << 3) | header.nuh_temporal_id_plus1;
     60  for (size_t i = 2; i < size; ++i) {
     61    buffer[i] = static_cast<uint8_t>(i);
     62  }
     63  // Last byte shouldn't be 0, or it may be counted as part of next 4-byte start
     64  // sequence.
     65  buffer[size - 1] |= 0x10;
     66  return buffer;
     67 }
     68 
     69 // Create frame consisting of nalus of given size.
     70 Buffer CreateFrame(std::initializer_list<size_t> nalu_sizes) {
     71  static constexpr int kStartCodeSize = 3;
     72  Buffer frame(absl::c_accumulate(nalu_sizes, size_t{0}) +
     73               kStartCodeSize * nalu_sizes.size());
     74  size_t offset = 0;
     75  for (size_t nalu_size : nalu_sizes) {
     76    EXPECT_GE(nalu_size, 1u);
     77    // Insert nalu start code
     78    frame[offset] = 0;
     79    frame[offset + 1] = 0;
     80    frame[offset + 2] = 1;
     81    // Set some valid header.
     82    frame[offset + 3] = 2;
     83    // Fill payload avoiding accidental start codes
     84    if (nalu_size > 1) {
     85      memset(frame.data() + offset + 4, 0x3f, nalu_size - 1);
     86    }
     87    offset += (kStartCodeSize + nalu_size);
     88  }
     89  return frame;
     90 }
     91 
     92 // Create frame consisting of given nalus.
     93 Buffer CreateFrame(ArrayView<const Buffer> nalus) {
     94  static constexpr int kStartCodeSize = 3;
     95  int frame_size = 0;
     96  for (const Buffer& nalu : nalus) {
     97    frame_size += (kStartCodeSize + nalu.size());
     98  }
     99  Buffer frame(frame_size);
    100  size_t offset = 0;
    101  for (const Buffer& nalu : nalus) {
    102    // Insert nalu start code
    103    frame[offset] = 0;
    104    frame[offset + 1] = 0;
    105    frame[offset + 2] = 1;
    106    // Copy the nalu unit.
    107    memcpy(frame.data() + offset + 3, nalu.data(), nalu.size());
    108    offset += (kStartCodeSize + nalu.size());
    109  }
    110  return frame;
    111 }
    112 
    113 std::vector<RtpPacketToSend> FetchAllPackets(RtpPacketizerH265* packetizer) {
    114  std::vector<RtpPacketToSend> result;
    115  size_t num_packets = packetizer->NumPackets();
    116  result.reserve(num_packets);
    117  RtpPacketToSend packet(kNoExtensions);
    118  while (packetizer->NextPacket(&packet)) {
    119    result.push_back(packet);
    120  }
    121  EXPECT_THAT(result, SizeIs(num_packets));
    122  return result;
    123 }
    124 
    125 // Single nalu tests.
    126 TEST(RtpPacketizerH265Test, SingleNalu) {
    127  const uint8_t frame[] = {0, 0, 1, H265::kIdrWRadl, 0xFF};
    128 
    129  RtpPacketizerH265 packetizer(frame, kNoLimits);
    130  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    131 
    132  ASSERT_THAT(packets, SizeIs(1));
    133  EXPECT_THAT(packets[0].payload(), ElementsAre(H265::kIdrWRadl, 0xFF));
    134 }
    135 
    136 TEST(RtpPacketizerH265Test, SingleNaluTwoPackets) {
    137  RtpPacketizer::PayloadSizeLimits limits;
    138  limits.max_payload_len = kMaxPayloadSizeBytes;
    139  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    140                                     .nuh_layer_id = 32,
    141                                     .nuh_temporal_id_plus1 = 2},
    142                                    kMaxPayloadSizeBytes),
    143                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    144                                     .nuh_layer_id = 32,
    145                                     .nuh_temporal_id_plus1 = 2},
    146                                    100)};
    147  Buffer frame = CreateFrame(nalus);
    148 
    149  RtpPacketizerH265 packetizer(frame, limits);
    150  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    151 
    152  ASSERT_THAT(packets, SizeIs(2));
    153  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
    154  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
    155 }
    156 
    157 TEST(RtpPacketizerH265Test,
    158     SingleNaluFirstPacketReductionAppliesOnlyToFirstFragment) {
    159  RtpPacketizer::PayloadSizeLimits limits;
    160  limits.max_payload_len = 200;
    161  limits.first_packet_reduction_len = 5;
    162  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    163                                     .nuh_layer_id = 32,
    164                                     .nuh_temporal_id_plus1 = 2},
    165                                    /*size=*/195),
    166                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    167                                     .nuh_layer_id = 32,
    168                                     .nuh_temporal_id_plus1 = 2},
    169                                    /*size=*/200),
    170                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    171                                     .nuh_layer_id = 32,
    172                                     .nuh_temporal_id_plus1 = 2},
    173                                    /*size=*/200)};
    174  Buffer frame = CreateFrame(nalus);
    175 
    176  RtpPacketizerH265 packetizer(frame, limits);
    177  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    178 
    179  ASSERT_THAT(packets, SizeIs(3));
    180  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
    181  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
    182  EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
    183 }
    184 
    185 TEST(RtpPacketizerH265Test,
    186     SingleNaluLastPacketReductionAppliesOnlyToLastFragment) {
    187  RtpPacketizer::PayloadSizeLimits limits;
    188  limits.max_payload_len = 200;
    189  limits.last_packet_reduction_len = 5;
    190  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    191                                     .nuh_layer_id = 32,
    192                                     .nuh_temporal_id_plus1 = 2},
    193                                    /*size=*/200),
    194                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    195                                     .nuh_layer_id = 32,
    196                                     .nuh_temporal_id_plus1 = 2},
    197                                    /*size=*/200),
    198                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    199                                     .nuh_layer_id = 32,
    200                                     .nuh_temporal_id_plus1 = 2},
    201                                    /*size=*/195)};
    202  Buffer frame = CreateFrame(nalus);
    203 
    204  RtpPacketizerH265 packetizer(frame, limits);
    205  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    206 
    207  ASSERT_THAT(packets, SizeIs(3));
    208  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
    209  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
    210  EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
    211 }
    212 
    213 TEST(RtpPacketizerH265Test, SingleNaluUsesSinglePacketReductionLen) {
    214  RtpPacketizer::PayloadSizeLimits limits;
    215  limits.max_payload_len = 200;
    216  limits.first_packet_reduction_len = 20;
    217  limits.single_packet_reduction_len = 40;
    218  limits.last_packet_reduction_len = 30;
    219  Buffer frame = CreateFrame({160});
    220 
    221  RtpPacketizerH265 packetizer(frame, limits);
    222 
    223  EXPECT_THAT(FetchAllPackets(&packetizer), SizeIs(1));
    224 }
    225 
    226 TEST(RtpPacketizerH265Test, FragmentsNalUnitWhenDoesntFitIntoSinglePacket) {
    227  RtpPacketizer::PayloadSizeLimits limits;
    228  limits.max_payload_len = 200;
    229  limits.first_packet_reduction_len = 10;
    230  limits.single_packet_reduction_len = 40;
    231  limits.last_packet_reduction_len = 10;
    232  Buffer frame = CreateFrame({170});
    233 
    234  RtpPacketizerH265 packetizer(frame, limits);
    235 
    236  EXPECT_THAT(FetchAllPackets(&packetizer), SizeIs(2));
    237 }
    238 
    239 // Aggregation tests.
    240 TEST(RtpPacketizerH265Test, ApRespectsNoPacketReduction) {
    241  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    242                                     .nuh_layer_id = 32,
    243                                     .nuh_temporal_id_plus1 = 2},
    244                                    /*size=*/3),
    245                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    246                                     .nuh_layer_id = 32,
    247                                     .nuh_temporal_id_plus1 = 2},
    248                                    /*size=*/3),
    249                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    250                                     .nuh_layer_id = 32,
    251                                     .nuh_temporal_id_plus1 = 2},
    252                                    /*size=*/0x123)};
    253  Buffer frame = CreateFrame(nalus);
    254 
    255  RtpPacketizerH265 packetizer(frame, kNoLimits);
    256  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    257 
    258  ASSERT_THAT(packets, SizeIs(1));
    259  auto payload = packets[0].payload();
    260  int type = H265::ParseNaluType(payload[0]);
    261  EXPECT_EQ(payload.size(), kH265NalHeaderSizeBytes +
    262                                3 * kH265LengthFieldSizeBytes + 3 + 3 + 0x123);
    263 
    264  EXPECT_EQ(type, H265::NaluType::kAp);
    265  payload = payload.subview(kH265NalHeaderSizeBytes);
    266  // 1st fragment.
    267  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes),
    268              ElementsAre(0, 3));  // Size.
    269  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes, 3),
    270              ElementsAreArray(nalus[0]));
    271  payload = payload.subview(kH265LengthFieldSizeBytes + 3);
    272  // 2nd fragment.
    273  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes),
    274              ElementsAre(0, 3));  // Size.
    275  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes, 3),
    276              ElementsAreArray(nalus[1]));
    277  payload = payload.subview(kH265LengthFieldSizeBytes + 3);
    278  // 3rd fragment.
    279  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes),
    280              ElementsAre(0x1, 0x23));  // Size.
    281  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes),
    282              ElementsAreArray(nalus[2]));
    283 }
    284 
    285 TEST(RtpPacketizerH265Test, ApRespectsLayerIdAndTemporalId) {
    286  // Generate 3 NALUs: NALU 1 with nuh_layer_id 2 and nuh_temporal_id_plus1 6,
    287  //                   NALU 2 with nuh_layer_id 0 and nuh_temporal_id_plus1 1,
    288  //                   NALU 3 with nuh_layer_id 32 and nuh_temporal_id_plus1 2,
    289  // So in the AP packet header, nuh_layer_id should be 0 which is the lowest
    290  // nuh_layer_id value of 3 NALUs and nuh_temporal_id_plus1 should be 1 which
    291  // is the lowest nuh_temporal_id_plus1 value of 3 NALUs
    292  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    293                                     .nuh_layer_id = 2,
    294                                     .nuh_temporal_id_plus1 = 6},
    295                                    /*size=*/3),
    296                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    297                                     .nuh_layer_id = 0,
    298                                     .nuh_temporal_id_plus1 = 1},
    299                                    /*size=*/3),
    300                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    301                                     .nuh_layer_id = 32,
    302                                     .nuh_temporal_id_plus1 = 2},
    303                                    /*size=*/0x123)};
    304  Buffer frame = CreateFrame(nalus);
    305 
    306  RtpPacketizerH265 packetizer(frame, kNoLimits);
    307  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    308 
    309  ASSERT_THAT(packets, SizeIs(1));
    310  auto payload = packets[0].payload();
    311  uint8_t type = H265::ParseNaluType(payload[0]);
    312  uint8_t layer_id = ((payload[0] & kH265LayerIDHMask) << 5) |
    313                     ((payload[1] & kH265LayerIDLMask) >> 3);
    314  uint8_t temporal_id = payload[1] & kH265TIDMask;
    315  EXPECT_EQ(payload.size(), kH265NalHeaderSizeBytes +
    316                                3 * kH265LengthFieldSizeBytes + 3 + 3 + 0x123);
    317 
    318  EXPECT_EQ(type, H265::NaluType::kAp);
    319  EXPECT_EQ(layer_id, 0);
    320  EXPECT_EQ(temporal_id, 1);
    321  payload = payload.subview(kH265NalHeaderSizeBytes);
    322  // 1st fragment.
    323  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes), ElementsAre(0, 3));
    324  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes, 3),
    325              ElementsAreArray(nalus[0]));
    326  payload = payload.subview(kH265LengthFieldSizeBytes + 3);
    327  // 2nd fragment.
    328  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes), ElementsAre(0, 3));
    329  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes, 3),
    330              ElementsAreArray(nalus[1]));
    331  payload = payload.subview(kH265LengthFieldSizeBytes + 3);
    332  // 3rd fragment.
    333  EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes),
    334              ElementsAre(0x1, 0x23));
    335  EXPECT_THAT(payload.subview(kH265LengthFieldSizeBytes),
    336              ElementsAreArray(nalus[2]));
    337 }
    338 
    339 TEST(RtpPacketizerH265Test, ApRespectsSinglePacketReduction) {
    340  RtpPacketizer::PayloadSizeLimits limits;
    341  limits.max_payload_len = 200;
    342  limits.first_packet_reduction_len = 5;
    343  limits.single_packet_reduction_len = 40;
    344  limits.last_packet_reduction_len = 5;
    345  Buffer frame = CreateFrame({60, 60, 60});
    346 
    347  RtpPacketizerH265 packetizer(frame, limits);
    348 
    349  EXPECT_THAT(FetchAllPackets(&packetizer), SizeIs(2));
    350 }
    351 
    352 TEST(RtpPacketizerH265Test, ApRespectsFirstPacketReduction) {
    353  RtpPacketizer::PayloadSizeLimits limits;
    354  limits.max_payload_len = 1000;
    355  limits.first_packet_reduction_len = 100;
    356  const size_t kFirstFragmentSize =
    357      limits.max_payload_len - limits.first_packet_reduction_len;
    358  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    359                                     .nuh_layer_id = 32,
    360                                     .nuh_temporal_id_plus1 = 2},
    361                                    /*size=*/kFirstFragmentSize),
    362                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    363                                     .nuh_layer_id = 32,
    364                                     .nuh_temporal_id_plus1 = 2},
    365                                    /*size=*/3),
    366                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    367                                     .nuh_layer_id = 32,
    368                                     .nuh_temporal_id_plus1 = 2},
    369                                    /*size=*/3)};
    370  Buffer frame = CreateFrame(nalus);
    371 
    372  RtpPacketizerH265 packetizer(frame, limits);
    373  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    374 
    375  ASSERT_THAT(packets, SizeIs(2));
    376  // Expect 1st packet is single nalu.
    377  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
    378  // Expect 2nd packet is aggregate of last two fragments.
    379  // The size of H265 nal_unit_header is 2 bytes, according to 7.3.1.2
    380  // in H265 spec. Aggregation packet type is 48, nuh_layer_id is 32 and
    381  // nuh_temporal_id_plus1 is 2, so the nal_unit_header should be "01100001
    382  // 00000010", which is 97 and 2.
    383  EXPECT_THAT(packets[1].payload(),
    384              ElementsAre(97, 2,                                        //
    385                          0, 3, nalus[1][0], nalus[1][1], nalus[1][2],  //
    386                          0, 3, nalus[2][0], nalus[2][1], nalus[2][2]));
    387 }
    388 
    389 TEST(RtpPacketizerH265Test, ApRespectsLastPacketReduction) {
    390  RtpPacketizer::PayloadSizeLimits limits;
    391  limits.max_payload_len = 1000;
    392  limits.last_packet_reduction_len = 100;
    393  const size_t kLastFragmentSize =
    394      limits.max_payload_len - limits.last_packet_reduction_len;
    395  // First nalu forces packetizer to consider last packet reduction len instead
    396  // of single packet reduction len when aggregating last 3 nalus.
    397  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kSps,
    398                                     .nuh_layer_id = 32,
    399                                     .nuh_temporal_id_plus1 = 2},
    400                                    /*size=*/999),
    401                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    402                                     .nuh_layer_id = 32,
    403                                     .nuh_temporal_id_plus1 = 2},
    404                                    /*size=*/3),
    405                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    406                                     .nuh_layer_id = 32,
    407                                     .nuh_temporal_id_plus1 = 2},
    408                                    /*size=*/3),
    409                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    410                                     .nuh_layer_id = 32,
    411                                     .nuh_temporal_id_plus1 = 2},
    412                                    /*size=*/kLastFragmentSize)};
    413  Buffer frame = CreateFrame(nalus);
    414 
    415  RtpPacketizerH265 packetizer(frame, limits);
    416  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    417 
    418  ASSERT_THAT(packets, SizeIs(3));
    419  // Expect 1st packet is single nalu with the 1st fragment.
    420  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
    421  // Expect 2nd packet is aggregate of 2nd and 3rd fragments.
    422  EXPECT_THAT(packets[1].payload(),
    423              ElementsAre(97, 2,                                        //
    424                          0, 3, nalus[1][0], nalus[1][1], nalus[1][2],  //
    425                          0, 3, nalus[2][0], nalus[2][1], nalus[2][2]));
    426  // Expect 3rd packet is single nalu with the last fragment.
    427  EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[3]));
    428 }
    429 
    430 TEST(RtpPacketizerH265Test, TooSmallForApHeaders) {
    431  RtpPacketizer::PayloadSizeLimits limits;
    432  limits.max_payload_len = 1000;
    433  const size_t kLastFragmentSize =
    434      limits.max_payload_len - 3 * kH265LengthFieldSizeBytes - 4;
    435  Buffer nalus[] = {GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    436                                     .nuh_layer_id = 32,
    437                                     .nuh_temporal_id_plus1 = 2},
    438                                    /*size=*/3),
    439                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    440                                     .nuh_layer_id = 32,
    441                                     .nuh_temporal_id_plus1 = 2},
    442                                    /*size=*/3),
    443                    GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    444                                     .nuh_layer_id = 32,
    445                                     .nuh_temporal_id_plus1 = 2},
    446                                    /*size=*/kLastFragmentSize)};
    447  Buffer frame = CreateFrame(nalus);
    448 
    449  RtpPacketizerH265 packetizer(frame, limits);
    450  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    451 
    452  ASSERT_THAT(packets, SizeIs(2));
    453  // Expect 1st packet is aggregate of 1st two fragments.
    454  EXPECT_THAT(packets[0].payload(),
    455              ElementsAre(97, 2,                                        //
    456                          0, 3, nalus[0][0], nalus[0][1], nalus[0][2],  //
    457                          0, 3, nalus[1][0], nalus[1][1], nalus[1][2]));
    458  // Expect 2nd packet is single nalu.
    459  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2]));
    460 }
    461 
    462 TEST(RtpPacketizerH265Test, LastFragmentFitsInSingleButNotLastPacket) {
    463  RtpPacketizer::PayloadSizeLimits limits;
    464  limits.max_payload_len = 1178;
    465  limits.first_packet_reduction_len = 0;
    466  limits.last_packet_reduction_len = 20;
    467  limits.single_packet_reduction_len = 20;
    468  // Actual sizes, which triggered this bug.
    469  Buffer frame = CreateFrame({20, 8, 18, 1161});
    470 
    471  RtpPacketizerH265 packetizer(frame, limits);
    472  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    473 
    474  // Last packet has to be of correct size.
    475  // Incorrect implementation might miss this constraint and not split the last
    476  // fragment in two packets.
    477  EXPECT_LE(static_cast<int>(packets.back().payload_size()),
    478            limits.max_payload_len - limits.last_packet_reduction_len);
    479 }
    480 
    481 // Splits frame with payload size `frame_payload_size` without fragmentation,
    482 // Returns sizes of the payloads excluding FU headers.
    483 std::vector<int> TestFu(size_t frame_payload_size,
    484                        const RtpPacketizer::PayloadSizeLimits& limits) {
    485  Buffer nalu[] = {
    486      GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    487                       .nuh_layer_id = 32,
    488                       .nuh_temporal_id_plus1 = 2},
    489                      kH265NalHeaderSizeBytes + frame_payload_size)};
    490  Buffer frame = CreateFrame(nalu);
    491 
    492  RtpPacketizerH265 packetizer(frame, limits);
    493  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    494 
    495  EXPECT_GE(packets.size(), 2u);  // Single packet indicates it is not FU.
    496  std::vector<uint16_t> fu_header;
    497  std::vector<int> payload_sizes;
    498 
    499  for (const RtpPacketToSend& packet : packets) {
    500    auto payload = packet.payload();
    501    EXPECT_GT(payload.size(), kFuHeaderSizeBytes);
    502    // FU header is after the 2-bytes size PayloadHdr according to 4.4.3 in spec
    503    fu_header.push_back(payload[2]);
    504    payload_sizes.push_back(payload.size() - kFuHeaderSizeBytes);
    505  }
    506 
    507  EXPECT_TRUE(fu_header.front() & kH265SBitMask);
    508  EXPECT_TRUE(fu_header.back() & kH265EBitMask);
    509  // Clear S and E bits before testing all are duplicating same original header.
    510  fu_header.front() &= ~kH265SBitMask;
    511  fu_header.back() &= ~kH265EBitMask;
    512  uint8_t nalu_type = (nalu[0][0] & kH265TypeMask) >> 1;
    513  EXPECT_THAT(fu_header, Each(Eq(nalu_type)));
    514 
    515  return payload_sizes;
    516 }
    517 
    518 // Fragmentation tests.
    519 TEST(RtpPacketizerH265Test, FuOddSize) {
    520  RtpPacketizer::PayloadSizeLimits limits;
    521  limits.max_payload_len = 1200;
    522  EXPECT_THAT(TestFu(1200, limits), ElementsAre(600, 600));
    523 }
    524 
    525 TEST(RtpPacketizerH265Test, FuWithFirstPacketReduction) {
    526  RtpPacketizer::PayloadSizeLimits limits;
    527  limits.max_payload_len = 1200;
    528  limits.first_packet_reduction_len = 4;
    529  limits.single_packet_reduction_len = 4;
    530  EXPECT_THAT(TestFu(1198, limits), ElementsAre(597, 601));
    531 }
    532 
    533 TEST(RtpPacketizerH265Test, FuWithLastPacketReduction) {
    534  RtpPacketizer::PayloadSizeLimits limits;
    535  limits.max_payload_len = 1200;
    536  limits.last_packet_reduction_len = 4;
    537  limits.single_packet_reduction_len = 4;
    538  EXPECT_THAT(TestFu(1198, limits), ElementsAre(601, 597));
    539 }
    540 
    541 TEST(RtpPacketizerH265Test, FuWithSinglePacketReduction) {
    542  RtpPacketizer::PayloadSizeLimits limits;
    543  limits.max_payload_len = 1199;
    544  limits.single_packet_reduction_len = 200;
    545  EXPECT_THAT(TestFu(1000, limits), ElementsAre(500, 500));
    546 }
    547 
    548 TEST(RtpPacketizerH265Test, FuEvenSize) {
    549  RtpPacketizer::PayloadSizeLimits limits;
    550  limits.max_payload_len = 1200;
    551  EXPECT_THAT(TestFu(1201, limits), ElementsAre(600, 601));
    552 }
    553 
    554 TEST(RtpPacketizerH265Test, FuRounding) {
    555  RtpPacketizer::PayloadSizeLimits limits;
    556  limits.max_payload_len = 1448;
    557  EXPECT_THAT(TestFu(10123, limits),
    558              ElementsAre(1265, 1265, 1265, 1265, 1265, 1266, 1266, 1266));
    559 }
    560 
    561 TEST(RtpPacketizerH265Test, FuBig) {
    562  RtpPacketizer::PayloadSizeLimits limits;
    563  limits.max_payload_len = 1200;
    564  // Generate 10 full sized packets, leave room for FU headers.
    565  EXPECT_THAT(
    566      TestFu(10 * (1200 - kFuHeaderSizeBytes), limits),
    567      ElementsAre(1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197));
    568 }
    569 
    570 // Invalid input tests.
    571 TEST(RtpPacketizerH265Test, TooShortNalUnitHeader) {
    572  const uint8_t kFrame[] = {0, 0, 0, 1, 15};
    573  RtpPacketizer::PayloadSizeLimits limits;
    574  RtpPacketizerH265 packetizer(kFrame, limits);
    575  EXPECT_EQ(packetizer.NumPackets(), 0u);
    576 }
    577 
    578 struct PacketInfo {
    579  bool first_fragment = false;
    580  bool last_fragment = false;
    581  bool aggregated = false;
    582  int nalu_index = 0;
    583  int nalu_number = 0;
    584  int payload_size = 0;
    585  int start_offset = 0;
    586 };
    587 
    588 struct MixedApFuTestParams {
    589  std::vector<int> nalus;
    590  int expect_packetsSize = 0;
    591  std::vector<PacketInfo> expected_packets;
    592 };
    593 
    594 class RtpPacketizerH265ParametrizedTest
    595    : public ::testing::TestWithParam<MixedApFuTestParams> {};
    596 
    597 // Fragmentation + aggregation mixed testing.
    598 TEST_P(RtpPacketizerH265ParametrizedTest, MixedApFu) {
    599  RtpPacketizer::PayloadSizeLimits limits;
    600  const MixedApFuTestParams params = GetParam();
    601  limits.max_payload_len = 100;
    602  std::vector<Buffer> nalus;
    603  nalus.reserve(params.nalus.size());
    604 
    605  // Generate nalus according to size specified in paramters
    606  for (size_t index = 0; index < params.nalus.size(); index++) {
    607    nalus.push_back(GenerateNalUnit({.nal_unit_type = H265::NaluType::kIdrNLp,
    608                                     .nuh_layer_id = 32,
    609                                     .nuh_temporal_id_plus1 = 2},
    610                                    params.nalus[index]));
    611  }
    612  Buffer frame = CreateFrame(nalus);
    613 
    614  RtpPacketizerH265 packetizer(frame, limits);
    615  std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
    616 
    617  ASSERT_THAT(packets, SizeIs(params.expect_packetsSize));
    618  for (int i = 0; i < params.expect_packetsSize; i++) {
    619    PacketInfo expected_packet = params.expected_packets[i];
    620    if (expected_packet.aggregated) {
    621      int type = H265::ParseNaluType(packets[i].payload()[0]);
    622      EXPECT_THAT(type, H265::NaluType::kAp);
    623      auto payload = packets[i].payload().subview(kH265NalHeaderSizeBytes);
    624      int offset = 0;
    625      // Generated AP packet header and payload align
    626      for (int j = expected_packet.nalu_index; j < expected_packet.nalu_number;
    627           j++) {
    628        EXPECT_THAT(payload.subview(0, kH265LengthFieldSizeBytes),
    629                    ElementsAre(0, nalus[j].size()));
    630        EXPECT_THAT(payload.subview(offset + kH265LengthFieldSizeBytes,
    631                                    nalus[j].size()),
    632                    ElementsAreArray(nalus[j]));
    633        offset += kH265LengthFieldSizeBytes + nalus[j].size();
    634      }
    635    } else {
    636      uint8_t fu_header = 0;
    637      fu_header |= (expected_packet.first_fragment ? kH265SBitMask : 0);
    638      fu_header |= (expected_packet.last_fragment ? kH265EBitMask : 0);
    639      fu_header |= H265::NaluType::kIdrNLp;
    640      EXPECT_THAT(packets[i].payload().subview(0, kFuHeaderSizeBytes),
    641                  ElementsAre(99, 2, fu_header));
    642      EXPECT_THAT(packets[i].payload().subview(kFuHeaderSizeBytes),
    643                  ElementsAreArray(nalus[expected_packet.nalu_index].data() +
    644                                       kH265NalHeaderSizeBytes +
    645                                       expected_packet.start_offset,
    646                                   expected_packet.payload_size));
    647    }
    648  }
    649 }
    650 
    651 INSTANTIATE_TEST_SUITE_P(
    652    RtpPacketizerH265Test,
    653    RtpPacketizerH265ParametrizedTest,
    654    testing::Values(
    655        // FU + AP + FU.
    656        // GenerateNalUnit will include 2 bytes nalu header, for FU packet split
    657        // calculation, this 2-byte nalu header length should be excluded.
    658        MixedApFuTestParams{.nalus = {140, 20, 20, 160},
    659                            .expect_packetsSize = 5,
    660                            .expected_packets = {{.first_fragment = true,
    661                                                  .nalu_index = 0,
    662                                                  .payload_size = 69,
    663                                                  .start_offset = 0},
    664                                                 {.last_fragment = true,
    665                                                  .nalu_index = 0,
    666                                                  .payload_size = 69,
    667                                                  .start_offset = 69},
    668                                                 {.aggregated = true,
    669                                                  .nalu_index = 1,
    670                                                  .nalu_number = 2},
    671                                                 {.first_fragment = true,
    672                                                  .nalu_index = 3,
    673                                                  .payload_size = 79,
    674                                                  .start_offset = 0},
    675                                                 {.last_fragment = true,
    676                                                  .nalu_index = 3,
    677                                                  .payload_size = 79,
    678                                                  .start_offset = 79}}},
    679        // AP + FU + AP
    680        MixedApFuTestParams{
    681            .nalus = {20, 20, 160, 30, 30},
    682            .expect_packetsSize = 4,
    683            .expected_packets = {
    684                {.aggregated = true, .nalu_index = 0, .nalu_number = 2},
    685                {.first_fragment = true,
    686                 .nalu_index = 2,
    687                 .payload_size = 79,
    688                 .start_offset = 0},
    689                {.last_fragment = true,
    690                 .nalu_index = 2,
    691                 .payload_size = 79,
    692                 .start_offset = 79},
    693                {.aggregated = true, .nalu_index = 3, .nalu_number = 2}}}));
    694 
    695 }  // namespace
    696 }  // namespace webrtc