-var Atom = function(buffer, offset) {
+var Atom = function (buffer, offset) {
this.setDefaults();
return this.parse(buffer, offset) ? this : null;
};
-Atom.create = function(buffer, offset) {
+Atom.create = function (buffer, offset) {
// 'offset' is optional.
- if (arguments.length < 2)
+ if (arguments.length < 2) {
offset = 0;
+ }
if (buffer.byteLength - offset < this.minimumSize)
return null;
var typeArrayView = new Uint8Array(buffer, offset + 4, 4);
var type = String.fromCharCode.apply(null, typeArrayView);
+ var atom;
switch (type) {
case 'ftyp':
return new FileTypeAtom(buffer, offset);
case 'moov':
+ return new ContainerAtom(buffer, offset, 'Movie Atom');
case 'trak':
+ return new ContainerAtom(buffer, offset, 'Track Atom');
case 'mdia':
+ return new ContainerAtom(buffer, offset, 'Media Atom');
case 'minf':
+ return new ContainerAtom(buffer, offset, 'Media Info Atom');
+ case 'mvex':
+ return new ContainerAtom(buffer, offset, 'Movie Extends Atom');
case 'stbl':
return new ContainerAtom(buffer, offset);
case 'mvhd':
return new SyncSampleAtom(buffer, offset);
case 'stts':
return new TimeToSampleAtom(buffer, offset);
+ case 'stsz':
+ return new SampleSizeAtom(buffer, offset);
+ case 'trex':
+ return new TrackExtendsAtom(buffer, offset);
+ case 'sinf':
+ return new ContainerAtom(buffer, offset, 'Protection Scheme Info Atom');
+ case 'ipro':
+ return new ContainerAtom(buffer, offset, 'Item Protection Atom');
+ case 'frma':
+ return new OriginalFormatBox(buffer, offset);
+ case 'schm':
+ return new SchemeTypeBox(buffer, offset);
+ case 'schi':
+ return new SchemeInfoBox(Buffer, offset);
default:
return new Atom(buffer, offset);
}
-}
+};
-Atom.prototype.super = function(object) {
+Atom.prototype.super = function (object) {
return Object.getPrototypeOf(object.prototype);
-}
+};
-Atom.prototype.setDefaults = function() {
+Atom.prototype.setDefaults = function () {
Object.defineProperty(this, "is64bit", {
value: false,
writable: true,
enumerable: false,
configurable: true,
});
+ Object.defineProperty(this, "description", {
+ value: "Undifferentiated Atom",
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+ this.offset = 0;
this.size = 0;
this.type = '';
-}
+};
-Atom.prototype.parse = function(buffer, offset) {
+Atom.prototype.parse = function (buffer, offset) {
// 'offset' is optional.
if (typeof(offset) == 'undefined')
offset = 0;
+ this.offset = offset;
+
if (buffer.byteLength - offset < this.minimumSize)
- return 0;
+ throw 'Buffer not long enough';
var view = new DataView(buffer, offset, 4);
- headerOffset = 0;
+ var headerOffset = 0;
this.size = view.getUint32(0);
headerOffset += 4;
if (this.size == 1) {
this.is64bit = true;
if (buffer.byteLength - offset < 8)
- return false;
+ throw 'Malformed extended size field';
// NOTE: JavaScript can only represent up to 2^53 as precise integer.
// This calculation may result in incorrect values.
return headerOffset;
};
-Atom.prototype.getAtomByType = function(type) {
+Atom.prototype.getAtomByType = function (type) {
if (typeof(this.childAtoms) == 'undefined')
return null;
// Bredth first
- for (index in this.childAtoms) {
+ for (var index in this.childAtoms) {
if (this.childAtoms[index].type == type)
return this.childAtoms[index];
}
var result = null;
- for (index in this.childAtoms) {
- if (result = this.childAtoms[index].getAtomsByType(type))
+ for (var index in this.childAtoms) {
+ if (result = this.childAtoms[index].getAtomByType(type))
break;
}
return result;
};
-Atom.prototype.getAtomsByType = function(type) {
+Atom.prototype.getAtomsByType = function (type) {
if (typeof(this.childAtoms) == 'undefined')
return [];
var result = [];
// Bredth first
- for (index in this.childAtoms) {
+ for (var index in this.childAtoms) {
if (this.childAtoms[index].type == type)
result.push(this.childAtoms[index]);
}
- for (index in this.childAtoms)
+ for (var index in this.childAtoms)
result = result.concat(this.childAtoms[index].getAtomsByType(type));
return result;
};
-var FileTypeAtom = function(buffer, offset) {
+var FileTypeAtom = function (buffer, offset) {
this.super(FileTypeAtom).constructor.call(this, buffer, offset);
}
FileTypeAtom.prototype = Object.create(Atom.prototype);
-FileTypeAtom.prototype.setDefaults = function() {
+FileTypeAtom.prototype.setDefaults = function () {
this.super(FileTypeAtom).setDefaults.call(this);
+ this.description = "File Type Atom";
this.minimumSize = 16;
this.brand = "";
this.version = 0;
this.compatible_brands = [];
}
-FileTypeAtom.prototype.parse = function(buffer, offset) {
+FileTypeAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(FileTypeAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset, this.size);
var brandArrayView = new Uint8Array(buffer, offset + headerOffset, 4);
return true;
}
-var ContainerAtom = function(buffer, offset) {
- this.super(ContainerAtom).constructor.call(this, buffer, offset);
+var ContainerAtom = function (buffer, offset, description) {
+ var atom = this.super(ContainerAtom).constructor.call(this, buffer, offset);
+ atom.description = description;
+ return;
}
ContainerAtom.prototype = Object.create(Atom.prototype);
-ContainerAtom.prototype.setDefaults = function() {
+ContainerAtom.prototype.setDefaults = function () {
this.super(ContainerAtom).setDefaults.call(this);
this.childAtoms = [];
}
-ContainerAtom.prototype.parse = function(buffer, offset) {
+ContainerAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(ContainerAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
while (headerOffset < this.size) {
var childAtom = Atom.create(buffer, offset + headerOffset);
if (!childAtom)
this.childAtoms.push(childAtom);
childAtom.parent = this;
}
+ return headerOffset;
}
-var VersionFlagsAtom = function(buffer, offset) {
+var VersionFlagsAtom = function (buffer, offset) {
this.super(VersionFlagsAtom).constructor.call(this, buffer, offset);
}
VersionFlagsAtom.prototype = Object.create(Atom.prototype);
-VersionFlagsAtom.prototype.setDefaults = function() {
+VersionFlagsAtom.prototype.setDefaults = function () {
this.super(VersionFlagsAtom).setDefaults.call(this);
this.version = 0;
this.flags = 0;
}
-VersionFlagsAtom.prototype.parse = function(buffer, offset) {
+VersionFlagsAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(VersionFlagsAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.version = view.getUint8(headerOffset);
return headerOffset;
}
-var MovieHeaderAtom = function(buffer, offset) {
+var MovieHeaderAtom = function (buffer, offset) {
return this.super(MovieHeaderAtom).constructor.call(this, buffer, offset);
}
MovieHeaderAtom.prototype = Object.create(VersionFlagsAtom.prototype);
-MovieHeaderAtom.prototype.setDefaults = function() {
+MovieHeaderAtom.prototype.setDefaults = function () {
this.super(MovieHeaderAtom).setDefaults.call(this);
+ this.description = "Movie Header Atom";
this.creationTime = 0;
this.modificationTime = 0;
this.timeScale = 0;
this.nextTrackID = 0;
}
-MovieHeaderAtom.prototype.parse = function(buffer, offset) {
+MovieHeaderAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(MovieHeaderAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
return true;
}
-var TrackHeaderAtom = function(buffer, offset) {
+var TrackHeaderAtom = function (buffer, offset) {
this.super(TrackHeaderAtom).constructor.call(this, buffer, offset);
}
TrackHeaderAtom.prototype = Object.create(VersionFlagsAtom.prototype);
-TrackHeaderAtom.prototype.setDefaults = function() {
+TrackHeaderAtom.prototype.setDefaults = function () {
this.super(TrackHeaderAtom).setDefaults.call(this);
+ this.description = "Track Header Atom";
this.creationTime = 0;
this.modificationTime = 0;
this.trackID = 0;
this.height = 0;
}
-TrackHeaderAtom.prototype.parse = function(buffer, offset) {
+TrackHeaderAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(TrackHeaderAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
headerOffset += 4;
}
-var MediaHeaderAtom = function(buffer, offset) {
+var MediaHeaderAtom = function (buffer, offset) {
this.super(MediaHeaderAtom).constructor.call(this, buffer, offset);
}
MediaHeaderAtom.prototype = Object.create(VersionFlagsAtom.prototype);
-MediaHeaderAtom.prototype.setDefaults = function() {
+MediaHeaderAtom.prototype.setDefaults = function () {
this.super(MediaHeaderAtom).setDefaults.call(this);
+ this.description = "Media Header Atom";
this.creationTime = 0;
this.modificationTime = 0;
this.timeScale = 0;
this.quality = 0;
}
-MediaHeaderAtom.prototype.parse = function(buffer, offset) {
+MediaHeaderAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(MediaHeaderAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
this.quality = view.getUint16(headerOffset);
headerOffset += 2;
-}
+};
-var SyncSampleAtom = function(buffer, offset) {
+var SyncSampleAtom = function (buffer, offset) {
this.super(SyncSampleAtom).constructor.call(this, buffer, offset);
-}
+};
SyncSampleAtom.prototype = Object.create(Atom.prototype);
-SyncSampleAtom.prototype.setDefaults = function() {
+SyncSampleAtom.prototype.setDefaults = function () {
this.super(SyncSampleAtom).setDefaults.call(this);
+ this.description = "Sync Sample Atom";
this.version = 0;
this.flags = 0;
this.entries = 0;
this.syncSamples = [];
-}
+};
-SyncSampleAtom.prototype.parse = function(buffer, offset) {
+SyncSampleAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(SyncSampleAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.version = view.getUint8(headerOffset);
this.entries = view.getUint32(headerOffset);
headerOffset += 4;
+ this.syncSamples = new Uint32Array(this.entries);
+ var i = 0;
while (headerOffset < this.size) {
var sampleNumber = view.getUint32(headerOffset);
headerOffset += 4;
- this.syncSamples.push(sampleNumber);
+ this.syncSamples[i] = sampleNumber;
+ ++i;
}
-}
+};
-var TimeToSampleAtom = function(buffer, offset) {
+var TimeToSampleAtom = function (buffer, offset) {
this.super(TimeToSampleAtom).constructor.call(this, buffer, offset);
-}
+};
TimeToSampleAtom.prototype = Object.create(VersionFlagsAtom.prototype);
-TimeToSampleAtom.prototype.setDefaults = function() {
+TimeToSampleAtom.prototype.setDefaults = function () {
this.super(TimeToSampleAtom).setDefaults.call(this);
+ this.description = "Time-to-Sample Atom";
this.entries = 0;
Object.defineProperty(this, "timeToSamples", {
- value: [],
+ value: null,
writable: true,
enumerable: false,
configurable: true,
});
}
-TimeToSampleAtom.prototype.parse = function(buffer, offset) {
+TimeToSampleAtom.prototype.parse = function (buffer, offset) {
var headerOffset = this.super(TimeToSampleAtom).parse.call(this, buffer, offset);
- if (!headerOffset)
- return 0;
-
var view = new DataView(buffer, offset);
this.entries = view.getUint32(headerOffset);
- headerOffset += 4;
+ headerOffset += 4;
+
+ this.timeToSamples = new Array(this.entries);
+ var i = 0;
while (headerOffset < this.size) {
var sampleCount = view.getUint32(headerOffset);
var sampleDuration = view.getUint32(headerOffset);
headerOffset += 4;
- this.timeToSamples.push([sampleCount, sampleDuration]);
+ this.timeToSamples[i] = [sampleCount, sampleDuration];
+ ++i;
+ }
+}
+
+var SampleSizeAtom = function (buffer, offset) {
+ this.super(SampleSizeAtom).constructor.call(this, buffer, offset);
+}
+
+SampleSizeAtom.prototype = Object.create(VersionFlagsAtom.prototype);
+
+SampleSizeAtom.prototype.setDefaults = function () {
+ this.super(SampleSizeAtom).setDefaults.call(this);
+
+ this.description = "Sample Size Atom";
+ this.sampleSize = 0;
+ this.entries = 0;
+
+ Object.defineProperty(this, "sampleSizes", {
+ value: null,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+}
+
+SampleSizeAtom.prototype.parse = function (buffer, offset) {
+ var headerOffset = this.super(SampleSizeAtom).parse.call(this, buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.sampleSize = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.entries = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.sampleSizes = new Uint32Array(this.entries);
+ var i = 0;
+
+ while (headerOffset < this.size) {
+ this.sampleSizes[i] = view.getUint32(headerOffset);
+ headerOffset += 4;
+ ++i;
+ }
+}
+
+var TrackExtendsAtom = function (buffer, offset) {
+ this.super(TrackExtendsAtom).constructor.call(this, buffer, offset);
+}
+
+TrackExtendsAtom.prototype = Object.create(VersionFlagsAtom.prototype);
+
+TrackExtendsAtom.prototype.setDefaults = function () {
+ this.super(TrackExtendsAtom).setDefaults.call(this);
+
+ 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;
+}
+
+TrackExtendsAtom.prototype.parse = function (buffer, offset) {
+ var headerOffset = this.super(TrackExtendsAtom).parse.call(this, 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;
+}
+
+var OriginalFormatBox = function (buffer, offset) {
+ this.super(OriginalFormatBox).constructor.call(this, buffer, offset);
+}
+
+OriginalFormatBox.prototype = Object.create(Atom.prototype);
+
+OriginalFormatBox.prototype.setDefaults = function () {
+ this.super(OriginalFormatBox).setDefaults.call(this);
+
+ this.description = "Original Format Box";
+ this.dataFormat = 0;
+}
+
+OriginalFormatBox.prototype.parse = function (buffer, offset) {
+ var headerOffset = this.super(OriginalFormatBox).parse.call(this, buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.dataFormat = view.getUint32(headerOffset);
+ headerOffset += 4;
+}
+
+var SchemeTypeBox = function (buffer, offset) {
+ this.super(SchemeTypeBox).constructor.call(this, buffer, offset);
+}
+
+SchemeTypeBox.prototype = Object.create(VersionFlagsAtom.prototype);
+
+SchemeTypeBox.prototype.setDefaults = function () {
+ this.super(SchemeTypeBox).setDefaults.call(this);
+
+ this.description = "Scheme Type Box";
+ this.schemeType = 0;
+ this.schemeVersion = 0;
+ this.schemeURL = 0;
+}
+
+SchemeTypeBox.prototype.parse = function (buffer, offset) {
+ var headerOffset = this.super(SchemeTypeBox).parse.call(this, buffer, offset);
+ var view = new DataView(buffer, offset);
+
+ this.schemeType = view.getUint32(headerOffset);
+ headerOffset += 4;
+ this.schemeVersion = view.getUint32(headerOffset);
+ headerOffset += 4;
+ if (this.flags & 0x1) {
+ var array = new Uint8Array(buffer, headerOffset, this.size - headerOffset);
+ this.schemeURL = String.fromCharCode.apply(null, array);
}
-}
\ No newline at end of file
+}
+
+var SchemeInfoBox = function (buffer, offset) {
+ this.super(SchemeInfoBox).constructor.call(this, buffer, offset);
+}
+
+SchemeInfoBox.prototype = Object.create(VersionFlagsAtom.prototype);
+
+SchemeInfoBox.prototype.setDefaults = function () {
+ this.super(SchemeInfoBox).setDefaults.call(this);
+
+ this.description = "Scheme Information Box";
+ this.schemeSpecificData = 0;
+}
+
+SchemeInfoBox.prototype.parse = function (buffer, offset) {
+ var headerOffset = this.super(SchemeInfoBox).parse.call(this, buffer, offset);
+ this.schemeSpecificData = buffer.slice(headerOffset, this.size - headerOffset);
+}
+
+