// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
#define MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_

#include <stddef.h>
#include <stdint.h>

#include <string>
#include <vector>

#include "base/compiler_specific.h"
#include "media/base/decrypt_config.h"
#include "media/base/media_export.h"
#include "media/base/media_log.h"
#include "media/base/video_codecs.h"
#include "media/formats/mp4/aac.h"
#include "media/formats/mp4/avc.h"
#include "media/formats/mp4/box_reader.h"
#include "media/formats/mp4/fourccs.h"

namespace media {
namespace mp4 {

enum TrackType { kInvalid = 0, kVideo, kAudio, kText, kHint };

enum SampleFlags {
  kSampleIsNonSyncSample = 0x10000
};

#define DECLARE_BOX_METHODS(T)            \
  T();                                    \
  T(const T& other);                      \
  ~T() override;                          \
  bool Parse(BoxReader* reader) override; \
  FourCC BoxType() const override;

struct MEDIA_EXPORT FileType : Box {
  DECLARE_BOX_METHODS(FileType);

  FourCC major_brand;
  uint32_t minor_version;
};

// If only copying the 'pssh' boxes, use ProtectionSystemSpecificHeader.
// If access to the individual fields is needed, use
// FullProtectionSystemSpecificHeader.
struct MEDIA_EXPORT ProtectionSystemSpecificHeader : Box {
  DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader);

  std::vector<uint8_t> raw_box;
};

struct MEDIA_EXPORT FullProtectionSystemSpecificHeader : Box {
  DECLARE_BOX_METHODS(FullProtectionSystemSpecificHeader);

  std::vector<uint8_t> system_id;
  std::vector<std::vector<uint8_t>> key_ids;
  std::vector<uint8_t> data;
};

struct MEDIA_EXPORT SampleAuxiliaryInformationOffset : Box {
  DECLARE_BOX_METHODS(SampleAuxiliaryInformationOffset);

  std::vector<uint64_t> offsets;
};

struct MEDIA_EXPORT SampleAuxiliaryInformationSize : Box {
  DECLARE_BOX_METHODS(SampleAuxiliaryInformationSize);

  uint8_t default_sample_info_size;
  uint32_t sample_count;
  std::vector<uint8_t> sample_info_sizes;
};

// Represent an entry in SampleEncryption box or CENC auxiliary info.
struct MEDIA_EXPORT SampleEncryptionEntry {
  SampleEncryptionEntry();
  SampleEncryptionEntry(const SampleEncryptionEntry& other);
  ~SampleEncryptionEntry();

  // Parse SampleEncryptionEntry from |reader|.
  // |iv_size| specifies the size of initialization vector. |has_subsamples|
  // indicates whether this sample encryption entry constains subsamples.
  // Returns false if parsing fails.
  bool Parse(BufferReader* reader, uint8_t iv_size, bool has_subsamples);

  // Get accumulated size of subsamples. Returns false if there is an overflow
  // anywhere.
  bool GetTotalSizeOfSubsamples(size_t* total_size) const;

  uint8_t initialization_vector[16];
  std::vector<SubsampleEntry> subsamples;
};

// ISO/IEC 23001-7:2015 8.1.1.
struct MEDIA_EXPORT SampleEncryption : Box {
  enum SampleEncryptionFlags {
    kUseSubsampleEncryption = 2,
  };

  DECLARE_BOX_METHODS(SampleEncryption);

  bool use_subsample_encryption;
  // We may not know |iv_size| before reading this box, so we store the box
  // data for parsing later when |iv_size| is known.
  std::vector<uint8_t> sample_encryption_data;
};

struct MEDIA_EXPORT OriginalFormat : Box {
  DECLARE_BOX_METHODS(OriginalFormat);

  FourCC format;
};

struct MEDIA_EXPORT SchemeType : Box {
  DECLARE_BOX_METHODS(SchemeType);

  FourCC type;
  uint32_t version;
};

struct MEDIA_EXPORT TrackEncryption : Box {
  DECLARE_BOX_METHODS(TrackEncryption);

  // Note: this definition is specific to the CENC protection type.
  bool is_encrypted;
  uint8_t default_iv_size;
  std::vector<uint8_t> default_kid;
};

struct MEDIA_EXPORT SchemeInfo : Box {
  DECLARE_BOX_METHODS(SchemeInfo);

  TrackEncryption track_encryption;
};

struct MEDIA_EXPORT ProtectionSchemeInfo : Box {
  DECLARE_BOX_METHODS(ProtectionSchemeInfo);

  OriginalFormat format;
  SchemeType type;
  SchemeInfo info;
};

struct MEDIA_EXPORT MovieHeader : Box {
  DECLARE_BOX_METHODS(MovieHeader);

  uint64_t creation_time;
  uint64_t modification_time;
  uint32_t timescale;
  uint64_t duration;
  int32_t rate;
  int16_t volume;
  uint32_t next_track_id;
};

struct MEDIA_EXPORT TrackHeader : Box {
  DECLARE_BOX_METHODS(TrackHeader);

