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

Side by Side Diff: media/webm/webm_parser.cc

Issue 8775035: Add support for incremental cluster parsing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Replace old list parsing with WebMListParser & implement incremental cluster parsing with that. Created 9 years 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/webm/webm_parser.h" 5 #include "media/webm/webm_parser.h"
6 6
7 // This file contains code to parse WebM file elements. It was created 7 // This file contains code to parse WebM file elements. It was created
8 // from information in the Matroska spec. 8 // from information in the Matroska spec.
9 // http://www.matroska.org/technical/specs/index.html 9 // http://www.matroska.org/technical/specs/index.html
10 10
11 #include <iomanip> 11 #include <iomanip>
12 12
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "media/webm/webm_constants.h" 14 #include "media/webm/webm_constants.h"
15 15
16 namespace media { 16 namespace media {
17 17
18 // Maximum depth of WebM elements. Some WebM elements are lists of 18 // Maximum depth of WebM elements. Some WebM elements are lists of
19 // other elements. This limits the number levels of recursion allowed. 19 // other elements. This limits the number levels of recursion allowed.
20 static const int kMaxLevelDepth = 6; 20 static const int kMaxLevelDepth = 6;
21 21
22 enum ElementType { 22 enum ElementType {
23 UNKNOWN,
23 LIST, 24 LIST,
24 UINT, 25 UINT,
25 FLOAT, 26 FLOAT,
26 BINARY, 27 BINARY,
27 STRING, 28 STRING,
28 SBLOCK, 29 SBLOCK,
29 SKIP, 30 SKIP,
30 }; 31 };
31 32
32 struct ElementIdInfo { 33 struct ElementIdInfo {
33 int level_;
34 ElementType type_; 34 ElementType type_;
35 int id_; 35 int id_;
36 }; 36 };
37 37
38 struct ListElementInfo { 38 struct ListElementInfo {
39 int id_; 39 int id_;
40 int level_;
40 const ElementIdInfo* id_info_; 41 const ElementIdInfo* id_info_;
41 int id_info_size_; 42 int id_info_size_;
42 }; 43 };
43 44
44 // The following are tables indicating what IDs are valid sub-elements 45 // The following are tables indicating what IDs are valid sub-elements
45 // of particular elements. If an element is encountered that doesn't 46 // of particular elements. If an element is encountered that doesn't
46 // appear in the list, a parsing error is signalled. Some elements are 47 // appear in the list, a parsing error is signalled. Some elements are
47 // marked as SKIP because they are valid, but we don't care about them 48 // marked as SKIP because they are valid, but we don't care about them
48 // right now. 49 // right now.
49 static const ElementIdInfo kClusterIds[] = { 50 static const ElementIdInfo kClusterIds[] = {
50 {2, UINT, kWebMIdTimecode}, 51 {UINT, kWebMIdTimecode},
51 {2, SBLOCK, kWebMIdSimpleBlock}, 52 {SBLOCK, kWebMIdSimpleBlock},
52 {2, LIST, kWebMIdBlockGroup}, 53 {LIST, kWebMIdBlockGroup},
54 };
55
56 static const ElementIdInfo kSegmentIds[] = {
57 {SKIP, kWebMIdSeekHead}, // TODO(acolwell): add SeekHead info
scherkus (not reviewing) 2011/12/09 18:18:04 two spaces before // comments
acolwell GONE FROM CHROMIUM 2011/12/09 19:06:10 Done.
58 {LIST, kWebMIdInfo},
59 {LIST, kWebMIdCluster},
60 {LIST, kWebMIdTracks},
61 {SKIP, kWebMIdCues}, // TODO(acolwell): add CUES info
53 }; 62 };
54 63
55 static const ElementIdInfo kInfoIds[] = { 64 static const ElementIdInfo kInfoIds[] = {
56 {2, SKIP, kWebMIdSegmentUID}, 65 {SKIP, kWebMIdSegmentUID},
57 {2, UINT, kWebMIdTimecodeScale}, 66 {UINT, kWebMIdTimecodeScale},
58 {2, FLOAT, kWebMIdDuration}, 67 {FLOAT, kWebMIdDuration},
59 {2, SKIP, kWebMIdDateUTC}, 68 {SKIP, kWebMIdDateUTC},
60 {2, SKIP, kWebMIdTitle}, 69 {SKIP, kWebMIdTitle},
61 {2, SKIP, kWebMIdMuxingApp}, 70 {SKIP, kWebMIdMuxingApp},
62 {2, SKIP, kWebMIdWritingApp}, 71 {SKIP, kWebMIdWritingApp},
63 }; 72 };
64 73
65 static const ElementIdInfo kTracksIds[] = { 74 static const ElementIdInfo kTracksIds[] = {
66 {2, LIST, kWebMIdTrackEntry}, 75 {LIST, kWebMIdTrackEntry},
67 }; 76 };
68 77
69 static const ElementIdInfo kTrackEntryIds[] = { 78 static const ElementIdInfo kTrackEntryIds[] = {
70 {3, UINT, kWebMIdTrackNumber}, 79 {UINT, kWebMIdTrackNumber},
71 {3, SKIP, kWebMIdTrackUID}, 80 {SKIP, kWebMIdTrackUID},
72 {3, UINT, kWebMIdTrackType}, 81 {UINT, kWebMIdTrackType},
73 {3, SKIP, kWebMIdFlagEnabled}, 82 {SKIP, kWebMIdFlagEnabled},
74 {3, SKIP, kWebMIdFlagDefault}, 83 {SKIP, kWebMIdFlagDefault},
75 {3, SKIP, kWebMIdFlagForced}, 84 {SKIP, kWebMIdFlagForced},
76 {3, UINT, kWebMIdFlagLacing}, 85 {UINT, kWebMIdFlagLacing},
77 {3, UINT, kWebMIdDefaultDuration}, 86 {UINT, kWebMIdDefaultDuration},
78 {3, SKIP, kWebMIdName}, 87 {SKIP, kWebMIdName},
79 {3, SKIP, kWebMIdLanguage}, 88 {SKIP, kWebMIdLanguage},
80 {3, STRING, kWebMIdCodecID}, 89 {STRING, kWebMIdCodecID},
81 {3, BINARY, kWebMIdCodecPrivate}, 90 {BINARY, kWebMIdCodecPrivate},
82 {3, SKIP, kWebMIdCodecName}, 91 {SKIP, kWebMIdCodecName},
83 {3, LIST, kWebMIdVideo}, 92 {LIST, kWebMIdVideo},
84 {3, LIST, kWebMIdAudio}, 93 {LIST, kWebMIdAudio},
85 }; 94 };
86 95
87 static const ElementIdInfo kVideoIds[] = { 96 static const ElementIdInfo kVideoIds[] = {
88 {4, SKIP, kWebMIdFlagInterlaced}, 97 {SKIP, kWebMIdFlagInterlaced},
89 {4, SKIP, kWebMIdStereoMode}, 98 {SKIP, kWebMIdStereoMode},
90 {4, UINT, kWebMIdPixelWidth}, 99 {UINT, kWebMIdPixelWidth},
91 {4, UINT, kWebMIdPixelHeight}, 100 {UINT, kWebMIdPixelHeight},
92 {4, SKIP, kWebMIdPixelCropBottom}, 101 {SKIP, kWebMIdPixelCropBottom},
93 {4, SKIP, kWebMIdPixelCropTop}, 102 {SKIP, kWebMIdPixelCropTop},
94 {4, SKIP, kWebMIdPixelCropLeft}, 103 {SKIP, kWebMIdPixelCropLeft},
95 {4, SKIP, kWebMIdPixelCropRight}, 104 {SKIP, kWebMIdPixelCropRight},
96 {4, SKIP, kWebMIdDisplayWidth}, 105 {SKIP, kWebMIdDisplayWidth},
97 {4, SKIP, kWebMIdDisplayHeight}, 106 {SKIP, kWebMIdDisplayHeight},
98 {4, SKIP, kWebMIdDisplayUnit}, 107 {SKIP, kWebMIdDisplayUnit},
99 {4, SKIP, kWebMIdAspectRatioType}, 108 {SKIP, kWebMIdAspectRatioType},
100 }; 109 };
101 110
102 static const ElementIdInfo kAudioIds[] = { 111 static const ElementIdInfo kAudioIds[] = {
103 {4, SKIP, kWebMIdSamplingFrequency}, 112 {SKIP, kWebMIdSamplingFrequency},
104 {4, SKIP, kWebMIdOutputSamplingFrequency}, 113 {SKIP, kWebMIdOutputSamplingFrequency},
105 {4, UINT, kWebMIdChannels}, 114 {UINT, kWebMIdChannels},
106 {4, SKIP, kWebMIdBitDepth}, 115 {SKIP, kWebMIdBitDepth},
107 };
108
109 static const ElementIdInfo kClustersOnly[] = {
110 {1, LIST, kWebMIdCluster},
111 }; 116 };
112 117
113 static const ListElementInfo kListElementInfo[] = { 118 static const ListElementInfo kListElementInfo[] = {
114 { kWebMIdCluster, kClusterIds, sizeof(kClusterIds) }, 119 { kWebMIdCluster, 1, kClusterIds, sizeof(kClusterIds) },
115 { kWebMIdInfo, kInfoIds, sizeof(kInfoIds) }, 120 { kWebMIdSegment, 0, kSegmentIds, sizeof(kSegmentIds) },
116 { kWebMIdTracks, kTracksIds, sizeof(kTracksIds) }, 121 { kWebMIdInfo, 1, kInfoIds, sizeof(kInfoIds) },
117 { kWebMIdTrackEntry, kTrackEntryIds, sizeof(kTrackEntryIds) }, 122 { kWebMIdTracks, 1, kTracksIds, sizeof(kTracksIds) },
118 { kWebMIdVideo, kVideoIds, sizeof(kVideoIds) }, 123 { kWebMIdTrackEntry, 2, kTrackEntryIds, sizeof(kTrackEntryIds) },
119 { kWebMIdAudio, kAudioIds, sizeof(kAudioIds) }, 124 { kWebMIdVideo, 3, kVideoIds, sizeof(kVideoIds) },
125 { kWebMIdAudio, 3, kAudioIds, sizeof(kAudioIds) },
120 }; 126 };
121 127
122 // Number of elements in kListElementInfo. 128 // Number of elements in kListElementInfo.
123 const int kListElementInfoCount = 129 const int kListElementInfoCount =
124 sizeof(kListElementInfo) / sizeof(ListElementInfo); 130 sizeof(kListElementInfo) / sizeof(ListElementInfo);
scherkus (not reviewing) 2011/12/09 18:18:04 nit: I think we have an arraysize() macro or somet
acolwell GONE FROM CHROMIUM 2011/12/09 19:06:10 Done.
125 131
126 WebMParserClient::~WebMParserClient() {}
127
128 // Parses an element header id or size field. These fields are variable length 132 // Parses an element header id or size field. These fields are variable length
129 // encoded. The first byte indicates how many bytes the field occupies. 133 // encoded. The first byte indicates how many bytes the field occupies.
130 // |buf| - The buffer to parse. 134 // |buf| - The buffer to parse.
131 // |size| - The number of bytes in |buf| 135 // |size| - The number of bytes in |buf|
132 // |max_bytes| - The maximum number of bytes the field can be. ID fields 136 // |max_bytes| - The maximum number of bytes the field can be. ID fields
133 // set this to 4 & element size fields set this to 8. If the 137 // set this to 4 & element size fields set this to 8. If the
134 // first byte indicates a larger field size than this it is a 138 // first byte indicates a larger field size than this it is a
135 // parser error. 139 // parser error.
136 // |mask_first_byte| - For element size fields the field length encoding bits 140 // |mask_first_byte| - For element size fields the field length encoding bits
137 // need to be masked off. This parameter is true for 141 // need to be masked off. This parameter is true for
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 size - num_id_bytes, 203 size - num_id_bytes,
200 8, true, &tmp); 204 8, true, &tmp);
201 205
202 if (num_size_bytes <= 0) 206 if (num_size_bytes <= 0)
203 return num_size_bytes; 207 return num_size_bytes;
204 208
205 *element_size = tmp; 209 *element_size = tmp;
206 return num_id_bytes + num_size_bytes; 210 return num_id_bytes + num_size_bytes;
207 } 211 }
208 212
209 // Finds ElementIdInfo for a specific ID. 213 // Finds ElementType for a specific ID.
210 static const ElementIdInfo* FindIdInfo(int id, 214 static const ElementType FindIdType(int id,
211 const ElementIdInfo* id_info, 215 const ElementIdInfo* id_info,
212 int id_info_size) { 216 int id_info_size) {
217
218 // Check for global element IDs that can be anywhere.
219 if (id == kWebMIdVoid || id == kWebMIdCRC32)
220 return SKIP;
221
213 int count = id_info_size / sizeof(*id_info); 222 int count = id_info_size / sizeof(*id_info);
214 for (int i = 0; i < count; ++i) { 223 for (int i = 0; i < count; ++i) {
215 if (id == id_info[i].id_) 224 if (id == id_info[i].id_)
216 return &id_info[i]; 225 return id_info[i].type_;
217 } 226 }
218 227
219 return NULL; 228 return UNKNOWN;
220 } 229 }
221 230
222 // Finds ListElementInfo for a specific ID. 231 // Finds ListElementInfo for a specific ID.
223 static const ListElementInfo* FindListInfo(int id) { 232 static const ListElementInfo* FindListInfo(int id) {
224 for (int i = 0; i < kListElementInfoCount; ++i) { 233 for (int i = 0; i < kListElementInfoCount; ++i) {
225 if (id == kListElementInfo[i].id_) 234 if (id == kListElementInfo[i].id_)
226 return &kListElementInfo[i]; 235 return &kListElementInfo[i];
227 } 236 }
228 237
229 return NULL; 238 return NULL;
230 } 239 }
231 240
232 static int ParseSimpleBlock(const uint8* buf, int size, 241 static int ParseSimpleBlock(const uint8* buf, int size,
233 WebMParserClient* client) { 242 WebMParserClient* client) {
234 if (size < 4) 243 if (size < 4)
235 return -1; 244 return -1;
236 245
237 // Return an error if the trackNum > 127. We just aren't 246 // Return an error if the trackNum > 127. We just aren't
238 // going to support large track numbers right now. 247 // going to support large track numbers right now.
239 if ((buf[0] & 0x80) != 0x80) { 248 if ((buf[0] & 0x80) != 0x80) {
240 VLOG(1) << "TrackNumber over 127 not supported"; 249 DVLOG(1) << "TrackNumber over 127 not supported";
241 return -1; 250 return -1;
242 } 251 }
243 252
244 int track_num = buf[0] & 0x7f; 253 int track_num = buf[0] & 0x7f;
245 int timecode = buf[1] << 8 | buf[2]; 254 int timecode = buf[1] << 8 | buf[2];
246 int flags = buf[3] & 0xff; 255 int flags = buf[3] & 0xff;
247 int lacing = (flags >> 1) & 0x3; 256 int lacing = (flags >> 1) & 0x3;
248 257
249 if (lacing != 0) { 258 if (lacing != 0) {
250 VLOG(1) << "Lacing " << lacing << " not supported yet."; 259 DVLOG(1) << "Lacing " << lacing << " not supported yet.";
251 return -1; 260 return -1;
252 } 261 }
253 262
254 // Sign extend negative timecode offsets. 263 // Sign extend negative timecode offsets.
255 if (timecode & 0x8000) 264 if (timecode & 0x8000)
256 timecode |= (-1 << 16); 265 timecode |= (-1 << 16);
257 266
258 const uint8* frame_data = buf + 4; 267 const uint8* frame_data = buf + 4;
259 int frame_size = size - (frame_data - buf); 268 int frame_size = size - (frame_data - buf);
260 if (!client->OnSimpleBlock(track_num, timecode, flags, 269 if (!client->OnSimpleBlock(track_num, timecode, flags,
261 frame_data, frame_size)) { 270 frame_data, frame_size)) {
262 return -1; 271 return -1;
263 } 272 }
264 273
265 return size; 274 return size;
266 } 275 }
267 276
268 static int ParseElements(const ElementIdInfo* id_info,
269 int id_info_size,
270 const uint8* buf, int size, int level,
271 WebMParserClient* client);
272
273 static int ParseElementList(const uint8* buf, int size,
274 int id, int level,
275 WebMParserClient* client) {
276 const ListElementInfo* list_info = FindListInfo(id);
277
278 if (!list_info) {
279 VLOG(1) << "Failed to find list info for ID " << std::hex << id;
280 return -1;
281 }
282
283 if (!client->OnListStart(id))
284 return -1;
285
286 int result = ParseElements(list_info->id_info_,
287 list_info->id_info_size_,
288 buf, size,
289 level + 1,
290 client);
291
292 if (result <= 0)
293 return result;
294
295 if (!client->OnListEnd(id))
296 return -1;
297
298 DCHECK_EQ(result, size);
299 return result;
300 }
301 277
302 static int ParseUInt(const uint8* buf, int size, int id, 278 static int ParseUInt(const uint8* buf, int size, int id,
303 WebMParserClient* client) { 279 WebMParserClient* client) {
304 if ((size <= 0) || (size > 8)) 280 if ((size <= 0) || (size > 8))
305 return -1; 281 return -1;
306 282
307 // Read in the big-endian integer. 283 // Read in the big-endian integer.
308 int64 value = 0; 284 int64 value = 0;
309 for (int i = 0; i < size; ++i) 285 for (int i = 0; i < size; ++i)
310 value = (value << 8) | buf[i]; 286 value = (value << 8) | buf[i];
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 } else { 323 } else {
348 return -1; 324 return -1;
349 } 325 }
350 326
351 if (!client->OnFloat(id, value)) 327 if (!client->OnFloat(id, value))
352 return -1; 328 return -1;
353 329
354 return size; 330 return size;
355 } 331 }
356 332
357 static int ParseElements(const ElementIdInfo* id_info, 333 static int ParseNonListElement(ElementType type, int id, int64 element_size,
358 int id_info_size, 334 const uint8* buf, int size,
359 const uint8* buf, int size, int level, 335 WebMParserClient* client) {
360 WebMParserClient* client) { 336 DCHECK_GE(size, element_size);
361 DCHECK_GE(id_info_size, 0); 337
362 DCHECK_GE(size, 0); 338 int result = -1;
363 DCHECK_GE(level, 0); 339 switch(type) {
364 340 case SBLOCK:
365 const uint8* cur = buf; 341 result = ParseSimpleBlock(buf, element_size, client);
366 int cur_size = size; 342 break;
367 int used = 0; 343 case LIST:
368 344 NOTIMPLEMENTED();
369 if (level > kMaxLevelDepth) 345 result = -1;
370 return -1; 346 break;
371 347 case UINT:
372 while (cur_size > 0) { 348 result = ParseUInt(buf, element_size, id, client);
373 int id = 0; 349 break;
374 int64 element_size = 0; 350 case FLOAT:
375 int result = WebMParseElementHeader(cur, cur_size, &id, &element_size); 351 result = ParseFloat(buf, element_size, id, client);
376 352 break;
377 if (result <= 0) 353 case BINARY:
378 return result; 354 if (client->OnBinary(id, buf, element_size)) {
379 355 result = element_size;
380 cur += result; 356 } else {
381 cur_size -= result; 357 result = -1;
382 used += result; 358 }
383 359 break;
384 // Check to see if the element is larger than the remaining data. 360 case STRING:
385 if (element_size > cur_size) 361 if (client->OnString(id,
386 return 0; 362 std::string(reinterpret_cast<const char*>(buf),
387 363 element_size))) {
388 const ElementIdInfo* info = FindIdInfo(id, id_info, id_info_size); 364 result = element_size;
389 365 } else {
390 if (info == NULL) { 366 result = -1;
391 VLOG(1) << "No info for ID " << std::hex << id; 367 }
392 368 break;
393 // TODO(acolwell): Change this to return -1 after the API has solidified. 369 case SKIP:
394 // We don't want to allow elements we don't recognize. 370 result = element_size;
395 cur += element_size; 371 break;
396 cur_size -= element_size; 372 default:
397 used += element_size; 373 DVLOG(1) << "Unhandled ID type " << type;
398 continue;
399 }
400
401 if (info->level_ != level) {
402 VLOG(1) << "ID " << std::hex << id << std::dec << " at level "
403 << level << " instead of " << info->level_;
404 return -1; 374 return -1;
405 } 375 };
406 376
407 switch(info->type_) { 377 DCHECK_LE(result, size);
408 case SBLOCK: 378 return result;
409 if (ParseSimpleBlock(cur, element_size, client) <= 0) 379 }
410 return -1; 380
411 break; 381 WebMParserClient::WebMParserClient() {}
412 case LIST: 382 WebMParserClient::~WebMParserClient() {}
413 if (ParseElementList(cur, element_size, id, level, client) < 0) 383
414 return -1; 384 WebMListParser::WebMListParser(int id)
415 break; 385 : state_(NEED_LIST_HEADER),
416 case UINT: 386 root_id_(id) {
417 if (ParseUInt(cur, element_size, id, client) <= 0) 387 const ListElementInfo* list_info = FindListInfo(id);
418 return -1; 388
419 break; 389 DCHECK(list_info);
420 case FLOAT: 390
421 if (ParseFloat(cur, element_size, id, client) <= 0) 391 root_level_ = list_info->level_;
422 return -1; 392 }
423 break; 393
424 case BINARY: 394 WebMListParser::~WebMListParser() {}
425 if (!client->OnBinary(id, cur, element_size)) 395
426 return -1; 396 void WebMListParser::Reset() {
427 break; 397 ChangeState(NEED_LIST_HEADER);
428 case STRING: 398 list_state_stack_.clear();
429 if (!client->OnString(id, 399 }
430 std::string(reinterpret_cast<const char*>(cur), 400
431 element_size))) 401 int WebMListParser::Parse(const uint8* buf, int size,
432 return -1; 402 WebMParserClient* client) {
433 break; 403 DCHECK(buf);
434 case SKIP: 404 DCHECK(client);
435 // Do nothing. 405
436 break; 406 if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
437 default:
438 VLOG(1) << "Unhandled id type " << info->type_;
439 return -1;
440 };
441
442 cur += element_size;
443 cur_size -= element_size;
444 used += element_size;
445 }
446
447 return used;
448 }
449
450 // Parses a single list element that matches |id|. This method fails if the
451 // buffer points to an element that does not match |id|.
452 int WebMParseListElement(const uint8* buf, int size, int id,
453 int level, WebMParserClient* client) {
454 if (size < 0)
455 return -1; 407 return -1;
456 408
457 if (size == 0) 409 if (size == 0)
458 return 0; 410 return 0;
459 411
460 const uint8* cur = buf; 412 const uint8* cur = buf;
461 int cur_size = size; 413 int cur_size = size;
462 int bytes_parsed = 0; 414 int bytes_parsed = 0;
463 int element_id = 0; 415
464 int64 element_size = 0; 416 while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
465 int result = WebMParseElementHeader(cur, cur_size, &element_id, 417 int element_id = 0;
466 &element_size); 418 int64 element_size = 0;
467 419 int result = WebMParseElementHeader(cur, cur_size, &element_id,
468 if (result <= 0) 420 &element_size);
469 return result; 421
470 422 if (result < 0)
471 cur += result;
472 cur_size -= result;
473 bytes_parsed += result;
474
475 if (element_id != id)
476 return -1;
477
478 if (element_size > cur_size)
479 return 0;
480
481 if (element_size > 0) {
482 result = ParseElementList(cur, element_size, element_id, level, client);
483
484 if (result <= 0)
485 return result; 423 return result;
486 424
425 if (result == 0)
426 return bytes_parsed;
427
428 switch(state_) {
429 case NEED_LIST_HEADER: {
430 if (element_id != root_id_) {
431 ChangeState(PARSE_ERROR);
432 return -1;
433 }
434
435 // TODO(acolwell): Add support for lists of unknown size.
436 if (element_size == kWebMUnknownSize) {
437 ChangeState(PARSE_ERROR);
438 return -1;
439 }
440
441 ChangeState(INSIDE_LIST);
442 if (!OnListStart(root_id_, element_size, client))
443 return -1;
444 } break;
scherkus (not reviewing) 2011/12/09 18:18:04 nit: this style is somewhat strange .. mind moving
acolwell GONE FROM CHROMIUM 2011/12/09 19:06:10 Done.
445
446 case INSIDE_LIST: {
447 int header_size = result;
448 const uint8* element_data = cur + header_size;
449 int element_data_size = cur_size - header_size;
450
451 if (element_size < element_data_size)
452 element_data_size = element_size;
453
454 result = ParseListElement(header_size, element_id, element_size,
455 element_data, element_data_size, client);
456
457 DCHECK_LE(result, header_size + element_data_size);
458 if (result < 0) {
459 ChangeState(PARSE_ERROR);
460 return -1;
461 }
462
463 if (result == 0)
464 return bytes_parsed;
465 } break;
466
467 case DONE_PARSING_LIST:
468 case PARSE_ERROR:
469 // Shouldn't be able to get here.
470 NOTIMPLEMENTED();
471 break;
472 }
473
487 cur += result; 474 cur += result;
488 cur_size -= result; 475 cur_size -= result;
489 bytes_parsed += result; 476 bytes_parsed += result;
490 } 477 }
491 478
492 return bytes_parsed; 479 return (state_ == PARSE_ERROR) ? -1 : bytes_parsed;
480 }
481
482 bool WebMListParser::IsParsingComplete() const {
483 return state_ == DONE_PARSING_LIST;
484 }
485
486 void WebMListParser::ChangeState(State new_state) {
487 state_ = new_state;
488 }
489
490 int WebMListParser::ParseListElement(int header_size,
491 int id, int64 element_size,
492 const uint8* data, int size,
493 WebMParserClient* client) {
494 DCHECK_GT(list_state_stack_.size(), 0u);
495
496 ListState& list_state = list_state_stack_.back();
497 DCHECK(list_state.element_info_);
498
499 const ListElementInfo* element_info = list_state.element_info_;
500 const ElementType id_type =
501 FindIdType(id, element_info->id_info_, element_info->id_info_size_);
502
503 // Unexpected ID.
504 if (id_type == UNKNOWN) {
505 DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
506 return -1;
507 }
508
509 // Make sure the whole element can fit inside the current list.
510 int64 total_element_size = header_size + element_size;
511 if (list_state.size_ != kWebMUnknownSize &&
512 list_state.size_ < list_state.bytes_parsed_ + total_element_size) {
513 return -1;
514 }
515
516 if (id_type == LIST) {
517 list_state.bytes_parsed_ += header_size;
518
519 if (!OnListStart(id, element_size, client))
520 return -1;
521 return header_size;
522 }
523
524 // Make sure we have the entire element before trying to parse a non-list
525 // element.
526 if (size < element_size)
527 return 0;
528
529 int bytes_parsed = ParseNonListElement(id_type, id, element_size,
530 data, size, client);
531 DCHECK_LE(bytes_parsed, size);
532
533 // Return if an error occurred or we need more data.
534 // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We
535 // need to check the element_size to disambiguate the "need more data" case
536 // from a successful parse.
537 if (bytes_parsed < 0 || (bytes_parsed == 0 && element_size != 0))
538 return bytes_parsed;
539
540 int result = header_size + bytes_parsed;
541 list_state.bytes_parsed_ += result;
542
543 // See if we have reached the end of the current list.
544 if (list_state.bytes_parsed_ == list_state.size_) {
545 if (!OnListEnd(client))
546 return -1;
547 }
548
549 return result;
550 }
551
552 bool WebMListParser::OnListStart(int id, int64 size, WebMParserClient* client) {
553 ListState list_state = { id, size, 0, FindListInfo(id)};
554
555 if (!list_state.element_info_)
556 return false;
557
558 int current_level = root_level_ + list_state_stack_.size() - 1;
559 if (current_level + 1 != list_state.element_info_->level_)
560 return false;
561
562 if (!list_state_stack_.empty()) {
563
564 // Make sure the new list doesn't go past the end of the current list.
565 ListState current_list = list_state_stack_.back();
566 if (current_list.size_ != kWebMUnknownSize &&
567 current_list.size_ < current_list.bytes_parsed_ + size)
568 return false;
569 }
570
571 if (!client->OnListStart(id))
572 return false;
573
574 list_state_stack_.push_back(list_state);
575
576 if (size == 0) {
577 return OnListEnd(client);
578 }
579
580 return true;
581 }
582
583 bool WebMListParser::OnListEnd(WebMParserClient* client) {
584 int lists_ended = 0;
585 for (; !list_state_stack_.empty(); ++lists_ended) {
586 const ListState& list_state = list_state_stack_.back();
587
588 if (list_state.bytes_parsed_ != list_state.size_)
589 break;
590
591 if (!client->OnListEnd(list_state.id_))
592 return false;
593
594 int64 bytes_parsed = list_state.bytes_parsed_;
595 list_state_stack_.pop_back();
596
597 if (!list_state_stack_.empty()) {
598 // Update the bytes_parsed_ for the parent element.
599 list_state_stack_.back().bytes_parsed_ += bytes_parsed;
600 }
601 }
602
603 DCHECK_GE(lists_ended, 1);
604
605 if (list_state_stack_.empty())
606 ChangeState(DONE_PARSING_LIST);
607
608 return true;
493 } 609 }
494 610
495 } // namespace media 611 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698