var Atom = function(buffer, offset) {
- this.is64bit = false;
- this.size = 0;
- this.minimumSize;
- this.type = '';
-
+ this.setDefaults();
return this.parse(buffer, offset) ? this : null;
};
case 'ftyp':
return new FtypAtom(buffer, offset);
case 'moov':
+ case 'trak':
+ case 'mdia':
+ case 'minf':
+ case 'stbl':
return new ContainerAtom(buffer, offset);
case 'mvhd':
return new MvhdAtom(buffer, offset);
+ case 'tkhd':
+ return new TkhdAtom(buffer, offset);
+ case 'mdhd':
+ return new MdhdAtom(buffer, offset);
default:
return new Atom(buffer, offset);
}
}
+Atom.prototype.setDefaults = function()
+{
+ Object.defineProperty(this, "is64bit", {
+ value: false,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+ Object.defineProperty(this, "minimumSize", {
+ value: 8,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+ Object.defineProperty(this, "parent", {
+ value: null,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+ this.size = 0;
+ this.type = '';
+}
+
Atom.prototype.parse = function(buffer, offset)
{
// 'offset' is optional.
return true;
};
-Atom.prototype.toDOMNode = function()
-{
- var output = document.createElement('dl');
-
- for (property in this) {
- var value = this[property];
- if (typeof(value) == 'function')
- continue;
- var div = document.createElement('div');
- var dt = document.createElement('dt');
- dt.innerText = property;
-
- var dd = document.createElement('dd');
- if (value instanceof Atom)
- dd.appendChild(value.toDOMNode());
- else if (value instanceof Array) {
- var ol = document.createElement('ol');
- for (index in value) {
- var li = document.createElement('li');
- li.value = index;
- if (value[index] instanceof Atom)
- li.appendChild(value[index].toDOMNode())
- else
- li.innerText = value[index];
- ol.appendChild(li);
- }
- dd.appendChild(ol);
- }
- else if (typeof(value) == "string")
- dd.innerText = '"' + value + '"';
- else
- dd.innerText = value;
-
- div.appendChild(dt);
- div.appendChild(dd);
- output.appendChild(div);
+Atom.prototype.getAtomByType = function(type) {
+ if (typeof(this.childAtoms) == 'undefined')
+ return null;
+
+ // Bredth first
+ for (index in this.childAtoms) {
+ if (this.childAtoms[index].type == type)
+ return this.childAtoms[index];
}
- return output;
-}
+
+ var result = null;
+ for (index in this.childAtoms) {
+ if (result = this.childAtoms[index].getAtomsByType(type))
+ break;
+ }
+ return result;
+};
+
+Atom.prototype.getAtomsByType = function(type) {
+ if (typeof(this.childAtoms) == 'undefined')
+ return [];
+
+ var result = [];
+
+ // Bredth first
+ for (index in this.childAtoms) {
+ if (this.childAtoms[index].type == type)
+ result.push(this.childAtoms[index]);
+ }
+
+ for (index in this.childAtoms)
+ result = result.concat(this.childAtoms[index].getAtomsByType(type));
+
+ return result;
+};
var FtypAtom = function(buffer, offset) {
+ return Atom.prototype.constructor.call(this, buffer, offset);
+}
+
+FtypAtom.prototype = Object.create(Atom.prototype);
+
+FtypAtom.prototype.setDefaults = function() {
+ Atom.prototype.setDefaults.call(this);
this.minimumSize = 16;
this.brand = "";
this.version = 0;
this.compatible_brands = [];
-
- return Object.getPrototypeOf(FtypAtom.prototype).constructor.call(this, buffer, offset)
}
-FtypAtom.prototype = Object.create(Atom.prototype);
-
FtypAtom.prototype.parse = function(buffer, offset) {
if (!Atom.prototype.parse.call(this, buffer, offset))
return false;
}
var ContainerAtom = function(buffer, offset) {
- this.childAtoms = [];
-
- return Object.getPrototypeOf(ContainerAtom.prototype).constructor.call(this, buffer, offset);
+ return Atom.prototype.constructor.call(this, buffer, offset);
}
ContainerAtom.prototype = Object.create(Atom.prototype);
+ContainerAtom.prototype.setDefaults = function()
+{
+ Atom.prototype.setDefaults.call(this);
+ this.childAtoms = [];
+}
+
ContainerAtom.prototype.parse = function(buffer, offset) {
if (!Atom.prototype.parse.call(this, buffer, offset))
return false;
break;
offset += childAtom.size;
this.childAtoms.push(childAtom);
+ childAtom.parent = this;
}
}
var MvhdAtom = function(buffer, offset) {
+ return Atom.prototype.constructor.call(this, buffer, offset);
+}
+
+MvhdAtom.prototype = Object.create(Atom.prototype);
+
+MvhdAtom.prototype.setDefaults = function() {
+ Atom.prototype.setDefaults.call(this);
this.version = 0;
this.creationTime = 0;
this.modificationTime = 0;
this.selectionTime = 0;
this.selectionDuration = 0;
this.nextTrackID = 0;
-
- return Object.getPrototypeOf(MvhdAtom.prototype).constructor.call(this, buffer, offset);
}
-MvhdAtom.prototype = Object.create(Atom.prototype);
-
MvhdAtom.prototype.parse = function(buffer, offset) {
if (!Atom.prototype.parse.call(this, buffer, offset))
return false;
this.version = view.getUint8(headerOffset);
headerOffset += 4;
- this.creationTime = view.getUint32(headerOffset);
+ this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
headerOffset += 4;
- this.modificationTime = view.getUint32(headerOffset);
+ this.modificationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
headerOffset += 4;
this.timeScale = view.getUint32(headerOffset);
this.preferredRate = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.preferredVolume = view.getUint32(headerOffset) / (1 << 16);
- headerOffset += 4;
+ this.preferredVolume = view.getUint16(headerOffset) / (1 << 8);
+ headerOffset += 2;
// Reserved
// Ten bytes reserved for use by Apple. Set to 0.
this.movieMatrix = new Array(3);
// a, b, u:
this.movieMatrix[0] = new Array(3);
- this.movieMatrix[0][1] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[0][0] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[0][2] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[0][1] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[0][3] = view.getUint32(headerOffset) / (1 << 30);
+ this.movieMatrix[0][2] = view.getUint32(headerOffset) / (1 << 30);
headerOffset += 4;
// c, d, v:
this.movieMatrix[1] = new Array(3);
- this.movieMatrix[1][1] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[1][0] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[1][2] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[1][1] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[1][3] = view.getUint32(headerOffset) / (1 << 30);
+ this.movieMatrix[1][2] = view.getUint32(headerOffset) / (1 << 30);
headerOffset += 4;
// x, y, w:
this.movieMatrix[2] = new Array(3);
- this.movieMatrix[2][1] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[2][0] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[2][2] = view.getUint32(headerOffset) / (1 << 16);
+ this.movieMatrix[2][1] = view.getUint32(headerOffset) / (1 << 16);
headerOffset += 4;
- this.movieMatrix[2][3] = view.getUint32(headerOffset) / (1 << 30);
+ this.movieMatrix[2][2] = view.getUint32(headerOffset) / (1 << 30);
headerOffset += 4;
this.previewTime = view.getUint32(headerOffset);
headerOffset += 4;
return true;
+}
+
+var TkhdAtom = function(buffer, offset) {
+ return Atom.prototype.constructor.call(this, buffer, offset);
+}
+
+TkhdAtom.prototype = Object.create(Atom.prototype);
+
+TkhdAtom.prototype.setDefaults = function() {
+ Atom.prototype.setDefaults.call(this);
+
+ this.version = 0;
+ this.flags = 0;
+ this.creationTime = 0;
+ this.modificationTime = 0;
+ this.trackID = 0;
+ this.duration = 0;
+ this.layer = 0;
+ this.alternateGroup = 0;
+ this.volume = 0.0;
+ this.trackMatrix = [];
+ this.width = 0;
+ this.height = 0;
+}
+
+TkhdAtom.prototype.parse = function(buffer, offset)
+{
+ if (!Atom.prototype.parse.call(this, buffer, offset))
+ return false;
+
+ offset += this.is64bit ? 16 : 8;
+
+ var headerOffset = 0;
+ var view = new DataView(buffer, offset);
+
+ this.version = view.getUint8(headerOffset);
+ headerOffset += 1;
+
+ // 'flags' is a 3-byte field, so retrieve from one extra byte and concatenate
+ this.flags = (view.getUint8(headerOffset) << 8) + view.getUint16(headerOffset + 1);
+ headerOffset += 3;
+
+ this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
+ headerOffset += 4;
+
+ this.modificationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
+ headerOffset += 4;
+
+ this.trackID = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ // Reserved
+ // A 32-bit integer that is reserved for use by Apple. Set this field to 0.
+ headerOffset += 4;
+
+ this.duration = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ // Reserved
+ // An 8-byte value that is reserved for use by Apple. Set this field to 0.
+ headerOffset += 8;
+
+ this.layer = view.getUint16(headerOffset);
+ headerOffset += 2;
+
+ this.alternateGroup = view.getUint16(headerOffset);
+ headerOffset += 2;
+
+ this.volume = view.getUint16(headerOffset) / (1 << 8);
+ headerOffset += 2;
+
+ // Reserved
+ // A 16-bit integer that is reserved for use by Apple. Set this field to 0.
+ headerOffset += 2;
+
+ this.trackMatrix = new Array(3);
+ // a, b, u:
+ this.trackMatrix[0] = new Array(3);
+ this.trackMatrix[0][0] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[0][1] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[0][2] = view.getUint32(headerOffset) / (1 << 30);
+ headerOffset += 4;
+
+ // c, d, v:
+ this.trackMatrix[1] = new Array(3);
+ this.trackMatrix[1][0] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[1][1] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[1][2] = view.getUint32(headerOffset) / (1 << 30);
+ headerOffset += 4;
+
+ // x, y, w:
+ this.trackMatrix[2] = new Array(3);
+ this.trackMatrix[2][0] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[2][1] = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+ this.trackMatrix[2][2] = view.getUint32(headerOffset) / (1 << 30);
+ headerOffset += 4;
+
+ this.width = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+
+ this.height = view.getUint32(headerOffset) / (1 << 16);
+ headerOffset += 4;
+}
+
+var MdhdAtom = function(buffer, offset) {
+ return Atom.prototype.constructor.call(this, buffer, offset);
+}
+
+MdhdAtom.prototype = Object.create(Atom.prototype);
+
+MdhdAtom.prototype.setDefaults = function() {
+ Atom.prototype.setDefaults.call(this);
+
+ this.version = 0;
+ this.flags = 0;
+ this.creationTime = 0;
+ this.modificationTime = 0;
+ this.timeScale = 0;
+ this.duration = 0;
+ this.language = 0;
+ this.quality = 0;
+}
+
+MdhdAtom.prototype.parse = function(buffer, offset)
+{
+ if (!Atom.prototype.parse.call(this, buffer, offset))
+ return false;
+
+ offset += this.is64bit ? 16 : 8;
+
+ var headerOffset = 0;
+ var view = new DataView(buffer, offset);
+
+ this.version = view.getUint8(headerOffset);
+ headerOffset += 1;
+
+ // 'flags' is a 3-byte field, so retrieve from one extra byte and concatenate
+ this.flags = (view.getUint8(headerOffset) << 8) + view.getUint16(headerOffset + 1);
+ headerOffset += 3;
+
+ this.creationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
+ headerOffset += 4;
+
+ this.modificationTime = new Date(view.getUint32(headerOffset)*1000 + Date.UTC(1904, 0, 1));
+ headerOffset += 4;
+
+ this.timeScale = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.duration = view.getUint32(headerOffset);
+ headerOffset += 4;
+
+ this.language = view.getUint16(headerOffset);
+ headerOffset += 2;
+
+ this.quality = view.getUint16(headerOffset);
+ headerOffset += 2;
}
\ No newline at end of file