  uint64_t creation_time;
  uint64_t modification_time;
  uint32_t track_id;
  uint64_t duration;
  int16_t layer;
  int16_t alternate_group;
  int16_t volume;
  uint32_t width;
  uint32_t height;
};

struct MEDIA_EXPORT EditListEntry {
  uint64_t segment_duration;
  int64_t media_time;
  int16_t media_rate_integer;
  int16_t media_rate_fraction;
};

struct MEDIA_EXPORT EditList : Box {
  DECLARE_BOX_METHODS(EditList);

  std::vector<EditListEntry> edits;
};

struct MEDIA_EXPORT Edit : Box {
  DECLARE_BOX_METHODS(Edit);

  EditList list;
};

struct MEDIA_EXPORT HandlerReference : Box {
  DECLARE_BOX_METHODS(HandlerReference);

  TrackType type;
  std::string name;
};

struct MEDIA_EXPORT AVCDecoderConfigurationRecord : Box {
  DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord);

  // Parses AVCDecoderConfigurationRecord data encoded in |data|.
  // Note: This method is intended to parse data outside the MP4StreamParser
  //       context and therefore the box header is not expected to be present
  //       in |data|.
  // Returns true if |data| was successfully parsed.
  bool Parse(const uint8_t* data, int data_size);

  uint8_t version;
  uint8_t profile_indication;
  uint8_t profile_compatibility;
  uint8_t avc_level;
  uint8_t length_size;

  typedef std::vector<uint8_t> SPS;
  typedef std::vector<uint8_t> PPS;

  std::vector<SPS> sps_list;
  std::vector<PPS> pps_list;

 private:
  bool ParseInternal(BufferReader* reader,
                     const scoped_refptr<MediaLog>& media_log);
};

struct MEDIA_EXPORT VPCodecConfigurationRecord : Box {
  DECLARE_BOX_METHODS(VPCodecConfigurationRecord);

  VideoCodecProfile profile;
};

struct MEDIA_EXPORT PixelAspectRatioBox : Box {
  DECLARE_BOX_METHODS(PixelAspectRatioBox);

  uint32_t h_spacing;
  uint32_t v_spacing;
};

struct MEDIA_EXPORT VideoSampleEntry : Box {
  DECLARE_BOX_METHODS(VideoSampleEntry);

  FourCC format;
  uint16_t data_reference_index;
  uint16_t width;
  uint16_t height;

  PixelAspectRatioBox pixel_aspect;
  ProtectionSchemeInfo sinf;

  VideoCodec video_codec;
  VideoCodecProfile video_codec_profile;

  bool IsFormatValid() const;

  scoped_refptr<BitstreamConverter> frame_bitstream_converter;
};

struct MEDIA_EXPORT ElementaryStreamDescriptor : Box {
  DECLARE_BOX_METHODS(ElementaryStreamDescriptor);

  uint8_t object_type;
  AAC aac;
};

struct MEDIA_EXPORT AudioSampleEntry : Box {
  DECLARE_BOX_METHODS(AudioSampleEntry);

  FourCC format;
  uint16_t data_reference_index;
  uint16_t channelcount;
  uint16_t samplesize;
  uint32_t samplerate;

  ProtectionSchemeInfo sinf;
  ElementaryStreamDescriptor esds;
};

struct MEDIA_EXPORT SampleDescription : Box {
  DECLARE_BOX_METHODS(SampleDescription);

  TrackType type;
  std::vector<VideoSampleEntry> video_entries;
  std::vector<AudioSampleEntry> audio_entries;
};

struct MEDIA_EXPORT CencSampleEncryptionInfoEntry {
  CencSampleEncryptionInfoEntry();
  CencSampleEncryptionInfoEntry(const CencSampleEncryptionInfoEntry& other);
  ~CencSampleEncryptionInfoEntry();

  bool is_encrypted;
  uint8_t iv_size;
  std::vector<uint8_t> key_id;
};

struct MEDIA_EXPORT SampleGroupDescription : Box {  // 'sgpd'.
  DECLARE_BOX_METHODS(SampleGroupDescription);

  uint32_t grouping_type;
  std::vector<CencSampleEncryptionInfoEntry> entries;
};

struct MEDIA_EXPORT SampleTable : Box {
  DECLARE_BOX_METHODS(SampleTable);

  // Media Source specific: we ignore many of the sub-boxes in this box,
  // including some that are required to be present in the BMFF spec. This
  // includes the 'stts', 'stsc', and 'stco' boxes, which must contain no
  // samples in order to be compliant files.
  SampleDescription description;
  SampleGroupDescription sample_group_description;
};

struct MEDIA_EXPORT MediaHeader : Box {
  DECLARE_BOX_METHODS(MediaHeader);

  std::string language() const;

  uint64_t creation_time;
  uint64_t modification_time;
  uint32_t timescale;
  uint64_t duration;
  uint16_t language_code;
};

struct MEDIA_EXPORT MediaInformation : Box {
  DECLARE_BOX_METHODS(MediaInformation);

