root/media/formats/mp4/box_definitions.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. BoxType
  2. Parse
  3. BoxType
  4. Parse
  5. BoxType
  6. Parse
  7. sample_count
  8. BoxType
  9. Parse
  10. BoxType
  11. Parse
  12. version
  13. BoxType
  14. Parse
  15. default_iv_size
  16. BoxType
  17. Parse
  18. BoxType
  19. Parse
  20. BoxType
  21. Parse
  22. next_track_id
  23. BoxType
  24. Parse
  25. height
  26. BoxType
  27. Parse
  28. BoxType
  29. Parse
  30. BoxType
  31. Parse
  32. BoxType
  33. Parse
  34. BoxType
  35. Parse
  36. BoxType
  37. Parse
  38. BoxType
  39. Parse
  40. length_size
  41. BoxType
  42. Parse
  43. v_spacing
  44. BoxType
  45. Parse
  46. height
  47. BoxType
  48. Parse
  49. IsFormatValid
  50. BoxType
  51. Parse
  52. samplerate
  53. BoxType
  54. Parse
  55. duration
  56. BoxType
  57. Parse
  58. BoxType
  59. Parse
  60. BoxType
  61. Parse
  62. BoxType
  63. Parse
  64. BoxType
  65. Parse
  66. default_sample_flags
  67. BoxType
  68. Parse
  69. BoxType
  70. Parse
  71. BoxType
  72. Parse
  73. BoxType
  74. Parse
  75. BoxType
  76. Parse
  77. has_default_sample_flags
  78. BoxType
  79. Parse
  80. data_offset
  81. BoxType
  82. Parse
  83. BoxType
  84. Parse
  85. BoxType
  86. Parse
  87. BoxType
  88. Parse
  89. sample_depends_on

// 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.

#include "media/formats/mp4/box_definitions.h"

#include "base/logging.h"
#include "media/formats/mp4/es_descriptor.h"
#include "media/formats/mp4/rcheck.h"

namespace media {
namespace mp4 {

FileType::FileType() {}
FileType::~FileType() {}
FourCC FileType::BoxType() const { return FOURCC_FTYP; }

bool FileType::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFourCC(&major_brand) && reader->Read4(&minor_version));
  size_t num_brands = (reader->size() - reader->pos()) / sizeof(FourCC);
  return reader->SkipBytes(sizeof(FourCC) * num_brands);  // compatible_brands
}

ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() {}
ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {}
FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; }

bool ProtectionSystemSpecificHeader::Parse(BoxReader* reader) {
  // Validate the box's contents and hang on to the system ID.
  uint32 size;
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->ReadVec(&system_id, 16) &&
         reader->Read4(&size) &&
         reader->HasBytes(size));

  // Copy the entire box, including the header, for passing to EME as initData.
  DCHECK(raw_box.empty());
  raw_box.assign(reader->data(), reader->data() + reader->size());
  return true;
}

SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {}
FourCC SampleAuxiliaryInformationOffset::BoxType() const { return FOURCC_SAIO; }

bool SampleAuxiliaryInformationOffset::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  if (reader->flags() & 1)
    RCHECK(reader->SkipBytes(8));

  uint32 count;
  RCHECK(reader->Read4(&count) &&
         reader->HasBytes(count * (reader->version() == 1 ? 8 : 4)));
  offsets.resize(count);

  for (uint32 i = 0; i < count; i++) {
    if (reader->version() == 1) {
      RCHECK(reader->Read8(&offsets[i]));
    } else {
      RCHECK(reader->Read4Into8(&offsets[i]));
    }
  }
  return true;
}

SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize()
  : default_sample_info_size(0), sample_count(0) {
}
SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() {}
FourCC SampleAuxiliaryInformationSize::BoxType() const { return FOURCC_SAIZ; }

bool SampleAuxiliaryInformationSize::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  if (reader->flags() & 1)
    RCHECK(reader->SkipBytes(8));

  RCHECK(reader->Read1(&default_sample_info_size) &&
         reader->Read4(&sample_count));
  if (default_sample_info_size == 0)
    return reader->ReadVec(&sample_info_sizes, sample_count);
  return true;
}

