/*
 *  Copyright (c) 2014 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 "modules/rtp_rtcp/source/rtp_format_video_generic.h"

#include <string.h>

#include "absl/types/optional.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"

namespace webrtc {

static const size_t kGenericHeaderLength = 1;
static const size_t kExtendedHeaderLength = 2;

RtpPacketizerGeneric::RtpPacketizerGeneric(
    rtc::ArrayView<const uint8_t> payload,
    PayloadSizeLimits limits,
    const RTPVideoHeader& rtp_video_header)
    : remaining_payload_(payload) {
  BuildHeader(rtp_video_header);

  limits.max_payload_len -= header_size_;
  payload_sizes_ = SplitAboutEqually(payload.size(), limits);
  current_packet_ = payload_sizes_.begin();
}

RtpPacketizerGeneric::RtpPacketizerGeneric(
    rtc::ArrayView<const uint8_t> payload,
    PayloadSizeLimits limits)
    : header_size_(0), remaining_payload_(payload) {
  payload_sizes_ = SplitAboutEqually(payload.size(), limits);
  current_packet_ = payload_sizes_.begin();
}

RtpPacketizerGeneric::~RtpPacketizerGeneric() = default;

size_t RtpPacketizerGeneric::NumPackets() const {
  return payload_sizes_.end() - current_packet_;
}

bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) {
  RTC_DCHECK(packet);
  if (current_packet_ == payload_sizes_.end())
    return false;

  size_t next_packet_payload_len = *current_packet_;

  uint8_t* out_ptr =
      packet->AllocatePayload(header_size_ + next_packet_payload_len);
  RTC_CHECK(out_ptr);

  if (header_size_ > 0) {
    memcpy(out_ptr, header_, header_size_);
    // Remove first-packet bit, following packets are intermediate.
    header_[0] &= ~RtpFormatVideoGeneric::kFirstPacketBit;
  }

  memcpy(out_ptr + header_size_, remaining_payload_.data(),
         next_packet_payload_len);

  remaining_payload_ = remaining_payload_.subview(next_packet_payload_len);

  ++current_packet_;

  // Packets left to produce and data left to split should end at the same time.
  RTC_DCHECK_EQ(current_packet_ == payload_sizes_.end(),
                remaining_payload_.empty());

  packet->SetMarker(remaining_payload_.empty());
  return true;
}

void RtpPacketizerGeneric::BuildHeader(const RTPVideoHeader& rtp_video_header) {
  header_size_ = kGenericHeaderLength;
  header_[0] = RtpFormatVideoGeneric::kFirstPacketBit;
  if (rtp_video_header.frame_type == VideoFrameType::kVideoFrameKey) {
    header_[0] |= RtpFormatVideoGeneric::kKeyFrameBit;
  }
  if (const auto* generic_header = absl::get_if<RTPVideoHeaderLegacyGeneric>(
          &rtp_video_header.video_type_header)) {
    // Store bottom 15 bits of the picture id. Only 15 bits are used for
    // compatibility with other packetizer implemenetations.
    uint16_t picture_id = generic_header->picture_id;
    header_[0] |= RtpFormatVideoGeneric::kExtendedHeaderBit;
    header_[1] = (picture_id >> 8) & 0x7F;
    header_[2] = picture_id & 0xFF;
    header_size_ += kExtendedHeaderLength;
  }
}
}  // namespace webrtc
