15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict'; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {MetadataDispatcher} parent Parent object. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function MpegParser(parent) { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MetadataParser.call(this, parent, 'mpeg', /\.(mp4|m4v|m4a|mpe?g4?)$/i); 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.mimeType = 'video/mpeg'; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype = {__proto__: MetadataParser.prototype}; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Size of the atom header. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.HEADER_SIZE = 8; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ByteReader} br ByteReader instance. 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end End of atom position. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Atom size. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.readAtomSize = function(br, opt_end) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var pos = br.tell(); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_end) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assert that opt_end <= buffer end. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When supplied, opt_end is the end of the enclosing atom and is used to 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // check the correct nesting. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.validateRead(opt_end - pos); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var size = br.readScalar(4, false, opt_end); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size < MpegParser.HEADER_SIZE) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw 'atom too short (' + size + ') @' + pos; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_end && pos + size > opt_end) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw 'atom too long (' + size + '>' + (opt_end - pos) + ') @' + pos; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return size; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ByteReader} br ByteReader instance. 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end End of atom position. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} Atom name. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.readAtomName = function(br, opt_end) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return br.readString(4, opt_end).toLowerCase(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} metadata Metadata object. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object} Root of the parser tree. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.createRootParser = function(metadata) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function findParentAtom(atom, name) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (;;) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) atom = atom.parent; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!atom) return null; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (atom.name == name) return atom; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseFtyp(br, atom) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.brand = br.readString(4, atom.end); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseMvhd(br, atom) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var version = br.readScalar(4, false, atom.end); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var offset = (version == 0) ? 8 : 16; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(offset, ByteReader.SEEK_CUR); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var timescale = br.readScalar(4, false, atom.end); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var duration = br.readScalar(4, false, atom.end); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.duration = duration / timescale; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseHdlr(br, atom) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(8, ByteReader.SEEK_CUR); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) findParentAtom(atom, 'trak').trackType = br.readString(4, atom.end); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseStsd(br, atom) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var track = findParentAtom(atom, 'trak'); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (track && track.trackType == 'vide') { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(40, ByteReader.SEEK_CUR); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.width = br.readScalar(2, false, atom.end); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.height = br.readScalar(2, false, atom.end); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseDataString(name, br, atom) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(8, ByteReader.SEEK_CUR); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata[name] = br.readString(atom.end - br.tell(), atom.end); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function parseCovr(br, atom) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(8, ByteReader.SEEK_CUR); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metadata.thumbnailURL = br.readImage(atom.end - br.tell(), atom.end); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'meta' atom can occur at one of the several places in the file structure. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var parseMeta = { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ilst: { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '©nam': { data: parseDataString.bind(null, 'title') }, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '©alb': { data: parseDataString.bind(null, 'album') }, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '©art': { data: parseDataString.bind(null, 'artist') }, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'covr': { data: parseCovr } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) versioned: true 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // main parser for the entire file structure. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftyp: parseFtyp, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) moov: { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mvhd: parseMvhd, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trak: { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mdia: { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdlr: parseHdlr, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minf: { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stbl: { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stsd: parseStsd 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) meta: parseMeta 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udta: { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) meta: parseMeta 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) meta: parseMeta 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) meta: parseMeta 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {File} file File. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} metadata Metadata. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(Object)} callback Success callback. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onError Error callback. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype.parse = function(file, metadata, callback, onError) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.rootParser_ = MpegParser.createRootParser(metadata); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Kick off the processing by reading the first atom's header. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.requestRead(file, 0, MpegParser.HEADER_SIZE, null, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onError, callback.bind(null, metadata)); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(ByteReader, Object)|Object} parser Parser tree node. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ByteReader} br ByteReader instance. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} atom Atom descriptor. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} filePos File position of the atom start. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype.applyParser = function(parser, br, atom, filePos) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.verbose) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var path = atom.name; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var p = atom.parent; p && p.name; p = p.parent) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = p.name + '.' + path; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var action; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parser) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action = 'skipping '; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (parser instanceof Function) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action = 'parsing '; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action = 'recursing'; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var start = atom.start - MpegParser.HEADER_SIZE; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog(path + ': ' + 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '@' + (filePos + start) + ':' + (atom.end - start), 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parser) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parser instanceof Function) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.pushSeek(atom.start); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser(br, atom); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.popSeek(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parser.versioned) { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) atom.start += 4; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.parseMpegAtomsInRange(parser, br, atom, filePos); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(ByteReader, Object)|Object} parser Parser tree node. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ByteReader} br ByteReader instance. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} parentAtom Parent atom descriptor. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} filePos File position of the atom start. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype.parseMpegAtomsInRange = function( 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser, br, parentAtom, filePos) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var count = 0; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var offset = parentAtom.start; offset != parentAtom.end;) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count++ > 100) // Most likely we are looping through a corrupt file. 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw 'too many child atoms in ' + parentAtom.name + ' @' + offset; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(offset); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var size = MpegParser.readAtomSize(br, parentAtom.end); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var name = MpegParser.readAtomName(br, parentAtom.end); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.applyParser( 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser[name], 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { start: offset + MpegParser.HEADER_SIZE, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end: offset + size, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name: name, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent: parentAtom 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filePos 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += size; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {File} file File. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} filePos Start position in the file. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} size Atom size. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name Atom name. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onError Error callback. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onSuccess Success callback. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype.requestRead = function( 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file, filePos, size, name, onError, onSuccess) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = this; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var reader = new FileReader(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.onerror = onError; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.onload = function(event) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.processTopLevelAtom( 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.result, file, filePos, size, name, onError, onSuccess); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('reading @' + filePos + ':' + size); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader.readAsArrayBuffer(file.slice(filePos, filePos + size)); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ArrayBuffer} buf Data buffer. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {File} file File. 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} filePos Start position in the file. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} size Atom size. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name Atom name. 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onError Error callback. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} onSuccess Success callback. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MpegParser.prototype.processTopLevelAtom = function( 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf, file, filePos, size, name, onError, onSuccess) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var br = new ByteReader(buf); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the header has already been read. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var atomEnd = size - MpegParser.HEADER_SIZE; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var bufLength = buf.byteLength; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check the available data size. It should be either exactly 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // what we requested or HEADER_SIZE bytes less (for the last atom). 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bufLength != atomEnd && bufLength != size) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw 'Read failure @' + filePos + ', ' + 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'requested ' + size + ', read ' + bufLength; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Process the top level atom. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name) { // name is null only the first time. 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.applyParser( 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.rootParser_[name], 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {start: 0, end: atomEnd, name: name}, 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filePos 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filePos += bufLength; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bufLength == size) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The previous read returned everything we asked for, including 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the next atom header at the end of the buffer. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parse this header and schedule the next read. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) br.seek(-MpegParser.HEADER_SIZE, ByteReader.SEEK_END); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var nextSize = MpegParser.readAtomSize(br); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var nextName = MpegParser.readAtomName(br); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we do not have a parser for the next atom, skip the content and 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // read only the header (the one after the next). 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.rootParser_[nextName]) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filePos += nextSize - MpegParser.HEADER_SIZE; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nextSize = MpegParser.HEADER_SIZE; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.requestRead(file, filePos, nextSize, nextName, onError, onSuccess); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The previous read did not return the next atom header, EOF reached. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vlog('EOF @' + filePos); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onSuccess(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onError(e.toString()); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MetadataDispatcher.registerParserClass(MpegParser); 318