Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: chrome/browser/resources/file_manager/js/mpeg_parser.js

Issue 9583009: [File Manager] Cleanup: Moving js/css/html files to dedicated directories (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 2011->2012 Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 function MpegParser(parent) {
6 MetadataParser.call(this, parent, 'mpeg', /\.(mp4|m4v|m4a|mpe?g4?)$/i);
7 this.mimeType = 'video/mpeg';
8 }
9
10 MpegParser.prototype = {__proto__: MetadataParser.prototype};
11
12 MpegParser.prototype.acceptsMimeType = function(mimeType) {
13 return mimeType.match(/^video\/(mp4|mpeg)$/);
14 };
15
16 MpegParser.HEADER_SIZE = 8;
17
18 MpegParser.readAtomSize = function(br, opt_end) {
19 var pos = br.tell();
20
21 if (opt_end) {
22 // Assert that opt_end <= buffer end.
23 // When supplied, opt_end is the end of the enclosing atom and is used to
24 // check the correct nesting.
25 br.validateRead(opt_end - pos);
26 }
27
28 var size = br.readScalar(4, false, opt_end);
29
30 if (size < MpegParser.HEADER_SIZE)
31 throw 'atom too short (' + size + ') @' + pos;
32
33 if (opt_end && pos + size > opt_end)
34 throw 'atom too long (' + size + '>' + (opt_end - pos)+ ') @' + pos;
35
36 return size;
37 };
38
39 MpegParser.readAtomName = function(br, opt_end) {
40 return br.readString(4, opt_end).toLowerCase();
41 };
42
43 MpegParser.createRootParser = function(metadata) {
44 function findParentAtom(atom, name) {
45 for (;;) {
46 atom = atom.parent;
47 if (!atom) return null;
48 if (atom.name == name) return atom;
49 }
50 }
51
52 function parseFtyp(br, atom) {
53 metadata.brand = br.readString(4, atom.end);
54 }
55
56 function parseMvhd(br, atom) {
57 var version = br.readScalar(4, false, atom.end);
58 var offset = (version == 0) ? 8 : 16;
59 br.seek(offset, ByteReader.SEEK_CUR);
60 var timescale = br.readScalar(4, false, atom.end);
61 var duration = br.readScalar(4, false, atom.end);
62 metadata.duration = duration / timescale;
63 }
64
65 function parseHdlr(br, atom) {
66 br.seek(8, ByteReader.SEEK_CUR);
67 findParentAtom(atom, 'trak').trackType = br.readString(4, atom.end);
68 }
69
70 function parseStsd(br, atom) {
71 var track = findParentAtom(atom, 'trak');
72 if (track && track.trackType == 'vide') {
73 br.seek(40, ByteReader.SEEK_CUR);
74 metadata.width = br.readScalar(2, false, atom.end);
75 metadata.height = br.readScalar(2, false, atom.end);
76 }
77 }
78
79 function parseDataString(name, br, atom) {
80 br.seek(8, ByteReader.SEEK_CUR);
81 metadata[name] = br.readString(atom.end - br.tell(), atom.end);
82 }
83
84 function parseCovr(br, atom) {
85 br.seek(8, ByteReader.SEEK_CUR);
86 metadata.thumbnailURL = br.readImage(atom.end - br.tell(), atom.end);
87 }
88
89 // 'meta' atom can occur at one of the several places in the file structure.
90 var parseMeta = {
91 ilst: {
92 "©nam": { data : parseDataString.bind(null, "title") },
93 "©alb": { data : parseDataString.bind(null, "album") },
94 "©art": { data : parseDataString.bind(null, "artist") },
95 "covr": { data : parseCovr }
96 },
97 versioned: true
98 };
99
100 // main parser for the entire file structure.
101 return {
102 ftyp: parseFtyp,
103 moov: {
104 mvhd : parseMvhd,
105 trak: {
106 mdia: {
107 hdlr: parseHdlr,
108 minf: {
109 stbl: {
110 stsd: parseStsd
111 }
112 }
113 },
114 meta: parseMeta
115 },
116 udta: {
117 meta: parseMeta
118 },
119 meta: parseMeta
120 },
121 meta: parseMeta
122 };
123 };
124
125 MpegParser.prototype.parse = function (file, metadata, callback, onError) {
126 this.rootParser_ = MpegParser.createRootParser(metadata);
127
128 // Kick off the processing by reading the first atom's header.
129 this.requestRead(file, 0, MpegParser.HEADER_SIZE, null,
130 onError, callback.bind(null, metadata));
131 };
132
133 MpegParser.prototype.applyParser = function(parser, br, atom, filePos) {
134 if (this.verbose) {
135 var path = atom.name;
136 for (var p = atom.parent; p && p.name; p = p.parent) {
137 path = p.name + '.' + path;
138 }
139
140 var action;
141 if (!parser) {
142 action = 'skipping ';
143 } else if (parser instanceof Function) {
144 action = 'parsing ';
145 } else {
146 action = 'recursing';
147 }
148
149 var start = atom.start - MpegParser.HEADER_SIZE;
150 this.vlog(path + ': ' +
151 '@' + (filePos + start) + ':' + (atom.end - start),
152 action);
153 }
154
155 if (parser) {
156 if (parser instanceof Function) {
157 br.pushSeek(atom.start);
158 parser(br, atom);
159 br.popSeek();
160 } else {
161 if (parser.versioned) {
162 atom.start += 4;
163 }
164 this.parseMpegAtomsInRange(parser, br, atom, filePos);
165 }
166 }
167 };
168
169 MpegParser.prototype.parseMpegAtomsInRange = function(
170 parser, br, parentAtom, filePos) {
171 var count = 0;
172 for (var offset = parentAtom.start; offset != parentAtom.end;) {
173 if (count++ > 100) // Most likely we are looping through a corrupt file.
174 throw "too many child atoms in " + parentAtom.name + " @" + offset;
175
176 br.seek(offset);
177 var size = MpegParser.readAtomSize(br, parentAtom.end);
178 var name = MpegParser.readAtomName(br, parentAtom.end);
179
180 this.applyParser(
181 parser[name],
182 br,
183 { start: offset + MpegParser.HEADER_SIZE,
184 end: offset + size,
185 name: name,
186 parent: parentAtom
187 },
188 filePos
189 );
190
191 offset += size;
192 }
193 }
194
195 MpegParser.prototype.requestRead = function(
196 file, filePos, size, name, onError, onSuccess) {
197 var self = this;
198 var reader = new FileReader();
199 reader.onerror = onError;
200 reader.onload = function(event) {
201 self.processTopLevelAtom(
202 reader.result, file, filePos, size, name, onError, onSuccess);
203 };
204 this.vlog("reading @" + filePos + ":" + size);
205 reader.readAsArrayBuffer(file.webkitSlice(filePos, filePos + size));
206 }
207
208 MpegParser.prototype.processTopLevelAtom = function(
209 buf, file, filePos, size, name, onError, onSuccess) {
210 try {
211 var br = new ByteReader(buf);
212
213 // the header has already been read.
214 var atomEnd = size - MpegParser.HEADER_SIZE;
215
216 var bufLength = buf.byteLength;
217
218 // Check the available data size. It should be either exactly
219 // what we requested or HEADER_SIZE bytes less (for the last atom).
220 if (bufLength != atomEnd && bufLength != size) {
221 throw "Read failure @" + filePos + ", " +
222 "requested " + size + ", read " + bufLength;
223 }
224
225 // Process the top level atom.
226 if (name) { // name is null only the first time.
227 this.applyParser(
228 this.rootParser_[name],
229 br,
230 {start: 0, end: atomEnd, name: name},
231 filePos
232 );
233 }
234
235 filePos += bufLength;
236 if (bufLength == size) {
237 // The previous read returned everything we asked for, including
238 // the next atom header at the end of the buffer.
239 // Parse this header and schedule the next read.
240 br.seek(-MpegParser.HEADER_SIZE, ByteReader.SEEK_END);
241 var nextSize = MpegParser.readAtomSize(br);
242 var nextName = MpegParser.readAtomName(br);
243
244 // If we do not have a parser for the next atom, skip the content and
245 // read only the header (the one after the next).
246 if (!this.rootParser_[nextName]) {
247 filePos += nextSize - MpegParser.HEADER_SIZE;
248 nextSize = MpegParser.HEADER_SIZE;
249 }
250
251 this.requestRead(file, filePos, nextSize, nextName, onError, onSuccess);
252 } else {
253 // The previous read did not return the next atom header, EOF reached.
254 this.vlog("EOF @" + filePos);
255 onSuccess();
256 }
257 } catch(e) {
258 return onError(e.toString());
259 }
260 };
261
262 MetadataDispatcher.registerParserClass(MpegParser);
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/js/metadata_provider.js ('k') | chrome/browser/resources/file_manager/main.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698