// Copyright (c) 2016 The WebM 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 "m2ts/vpxpes2ts.h"

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <vector>

namespace libwebm {
// TODO(tomfinegan): Dedupe this and PesHeaderField.
// Stores a value and its size in bits for writing into a MPEG2 TS Header.
// Maximum size is 64 bits. Users may call the Check() method to perform minimal
// validation (size > 0 and <= 64).
struct TsHeaderField {
  TsHeaderField(std::uint64_t value, std::uint32_t size_in_bits,
                std::uint8_t byte_index, std::uint8_t bits_to_shift)
      : bits(value),
        num_bits(size_in_bits),
        index(byte_index),
        shift(bits_to_shift) {}
  TsHeaderField() = delete;
  TsHeaderField(const TsHeaderField&) = default;
  TsHeaderField(TsHeaderField&&) = default;
  ~TsHeaderField() = default;
  bool Check() const {
    return num_bits > 0 && num_bits <= 64 && shift >= 0 && shift < 64;
  }

  // Value to be stored in the field.
  std::uint64_t bits;

  // Number of bits in the value.
  const int num_bits;

  // Index into the header for the byte in which |bits| will be written.
  const std::uint8_t index;

  // Number of bits to left shift value before or'ing. Ignored for whole bytes.
  const int shift;
};

// Data storage for MPEG2 Transport Stream headers.
// https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet
struct TsHeader {
  TsHeader(bool payload_start, bool adaptation_flag, std::uint8_t counter)
      : is_payload_start(payload_start),
        has_adaptation(adaptation_flag),
        counter_value(counter) {}
  TsHeader() = delete;
  TsHeader(const TsHeader&) = default;
  TsHeader(TsHeader&&) = default;
  ~TsHeader() = default;

  void Write(PacketDataBuffer* buffer) const;

  // Indicates the packet is the beginning of a new fragmented payload.
  const bool is_payload_start;

  // Indicates the packet contains an adaptation field.
  const bool has_adaptation;

  // The sync byte is the bit pattern of 0x47 (ASCII char 'G').
  const std::uint8_t kTsHeaderSyncByte = 0x47;
  const std::uint8_t sync_byte = kTsHeaderSyncByte;

  // Value for |continuity_counter|. Used to detect gaps when demuxing.
  const std::uint8_t counter_value;

  // Set when FEC is impossible. Always 0.
  const TsHeaderField transport_error_indicator = TsHeaderField(0, 1, 1, 7);

  // This MPEG2 TS header is the start of a new payload (aka PES packet).
  const TsHeaderField payload_unit_start_indicator =
      TsHeaderField(is_payload_start ? 1 : 0, 1, 1, 6);

  // Set when the current packet has a higher priority than other packets with
  // the same PID. Always 0 for VPX.
  const TsHeaderField transport_priority = TsHeaderField(0, 1, 1, 5);

  // https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet_Identifier_.28PID.29
  // 0x0020-0x1FFA May be assigned as needed to Program Map Tables, elementary
  // streams and other data tables.
  // Note: Though we hard code to 0x20, this value is actually 13 bits-- the
  // buffer for the header is always set to 0, so it doesn't matter in practice.
  const TsHeaderField pid = TsHeaderField(0x20, 8, 2, 0);

  // Indicates scrambling key. Unused; always 0.
  const TsHeaderField scrambling_control = TsHeaderField(0, 2, 3, 6);

  // Adaptation field flag. Unused; always 0.
  // TODO(tomfinegan): Not sure this is OK. Might need to add support for
  // writing the Adaptation Field.
  const TsHeaderField adaptation_field_flag =
      TsHeaderField(has_adaptation ? 1 : 0, 1, 3, 5);

  // Payload flag. All output packets created here have payloads. Always 1.
  const TsHeaderField payload_flag = TsHeaderField(1, 1, 3, 4);

