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

Side by Side Diff: media/mp4/box_definitions.cc

Issue 10536014: Implement ISO BMFF support in Media Source. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 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
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 #include "media/mp4/box_definitions.h"
6
7 #include "base/logging.h"
8 #include "media/mp4/box_reader.h"
9 #include "media/mp4/rcheck.h"
10 #include "media/mp4/fourccs.h"
11
12 namespace media {
13 namespace mp4 {
14
15 bool Parse(BoxReader* r, FileType* type) {
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 nit: r -> reader here and elsewhere
strobe_ 2012/06/07 16:33:54 I'd argue that in this file, the reduced visual de
acolwell GONE FROM CHROMIUM 2012/06/07 19:44:02 I'm unconvinced. :) Please change it here and in a
16 RCHECK(r->Read(&type->major_brand) && r->Read(&type->minor_version));
17 size_t num_brands = (r->size() - r->pos()) / sizeof(FourCC);
18 return r->Skip(sizeof(FourCC) * num_brands); // compatible_brands
19 }
20
21 ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() {}
22 ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {}
23
24 bool Parse(BoxReader* r, ProtectionSystemSpecificHeader* pssh) {
25 uint32 size;
26 return r->Skip(4) &&
27 r->Read(&pssh->system_id, 16) &&
28 r->Read(&size) &&
29 r->Read(&pssh->data, size);
30 }
31
32 SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
33 SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {}
34
35 bool Parse(BoxReader* r, SampleAuxiliaryInformationOffset* saio) {
36 RCHECK(r->ReadFullBoxHeader());
37 if (r->flags() & 1)
38 RCHECK(r->Skip(8));
39
40 uint32 count;
41 RCHECK(r->Read(&count) &&
42 r->HasBytes(count * (r->version() == 1 ? 8 : 4)));
43 saio->offsets.resize(count);
44
45 for (uint32 i = 0; i < count; i++) {
46 if (r->version() == 1) {
47 RCHECK(r->Read(&saio->offsets[i]));
48 } else {
49 RCHECK(r->Read4(&saio->offsets[i]));
50 }
51 }
52 return true;
53 }
54
55 SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize()
56 : default_sample_info_size(0), sample_count(0) {}
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 nit: } on next line
strobe_ 2012/06/07 16:33:54 Done.
57
58 SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() {}
59
60 bool Parse(BoxReader* r, SampleAuxiliaryInformationSize* saiz) {
61 RCHECK(r->ReadFullBoxHeader());
62 if (r->flags() & 1)
63 RCHECK(r->Skip(8));
64
65 RCHECK(r->Read(&saiz->default_sample_info_size) &&
66 r->Read(&saiz->sample_count));
67 if (saiz->default_sample_info_size == 0)
68 return r->Read(&saiz->sample_info_sizes, saiz->sample_count);
69 return true;
70 }
71
72 bool Parse(BoxReader* r, OriginalFormat* format) {
73 return r->Read(&format->format);
74 }
75
76 bool Parse(BoxReader* r, SchemeType* schm) {
77 RCHECK(r->Skip(4) && r->Read(&schm->type) && r->Read(&schm->version));
78 RCHECK(schm->type == FOURCC_CENC);
79 return true;
80 }
81
82 TrackEncryption::TrackEncryption()
83 : is_encrypted(false), default_iv_size(0) {}
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 nit: } on next line.
strobe_ 2012/06/07 16:33:54 Done.
84 TrackEncryption::~TrackEncryption() {}
85
86 bool Parse(BoxReader* r, TrackEncryption* tenc) {
87 uint8 flag;
88 RCHECK(r->Skip(2) &&
89 r->Read(&flag) &&
90 r->Read(&tenc->default_iv_size) &&
91 r->Read(&tenc->default_kid, 16));
92 tenc->is_encrypted = (flag != 0);
93 if (tenc->is_encrypted) {
94 RCHECK(tenc->default_iv_size == 8 || tenc->default_iv_size == 16);
95 } else {
96 RCHECK(tenc->default_iv_size == 0);
97 }
98 return true;
99 }
100
101 bool Parse(BoxReader* r, SchemeInfo* schi) {
102 return r->ScanChildren() && r->ReadChild(&schi->track_encryption);
103 }
104
105 bool Parse(BoxReader* r, ProtectionSchemeInfo* sinf) {
106 return r->ScanChildren() &&
107 r->ReadChild(&sinf->type) &&
108 r->ReadChild(&sinf->info);
109 }
110
111 bool Parse(BoxReader* r, MovieHeader* mvhd) {
112 RCHECK(r->ReadFullBoxHeader());
113
114 if (r->version() == 1) {
115 RCHECK(r->Read(&mvhd->creation_time) &&
116 r->Read(&mvhd->modification_time) &&
117 r->Read(&mvhd->timescale) &&
118 r->Read(&mvhd->duration));
119 } else {
120 RCHECK(r->Read4(&mvhd->creation_time) &&
121 r->Read4(&mvhd->modification_time) &&
122 r->Read(&mvhd->timescale) &&
123 r->Read4(&mvhd->duration));
124 }
125
126 RCHECK(r->Read(&mvhd->rate) &&
127 r->Read(&mvhd->volume) &&
128 r->Skip(10) && // reserved
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 WDYT about renaming this to SkipBytes so the units
strobe_ 2012/06/07 16:33:54 Done.
129 r->Skip(36) && // matrix
130 r->Skip(24) && // predefined zero
131 r->Read(&mvhd->next_track_id));
132 return true;
133 }
134
135 TrackHeader::TrackHeader() {}
136 TrackHeader::~TrackHeader() {}
137
138
139 bool Parse(BoxReader* r, TrackHeader* tkhd) {
140 RCHECK(r->ReadFullBoxHeader());
141 if (r->version() == 1) {
142 RCHECK(r->Read(&tkhd->creation_time) &&
143 r->Read(&tkhd->modification_time) &&
144 r->Read(&tkhd->track_id) &&
145 r->Skip(4) && // reserved
146 r->Read(&tkhd->duration));
147 } else {
148 RCHECK(r->Read4(&tkhd->creation_time) &&
149 r->Read4(&tkhd->modification_time) &&
150 r->Read(&tkhd->track_id) &&
151 r->Skip(4) && // reserved
152 r->Read4(&tkhd->duration));
153 }
154
155 RCHECK(r->Skip(8) && // reserved
156 r->Read(&tkhd->layer) &&
157 r->Read(&tkhd->alternate_group) &&
158 r->Read(&tkhd->volume) &&
159 r->Skip(2) && // reserved
160 r->Skip(36) && // matrix
161 r->Read(&tkhd->width) &&
162 r->Read(&tkhd->height));
163 tkhd->width >>= 16;
164 tkhd->height >>= 16;
165 return true;
166 }
167
168 SampleDescription::SampleDescription() {}
169 SampleDescription::~SampleDescription() {}
170
171 bool Parse(BoxReader* r, SampleDescription* desc) {
172 uint32 count;
173 RCHECK(r->Skip(4) && r->Read(&count) && r->ScanChildren());
174 desc->video_entries.clear();
175 desc->audio_entries.clear();
176
177 // Note: this value is preset before scanning begins. See comments in the
178 // Parse(Media*) function.
179 if (desc->type == kVideo) {
180 RCHECK(r->ReadAllChildren(&desc->video_entries));
181 } else if (desc->type == kAudio) {
182 RCHECK(r->ReadAllChildren(&desc->audio_entries));
183 }
184 return true;
185 }
186
187 SampleTable::SampleTable() {}
188 SampleTable::~SampleTable() {}
189
190 bool Parse(BoxReader* r, SampleTable* table) {
191 return r->ScanChildren() &&
192 r->ReadChild(&table->description);
193 }
194
195 EditList::EditList() {}
196 EditList::~EditList() {}
197
198 bool Parse(BoxReader* r, EditList* list) {
199 uint32 count;
200 RCHECK(r->ReadFullBoxHeader() && r->Read(&count));
201
202 if (r->version() == 1) {
203 RCHECK(r->HasBytes(count * 20));
204 } else {
205 RCHECK(r->HasBytes(count * 12));
206 }
207 list->edits.resize(count);
208
209 for (auto edit = list->edits.begin(); edit != list->edits.end(); ++edit) {
210 if (r->version() == 1) {
211 RCHECK(r->Read(&edit->segment_duration) &&
212 r->Read(&edit->media_time));
213 } else {
214 RCHECK(r->Read4(&edit->segment_duration) &&
215 r->Read4(&edit->media_time));
216 }
217 RCHECK(r->Read(&edit->media_rate_integer) &&
218 r->Read(&edit->media_rate_fraction));
219 }
220 return true;
221 }
222
223 Edit::Edit() {}
224 Edit::~Edit() {}
225
226 bool Parse(BoxReader* r, Edit* box) {
227 return r->ScanChildren() && r->ReadChild(&box->list);
228 }
229
230 bool Parse(BoxReader* r, HandlerReference* reference) {
231 FourCC type;
232 RCHECK(r->Skip(8) && r->Read(&type));
233 // Note: remaining fields in box ignored
234 if (type == FOURCC_VIDE) {
235
236 reference->type = kVideo;
237 } else if (type == FOURCC_SOUN) {
238 reference->type = kAudio;
239 } else {
240 reference->type = kInvalid;
241 }
242 return true;
243 }
244
245 SampleEntry::SampleEntry() {}
246 SampleEntry::~SampleEntry() {}
247
248 bool ParseSampleEntryHead(BoxReader* r, SampleEntry* entry) {
249 entry->format = r->type();
250 return r->Skip(6) && r->Read(&entry->data_reference_index);
251 }
252
253 AudioSampleEntry::AudioSampleEntry() {}
254 AudioSampleEntry::~AudioSampleEntry() {}
255
256 bool Parse(BoxReader* r, AudioSampleEntry* entry) {
257 RCHECK(ParseSampleEntryHead(r, entry) &&
258 r->Skip(8) &&
259 r->Read(&entry->channelcount) &&
260 r->Read(&entry->samplesize) &&
261 r->Skip(4) &&
262 r->Read(&entry->samplerate));
263 // Convert from 16.16 fixed point to integer
264 entry->samplerate >>= 16;
265
266 RCHECK(r->ScanChildren());
267 if (entry->format == FOURCC_ENCA) {
268 RCHECK(r->ReadChild(&entry->sinf));
269 }
270 return true;
271 }
272
273 VideoSampleEntry::VideoSampleEntry() {}
274 VideoSampleEntry::~VideoSampleEntry() {}
275
276 bool Parse(BoxReader* r, VideoSampleEntry* entry) {
277 RCHECK(ParseSampleEntryHead(r, entry) &&
278 r->Skip(16) &&
279 r->Read(&entry->width) &&
280 r->Read(&entry->height) &&
281 r->Skip(50));
282
283 RCHECK(r->ScanChildren());
284 if (entry->format == FOURCC_ENCV) {
285 RCHECK(r->ReadChild(&entry->sinf));
286 }
287
288 // TODO(strobe): Widevine test files do not follow spec here; check disabled
289 //if (entry->format == FOURCC_AVC1 ||
290 // (entry->format == FOURCC_ENCV &&
291 // entry->sinf.format.format == FOURCC_AVC1)) {
292 RCHECK(r->ReadChild(&entry->avcc));
293 //}
294 return true;
295 }
296
297 MediaHeader::MediaHeader() {}
298 MediaHeader::~MediaHeader() {}
299
300 bool Parse(BoxReader* r, MediaHeader* header) {
301 RCHECK(r->ReadFullBoxHeader());
302
303 if (r->version() == 1) {
304 RCHECK(r->Read(&header->creation_time) &&
305 r->Read(&header->modification_time) &&
306 r->Read(&header->timescale) &&
307 r->Read(&header->duration));
308 } else {
309 RCHECK(r->Read4(&header->creation_time) &&
310 r->Read4(&header->modification_time) &&
311 r->Read(&header->timescale) &&
312 r->Read4(&header->duration));
313 }
314 // Skip language information
315 return r->Skip(4);
316 }
317
318 bool Parse(BoxReader* r, MediaInformation* information) {
319 return r->ScanChildren() &&
320 r->ReadChild(&information->sample_table);
321 }
322
323 bool Parse(BoxReader* r, Media* media) {
324 RCHECK(r->ScanChildren() &&
325 r->ReadChild(&media->header) &&
326 r->ReadChild(&media->handler));
327
328 // Maddeningly, the HandlerReference box specifies how to parse the
329 // SampleDescription box, making the latter the only box (of those that we
330 // support) which cannot be parsed correctly on its own (or even with
331 // information from its strict ancestor tree). We thus copy the handler type
332 // to the sample description box *before* parsing it to provide this
333 // information while parsing.
334 media->information.sample_table.description.type = media->handler.type;
335 RCHECK(r->ReadChild(&media->information));
336 return true;
337 }
338
339 bool Parse(BoxReader* r, Track* track) {
340 RCHECK(r->ScanChildren() &&
341 r->ReadChild(&track->header) &&
342 r->ReadChild(&track->media) &&
343 r->MaybeReadChild(&track->edit));
344 return true;
345 }
346
347 bool Parse(BoxReader* r, MovieExtendsHeader* header) {
348 RCHECK(r->Read(&header->fragment_duration));
349 return true;
350 }
351
352 bool Parse(BoxReader* r, TrackExtends* extends) {
353 RCHECK(r->ReadFullBoxHeader() &&
354 r->Read(&extends->track_id) &&
355 r->Read(&extends->default_sample_description_index) &&
356 r->Read(&extends->default_sample_duration) &&
357 r->Read(&extends->default_sample_size) &&
358 r->Read(&extends->default_sample_flags));
359 return true;
360 }
361
362 MovieExtends::MovieExtends() {};
363 MovieExtends::~MovieExtends() {};
364
365 bool Parse(BoxReader* r, MovieExtends* extends) {
366 extends->header.fragment_duration = 0;
367 return r->ScanChildren() &&
368 r->MaybeReadChild(&extends->header) &&
369 // TODO(strobe): does not detect correspondence rule (trex must match
370 // one-to-one with trak)
371 r->ReadChildren(&extends->tracks);
372 }
373
374 Movie::Movie() {};
375 Movie::~Movie() {};
376
377 bool Parse(BoxReader* r, Movie* moov) {
378 return r->ScanChildren() &&
379 r->ReadChild(&moov->header) &&
380 r->ReadChildren(&moov->tracks) &&
381 // Media Source specific: 'mvex' required
382 r->ReadChild(&moov->extends) &&
383 r->MaybeReadChildren(&moov->pssh);
384 }
385
386 bool Parse(BoxReader* r, TrackFragmentDecodeTime* tfdt) {
387 RCHECK(r->ReadFullBoxHeader());
388 if (r->version() == 1)
389 return r->Read(&tfdt->decode_time);
390 else
391 return r->Read4(&tfdt->decode_time);
392 }
393
394 bool Parse(BoxReader* r, MovieFragmentHeader* mfhd) {
395 return r->Skip(4) && r->Read(&mfhd->sequence_number);
396 }
397
398 bool Parse(BoxReader* r, TrackFragmentHeader* tfhd) {
399 memset(tfhd, 0, sizeof(TrackFragmentHeader));
400
401 RCHECK(r->ReadFullBoxHeader() && r->Read(&tfhd->track_id));
402
403 // Media Source specific: we require that 'default-base-is-moof' (14496-12
404 // Amendment 2) be set, and reject tracks that set 'base-data-offset-present'.
405 //
406 // TODO(strobe): Test files do not have 'default-base-is-moof' set explicitly
407 // (although they are structured as if it is set). Because this flag is hidden
408 // in Amendment 2, it might not be set by all implementors. Should we reject
409 // such files, or try them anyway?
410 //
411 // RCHECK((flags & 0x020000) && !(flags & 0x1));
412 RCHECK(!(r->flags() & 0x1));
413
414 if (r->flags() & 0x2)
415 RCHECK(r->Skip(4)); // sample_description_index
416
417 if (r->flags() & 0x8)
418 RCHECK(r->Read(&tfhd->default_sample_duration));
419
420 if (r->flags() & 0x10)
421 RCHECK(r->Read(&tfhd->default_sample_size));
422
423 if (r->flags() & 0x20)
424 RCHECK(r->Read(&tfhd->default_sample_flags));
425
426 return true;
427 }
428
429 TrackFragmentRun::TrackFragmentRun() {}
430 TrackFragmentRun::~TrackFragmentRun() {}
431
432 bool Parse(BoxReader* r, TrackFragmentRun* trun) {
433 RCHECK(r->ReadFullBoxHeader() &&
434 r->Read(&trun->sample_count));
435 const uint32 flags = r->flags();
436
437 bool data_offset_present = flags & 0x1;
438 bool first_sample_flags_present = flags & 0x4;
439 bool sample_duration_present = flags & 0x100;
440 bool sample_size_present = flags & 0x200;
441 bool sample_flags_present = flags & 0x400;
442 bool sample_composition_time_offsets_present = flags & 0x800;
443
444 if (data_offset_present) {
445 RCHECK(r->Read(&trun->data_offset));
446 } else {
447 trun->data_offset = 0;
448 }
449
450 uint32 first_sample_flags;
451 if (first_sample_flags_present)
452 RCHECK(r->Read(&first_sample_flags));
453
454 int fields = sample_duration_present + sample_size_present
455 + sample_flags_present + sample_composition_time_offsets_present;
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 nit: + goes on the end of the previous line and th
strobe_ 2012/06/07 16:33:54 Done.
456 RCHECK(r->HasBytes(fields * trun->sample_count));
457
458 if (sample_duration_present)
459 trun->sample_durations.resize(trun->sample_count);
460 if (sample_size_present)
461 trun->sample_sizes.resize(trun->sample_count);
462 if (sample_flags_present)
463 trun->sample_flags.resize(trun->sample_count);
464 if (sample_composition_time_offsets_present)
465 trun->sample_composition_time_offsets.resize(trun->sample_count);
466
467 for (uint32 i = 0; i < trun->sample_count; ++i) {
468 if (sample_duration_present)
469 RCHECK(r->Read(&trun->sample_durations[i]));
470 if (sample_size_present)
471 RCHECK(r->Read(&trun->sample_sizes[i]));
472 if (sample_flags_present)
473 RCHECK(r->Read(&trun->sample_flags[i]));
474 if (sample_composition_time_offsets_present)
475 RCHECK(r->Read(&trun->sample_composition_time_offsets[i]));
476 }
477
478 if (first_sample_flags_present) {
479 if (trun->sample_flags.size() == 0) {
480 trun->sample_flags.push_back(first_sample_flags);
481 } else {
482 trun->sample_flags[0] = first_sample_flags;
483 }
484 }
485 return true;
486 }
487
488 TrackFragment::TrackFragment() {}
489 TrackFragment::~TrackFragment() {}
490
491 bool Parse(BoxReader* r, TrackFragment* traf) {
492 return r->ScanChildren() &&
493 r->ReadChild(&traf->header) &&
494 // Media Source specific: 'tfdt' required
495 r->ReadChild(&traf->decode_time) &&
496 r->MaybeReadChildren(&traf->runs) &&
497 r->MaybeReadChild(&traf->auxiliary_offset) &&
498 r->MaybeReadChild(&traf->auxiliary_size);
499 }
500
501 MovieFragment::MovieFragment() {}
502 MovieFragment::~MovieFragment() {}
503
504 bool Parse(BoxReader* r, MovieFragment* moof) {
505 RCHECK(r->ScanChildren() &&
506 r->ReadChild(&moof->header) &&
507 r->ReadChildren(&moof->tracks) &&
508 r->MaybeReadChildren(&moof->pssh));
509 return true;
510 }
511
512 bool Parse(BoxReader* r, SegmentIndex* sidx) {
513 RCHECK(r->ReadFullBoxHeader() &&
514 r->Read(&sidx->reference_id) &&
515 r->Read(&sidx->timescale));
516
517 if (r->version() == 0) {
518 RCHECK(r->Read4(&sidx->earliest_presentation_time) &&
519 r->Read4(&sidx->first_offset));
520 } else {
521 RCHECK(r->Read(&sidx->earliest_presentation_time) &&
522 r->Read(&sidx->first_offset));
523 }
524
525 uint32 reference_count;
526 RCHECK(r->Skip(2) && // reserved
527 r->Read(&reference_count) &&
528 r->HasBytes(12 * reference_count));
529
530 for (uint32 i = 0; i < reference_count; ++i) {
531 uint32 flags;
532 RCHECK(r->Read(&sidx->sizes[i]) &&
533 r->Read(&sidx->durations[i]) &&
534 r->Read(&flags));
535
536 uint32 type = flags / 0x10000000 % 8;
537
538 RCHECK(!(sidx->sizes[i] & 0x8000000) != 0 ||
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 What?!? A comment indicating what this is checking
539 (flags & 0x80000000) != 0x80000000 ||
540 (type != 0 && type != 1) ||
541 (flags % 0x10000000 != 0));
542 }
543 return true;
544 }
545
546 } // namespace mp4
547 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698