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

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

Issue 7203002: Adding ChunkDemuxer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More cleanup & commenting Created 9 years, 6 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) 2011 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 #include "media/filters/webm_parser.h"
6
scherkus (not reviewing) 2011/06/22 17:31:09 I believe you're doing ebml parsing here, so how a
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
7 #include <iomanip>
8
9 #include "base/logging.h"
10
11 namespace media {
12
13 static const int kMaxLevelDepth = 6;
scherkus (not reviewing) 2011/06/22 17:31:09 docs?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
14
15 WebMParserClient::~WebMParserClient() {}
scherkus (not reviewing) 2011/06/22 17:31:09 you can actually inline this in the .h if you want
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 If I remember correctly there was this pass over a
16
17 int webm_parse_num(const uint8* buf, int size, int max_bytes,
scherkus (not reviewing) 2011/06/22 17:31:09 docs? I don't think we need to document the bit-t
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
18 bool mask_first_byte, int64* num) {
19 DCHECK(buf);
20 DCHECK(num);
21
22 if (size <= 0)
23 return -1;
24
25 int mask = 0x80;
26 uint8 ch = buf[0];
27 int extra_bytes = -1;
28 for (int i = 0; i < max_bytes; ++i) {
29 if ((ch & mask) == mask) {
30 *num = mask_first_byte ? ch & ~mask : ch;
31 extra_bytes = i;
32 break;
33 }
34 mask >>= 1;
35 }
36
37 if ((extra_bytes == -1) || ((1 + extra_bytes) > size))
38 return -1;
39
40 int bytes_used = 1;
41
42 for (int i = 0; i < extra_bytes; ++i)
43 *num = (*num << 8) | (0xff & buf[bytes_used++]);
44
45 return bytes_used;
46 }
47
48 int webm_parse_element_header(const uint8* buf, int size,
49 int* id, int64* element_size) {
scherkus (not reviewing) 2011/06/22 17:31:09 docs
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
50 DCHECK(buf);
51 DCHECK_GE(size, 0);
52 DCHECK(id);
53 DCHECK(element_size);
54
55 if (size == 0)
56 return 0;
57
58 int64 tmp;
59 int num_id_bytes = webm_parse_num(buf, size, 4, false, &tmp);
60
61 if (num_id_bytes <= 0)
62 return num_id_bytes;
63
64 *id = (int)tmp;
scherkus (not reviewing) 2011/06/22 17:31:09 static_cast
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
65
66 int num_sz_bytes = webm_parse_num(buf + num_id_bytes,
scherkus (not reviewing) 2011/06/22 17:31:09 sz? I'm guessing it's size but I see a lot of oth
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
67 size - num_id_bytes,
68 8, true, &tmp);
69
70 if (num_sz_bytes <= 0)
71 return num_sz_bytes;
72
73 *element_size = tmp;
74 return num_id_bytes + num_sz_bytes;
75 }
76
77 enum ElementType {
78 LIST,
79 UINT,
80 FLOAT,
81 BINARY,
82 STRING,
83 SBLOCK,
84 SKIP,
85 };
86
87 struct ElementIdInfo {
88 int level_;
89 ElementType type_;
90 int id_;
91 };
92
93 static const ElementIdInfo kClusterIds[] = {
94 {2, UINT, kWebMIdTimecode},
95 {2, SBLOCK, kWebMIdSimpleBlock},
96 {2, LIST, kWebMIdBlockGroup},
97 };
98
99 static const ElementIdInfo kInfoIds[] = {
100 {2, SKIP, kWebMIdSegmentUID},
101 {2, UINT, kWebMIdTimecodeScale},
102 {2, FLOAT, kWebMIdDuration},
103 {2, SKIP, kWebMIdDateUTC},
104 {2, SKIP, kWebMIdTitle},
105 {2, SKIP, kWebMIdMuxingApp},
106 {2, SKIP, kWebMIdWritingApp},
107 };
108
109 static const ElementIdInfo kTracksIds[] = {
110 {2, LIST, kWebMIdTrackEntry},
111 };
112
113 static const ElementIdInfo kTrackEntryIds[] = {
114 {3, UINT, kWebMIdTrackNumber},
115 {3, SKIP, kWebMIdTrackUID},
116 {3, UINT, kWebMIdTrackType},
117 {3, SKIP, kWebMIdFlagEnabled},
118 {3, SKIP, kWebMIdFlagDefault},
119 {3, SKIP, kWebMIdFlagForced},
120 {3, UINT, kWebMIdFlagLacing},
121 {3, UINT, kWebMIdDefaultDuration},
122 {3, SKIP, kWebMIdName},
123 {3, SKIP, kWebMIdLanguage},
124 {3, STRING, kWebMIdCodecID},
125 {3, BINARY, kWebMIdCodecPrivate},
126 {3, SKIP, kWebMIdCodecName},
127 {3, LIST, kWebMIdVideo},
128 {3, LIST, kWebMIdAudio},
129 };
130
131 static const ElementIdInfo kVideoIds[] = {
132 {4, SKIP, kWebMIdFlagInterlaced},
133 {4, SKIP, kWebMIdStereoMode},
134 {4, UINT, kWebMIdPixelWidth},
135 {4, UINT, kWebMIdPixelHeight},
136 {4, SKIP, kWebMIdPixelCropBottom},
137 {4, SKIP, kWebMIdPixelCropTop},
138 {4, SKIP, kWebMIdPixelCropLeft},
139 {4, SKIP, kWebMIdPixelCropRight},
140 {4, SKIP, kWebMIdDisplayWidth},
141 {4, SKIP, kWebMIdDisplayHeight},
142 {4, SKIP, kWebMIdDisplayUnit},
143 {4, SKIP, kWebMIdAspectRatioType},
144 };
145
146 static const ElementIdInfo kAudioIds[] = {
147 {4, SKIP, kWebMIdSamplingFrequency},
148 {4, SKIP, kWebMIdOutputSamplingFrequency},
149 {4, UINT, kWebMIdChannels},
150 {4, SKIP, kWebMIdBitDepth},
151 };
152
153 static const ElementIdInfo kInfoAndTracksOnly[] = {
154 {1, LIST, kWebMIdInfo},
155 {1, LIST, kWebMIdTracks},
156 };
157
158 static const ElementIdInfo kClustersOnly[] = {
159 {1, LIST, kWebMIdCluster},
160 };
161
scherkus (not reviewing) 2011/06/22 17:31:09 nit: remove extra blank lines
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
162
163
164 struct ListElementInfo {
165 int id_;
166 const ElementIdInfo* id_info_;
167 int id_info_size_;
168 };
169
170 const ListElementInfo kListElementInfo[] = {
171 { kWebMIdCluster, kClusterIds, sizeof(kClusterIds) },
172 { kWebMIdInfo, kInfoIds, sizeof(kInfoIds) },
173 { kWebMIdTracks, kTracksIds, sizeof(kTracksIds) },
174 { kWebMIdTrackEntry, kTrackEntryIds, sizeof(kTrackEntryIds) },
175 { kWebMIdVideo, kVideoIds, sizeof(kVideoIds) },
176 { kWebMIdAudio, kAudioIds, sizeof(kAudioIds) },
177 };
178
179 const ElementIdInfo* webm_find_id_info(int id,
180 const ElementIdInfo* id_info,
181 int id_info_size) {
182 int count = id_info_size / sizeof(ElementIdInfo);
scherkus (not reviewing) 2011/06/22 17:31:09 nit: sizeof(*id_info)
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
183 for (int i = 0; i < count; ++i) {
184 if (id == id_info[i].id_)
185 return &id_info[i];
186 }
187
188 return NULL;
189 }
190
191 const ListElementInfo* webm_find_list_info(int id) {
192 int count = sizeof(kListElementInfo) / sizeof(ListElementInfo);
scherkus (not reviewing) 2011/06/22 17:31:09 isn't this a contsant?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
193 for (int i = 0; i < count; ++i) {
194 if (id == kListElementInfo[i].id_)
195 return &kListElementInfo[i];
196 }
197
198 return NULL;
199 }
200
201 int webm_parse_simple_block(WebMParserClient* client,
202 const uint8* buf, int size) {
203 if (size < 4)
204 return -1;
205
206 // Return an error if the trackNum > 127. We just aren't
207 // going to support large track numbers right now.
208 if ((buf[0] & 0x80) != 0x80) {
209 VLOG(1) << "TrackNumber over 127 not supported";
210 return -1;
211 }
212
213 int track_num = buf[0] & 0x7f;
214 int timecode = buf[1] << 8 | buf[2];
215 int flags = buf[3] & 0xff;
216 int lacing = (flags >> 1) & 0x3;
217
218 if (lacing != 0) {
219 VLOG(1) << "Lacing " << lacing << " not supported yet.";
220 return -1;
221 }
222
223 const uint8* frame_data = buf + 4;
224 int frame_size = size - (frame_data - buf);
225 if (!client->OnSimpleBlock(track_num, timecode, flags,
226 frame_data, frame_size)) {
227 return -1;
228 }
229
230 return size;
231 }
232
233 int webm_parse_elements(WebMParserClient* client,
234 const ElementIdInfo* id_info,
235 int id_info_size,
236 const uint8* buf, int size, int level) {
237 DCHECK_GE(id_info_size, 0);
238 DCHECK_GE(size, 0);
239 DCHECK_GE(level, 0);
240
241 const uint8* pCur = buf;
scherkus (not reviewing) 2011/06/22 17:31:09 pCur -> cur ?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done. Old habits sneak back in sometimes. :)
242 int cur_size = size;
243 int used = 0;
244
245 if (level > kMaxLevelDepth)
246 return -1;
247
248 while (cur_size > 0) {
249 int id;
250 int64 element_size;
251 int res = webm_parse_element_header(pCur, cur_size,
252 &id, &element_size);
253
254 if (res < 0)
255 return res;
256
257 if (res == 0)
258 break;
259
260 pCur += res;
261 cur_size -= res;
262 used += res;
263
264 // Check to see if the element is larger than the remaining data.
265 if (element_size > cur_size)
266 return -1;
267
268 const ElementIdInfo* info = webm_find_id_info(id, id_info, id_info_size);
269
270 if (info == NULL) {
271 VLOG(1) << "No info for ID " << std::hex << id;
272
273 // TODO(acolwell): Change this to return -1 after the API has solidified.
274 // We don't want to allow elements we don't recognize.
275 pCur += element_size;
276 cur_size -= element_size;
277 used += element_size;
278 continue;
279 }
280
281 if (info->level_ != level) {
282 VLOG(1) << "ID " << std::hex << id << std::dec << " at level "
283 << level << " instead of " << info->level_;
284 return -1;
285 }
286
287 if (info->type_ == SBLOCK) {
scherkus (not reviewing) 2011/06/22 17:31:09 use switch/case + helper functions to parse each t
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
288 int r2 = webm_parse_simple_block(client, pCur, element_size);
289 if (r2 <= 0)
290 return -1;
291
292 DCHECK_EQ(r2, element_size);
293 } else if (info->type_ == LIST) {
294 const ListElementInfo* list_info = webm_find_list_info(id);
295
296 if (!list_info) {
297 VLOG(1) << "Failed to find list info for ID " << std::hex << id;
298 return -1;
299 }
300
301 if (!client->OnListStart(id))
302 return -1;
303
304 int r2 = webm_parse_elements(client,
305 list_info->id_info_,
306 list_info->id_info_size_,
307 pCur, element_size,
308 level + 1);
309
310 if (r2 < 0)
311 return -1;
312
313 if (!client->OnListEnd(id))
314 return -1;
315
316 DCHECK_EQ(r2, element_size);
317 } else if (info->type_ == UINT) {
318 if ((element_size <= 0) || (element_size > 8))
319 return -1;
320
321 int64 tmp = 0;
322 for (int i = 0; i < element_size; ++i)
scherkus (not reviewing) 2011/06/22 17:31:09 endianess?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Added a comment indicating the integer is stored a
323 tmp = (tmp << 8) | pCur[i];
324
325 if (!client->OnUInt(id, tmp))
326 return -1;
327 } else if (info->type_ == FLOAT) {
328
scherkus (not reviewing) 2011/06/22 17:31:09 nit: remove blank line
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
329 if ((element_size != 4) && (element_size != 8))
330 return -1;
331
332 double value = -1;
333
334 int64 tmp = 0;
335 for (int i = 0; i < element_size; ++i)
336 tmp = (tmp << 8) | pCur[i];
337
338 if (element_size == 4) {
339 union {
340 int32 src;
341 float dst;
342 } tmp2;
343 tmp2.src = (int32)tmp;
scherkus (not reviewing) 2011/06/22 17:31:09 does ebml specify anything w.r.t. endianess?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Yes all fields are big endian. I've added a commen
344 value = tmp2.dst;
345 } else if (element_size == 8) {
346 union {
347 int64 src;
348 double dst;
349 } tmp2;
scherkus (not reviewing) 2011/06/22 17:31:09 ditto
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
350 tmp2.src = tmp;
351 value = tmp2.dst;
352 } else {
353 return -1;
354 }
355
356 if (!client->OnFloat(id, value))
357 return -1;
358 } else if (info->type_ == BINARY) {
359 if (!client->OnBinary(id, pCur, element_size))
360 return -1;
361 } else if (info->type_ == STRING) {
362 std::string s((const char*)pCur, element_size);
scherkus (not reviewing) 2011/06/22 17:31:09 reinterpret_cast<> is the string null terminated
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 The string is not null terminated. The constructor
363 if (!client->OnString(id, s))
364 return -1;
365 } else if (info->type_ != SKIP) {
366 VLOG(1) << "Unhandled id type " << info->type_;
367 return -1;
368 }
369
370 pCur += element_size;
371 cur_size -= element_size;
372 used += element_size;
373 }
374
375 return used;
376 }
377
378 int webm_parse_headers(WebMParserClient* client,
379 const uint8* buf, int size) {
380 return webm_parse_elements(client,
381 kInfoAndTracksOnly,
382 sizeof(kInfoAndTracksOnly),
383 buf, size, 1);
384 }
385
386 int webm_parse_cluster(WebMParserClient* client,
387 const uint8* buf, int size) {
388 return webm_parse_elements(client,
389 kClustersOnly,
390 sizeof(kClustersOnly),
391 buf, size, 1);
392 }
393
394 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698