+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['avcC'] = AVCConfigurationBox.bind(null);
+
+class HEVCConfigurationBox extends Atom {
+ constructor(parent) {
+ super(parent);
+
+ this.description = 'HEVC Configuration Box';
+ this.configuration_version = 0;
+ this.general_profile_space = 0;
+ this.general_tier_flag = 0;
+ this.general_profile_idc = 0;
+ this.general_profile_compatibility_flags = 0;
+ this.general_constraint_indicator_flags = 0;
+ this.general_level_idc = 0;
+ this.min_spatial_segmentation_idc = 0;
+ this.parallelismType = 0;
+ this.chromaFormat = 0;
+ this.bitDepthLumaMinus8 = 0;
+ this.bitDepthChromaMinus8 = 0;
+ this.avgFrameRate = 0;
+ this.constantFrameRate = 0;
+ this.numTemporalLayers = 0;
+ this.temporalIdNested = 0;
+ };
+
+ parse(buffer, offset)
+ {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.configuration_version = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ var byte = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ this.general_profile_space = (byte & 0x00C0) >> 6;
+ this.general_tier_flag = (byte & 0x0020) >> 5;
+ this.general_profile_idc = byte & 0x001F;
+
+ this.general_profile_compatibility_flags = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.general_constraint_indicator_flags = view.getUint16(headerOffset) << 32
+ + view.getUint32(headerOffset + 2);
+ headerOffset += 6;
+
+ this.general_level_idc = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ // bit(4) reserved = ‘1111’b;
+ this.min_spatial_segmentation_idc = view.getUint16(headerOffset) & 0x0FFF;
+ headerOffset += 2;
+
+ // bit(6) reserved = ‘111111’b;
+ this.parallelismType = view.getUint8(headerOffset) & 0x03;
+ ++headerOffset;
+
+ // bit(6) reserved = ‘111111’b;
+ this.chromaFormat = view.getUint8(headerOffset) & 0x03;
+ ++headerOffset;
+
+ // bit(5) reserved = ‘11111’b;
+ this.bitDepthLumaMinus8 = view.getUint8(headerOffset) & 0x07;
+ ++headerOffset;
+
+ // bit(5) reserved = ‘11111’b;
+ this.bitDepthChromaMinus8 = view.getUint8(headerOffset) & 0x07;
+ ++headerOffset;
+
+ this.avgFrameRate = view.getUint16(headerOffset);
+ headerOffset += 2;
+
+ byte = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ this.constantFrameRate = (byte & 0xC0) >> 6;
+ this.numTemporalLayers = (byte & 0x38) >> 3;
+ this.temporalIdNested = (byte & 0x04) >> 2;
+ this.lengthSizeMinusOne = byte & 0x02;
+
+ return this.size;
+ };
+};
+
+Atom.constructorMap['hvcC'] = HEVCConfigurationBox.bind(null);
+
+class CleanApertureBox extends Atom {
+ constructor(parent) {
+ super(parent);
+
+ this.description = 'Clean Aperture Box';
+ this.cleanApertureWidthN = 0;
+ this.cleanApertureWidthD = 0;
+ this.cleanApertureHeightN = 0;
+ this.cleanApertureHeightD = 0;
+ this.horizOffN = 0;
+ this.horizOffD = 0;
+ this.vertOffN = 0;
+ this.vertOffD = 0;
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.cleanApertureWidthN = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.cleanApertureWidthD = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.cleanApertureHeightN = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.cleanApertureHeightD = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.horizOffN = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.horizOffD = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.vertOffN = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.vertOffD = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['clap'] = CleanApertureBox.bind(null);
+
+class TrackExtendsAtom extends FullBox {
+ constructor(parent) {
+ super(parent);
+ this.description = "Track Extends Atom";
+ this.trackID = 0;
+ this.default_sample_description_index = 0;
+ this.default_sample_duration = 0;
+ this.default_sample_size = 0;
+ this.default_sample_flags = 0;
+ }
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.trackID = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.default_sample_description_index = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.default_sample_duration = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.default_sample_size = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.default_sample_flags = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['trex'] = TrackExtendsAtom.bind(null);
+
+class OriginalFormatBox extends Atom {
+ constructor(parent) {
+ super(parent);
+ this.description = "Original Format Box";
+ this.dataFormat = 0;
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+
+ var array = new Uint8Array(buffer, offset + headerOffset, 4);
+ this.dataFormat = String.fromCharCode.apply(null, array);
+ headerOffset += 4;
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['frma'] = OriginalFormatBox.bind(null);
+
+class SchemeTypeBox extends FullBox {
+ constructor(parent) {
+ super(parent);
+ this.description = "Scheme Type Box";
+ this.schemeType = 0;
+ this.schemeVersion = 0;
+ this.schemeURL = 0;
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ var array = new Uint8Array(buffer, offset + headerOffset, 4);
+ this.schemeType = String.fromCharCode.apply(null, array);
+ headerOffset += 4;
+
+ this.schemeVersion = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ if (this.flags & 0x1) {
+ var remaining = this.size - headerOffset;
+ array = new Uint8Array(buffer, offset + headerOffset, remaining);
+ headerOffset += remaining;
+ this.schemeURL = String.fromCharCode.apply(null, array);
+ }
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['schm'] = SchemeTypeBox.bind(null);
+
+class TrackEncryptionBox extends FullBox {
+ constructor(parent) {
+ super(parent);
+
+ this.description = "Track Encryption Box";
+ this.defaultCryptByteBlock = 0;
+ this.defaultSkipByteBlock = 0;
+ this.defaultIsProtected = 0;
+ this.defaultPerSampleIVSize = 0;
+ this.defaultKID = '';
+ this.defaultConstantIV = null;
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ // unsigned int(8) reserved = 0
+ ++headerOffset;
+
+ if (!this.version) {
+ // unsigned int(8) reserved = 0
+ ++headerOffset
+ } else {
+ this.defaultCryptByteBlock = (view.getUint8(headerOffset) >> 4) & 0xF;
+ this.defaultSkipByteBlock = view.getUint8(headerOffset) & 0xF;
+ ++headerOffset;
+ }
+
+ this.defaultIsProtected = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ this.defaultPerSampleIVSize = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ var KIDArrayView = new Uint8Array(buffer, offset + headerOffset, 16);
+ this.defaultKID = String.prototype.concat.apply("0x", Array.prototype.map.call(KIDArrayView, function(value){ return value.toString(16); }));
+ headerOffset += 16;
+
+ if (this.defaultIsProtected && !this.defaultPerSampleIVSize) {
+ var size = view.getUint8(headerOffset);
+ ++headerOffset;
+
+ this.defaultConstantIV = new Uint8Array(buffer, offset + headerOffset, size);
+ headerOffset += size;
+ }
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['tenc'] = TrackEncryptionBox.bind(null);
+
+class SegmentIndexBox extends FullBox {
+ constructor(parent) {
+ super(parent);
+
+ this.description = "Segment Index Box";
+ this.referenceID = 0;
+ this.timeScale = 0;
+ this.earliestPresentationTime = 0;
+ this.firstOffset = 0;
+ this.references = [];
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.referenceID = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.timeScale = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ if (this.version == 1) {
+ var upper = view.getUint32(headerOffset);
+ headerOffset += 4;
+ var lower = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.earliestPresentationTime = (upper << 32) + lower;
+
+ upper = view.getUint32(headerOffset);
+ headerOffset += 4;
+ lower = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.firstOffset = (upper << 32) + lower;
+ } else {
+ this.earliestPresentationTime = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.firstOffset = view.getUint32(headerOffset);
+ headerOffset += 4;
+ }
+
+ headerOffset += 2; // Reserved uint(16)
+
+ this.referenceCount = view.getUint16(headerOffset);
+ headerOffset += 2;
+
+ this.references = [];
+
+ for (var i = 0; i < this.referenceCount; ++i) {
+ var value = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ var reference = {};
+ reference.type = (value & 0x80000000) == 0x80000000;
+ reference.size = value & ~0x80000000;
+
+ reference.subsegmentDuration = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ value = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ reference.startsWithSAP = (value & 0x80000000) == 0x80000000;
+ reference.SAPType = (value & 0x70000000) >> 28;
+ reference.SAPDeltaTime = value & ~0xF0000000;
+ this.references.push(reference);
+ }
+
+ this.totalDuration = this.references.reduce(function(previousValue, reference) {
+ return previousValue + reference.subsegmentDuration;
+ }, 0);
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['sidx'] = SegmentIndexBox.bind(null);
+
+class ProtectionSystemBox extends FullBox {
+ constructor(parent) {
+ super(parent)
+ this.description = "Protection System Box";
+ this.systemID = 0;
+ this.KIDs = [];
+ this.data = null;
+ };
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ var UUIDArrayView = new Uint8Array(buffer, offset + headerOffset, 16);
+ this.systemID = String.prototype.concat.apply("0x", Array.prototype.map.call(UUIDArrayView, function(value){
+ return value.toString(16);
+ }));
+ headerOffset += 16;
+
+ if (this.version > 0) {
+ var kidCount = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ for (var index = 0; index < kidCount; ++index) {
+ var KIDArrayView = new Uint8Array(buffer, offset + headerOffset, 16);
+ var KIDString = String.prototype.concat.apply("0x", Array.prototype.map.call(KIDArrayView, function(value){ return value.toString(16); }));
+ this.KIDs.push(KIDString);
+ headerOffset += 16;
+ }
+ }
+
+ var dataSize = view.getUint32(headerOffset);
+ this.data = new Uint8Array(buffer, offset + headerOffset, dataSize);
+ headerOffset += dataSize;
+
+ return headerOffset;
+ };
+};
+
+Atom.constructorMap['pssh'] = ProtectionSystemBox.bind(null);
+
+class MovieExtendsHeaderBox extends FullBox {
+ constructor(parent) {
+ super(parent);
+ this.description = 'Movie Extends Header Box';
+ this.duration = 0;
+ }
+
+ parse(buffer, offset) {
+ var headerOffset = super.parse(buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.duration = view.getUint32(headerOffset);