OriginalFormat::OriginalFormat() : format(FOURCC_NULL) {}
OriginalFormat::~OriginalFormat() {}
FourCC OriginalFormat::BoxType() const { return FOURCC_FRMA; }

bool OriginalFormat::Parse(BoxReader* reader) {
  return reader->ReadFourCC(&format);
}

SchemeType::SchemeType() : type(FOURCC_NULL), version(0) {}
SchemeType::~SchemeType() {}
FourCC SchemeType::BoxType() const { return FOURCC_SCHM; }

bool SchemeType::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->ReadFourCC(&type) &&
         reader->Read4(&version));
  return true;
}

TrackEncryption::TrackEncryption()
  : is_encrypted(false), default_iv_size(0) {
}
TrackEncryption::~TrackEncryption() {}
FourCC TrackEncryption::BoxType() const { return FOURCC_TENC; }

bool TrackEncryption::Parse(BoxReader* reader) {
  uint8 flag;
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->SkipBytes(2) &&
         reader->Read1(&flag) &&
         reader->Read1(&default_iv_size) &&
         reader->ReadVec(&default_kid, 16));
  is_encrypted = (flag != 0);
  if (is_encrypted) {
    RCHECK(default_iv_size == 8 || default_iv_size == 16);
  } else {
    RCHECK(default_iv_size == 0);
  }
  return true;
}

SchemeInfo::SchemeInfo() {}
SchemeInfo::~SchemeInfo() {}
FourCC SchemeInfo::BoxType() const { return FOURCC_SCHI; }

bool SchemeInfo::Parse(BoxReader* reader) {
  return reader->ScanChildren() && reader->ReadChild(&track_encryption);
}

ProtectionSchemeInfo::ProtectionSchemeInfo() {}
ProtectionSchemeInfo::~ProtectionSchemeInfo() {}
FourCC ProtectionSchemeInfo::BoxType() const { return FOURCC_SINF; }

bool ProtectionSchemeInfo::Parse(BoxReader* reader) {
  RCHECK(reader->ScanChildren() &&
         reader->ReadChild(&format) &&
         reader->ReadChild(&type));
  if (type.type == FOURCC_CENC)
    RCHECK(reader->ReadChild(&info));
  // Other protection schemes are silently ignored. Since the protection scheme
  // type can't be determined until this box is opened, we return 'true' for
  // non-CENC protection scheme types. It is the parent box's responsibility to
  // ensure that this scheme type is a supported one.
  return true;
}

MovieHeader::MovieHeader()
    : creation_time(0),
      modification_time(0),
      timescale(0),
      duration(0),
      rate(-1),
      volume(-1),
      next_track_id(0) {}
MovieHeader::~MovieHeader() {}
FourCC MovieHeader::BoxType() const { return FOURCC_MVHD; }

bool MovieHeader::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());

  if (reader->version() == 1) {
    RCHECK(reader->Read8(&creation_time) &&
           reader->Read8(&modification_time) &&
           reader->Read4(&timescale) &&
           reader->Read8(&duration));
  } else {
    RCHECK(reader->Read4Into8(&creation_time) &&
           reader->Read4Into8(&modification_time) &&
           reader->Read4(&timescale) &&
           reader->Read4Into8(&duration));
  }

  RCHECK(reader->Read4s(&rate) &&
         reader->Read2s(&volume) &&
         reader->SkipBytes(10) &&  // reserved
         reader->SkipBytes(36) &&  // matrix
         reader->SkipBytes(24) &&  // predefined zero
         reader->Read4(&next_track_id));
  return true;
}

TrackHeader::TrackHeader()
    : creation_time(0),
      modification_time(0),
      track_id(0),
      duration(0),
      layer(-1),
      alternate_group(-1),
      volume(-1),
      width(0),
      height(0) {}
TrackHeader::~TrackHeader() {}
FourCC TrackHeader::BoxType() const { return FOURCC_TKHD; }

