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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: media/mp4/box_definitions.cc
diff --git a/media/mp4/box_definitions.cc b/media/mp4/box_definitions.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7a2964c56692c26958f80cdc18f04f35aa0c838f
--- /dev/null
+++ b/media/mp4/box_definitions.cc
@@ -0,0 +1,547 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/mp4/box_definitions.h"
+
+#include "base/logging.h"
+#include "media/mp4/box_reader.h"
+#include "media/mp4/rcheck.h"
+#include "media/mp4/fourccs.h"
+
+namespace media {
+namespace mp4 {
+
+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
+ RCHECK(r->Read(&type->major_brand) && r->Read(&type->minor_version));
+ size_t num_brands = (r->size() - r->pos()) / sizeof(FourCC);
+ return r->Skip(sizeof(FourCC) * num_brands); // compatible_brands
+}
+
+ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() {}
+ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {}
+
+bool Parse(BoxReader* r, ProtectionSystemSpecificHeader* pssh) {
+ uint32 size;
+ return r->Skip(4) &&
+ r->Read(&pssh->system_id, 16) &&
+ r->Read(&size) &&
+ r->Read(&pssh->data, size);
+}
+
+SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
+SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {}
+
+bool Parse(BoxReader* r, SampleAuxiliaryInformationOffset* saio) {
+ RCHECK(r->ReadFullBoxHeader());
+ if (r->flags() & 1)
+ RCHECK(r->Skip(8));
+
+ uint32 count;
+ RCHECK(r->Read(&count) &&
+ r->HasBytes(count * (r->version() == 1 ? 8 : 4)));
+ saio->offsets.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ if (r->version() == 1) {
+ RCHECK(r->Read(&saio->offsets[i]));
+ } else {
+ RCHECK(r->Read4(&saio->offsets[i]));
+ }
+ }
+ return true;
+}
+
+SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize()
+ : 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.
+
+SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() {}
+
+bool Parse(BoxReader* r, SampleAuxiliaryInformationSize* saiz) {
+ RCHECK(r->ReadFullBoxHeader());
+ if (r->flags() & 1)
+ RCHECK(r->Skip(8));
+
+ RCHECK(r->Read(&saiz->default_sample_info_size) &&
+ r->Read(&saiz->sample_count));
+ if (saiz->default_sample_info_size == 0)
+ return r->Read(&saiz->sample_info_sizes, saiz->sample_count);
+ return true;
+}
+
+bool Parse(BoxReader* r, OriginalFormat* format) {
+ return r->Read(&format->format);
+}
+
+bool Parse(BoxReader* r, SchemeType* schm) {
+ RCHECK(r->Skip(4) && r->Read(&schm->type) && r->Read(&schm->version));
+ RCHECK(schm->type == FOURCC_CENC);
+ return true;
+}
+
+TrackEncryption::TrackEncryption()
+ : 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.
+TrackEncryption::~TrackEncryption() {}
+
+bool Parse(BoxReader* r, TrackEncryption* tenc) {
+ uint8 flag;
+ RCHECK(r->Skip(2) &&
+ r->Read(&flag) &&
+ r->Read(&tenc->default_iv_size) &&
+ r->Read(&tenc->default_kid, 16));
+ tenc->is_encrypted = (flag != 0);
+ if (tenc->is_encrypted) {
+ RCHECK(tenc->default_iv_size == 8 || tenc->default_iv_size == 16);
+ } else {
+ RCHECK(tenc->default_iv_size == 0);
+ }
+ return true;
+}
+
+bool Parse(BoxReader* r, SchemeInfo* schi) {
+ return r->ScanChildren() && r->ReadChild(&schi->track_encryption);
+}
+
+bool Parse(BoxReader* r, ProtectionSchemeInfo* sinf) {
+ return r->ScanChildren() &&
+ r->ReadChild(&sinf->type) &&
+ r->ReadChild(&sinf->info);
+}
+
+bool Parse(BoxReader* r, MovieHeader* mvhd) {
+ RCHECK(r->ReadFullBoxHeader());
+
+ if (r->version() == 1) {
+ RCHECK(r->Read(&mvhd->creation_time) &&
+ r->Read(&mvhd->modification_time) &&
+ r->Read(&mvhd->timescale) &&
+ r->Read(&mvhd->duration));
+ } else {
+ RCHECK(r->Read4(&mvhd->creation_time) &&
+ r->Read4(&mvhd->modification_time) &&
+ r->Read(&mvhd->timescale) &&
+ r->Read4(&mvhd->duration));
+ }
+
+ RCHECK(r->Read(&mvhd->rate) &&
+ r->Read(&mvhd->volume) &&
+ 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.
+ r->Skip(36) && // matrix
+ r->Skip(24) && // predefined zero
+ r->Read(&mvhd->next_track_id));
+ return true;
+}
+
+TrackHeader::TrackHeader() {}
+TrackHeader::~TrackHeader() {}
+
+
+bool Parse(BoxReader* r, TrackHeader* tkhd) {
+ RCHECK(r->ReadFullBoxHeader());
+ if (r->version() == 1) {
+ RCHECK(r->Read(&tkhd->creation_time) &&
+ r->Read(&tkhd->modification_time) &&
+ r->Read(&tkhd->track_id) &&
+ r->Skip(4) && // reserved
+ r->Read(&tkhd->duration));
+ } else {
+ RCHECK(r->Read4(&tkhd->creation_time) &&
+ r->Read4(&tkhd->modification_time) &&
+ r->Read(&tkhd->track_id) &&
+ r->Skip(4) && // reserved
+ r->Read4(&tkhd->duration));
+ }
+
+ RCHECK(r->Skip(8) && // reserved
+ r->Read(&tkhd->layer) &&
+ r->Read(&tkhd->alternate_group) &&
+ r->Read(&tkhd->volume) &&
+ r->Skip(2) && // reserved
+ r->Skip(36) && // matrix
+ r->Read(&tkhd->width) &&
+ r->Read(&tkhd->height));
+ tkhd->width >>= 16;
+ tkhd->height >>= 16;
+ return true;
+}
+
+SampleDescription::SampleDescription() {}
+SampleDescription::~SampleDescription() {}
+
+bool Parse(BoxReader* r, SampleDescription* desc) {
+ uint32 count;
+ RCHECK(r->Skip(4) && r->Read(&count) && r->ScanChildren());
+ desc->video_entries.clear();
+ desc->audio_entries.clear();
+
+ // Note: this value is preset before scanning begins. See comments in the
+ // Parse(Media*) function.
+ if (desc->type == kVideo) {
+ RCHECK(r->ReadAllChildren(&desc->video_entries));
+ } else if (desc->type == kAudio) {
+ RCHECK(r->ReadAllChildren(&desc->audio_entries));
+ }
+ return true;
+}
+
+SampleTable::SampleTable() {}
+SampleTable::~SampleTable() {}
+
+bool Parse(BoxReader* r, SampleTable* table) {
+ return r->ScanChildren() &&
+ r->ReadChild(&table->description);
+}
+
+EditList::EditList() {}
+EditList::~EditList() {}
+
+bool Parse(BoxReader* r, EditList* list) {
+ uint32 count;
+ RCHECK(r->ReadFullBoxHeader() && r->Read(&count));
+
+ if (r->version() == 1) {
+ RCHECK(r->HasBytes(count * 20));
+ } else {
+ RCHECK(r->HasBytes(count * 12));
+ }
+ list->edits.resize(count);
+
+ for (auto edit = list->edits.begin(); edit != list->edits.end(); ++edit) {
+ if (r->version() == 1) {
+ RCHECK(r->Read(&edit->segment_duration) &&
+ r->Read(&edit->media_time));
+ } else {
+ RCHECK(r->Read4(&edit->segment_duration) &&
+ r->Read4(&edit->media_time));
+ }
+ RCHECK(r->Read(&edit->media_rate_integer) &&
+ r->Read(&edit->media_rate_fraction));
+ }
+ return true;
+}
+
+Edit::Edit() {}
+Edit::~Edit() {}
+
+bool Parse(BoxReader* r, Edit* box) {
+ return r->ScanChildren() && r->ReadChild(&box->list);
+}
+
+bool Parse(BoxReader* r, HandlerReference* reference) {
+ FourCC type;
+ RCHECK(r->Skip(8) && r->Read(&type));
+ // Note: remaining fields in box ignored
+ if (type == FOURCC_VIDE) {
+
+ reference->type = kVideo;
+ } else if (type == FOURCC_SOUN) {
+ reference->type = kAudio;
+ } else {
+ reference->type = kInvalid;
+ }
+ return true;
+}
+
+SampleEntry::SampleEntry() {}
+SampleEntry::~SampleEntry() {}
+
+bool ParseSampleEntryHead(BoxReader* r, SampleEntry* entry) {
+ entry->format = r->type();
+ return r->Skip(6) && r->Read(&entry->data_reference_index);
+}
+
+AudioSampleEntry::AudioSampleEntry() {}
+AudioSampleEntry::~AudioSampleEntry() {}
+
+bool Parse(BoxReader* r, AudioSampleEntry* entry) {
+ RCHECK(ParseSampleEntryHead(r, entry) &&
+ r->Skip(8) &&
+ r->Read(&entry->channelcount) &&
+ r->Read(&entry->samplesize) &&
+ r->Skip(4) &&
+ r->Read(&entry->samplerate));
+ // Convert from 16.16 fixed point to integer
+ entry->samplerate >>= 16;
+
+ RCHECK(r->ScanChildren());
+ if (entry->format == FOURCC_ENCA) {
+ RCHECK(r->ReadChild(&entry->sinf));
+ }
+ return true;
+}
+
+VideoSampleEntry::VideoSampleEntry() {}
+VideoSampleEntry::~VideoSampleEntry() {}
+
+bool Parse(BoxReader* r, VideoSampleEntry* entry) {
+ RCHECK(ParseSampleEntryHead(r, entry) &&
+ r->Skip(16) &&
+ r->Read(&entry->width) &&
+ r->Read(&entry->height) &&
+ r->Skip(50));
+
+ RCHECK(r->ScanChildren());
+ if (entry->format == FOURCC_ENCV) {
+ RCHECK(r->ReadChild(&entry->sinf));
+ }
+
+ // TODO(strobe): Widevine test files do not follow spec here; check disabled
+ //if (entry->format == FOURCC_AVC1 ||
+ // (entry->format == FOURCC_ENCV &&
+ // entry->sinf.format.format == FOURCC_AVC1)) {
+ RCHECK(r->ReadChild(&entry->avcc));
+ //}
+ return true;
+}
+
+MediaHeader::MediaHeader() {}
+MediaHeader::~MediaHeader() {}
+
+bool Parse(BoxReader* r, MediaHeader* header) {
+ RCHECK(r->ReadFullBoxHeader());
+
+ if (r->version() == 1) {
+ RCHECK(r->Read(&header->creation_time) &&
+ r->Read(&header->modification_time) &&
+ r->Read(&header->timescale) &&
+ r->Read(&header->duration));
+ } else {
+ RCHECK(r->Read4(&header->creation_time) &&
+ r->Read4(&header->modification_time) &&
+ r->Read(&header->timescale) &&
+ r->Read4(&header->duration));
+ }
+ // Skip language information
+ return r->Skip(4);
+}
+
+bool Parse(BoxReader* r, MediaInformation* information) {
+ return r->ScanChildren() &&
+ r->ReadChild(&information->sample_table);
+}
+
+bool Parse(BoxReader* r, Media* media) {
+ RCHECK(r->ScanChildren() &&
+ r->ReadChild(&media->header) &&
+ r->ReadChild(&media->handler));
+
+ // Maddeningly, the HandlerReference box specifies how to parse the
+ // SampleDescription box, making the latter the only box (of those that we
+ // support) which cannot be parsed correctly on its own (or even with
+ // information from its strict ancestor tree). We thus copy the handler type
+ // to the sample description box *before* parsing it to provide this
+ // information while parsing.
+ media->information.sample_table.description.type = media->handler.type;
+ RCHECK(r->ReadChild(&media->information));
+ return true;
+}
+
+bool Parse(BoxReader* r, Track* track) {
+ RCHECK(r->ScanChildren() &&
+ r->ReadChild(&track->header) &&
+ r->ReadChild(&track->media) &&
+ r->MaybeReadChild(&track->edit));
+ return true;
+}
+
+bool Parse(BoxReader* r, MovieExtendsHeader* header) {
+ RCHECK(r->Read(&header->fragment_duration));
+ return true;
+}
+
+bool Parse(BoxReader* r, TrackExtends* extends) {
+ RCHECK(r->ReadFullBoxHeader() &&
+ r->Read(&extends->track_id) &&
+ r->Read(&extends->default_sample_description_index) &&
+ r->Read(&extends->default_sample_duration) &&
+ r->Read(&extends->default_sample_size) &&
+ r->Read(&extends->default_sample_flags));
+ return true;
+}
+
+MovieExtends::MovieExtends() {};
+MovieExtends::~MovieExtends() {};
+
+bool Parse(BoxReader* r, MovieExtends* extends) {
+ extends->header.fragment_duration = 0;
+ return r->ScanChildren() &&
+ r->MaybeReadChild(&extends->header) &&
+ // TODO(strobe): does not detect correspondence rule (trex must match
+ // one-to-one with trak)
+ r->ReadChildren(&extends->tracks);
+}
+
+Movie::Movie() {};
+Movie::~Movie() {};
+
+bool Parse(BoxReader* r, Movie* moov) {
+ return r->ScanChildren() &&
+ r->ReadChild(&moov->header) &&
+ r->ReadChildren(&moov->tracks) &&
+ // Media Source specific: 'mvex' required
+ r->ReadChild(&moov->extends) &&
+ r->MaybeReadChildren(&moov->pssh);
+}
+
+bool Parse(BoxReader* r, TrackFragmentDecodeTime* tfdt) {
+ RCHECK(r->ReadFullBoxHeader());
+ if (r->version() == 1)
+ return r->Read(&tfdt->decode_time);
+ else
+ return r->Read4(&tfdt->decode_time);
+}
+
+bool Parse(BoxReader* r, MovieFragmentHeader* mfhd) {
+ return r->Skip(4) && r->Read(&mfhd->sequence_number);
+}
+
+bool Parse(BoxReader* r, TrackFragmentHeader* tfhd) {
+ memset(tfhd, 0, sizeof(TrackFragmentHeader));
+
+ RCHECK(r->ReadFullBoxHeader() && r->Read(&tfhd->track_id));
+
+ // Media Source specific: we require that 'default-base-is-moof' (14496-12
+ // Amendment 2) be set, and reject tracks that set 'base-data-offset-present'.
+ //
+ // TODO(strobe): Test files do not have 'default-base-is-moof' set explicitly
+ // (although they are structured as if it is set). Because this flag is hidden
+ // in Amendment 2, it might not be set by all implementors. Should we reject
+ // such files, or try them anyway?
+ //
+ // RCHECK((flags & 0x020000) && !(flags & 0x1));
+ RCHECK(!(r->flags() & 0x1));
+
+ if (r->flags() & 0x2)
+ RCHECK(r->Skip(4)); // sample_description_index
+
+ if (r->flags() & 0x8)
+ RCHECK(r->Read(&tfhd->default_sample_duration));
+
+ if (r->flags() & 0x10)
+ RCHECK(r->Read(&tfhd->default_sample_size));
+
+ if (r->flags() & 0x20)
+ RCHECK(r->Read(&tfhd->default_sample_flags));
+
+ return true;
+}
+
+TrackFragmentRun::TrackFragmentRun() {}
+TrackFragmentRun::~TrackFragmentRun() {}
+
+bool Parse(BoxReader* r, TrackFragmentRun* trun) {
+ RCHECK(r->ReadFullBoxHeader() &&
+ r->Read(&trun->sample_count));
+ const uint32 flags = r->flags();
+
+ bool data_offset_present = flags & 0x1;
+ bool first_sample_flags_present = flags & 0x4;
+ bool sample_duration_present = flags & 0x100;
+ bool sample_size_present = flags & 0x200;
+ bool sample_flags_present = flags & 0x400;
+ bool sample_composition_time_offsets_present = flags & 0x800;
+
+ if (data_offset_present) {
+ RCHECK(r->Read(&trun->data_offset));
+ } else {
+ trun->data_offset = 0;
+ }
+
+ uint32 first_sample_flags;
+ if (first_sample_flags_present)
+ RCHECK(r->Read(&first_sample_flags));
+
+ int fields = sample_duration_present + sample_size_present
+ + 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.
+ RCHECK(r->HasBytes(fields * trun->sample_count));
+
+ if (sample_duration_present)
+ trun->sample_durations.resize(trun->sample_count);
+ if (sample_size_present)
+ trun->sample_sizes.resize(trun->sample_count);
+ if (sample_flags_present)
+ trun->sample_flags.resize(trun->sample_count);
+ if (sample_composition_time_offsets_present)
+ trun->sample_composition_time_offsets.resize(trun->sample_count);
+
+ for (uint32 i = 0; i < trun->sample_count; ++i) {
+ if (sample_duration_present)
+ RCHECK(r->Read(&trun->sample_durations[i]));
+ if (sample_size_present)
+ RCHECK(r->Read(&trun->sample_sizes[i]));
+ if (sample_flags_present)
+ RCHECK(r->Read(&trun->sample_flags[i]));
+ if (sample_composition_time_offsets_present)
+ RCHECK(r->Read(&trun->sample_composition_time_offsets[i]));
+ }
+
+ if (first_sample_flags_present) {
+ if (trun->sample_flags.size() == 0) {
+ trun->sample_flags.push_back(first_sample_flags);
+ } else {
+ trun->sample_flags[0] = first_sample_flags;
+ }
+ }
+ return true;
+}
+
+TrackFragment::TrackFragment() {}
+TrackFragment::~TrackFragment() {}
+
+bool Parse(BoxReader* r, TrackFragment* traf) {
+ return r->ScanChildren() &&
+ r->ReadChild(&traf->header) &&
+ // Media Source specific: 'tfdt' required
+ r->ReadChild(&traf->decode_time) &&
+ r->MaybeReadChildren(&traf->runs) &&
+ r->MaybeReadChild(&traf->auxiliary_offset) &&
+ r->MaybeReadChild(&traf->auxiliary_size);
+}
+
+MovieFragment::MovieFragment() {}
+MovieFragment::~MovieFragment() {}
+
+bool Parse(BoxReader* r, MovieFragment* moof) {
+ RCHECK(r->ScanChildren() &&
+ r->ReadChild(&moof->header) &&
+ r->ReadChildren(&moof->tracks) &&
+ r->MaybeReadChildren(&moof->pssh));
+ return true;
+}
+
+bool Parse(BoxReader* r, SegmentIndex* sidx) {
+ RCHECK(r->ReadFullBoxHeader() &&
+ r->Read(&sidx->reference_id) &&
+ r->Read(&sidx->timescale));
+
+ if (r->version() == 0) {
+ RCHECK(r->Read4(&sidx->earliest_presentation_time) &&
+ r->Read4(&sidx->first_offset));
+ } else {
+ RCHECK(r->Read(&sidx->earliest_presentation_time) &&
+ r->Read(&sidx->first_offset));
+ }
+
+ uint32 reference_count;
+ RCHECK(r->Skip(2) && // reserved
+ r->Read(&reference_count) &&
+ r->HasBytes(12 * reference_count));
+
+ for (uint32 i = 0; i < reference_count; ++i) {
+ uint32 flags;
+ RCHECK(r->Read(&sidx->sizes[i]) &&
+ r->Read(&sidx->durations[i]) &&
+ r->Read(&flags));
+
+ uint32 type = flags / 0x10000000 % 8;
+
+ RCHECK(!(sidx->sizes[i] & 0x8000000) != 0 ||
acolwell GONE FROM CHROMIUM 2012/06/06 17:32:39 What?!? A comment indicating what this is checking
+ (flags & 0x80000000) != 0x80000000 ||
+ (type != 0 && type != 1) ||
+ (flags % 0x10000000 != 0));
+ }
+ return true;
+}
+
+} // namespace mp4
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698