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

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

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

Powered by Google App Engine
This is Rietveld 408576698