bool TrackHeader::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  if (reader->version() == 1) {
    RCHECK(reader->Read8(&creation_time) &&
           reader->Read8(&modification_time) &&
           reader->Read4(&track_id) &&
           reader->SkipBytes(4) &&    // reserved
           reader->Read8(&duration));
  } else {
    RCHECK(reader->Read4Into8(&creation_time) &&
           reader->Read4Into8(&modification_time) &&
           reader->Read4(&track_id) &&
           reader->SkipBytes(4) &&   // reserved
           reader->Read4Into8(&duration));
  }

  RCHECK(reader->SkipBytes(8) &&  // reserved
         reader->Read2s(&layer) &&
         reader->Read2s(&alternate_group) &&
         reader->Read2s(&volume) &&
         reader->SkipBytes(2) &&  // reserved
         reader->SkipBytes(36) &&  // matrix
         reader->Read4(&width) &&
         reader->Read4(&height));
  width >>= 16;
  height >>= 16;
  return true;
}

SampleDescription::SampleDescription() : type(kInvalid) {}
SampleDescription::~SampleDescription() {}
FourCC SampleDescription::BoxType() const { return FOURCC_STSD; }

bool SampleDescription::Parse(BoxReader* reader) {
  uint32 count;
  RCHECK(reader->SkipBytes(4) &&
         reader->Read4(&count));
  video_entries.clear();
  audio_entries.clear();

  // Note: this value is preset before scanning begins. See comments in the
  // Parse(Media*) function.
  if (type == kVideo) {
    RCHECK(reader->ReadAllChildren(&video_entries));
  } else if (type == kAudio) {
    RCHECK(reader->ReadAllChildren(&audio_entries));
  }
  return true;
}

SyncSample::SyncSample() : is_present(false) {}
SyncSample::~SyncSample() {}
FourCC SyncSample::BoxType() const { return FOURCC_STSS; }

bool SyncSample::Parse(BoxReader* reader) {
  uint32 entry_count;
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->Read4(&entry_count));

  is_present = true;

  if (entry_count == 0)
    return true;

  // Skip over the entries since we don't actually care about
  // them right now. In most fragmented files with an stss, there
  // aren't any entries anyways because the random access point info
  // is signalled in the fragments.
  int64 skip_size = 4 * entry_count;
  if (skip_size > INT_MAX)
    return false;

  RCHECK(reader->SkipBytes(skip_size));

  return true;
}

SampleTable::SampleTable() {}
SampleTable::~SampleTable() {}
FourCC SampleTable::BoxType() const { return FOURCC_STBL; }

bool SampleTable::Parse(BoxReader* reader) {
  return reader->ScanChildren() &&
      reader->ReadChild(&description) &&
      reader->MaybeReadChild(&sync_sample);
}

EditList::EditList() {}
EditList::~EditList() {}
FourCC EditList::BoxType() const { return FOURCC_ELST; }

bool EditList::Parse(BoxReader* reader) {
  uint32 count;
  RCHECK(reader->ReadFullBoxHeader() && reader->Read4(&count));

  if (reader->version() == 1) {
    RCHECK(reader->HasBytes(count * 20));
  } else {
    RCHECK(reader->HasBytes(count * 12));
  }
  edits.resize(count);

  for (std::vector<EditListEntry>::iterator edit = edits.begin();
       edit != edits.end(); ++edit) {
    if (reader->version() == 1) {
      RCHECK(reader->Read8(&edit->segment_duration) &&
             reader->Read8s(&edit->media_time));
    } else {
      RCHECK(reader->Read4Into8(&edit->segment_duration) &&
             reader->Read4sInto8s(&edit->media_time));
    }
    RCHECK(reader->Read2s(&edit->media_rate_integer) &&
           reader->Read2s(&edit->media_rate_fraction));
  }
  return true;
}

Edit::Edit() {}
Edit::~Edit() {}
FourCC Edit::BoxType() const { return FOURCC_EDTS; }

bool Edit::Parse(BoxReader* reader) {
  return reader->ScanChildren() && reader->ReadChild(&list);
}

HandlerReference::HandlerReference() : type(kInvalid) {}
HandlerReference::~HandlerReference() {}
FourCC HandlerReference::BoxType() const { return FOURCC_HDLR; }

bool HandlerReference::Parse(BoxReader* reader) {
  FourCC hdlr_type;
  RCHECK(reader->SkipBytes(8) && reader->ReadFourCC(&hdlr_type));
  // Note: remaining fields in box ignored
  if (hdlr_type == FOURCC_VIDE) {
    type = kVideo;
  } else if (hdlr_type == FOURCC_SOUN) {
    type = kAudio;
  } else {
    type = kInvalid;
  }
  return true;
}