  // Continuity counter. Two bit field that is incremented for every packet.
  const TsHeaderField continuity_counter =
      TsHeaderField(counter_value, 4, 3, 3);
};

void TsHeader::Write(PacketDataBuffer* buffer) const {
  std::uint8_t* byte = &(*buffer)[0];
  *byte = sync_byte;

  *++byte = 0;
  *byte |= transport_error_indicator.bits << transport_error_indicator.shift;
  *byte |= payload_unit_start_indicator.bits
           << payload_unit_start_indicator.shift;
  *byte |= transport_priority.bits << transport_priority.shift;

  *++byte = pid.bits & 0xff;

  *++byte = 0;
  *byte |= scrambling_control.bits << scrambling_control.shift;
  *byte |= adaptation_field_flag.bits << adaptation_field_flag.shift;
  *byte |= payload_flag.bits << payload_flag.shift;
  *byte |= continuity_counter.bits;  // last 4 bits.
}

bool VpxPes2Ts::ConvertToFile() {
  output_file_ = FilePtr(fopen(output_file_name_.c_str(), "wb"), FILEDeleter());
  if (output_file_ == nullptr) {
    std::fprintf(stderr, "VpxPes2Ts: Cannot open %s for output.\n",
                 output_file_name_.c_str());
    return false;
  }
  pes_converter_.reset(new Webm2Pes(input_file_name_, this));
  if (pes_converter_ == nullptr) {
    std::fprintf(stderr, "VpxPes2Ts: Out of memory.\n");
    return false;
  }
  return pes_converter_->ConvertToPacketReceiver();
}

bool VpxPes2Ts::ReceivePacket(const PacketDataBuffer& packet_data) {
  const int kTsHeaderSize = 4;
  const int kTsPayloadSize = 184;
  const int kTsPacketSize = kTsHeaderSize + kTsPayloadSize;
  int bytes_to_packetize = static_cast<int>(packet_data.size());
  std::uint8_t continuity_counter = 0;
  std::size_t read_pos = 0;

  ts_buffer_.reserve(kTsPacketSize);

  while (bytes_to_packetize > 0) {
    if (continuity_counter > 0xf)
      continuity_counter = 0;

    // Calculate payload size (need to know if we'll have to pad with an empty
    // adaptation field).
    int payload_size = std::min(bytes_to_packetize, kTsPayloadSize);

    // Write the TS header.
    const TsHeader header(
        bytes_to_packetize == static_cast<int>(packet_data.size()),
        payload_size != kTsPayloadSize, continuity_counter);
    header.Write(&ts_buffer_);
    int write_pos = kTsHeaderSize;

    // (pre)Pad payload with an empty adaptation field. All packets must be
    // |kTsPacketSize| (188).
    if (payload_size < kTsPayloadSize) {
      // We need at least 2 bytes to write an empty adaptation field.
      if (payload_size == (kTsPayloadSize - 1)) {
        payload_size--;
      }

      // Padding adaptation field:
      //   8 bits: number of adaptation field bytes following this byte.
      //   8 bits: unused (in this program) flags.
      // This is followed by a run of 0xff to reach |kTsPayloadSize| (184)
      // bytes.
      const int pad_size = kTsPayloadSize - payload_size - 1 - 1;
      ts_buffer_[write_pos++] = pad_size + 1;
      ts_buffer_[write_pos++] = 0;

      const std::uint8_t kStuffingByte = 0xff;
      for (int i = 0; i < pad_size; ++i) {
        ts_buffer_[write_pos++] = kStuffingByte;
      }
    }

    for (int i = 0; i < payload_size; ++i) {
      ts_buffer_[write_pos++] = packet_data[read_pos++];
    }

    bytes_to_packetize -= payload_size;
    continuity_counter++;

    if (write_pos != kTsPacketSize) {
      fprintf(stderr, "VpxPes2Ts: Invalid packet length.\n");
      return false;
    }

    // Write contents of |ts_buffer_| to |output_file_|.
    // TODO(tomfinegan): Writing 188 bytes at a time isn't exactly efficient...
    // Fix me.
    if (static_cast<int>(std::fwrite(&ts_buffer_[0], 1, kTsPacketSize,
                                     output_file_.get())) != kTsPacketSize) {
      std::fprintf(stderr, "VpxPes2Ts: TS packet write failed.\n");
      return false;
    }
  }

  return true;
}

}  // namespace libwebm
