text: /*
   *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include <algorithm>
  #include <limits>
  #include <memory>
  #include <vector>
  
  #include "api/array_view.h"
  #include "modules/include/module_common_types.h"
  #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
  #include "modules/rtp_rtcp/source/byte_io.h"
  #include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
  #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
  #include "test/gmock.h"
  #include "test/gtest.h"
  
  namespace webrtc {
  namespace {
  
  using ::testing::Each;
  using ::testing::ElementsAreArray;
  using ::testing::Le;
  using ::testing::SizeIs;
  using ::testing::Contains;
  
  constexpr RtpPacketizer::PayloadSizeLimits kNoSizeLimits;
  
  std::vector<int> NextPacketFillPayloadSizes(RtpPacketizerGeneric* packetizer) {
    RtpPacketToSend packet(nullptr);
    std::vector<int> result;
    while (packetizer->NextPacket(&packet)) {
      result.push_back(packet.payload_size());
    }
    return result;
  }
  
  TEST(RtpPacketizerVideoGeneric, RespectsMaxPayloadSize) {
    const size_t kPayloadSize = 50;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RtpPacketizer::PayloadSizeLimits limits;
    limits.max_payload_len = 6;
    RtpPacketizerGeneric packetizer(kPayload, limits, RTPVideoHeader(),
                                    VideoFrameType::kVideoFrameKey);
  
    std::vector<int> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
  
    EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
  }
  
  TEST(RtpPacketizerVideoGeneric, UsesMaxPayloadSize) {
    const size_t kPayloadSize = 50;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RtpPacketizer::PayloadSizeLimits limits;
    limits.max_payload_len = 6;
    RtpPacketizerGeneric packetizer(kPayload, limits, RTPVideoHeader(),
                                    VideoFrameType::kVideoFrameKey);
  
    std::vector<int> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
  
    // With kPayloadSize > max_payload_len^2, there should be packets that use
    // all the payload, otherwise it is possible to use less packets.
    EXPECT_THAT(payload_sizes, Contains(limits.max_payload_len));
  }
  
  TEST(RtpPacketizerVideoGeneric, WritesExtendedHeaderWhenPictureIdIsSet) {
    const size_t kPayloadSize = 13;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RTPVideoHeader rtp_video_header;
    rtp_video_header.generic.emplace().frame_id = 37;
    RtpPacketizerGeneric packetizer(kPayload, kNoSizeLimits, rtp_video_header,
                                    VideoFrameType::kVideoFrameKey);
  
    RtpPacketToSend packet(nullptr);
    ASSERT_TRUE(packetizer.NextPacket(&packet));
  
    rtc::ArrayView<const uint8_t> payload = packet.payload();
    EXPECT_EQ(payload.size(), 3 + kPayloadSize);
    EXPECT_TRUE(payload[0] & 0x04);  // Extended header bit is set.
    // Frame id is 37.
    EXPECT_EQ(0u, payload[1]);
    EXPECT_EQ(37u, payload[2]);
  }
  
  TEST(RtpPacketizerVideoGeneric, RespectsMaxPayloadSizeWithExtendedHeader) {
    const int kPayloadSize = 50;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RtpPacketizer::PayloadSizeLimits limits;
    limits.max_payload_len = 6;
    RTPVideoHeader rtp_video_header;
    rtp_video_header.generic.emplace().frame_id = 37;
    RtpPacketizerGeneric packetizer(kPayload, limits, rtp_video_header,
                                    VideoFrameType::kVideoFrameKey);
  
    std::vector<int> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
  
    EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
  }
  
  TEST(RtpPacketizerVideoGeneric, UsesMaxPayloadSizeWithExtendedHeader) {
    const int kPayloadSize = 50;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RtpPacketizer::PayloadSizeLimits limits;
    limits.max_payload_len = 6;
    RTPVideoHeader rtp_video_header;
    rtp_video_header.generic.emplace().frame_id = 37;
    RtpPacketizerGeneric packetizer(kPayload, limits, rtp_video_header,
                                    VideoFrameType::kVideoFrameKey);
    std::vector<int> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
  
    // With kPayloadSize > max_payload_len^2, there should be packets that use
    // all the payload, otherwise it is possible to use less packets.
    EXPECT_THAT(payload_sizes, Contains(limits.max_payload_len));
  }
  
  TEST(RtpPacketizerVideoGeneric, FrameIdOver15bitsWrapsAround) {
    const int kPayloadSize = 13;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RTPVideoHeader rtp_video_header;
    rtp_video_header.generic.emplace().frame_id = 0x8137;
    RtpPacketizerGeneric packetizer(kPayload, kNoSizeLimits, rtp_video_header,
                                    VideoFrameType::kVideoFrameKey);
  
    RtpPacketToSend packet(nullptr);
    ASSERT_TRUE(packetizer.NextPacket(&packet));
  
    rtc::ArrayView<const uint8_t> payload = packet.payload();
    EXPECT_TRUE(payload[0] & 0x04);  // Extended header bit is set.
    // Frame id is 0x137.
    EXPECT_EQ(0x01u, payload[1]);
    EXPECT_EQ(0x37u, payload[2]);
  }
  
  TEST(RtpPacketizerVideoGeneric, NoFrameIdDoesNotWriteExtendedHeader) {
    const int kPayloadSize = 13;
    const uint8_t kPayload[kPayloadSize] = {};
  
    RtpPacketizerGeneric packetizer(kPayload, kNoSizeLimits, RTPVideoHeader(),
                                    VideoFrameType::kVideoFrameKey);
  
    RtpPacketToSend packet(nullptr);
    ASSERT_TRUE(packetizer.NextPacket(&packet));
  
    rtc::ArrayView<const uint8_t> payload = packet.payload();
    EXPECT_FALSE(payload[0] & 0x04);
  }
  
  TEST(RtpPacketizerVideoGeneric, DoesNotWriteHeaderForRawPayload) {
    const uint8_t kPayload[] = {0x05, 0x25, 0x52};
  
    RtpPacketizerGeneric packetizer(kPayload, kNoSizeLimits);
  
    RtpPacketToSend packet(nullptr);
    ASSERT_TRUE(packetizer.NextPacket(&packet));
  
    rtc::ArrayView<const uint8_t> payload = packet.payload();
    EXPECT_THAT(payload, ElementsAreArray(kPayload));
  }
  
  TEST(RtpDepacketizerVideoGeneric, NonExtendedHeaderNoFrameId) {
    const size_t kPayloadLen = 1;
    uint8_t payload[kPayloadLen] = {0x01};
  
    RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/true);
    RtpDepacketizer::ParsedPayload parsed_payload;
    depacketizer.Parse(&parsed_payload, payload, kPayloadLen);
  
    EXPECT_FALSE(parsed_payload.video_header().generic);
  }
  
  TEST(RtpDepacketizerVideoGeneric, ExtendedHeaderParsesFrameId) {
    const size_t kPayloadLen = 3;
    uint8_t payload[kPayloadLen] = {0x05, 0x13, 0x37};
  
    RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/true);
    RtpDepacketizer::ParsedPayload parsed_payload;
    depacketizer.Parse(&parsed_payload, payload, kPayloadLen);
  
    ASSERT_TRUE(parsed_payload.video_header().generic);
    EXPECT_EQ(0x1337, parsed_payload.video_header().generic->frame_id);
  }
  
  TEST(RtpDepacketizerVideoGeneric, DoesNotParseHeaderForRawPayload) {
    const uint8_t kPayload[] = {0x05, 0x25, 0x52};
    const size_t kPayloadLen = sizeof(kPayload);
  
    RtpDepacketizerGeneric depacketizer(/*generic_header_enabled=*/false);
    RtpDepacketizer::ParsedPayload parsed_payload;
    depacketizer.Parse(&parsed_payload, kPayload, kPayloadLen);
  
    EXPECT_FALSE(parsed_payload.video_header().generic);
    EXPECT_THAT(rtc::MakeArrayView<const uint8_t>(parsed_payload.payload,
                                                  parsed_payload.payload_length),
                ElementsAreArray(kPayload));
  }
  
  }  // namespace
  }  // namespace webrtc
  