AVCDecoderConfigurationRecord::AVCDecoderConfigurationRecord()
    : version(0),
      profile_indication(0),
      profile_compatibility(0),
      avc_level(0),
      length_size(0) {}

AVCDecoderConfigurationRecord::~AVCDecoderConfigurationRecord() {}
FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; }

bool AVCDecoderConfigurationRecord::Parse(BoxReader* reader) {
  RCHECK(reader->Read1(&version) && version == 1 &&
         reader->Read1(&profile_indication) &&
         reader->Read1(&profile_compatibility) &&
         reader->Read1(&avc_level));

  uint8 length_size_minus_one;
  RCHECK(reader->Read1(&length_size_minus_one) &&
         (length_size_minus_one & 0xfc) == 0xfc);
  length_size = (length_size_minus_one & 0x3) + 1;

  uint8 num_sps;
  RCHECK(reader->Read1(&num_sps) && (num_sps & 0xe0) == 0xe0);
  num_sps &= 0x1f;

  sps_list.resize(num_sps);
  for (int i = 0; i < num_sps; i++) {
    uint16 sps_length;
    RCHECK(reader->Read2(&sps_length) &&
           reader->ReadVec(&sps_list[i], sps_length));
  }

  uint8 num_pps;
  RCHECK(reader->Read1(&num_pps));

  pps_list.resize(num_pps);
  for (int i = 0; i < num_pps; i++) {
    uint16 pps_length;
    RCHECK(reader->Read2(&pps_length) &&
           reader->ReadVec(&pps_list[i], pps_length));
  }

  return true;
}

PixelAspectRatioBox::PixelAspectRatioBox() : h_spacing(1), v_spacing(1) {}
PixelAspectRatioBox::~PixelAspectRatioBox() {}
FourCC PixelAspectRatioBox::BoxType() const { return FOURCC_PASP; }

bool PixelAspectRatioBox::Parse(BoxReader* reader) {
  RCHECK(reader->Read4(&h_spacing) &&
         reader->Read4(&v_spacing));
  return true;
}

VideoSampleEntry::VideoSampleEntry()
    : format(FOURCC_NULL),
      data_reference_index(0),
      width(0),
      height(0) {}

VideoSampleEntry::~VideoSampleEntry() {}
FourCC VideoSampleEntry::BoxType() const {
  DCHECK(false) << "VideoSampleEntry should be parsed according to the "
                << "handler type recovered in its Media ancestor.";
  return FOURCC_NULL;
}

bool VideoSampleEntry::Parse(BoxReader* reader) {
  format = reader->type();
  RCHECK(reader->SkipBytes(6) &&
         reader->Read2(&data_reference_index) &&
         reader->SkipBytes(16) &&
         reader->Read2(&width) &&
         reader->Read2(&height) &&
         reader->SkipBytes(50));

  RCHECK(reader->ScanChildren() &&
         reader->MaybeReadChild(&pixel_aspect));

  if (format == FOURCC_ENCV) {
    // Continue scanning until a recognized protection scheme is found, or until
    // we run out of protection schemes.
    while (sinf.type.type != FOURCC_CENC) {
      if (!reader->ReadChild(&sinf))
        return false;
    }
  }

  if (IsFormatValid())
    RCHECK(reader->ReadChild(&avcc));

  return true;
}

bool VideoSampleEntry::IsFormatValid() const {
  return format == FOURCC_AVC1 || format == FOURCC_AVC3 ||
      (format == FOURCC_ENCV && (sinf.format.format == FOURCC_AVC1 ||
                                 sinf.format.format == FOURCC_AVC3));
}

ElementaryStreamDescriptor::ElementaryStreamDescriptor()
    : object_type(kForbidden) {}

ElementaryStreamDescriptor::~ElementaryStreamDescriptor() {}

FourCC ElementaryStreamDescriptor::BoxType() const {
  return FOURCC_ESDS;
}

