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

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

Powered by Google App Engine
This is Rietveld 408576698