  SampleTable sample_table;
};

struct MEDIA_EXPORT Media : Box {
  DECLARE_BOX_METHODS(Media);

  MediaHeader header;
  HandlerReference handler;
  MediaInformation information;
};

struct MEDIA_EXPORT Track : Box {
  DECLARE_BOX_METHODS(Track);

  TrackHeader header;
  Media media;
  Edit edit;
};

struct MEDIA_EXPORT MovieExtendsHeader : Box {
  DECLARE_BOX_METHODS(MovieExtendsHeader);

  uint64_t fragment_duration;
};

struct MEDIA_EXPORT TrackExtends : Box {
  DECLARE_BOX_METHODS(TrackExtends);

  uint32_t track_id;
  uint32_t default_sample_description_index;
  uint32_t default_sample_duration;
  uint32_t default_sample_size;
  uint32_t default_sample_flags;
};

struct MEDIA_EXPORT MovieExtends : Box {
  DECLARE_BOX_METHODS(MovieExtends);

  MovieExtendsHeader header;
  std::vector<TrackExtends> tracks;
};

struct MEDIA_EXPORT Movie : Box {
  DECLARE_BOX_METHODS(Movie);

  bool fragmented;
  MovieHeader header;
  MovieExtends extends;
  std::vector<Track> tracks;
  std::vector<ProtectionSystemSpecificHeader> pssh;
};

struct MEDIA_EXPORT TrackFragmentDecodeTime : Box {
  DECLARE_BOX_METHODS(TrackFragmentDecodeTime);

  uint64_t decode_time;
};

struct MEDIA_EXPORT MovieFragmentHeader : Box {
  DECLARE_BOX_METHODS(MovieFragmentHeader);

  uint32_t sequence_number;
};

struct MEDIA_EXPORT TrackFragmentHeader : Box {
  DECLARE_BOX_METHODS(TrackFragmentHeader);

  uint32_t track_id;

  uint32_t sample_description_index;
  uint32_t default_sample_duration;
  uint32_t default_sample_size;
  uint32_t default_sample_flags;

  // As 'flags' might be all zero, we cannot use zeroness alone to identify
  // when default_sample_flags wasn't specified, unlike the other values.
  bool has_default_sample_flags;
};

struct MEDIA_EXPORT TrackFragmentRun : Box {
  DECLARE_BOX_METHODS(TrackFragmentRun);

  uint32_t sample_count;
  uint32_t data_offset;
  std::vector<uint32_t> sample_flags;
  std::vector<uint32_t> sample_sizes;
  std::vector<uint32_t> sample_durations;
  std::vector<int32_t> sample_composition_time_offsets;
};

// sample_depends_on values in ISO/IEC 14496-12 Section 8.40.2.3.
enum SampleDependsOn {
  kSampleDependsOnUnknown = 0,
  kSampleDependsOnOthers = 1,
  kSampleDependsOnNoOther = 2,
  kSampleDependsOnReserved = 3,
};

class MEDIA_EXPORT IndependentAndDisposableSamples : public Box {
 public:
  DECLARE_BOX_METHODS(IndependentAndDisposableSamples);

  // Returns the SampleDependsOn value for the |i|'th value
  // in the track. If no data was parsed for the |i|'th sample,
  // then |kSampleDependsOnUnknown| is returned.
  SampleDependsOn sample_depends_on(size_t i) const;

 private:
  std::vector<SampleDependsOn> sample_depends_on_;
};

struct MEDIA_EXPORT SampleToGroupEntry {
  enum GroupDescriptionIndexBase {
    kTrackGroupDescriptionIndexBase = 0,
    kFragmentGroupDescriptionIndexBase = 0x10000,
  };

  uint32_t sample_count;
  uint32_t group_description_index;
};

struct MEDIA_EXPORT SampleToGroup : Box {  // 'sbgp'.
  DECLARE_BOX_METHODS(SampleToGroup);

  uint32_t grouping_type;
  uint32_t grouping_type_parameter;  // Version 1 only.
  std::vector<SampleToGroupEntry> entries;
};

struct MEDIA_EXPORT TrackFragment : Box {
  DECLARE_BOX_METHODS(TrackFragment);

  TrackFragmentHeader header;
  std::vector<TrackFragmentRun> runs;
  TrackFragmentDecodeTime decode_time;
  SampleAuxiliaryInformationOffset auxiliary_offset;
  SampleAuxiliaryInformationSize auxiliary_size;
  IndependentAndDisposableSamples sdtp;
  SampleGroupDescription sample_group_description;
  SampleToGroup sample_to_group;
  SampleEncryption sample_encryption;
};

struct MEDIA_EXPORT MovieFragment : Box {
  DECLARE_BOX_METHODS(MovieFragment);

  MovieFragmentHeader header;
  std::vector<TrackFragment> tracks;
  std::vector<ProtectionSystemSpecificHeader> pssh;
};

#undef DECLARE_BOX

}  // namespace mp4
}  // namespace media

#endif  // MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