bool ElementaryStreamDescriptor::Parse(BoxReader* reader) {
  std::vector<uint8> data;
  ESDescriptor es_desc;

  RCHECK(reader->ReadFullBoxHeader());
  RCHECK(reader->ReadVec(&data, reader->size() - reader->pos()));
  RCHECK(es_desc.Parse(data));

  object_type = es_desc.object_type();

  RCHECK(aac.Parse(es_desc.decoder_specific_info()));

  return true;
}

AudioSampleEntry::AudioSampleEntry()
    : format(FOURCC_NULL),
      data_reference_index(0),
      channelcount(0),
      samplesize(0),
      samplerate(0) {}

AudioSampleEntry::~AudioSampleEntry() {}

FourCC AudioSampleEntry::BoxType() const {
  DCHECK(false) << "AudioSampleEntry should be parsed according to the "
                << "handler type recovered in its Media ancestor.";
  return FOURCC_NULL;
}

bool AudioSampleEntry::Parse(BoxReader* reader) {
  format = reader->type();
  RCHECK(reader->SkipBytes(6) &&
         reader->Read2(&data_reference_index) &&
         reader->SkipBytes(8) &&
         reader->Read2(&channelcount) &&
         reader->Read2(&samplesize) &&
         reader->SkipBytes(4) &&
         reader->Read4(&samplerate));
  // Convert from 16.16 fixed point to integer
  samplerate >>= 16;

  RCHECK(reader->ScanChildren());
  if (format == FOURCC_ENCA) {
    // Continue scanning until a recognized protection scheme is found, or until
    // we run out of protection schemes.
    while (sinf.type.type != FOURCC_CENC) {
      if (!reader->ReadChild(&sinf))
        return false;
    }
  }

  // ESDS is not valid in case of EAC3.
  RCHECK(reader->MaybeReadChild(&esds));
  return true;
}

MediaHeader::MediaHeader()
    : creation_time(0),
      modification_time(0),
      timescale(0),
      duration(0) {}
MediaHeader::~MediaHeader() {}
FourCC MediaHeader::BoxType() const { return FOURCC_MDHD; }

bool MediaHeader::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());

  if (reader->version() == 1) {
    RCHECK(reader->Read8(&creation_time) &&
           reader->Read8(&modification_time) &&
           reader->Read4(&timescale) &&
           reader->Read8(&duration));
  } else {
    RCHECK(reader->Read4Into8(&creation_time) &&
           reader->Read4Into8(&modification_time) &&
           reader->Read4(&timescale) &&
           reader->Read4Into8(&duration));
  }
  // Skip language information
  return reader->SkipBytes(4);
}

MediaInformation::MediaInformation() {}
MediaInformation::~MediaInformation() {}
FourCC MediaInformation::BoxType() const { return FOURCC_MINF; }

bool MediaInformation::Parse(BoxReader* reader) {
  return reader->ScanChildren() &&
         reader->ReadChild(&sample_table);
}

Media::Media() {}
Media::~Media() {}
FourCC Media::BoxType() const { return FOURCC_MDIA; }

bool Media::Parse(BoxReader* reader) {
  RCHECK(reader->ScanChildren() &&
         reader->ReadChild(&header) &&
         reader->ReadChild(&handler));

  // Maddeningly, the HandlerReference box specifies how to parse the
  // SampleDescription box, making the latter the only box (of those that we
  // support) which cannot be parsed correctly on its own (or even with
  // information from its strict ancestor tree). We thus copy the handler type
  // to the sample description box *before* parsing it to provide this
  // information while parsing.
  information.sample_table.description.type = handler.type;
  RCHECK(reader->ReadChild(&information));
  return true;
}

Track::Track() {}
Track::~Track() {}
FourCC Track::BoxType() const { return FOURCC_TRAK; }

bool Track::Parse(BoxReader* reader) {
  RCHECK(reader->ScanChildren() &&
         reader->ReadChild(&header) &&
         reader->ReadChild(&media) &&
         reader->MaybeReadChild(&edit));
  return true;
}

MovieExtendsHeader::MovieExtendsHeader() : fragment_duration(0) {}
MovieExtendsHeader::~MovieExtendsHeader() {}
FourCC MovieExtendsHeader::BoxType() const { return FOURCC_MEHD; }

bool MovieExtendsHeader::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  if (reader->version() == 1) {
    RCHECK(reader->Read8(&fragment_duration));
  } else {
    RCHECK(reader->Read4Into8(&fragment_duration));
  }
  return true;
}

TrackExtends::TrackExtends()
    : track_id(0),
      default_sample_description_index(0),
      default_sample_duration(0),
      default_sample_size(0),
      default_sample_flags(0) {}
TrackExtends::~TrackExtends() {}
FourCC TrackExtends::BoxType() const { return FOURCC_TREX; }

bool TrackExtends::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->Read4(&track_id) &&
         reader->Read4(&default_sample_description_index) &&
         reader->Read4(&default_sample_duration) &&
         reader->Read4(&default_sample_size) &&
         reader->Read4(&default_sample_flags));
  return true;
}

MovieExtends::MovieExtends() {}
MovieExtends::~MovieExtends() {}
FourCC MovieExtends::BoxType() const { return FOURCC_MVEX; }

bool MovieExtends::Parse(BoxReader* reader) {
  header.fragment_duration = 0;
  return reader->ScanChildren() &&
         reader->MaybeReadChild(&header) &&
         reader->ReadChildren(&tracks);
}

Movie::Movie() : fragmented(false) {}
Movie::~Movie() {}
FourCC Movie::BoxType() const { return FOURCC_MOOV; }

bool Movie::Parse(BoxReader* reader) {
  return reader->ScanChildren() &&
         reader->ReadChild(&header) &&
         reader->ReadChildren(&tracks) &&
         // Media Source specific: 'mvex' required
         reader->ReadChild(&extends) &&
         reader->MaybeReadChildren(&pssh);
}

TrackFragmentDecodeTime::TrackFragmentDecodeTime() : decode_time(0) {}
TrackFragmentDecodeTime::~TrackFragmentDecodeTime() {}
FourCC TrackFragmentDecodeTime::BoxType() const { return FOURCC_TFDT; }

bool TrackFragmentDecodeTime::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  if (reader->version() == 1)
    return reader->Read8(&decode_time);
  else
    return reader->Read4Into8(&decode_time);
}

MovieFragmentHeader::MovieFragmentHeader() : sequence_number(0) {}
MovieFragmentHeader::~MovieFragmentHeader() {}
FourCC MovieFragmentHeader::BoxType() const { return FOURCC_MFHD; }

bool MovieFragmentHeader::Parse(BoxReader* reader) {
  return reader->SkipBytes(4) && reader->Read4(&sequence_number);
}

TrackFragmentHeader::TrackFragmentHeader()
    : track_id(0),
      sample_description_index(0),
      default_sample_duration(0),
      default_sample_size(0),
      default_sample_flags(0),
      has_default_sample_flags(false) {}

TrackFragmentHeader::~TrackFragmentHeader() {}
FourCC TrackFragmentHeader::BoxType() const { return FOURCC_TFHD; }

bool TrackFragmentHeader::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader() && reader->Read4(&track_id));

  // Media Source specific: reject tracks that set 'base-data-offset-present'.
  // Although the Media Source requires that 'default-base-is-moof' (14496-12
  // Amendment 2) be set, we omit this check as many otherwise-valid files in
  // the wild don't set it.
  //
  //  RCHECK((flags & 0x020000) && !(flags & 0x1));
  RCHECK(!(reader->flags() & 0x1));

  if (reader->flags() & 0x2) {
    RCHECK(reader->Read4(&sample_description_index));
  } else {
    sample_description_index = 0;
  }

  if (reader->flags() & 0x8) {
    RCHECK(reader->Read4(&default_sample_duration));
  } else {
    default_sample_duration = 0;
  }

  if (reader->flags() & 0x10) {
    RCHECK(reader->Read4(&default_sample_size));
  } else {
    default_sample_size = 0;
  }

  if (reader->flags() & 0x20) {
    RCHECK(reader->Read4(&default_sample_flags));
    has_default_sample_flags = true;
  } else {
    has_default_sample_flags = false;
  }

  return true;
}

TrackFragmentRun::TrackFragmentRun()
    : sample_count(0), data_offset(0) {}
TrackFragmentRun::~TrackFragmentRun() {}
FourCC TrackFragmentRun::BoxType() const { return FOURCC_TRUN; }

bool TrackFragmentRun::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader() &&
         reader->Read4(&sample_count));
  const uint32 flags = reader->flags();

  bool data_offset_present = (flags & 0x1) != 0;
  bool first_sample_flags_present = (flags & 0x4) != 0;
  bool sample_duration_present = (flags & 0x100) != 0;
  bool sample_size_present = (flags & 0x200) != 0;
  bool sample_flags_present = (flags & 0x400) != 0;
  bool sample_composition_time_offsets_present = (flags & 0x800) != 0;

  if (data_offset_present) {
    RCHECK(reader->Read4(&data_offset));
  } else {
    data_offset = 0;
  }

  uint32 first_sample_flags;
  if (first_sample_flags_present)
    RCHECK(reader->Read4(&first_sample_flags));

  int fields = sample_duration_present + sample_size_present +
      sample_flags_present + sample_composition_time_offsets_present;
  RCHECK(reader->HasBytes(fields * sample_count));

  if (sample_duration_present)
    sample_durations.resize(sample_count);
  if (sample_size_present)
    sample_sizes.resize(sample_count);
  if (sample_flags_present)
    sample_flags.resize(sample_count);
  if (sample_composition_time_offsets_present)
    sample_composition_time_offsets.resize(sample_count);

  for (uint32 i = 0; i < sample_count; ++i) {
    if (sample_duration_present)
      RCHECK(reader->Read4(&sample_durations[i]));
    if (sample_size_present)
      RCHECK(reader->Read4(&sample_sizes[i]));
    if (sample_flags_present)
      RCHECK(reader->Read4(&sample_flags[i]));
    if (sample_composition_time_offsets_present)
      RCHECK(reader->Read4s(&sample_composition_time_offsets[i]));
  }

  if (first_sample_flags_present) {
    if (sample_flags.size() == 0) {
      sample_flags.push_back(first_sample_flags);
    } else {
      sample_flags[0] = first_sample_flags;
    }
  }
  return true;
}

TrackFragment::TrackFragment() {}
TrackFragment::~TrackFragment() {}
FourCC TrackFragment::BoxType() const { return FOURCC_TRAF; }

bool TrackFragment::Parse(BoxReader* reader) {
  return reader->ScanChildren() &&
         reader->ReadChild(&header) &&
         // Media Source specific: 'tfdt' required
         reader->ReadChild(&decode_time) &&
         reader->MaybeReadChildren(&runs) &&
         reader->MaybeReadChild(&auxiliary_offset) &&
         reader->MaybeReadChild(&auxiliary_size) &&
         reader->MaybeReadChild(&sdtp);
}

MovieFragment::MovieFragment() {}
MovieFragment::~MovieFragment() {}
FourCC MovieFragment::BoxType() const { return FOURCC_MOOF; }

bool MovieFragment::Parse(BoxReader* reader) {
  RCHECK(reader->ScanChildren() &&
         reader->ReadChild(&header) &&
         reader->ReadChildren(&tracks) &&
         reader->MaybeReadChildren(&pssh));
  return true;
}

IndependentAndDisposableSamples::IndependentAndDisposableSamples() {}
IndependentAndDisposableSamples::~IndependentAndDisposableSamples() {}
FourCC IndependentAndDisposableSamples::BoxType() const { return FOURCC_SDTP; }

bool IndependentAndDisposableSamples::Parse(BoxReader* reader) {
  RCHECK(reader->ReadFullBoxHeader());
  RCHECK(reader->version() == 0);
  RCHECK(reader->flags() == 0);

  int sample_count = reader->size() - reader->pos();
  sample_depends_on_.resize(sample_count);
  for (int i = 0; i < sample_count; ++i) {
    uint8 sample_info;
    RCHECK(reader->Read1(&sample_info));

    sample_depends_on_[i] =
        static_cast<SampleDependsOn>((sample_info >> 4) & 0x3);

    RCHECK(sample_depends_on_[i] != kSampleDependsOnReserved);
  }

  return true;
}

SampleDependsOn IndependentAndDisposableSamples::sample_depends_on(
    size_t i) const {
  if (i >= sample_depends_on_.size())
    return kSampleDependsOnUnknown;

  return sample_depends_on_[i];
}

}  // namespace mp4
}  // namespace media

/* [<][>][^][v][top][bottom][index][help] */