Implement mp4 box read/write.

The box may be optimized if necessary during writing.

Change-Id: I7a46e72a0bcbeacb23085a87e1f0df3a826e4da7
This commit is contained in:
Kongqun Yang 2013-11-26 17:52:13 -08:00
parent 0f3bc4b6b4
commit 57474b31d6
3 changed files with 1410 additions and 518 deletions

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,14 @@
#include <vector> #include <vector>
#include "media/mp4/aac.h" #include "media/mp4/aac.h"
#include "media/mp4/box_reader.h" #include "media/mp4/box.h"
#include "media/mp4/es_descriptor.h"
#include "media/mp4/fourccs.h" #include "media/mp4/fourccs.h"
namespace media { namespace media {
class BufferReader;
namespace mp4 { namespace mp4 {
enum TrackType { enum TrackType {
@ -22,33 +26,42 @@ enum TrackType {
kHint kHint
}; };
class BoxBuffer;
#define DECLARE_BOX_METHODS(T) \ #define DECLARE_BOX_METHODS(T) \
T(); \ T(); \
virtual ~T(); \ virtual ~T(); \
virtual bool Parse(BoxReader* reader) OVERRIDE; \ virtual bool ReadWrite(BoxBuffer* buffer) OVERRIDE; \
virtual FourCC BoxType() const OVERRIDE; \ virtual FourCC BoxType() const OVERRIDE; \
virtual uint32 ComputeSize() OVERRIDE;
struct FileType : Box { struct FileType : Box {
DECLARE_BOX_METHODS(FileType); DECLARE_BOX_METHODS(FileType);
FourCC major_brand; FourCC major_brand;
uint32 minor_version; uint32 minor_version;
std::vector<FourCC> compatible_brands;
}; };
struct ProtectionSystemSpecificHeader : Box { struct SegmentType : FileType {
DECLARE_BOX_METHODS(SegmentType);
};
struct ProtectionSystemSpecificHeader : FullBox {
DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader); DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader);
std::vector<uint8> system_id; std::vector<uint8> system_id;
std::vector<uint8> data;
std::vector<uint8> raw_box; std::vector<uint8> raw_box;
}; };
struct SampleAuxiliaryInformationOffset : Box { struct SampleAuxiliaryInformationOffset : FullBox {
DECLARE_BOX_METHODS(SampleAuxiliaryInformationOffset); DECLARE_BOX_METHODS(SampleAuxiliaryInformationOffset);
std::vector<uint64> offsets; std::vector<uint64> offsets;
}; };
struct SampleAuxiliaryInformationSize : Box { struct SampleAuxiliaryInformationSize : FullBox {
DECLARE_BOX_METHODS(SampleAuxiliaryInformationSize); DECLARE_BOX_METHODS(SampleAuxiliaryInformationSize);
uint8 default_sample_info_size; uint8 default_sample_info_size;
@ -62,14 +75,14 @@ struct OriginalFormat : Box {
FourCC format; FourCC format;
}; };
struct SchemeType : Box { struct SchemeType : FullBox {
DECLARE_BOX_METHODS(SchemeType); DECLARE_BOX_METHODS(SchemeType);
FourCC type; FourCC type;
uint32 version; uint32 version;
}; };
struct TrackEncryption : Box { struct TrackEncryption : FullBox {
DECLARE_BOX_METHODS(TrackEncryption); DECLARE_BOX_METHODS(TrackEncryption);
// Note: this definition is specific to the CENC protection type. // Note: this definition is specific to the CENC protection type.
@ -92,7 +105,7 @@ struct ProtectionSchemeInfo : Box {
SchemeInfo info; SchemeInfo info;
}; };
struct MovieHeader : Box { struct MovieHeader : FullBox {
DECLARE_BOX_METHODS(MovieHeader); DECLARE_BOX_METHODS(MovieHeader);
uint64 creation_time; uint64 creation_time;
@ -104,7 +117,13 @@ struct MovieHeader : Box {
uint32 next_track_id; uint32 next_track_id;
}; };
struct TrackHeader : Box { struct TrackHeader : FullBox {
enum TrackHeaderFlags {
kTrackEnabled = 0x000001,
kTrackInMovie = 0x000002,
kTrackInPreview = 0x000004,
};
DECLARE_BOX_METHODS(TrackHeader); DECLARE_BOX_METHODS(TrackHeader);
uint64 creation_time; uint64 creation_time;
@ -125,7 +144,7 @@ struct EditListEntry {
int16 media_rate_fraction; int16 media_rate_fraction;
}; };
struct EditList : Box { struct EditList : FullBox {
DECLARE_BOX_METHODS(EditList); DECLARE_BOX_METHODS(EditList);
std::vector<EditListEntry> edits; std::vector<EditListEntry> edits;
@ -137,7 +156,7 @@ struct Edit : Box {
EditList list; EditList list;
}; };
struct HandlerReference : Box { struct HandlerReference : FullBox {
DECLARE_BOX_METHODS(HandlerReference); DECLARE_BOX_METHODS(HandlerReference);
TrackType type; TrackType type;
@ -188,11 +207,11 @@ struct VideoSampleEntry : Box {
AVCDecoderConfigurationRecord avcc; AVCDecoderConfigurationRecord avcc;
}; };
struct ElementaryStreamDescriptor : Box { struct ElementaryStreamDescriptor : FullBox {
DECLARE_BOX_METHODS(ElementaryStreamDescriptor); DECLARE_BOX_METHODS(ElementaryStreamDescriptor);
uint8 object_type;
AAC aac; AAC aac;
ESDescriptor es_descriptor;
}; };
struct AudioSampleEntry : Box { struct AudioSampleEntry : Box {
@ -208,7 +227,7 @@ struct AudioSampleEntry : Box {
ElementaryStreamDescriptor esds; ElementaryStreamDescriptor esds;
}; };
struct SampleDescription : Box { struct SampleDescription : FullBox {
DECLARE_BOX_METHODS(SampleDescription); DECLARE_BOX_METHODS(SampleDescription);
TrackType type; TrackType type;
@ -222,7 +241,7 @@ struct DecodingTime {
}; };
// stts. // stts.
struct DecodingTimeToSample : Box { struct DecodingTimeToSample : FullBox {
DECLARE_BOX_METHODS(DecodingTimeToSample); DECLARE_BOX_METHODS(DecodingTimeToSample);
std::vector<DecodingTime> decoding_time; std::vector<DecodingTime> decoding_time;
@ -232,13 +251,13 @@ struct CompositionOffset {
uint32 sample_count; uint32 sample_count;
// If version == 0, sample_offset is uint32; // If version == 0, sample_offset is uint32;
// If version == 1, sample_offset is int32. // If version == 1, sample_offset is int32.
// Let us always use signed version, which should work unless the offset // Always use signed version, which should work unless the offset
// exceeds 31 bits, which shouldn't happen. // exceeds 31 bits, which shouldn't happen.
int32 sample_offset; int32 sample_offset;
}; };
// ctts. Optional. // ctts. Optional.
struct CompositionTimeToSample : Box { struct CompositionTimeToSample : FullBox {
DECLARE_BOX_METHODS(CompositionTimeToSample); DECLARE_BOX_METHODS(CompositionTimeToSample);
std::vector<CompositionOffset> composition_offset; std::vector<CompositionOffset> composition_offset;
@ -251,14 +270,14 @@ struct ChunkInfo {
}; };
// stsc. // stsc.
struct SampleToChunk : Box { struct SampleToChunk : FullBox {
DECLARE_BOX_METHODS(SampleToChunk); DECLARE_BOX_METHODS(SampleToChunk);
std::vector<ChunkInfo> chunk_info; std::vector<ChunkInfo> chunk_info;
}; };
// stsz. // stsz.
struct SampleSize : Box { struct SampleSize : FullBox {
DECLARE_BOX_METHODS(SampleSize); DECLARE_BOX_METHODS(SampleSize);
uint32 sample_size; uint32 sample_size;
@ -267,27 +286,27 @@ struct SampleSize : Box {
}; };
// stz2. // stz2.
struct CompactSampleSize : SampleSize { struct CompactSampleSize : FullBox {
DECLARE_BOX_METHODS(CompactSampleSize); DECLARE_BOX_METHODS(CompactSampleSize);
};
// stco. uint8 field_size;
struct ChunkOffset : Box { std::vector<uint32> sizes;
DECLARE_BOX_METHODS(ChunkOffset);
// Chunk byte offsets into mdat relative to the beginning of the file.
// Use 64 bits instead of 32 bits so it is large enough to hold
// ChunkLargeOffset data.
std::vector<uint64> offsets;
}; };
// co64. // co64.
struct ChunkLargeOffset : ChunkOffset { struct ChunkLargeOffset : FullBox {
DECLARE_BOX_METHODS(ChunkLargeOffset); DECLARE_BOX_METHODS(ChunkLargeOffset);
std::vector<uint64> offsets;
};
// stco.
struct ChunkOffset : ChunkLargeOffset {
DECLARE_BOX_METHODS(ChunkOffset);
}; };
// stss. Optional. // stss. Optional.
struct SyncSample : Box { struct SyncSample : FullBox {
DECLARE_BOX_METHODS(SyncSample); DECLARE_BOX_METHODS(SyncSample);
std::vector<uint32> sample_number; std::vector<uint32> sample_number;
@ -302,12 +321,13 @@ struct SampleTable : Box {
SampleToChunk sample_to_chunk; SampleToChunk sample_to_chunk;
// Either SampleSize or CompactSampleSize must present. Store in SampleSize. // Either SampleSize or CompactSampleSize must present. Store in SampleSize.
SampleSize sample_size; SampleSize sample_size;
// Either ChunkOffset or ChunkLargeOffset must present. Store in ChunkOffset. // Either ChunkOffset or ChunkLargeOffset must present. Store in
ChunkOffset chunk_offset; // ChunkLargeOffset.
ChunkLargeOffset chunk_large_offset;
SyncSample sync_sample; SyncSample sync_sample;
}; };
struct MediaHeader : Box { struct MediaHeader : FullBox {
DECLARE_BOX_METHODS(MediaHeader); DECLARE_BOX_METHODS(MediaHeader);
uint64 creation_time; uint64 creation_time;
@ -318,10 +338,48 @@ struct MediaHeader : Box {
char language[4]; char language[4];
}; };
struct VideoMediaHeader : FullBox {
DECLARE_BOX_METHODS(VideoMediaHeader);
uint16 graphicsmode;
uint16 opcolor_red;
uint16 opcolor_green;
uint16 opcolor_blue;
};
struct SoundMediaHeader : FullBox {
DECLARE_BOX_METHODS(SoundMediaHeader);
uint16 balance;
};
struct DataEntryUrl : FullBox {
DECLARE_BOX_METHODS(DataEntryUrl);
std::vector<uint8> location;
};
struct DataReference : FullBox {
DECLARE_BOX_METHODS(DataReference);
// data entry can be either url or urn box. Fix to url box for now.
std::vector<DataEntryUrl> data_entry;
};
struct DataInformation : Box {
DECLARE_BOX_METHODS(DataInformation);
DataReference dref;
};
struct MediaInformation : Box { struct MediaInformation : Box {
DECLARE_BOX_METHODS(MediaInformation); DECLARE_BOX_METHODS(MediaInformation);
DataInformation dinf;
SampleTable sample_table; SampleTable sample_table;
// Exactly one specific meida header shall be present, vmhd, smhd, hmhd, nmhd.
VideoMediaHeader vmhd;
SoundMediaHeader smhd;
}; };
struct Media : Box { struct Media : Box {
@ -340,13 +398,13 @@ struct Track : Box {
Edit edit; Edit edit;
}; };
struct MovieExtendsHeader : Box { struct MovieExtendsHeader : FullBox {
DECLARE_BOX_METHODS(MovieExtendsHeader); DECLARE_BOX_METHODS(MovieExtendsHeader);
uint64 fragment_duration; uint64 fragment_duration;
}; };
struct TrackExtends : Box { struct TrackExtends : FullBox {
DECLARE_BOX_METHODS(TrackExtends); DECLARE_BOX_METHODS(TrackExtends);
uint32 track_id; uint32 track_id;
@ -366,41 +424,64 @@ struct MovieExtends : Box {
struct Movie : Box { struct Movie : Box {
DECLARE_BOX_METHODS(Movie); DECLARE_BOX_METHODS(Movie);
bool fragmented;
MovieHeader header; MovieHeader header;
MovieExtends extends; MovieExtends extends;
std::vector<Track> tracks; std::vector<Track> tracks;
std::vector<ProtectionSystemSpecificHeader> pssh; std::vector<ProtectionSystemSpecificHeader> pssh;
}; };
struct TrackFragmentDecodeTime : Box { struct TrackFragmentDecodeTime : FullBox {
DECLARE_BOX_METHODS(TrackFragmentDecodeTime); DECLARE_BOX_METHODS(TrackFragmentDecodeTime);
uint64 decode_time; uint64 decode_time;
}; };
struct MovieFragmentHeader : Box { struct MovieFragmentHeader : FullBox {
DECLARE_BOX_METHODS(MovieFragmentHeader); DECLARE_BOX_METHODS(MovieFragmentHeader);
uint32 sequence_number; uint32 sequence_number;
}; };
struct TrackFragmentHeader : Box { struct TrackFragmentHeader : FullBox {
enum TrackFragmentFlagsMasks {
kDataOffsetPresentMask = 0x000001,
kSampleDescriptionIndexPresentMask = 0x000002,
kDefaultSampleDurationPresentMask = 0x000008,
kDefaultSampleSizePresentMask = 0x000010,
kDefaultSampleFlagsPresentMask = 0x000020,
kDurationIsEmptyMask = 0x010000,
kDefaultBaseIsMoofMask = 0x020000,
};
enum SampleFlagsMasks {
kReservedMask = 0xFC000000,
kSampleDependsOnMask = 0x03000000,
kSampleIsDependedOnMask = 0x00C00000,
kSampleHasRedundancyMask = 0x00300000,
kSamplePaddingValueMask = 0x000E0000,
kNonKeySampleMask = 0x00010000,
kSampleDegradationPriorityMask = 0x0000FFFF,
};
DECLARE_BOX_METHODS(TrackFragmentHeader); DECLARE_BOX_METHODS(TrackFragmentHeader);
uint32 track_id; uint32 track_id;
uint32 sample_description_index; uint32 sample_description_index;
uint32 default_sample_duration; uint32 default_sample_duration;
uint32 default_sample_size; uint32 default_sample_size;
uint32 default_sample_flags; uint32 default_sample_flags;
// As 'flags' might be all zero, we cannot use zeroness alone to identify
// when default_sample_flags wasn't specified, unlike the other values.
bool has_default_sample_flags;
}; };
struct TrackFragmentRun : Box { struct TrackFragmentRun : FullBox {
enum TrackFragmentFlagsMasks {
kDataOffsetPresentMask = 0x000001,
kFirstSampleFlagsPresentMask = 0x000004,
kSampleDurationPresentMask = 0x000100,
kSampleSizePresentMask = 0x000200,
kSampleFlagsPresentMask = 0x000400,
kSampleCompTimeOffsetsPresentMask = 0x000800,
};
DECLARE_BOX_METHODS(TrackFragmentRun); DECLARE_BOX_METHODS(TrackFragmentRun);
uint32 sample_count; uint32 sample_count;
@ -429,6 +510,50 @@ struct MovieFragment : Box {
std::vector<ProtectionSystemSpecificHeader> pssh; std::vector<ProtectionSystemSpecificHeader> pssh;
}; };
struct SegmentReference {
enum SAPType {
TypeUnknown = 0,
Type1 = 1, // T(ept) = T(dec) = T(sap) = T(ptf)
Type2 = 2, // T(ept) = T(dec) = T(sap) < T(ptf)
Type3 = 3, // T(ept) < T(dec) = T(sap) <= T(ptf)
Type4 = 4, // T(ept) <= T(ptf) < T(dec) = T(sap)
Type5 = 5, // T(ept) = T(dec) < T(sap)
Type6 = 6, // T(ept) < T(dec) < T(sap)
};
bool reference_type;
uint32 referenced_size;
uint32 subsegment_duration;
bool starts_with_sap;
SAPType sap_type;
uint32 sap_delta_time;
// We add this field to keep track of earliest_presentation_time in this
// subsegment. It is not part of SegmentReference.
uint64 earliest_presentation_time;
};
struct SegmentIndex : FullBox {
DECLARE_BOX_METHODS(SegmentIndex);
uint32 reference_id;
uint32 timescale;
uint64 earliest_presentation_time;
uint64 first_offset;
std::vector<SegmentReference> references;
};
// The actual data is parsed and written separately, so we do not inherit it
// from Box.
struct MediaData {
MediaData();
~MediaData();
void Write(BufferWriter* buffer_writer);
uint32 ComputeSize();
FourCC BoxType() const;
uint32 data_size;
};
#undef DECLARE_BOX #undef DECLARE_BOX
} // namespace mp4 } // namespace mp4

View File

@ -18,7 +18,9 @@ enum FourCC {
FOURCC_CENC = 0x63656e63, FOURCC_CENC = 0x63656e63,
FOURCC_CO64 = 0x636f3634, FOURCC_CO64 = 0x636f3634,
FOURCC_CTTS = 0x63747473, FOURCC_CTTS = 0x63747473,
FOURCC_DASH = 0x64617368,
FOURCC_DINF = 0x64696e66, FOURCC_DINF = 0x64696e66,
FOURCC_DREF = 0x64726566,
FOURCC_EAC3 = 0x65632d33, FOURCC_EAC3 = 0x65632d33,
FOURCC_EDTS = 0x65647473, FOURCC_EDTS = 0x65647473,
FOURCC_ELST = 0x656c7374, FOURCC_ELST = 0x656c7374,
@ -30,6 +32,7 @@ enum FourCC {
FOURCC_FTYP = 0x66747970, FOURCC_FTYP = 0x66747970,
FOURCC_HDLR = 0x68646c72, FOURCC_HDLR = 0x68646c72,
FOURCC_HINT = 0x68696e74, FOURCC_HINT = 0x68696e74,
FOURCC_ISO6 = 0x69736f36,
FOURCC_IODS = 0x696f6473, FOURCC_IODS = 0x696f6473,
FOURCC_MDAT = 0x6d646174, FOURCC_MDAT = 0x6d646174,
FOURCC_MDHD = 0x6d646864, FOURCC_MDHD = 0x6d646864,
@ -42,6 +45,7 @@ enum FourCC {
FOURCC_MINF = 0x6d696e66, FOURCC_MINF = 0x6d696e66,
FOURCC_MOOF = 0x6d6f6f66, FOURCC_MOOF = 0x6d6f6f66,
FOURCC_MOOV = 0x6d6f6f76, FOURCC_MOOV = 0x6d6f6f76,
FOURCC_MP41 = 0x6d703431,
FOURCC_MP4A = 0x6d703461, FOURCC_MP4A = 0x6d703461,
FOURCC_MP4V = 0x6d703476, FOURCC_MP4V = 0x6d703476,
FOURCC_MVEX = 0x6d766578, FOURCC_MVEX = 0x6d766578,
@ -79,6 +83,8 @@ enum FourCC {
FOURCC_TREX = 0x74726578, FOURCC_TREX = 0x74726578,
FOURCC_TRUN = 0x7472756e, FOURCC_TRUN = 0x7472756e,
FOURCC_UDTA = 0x75647461, FOURCC_UDTA = 0x75647461,
FOURCC_URL = 0x75726c20,
FOURCC_URN = 0x75726e20,
FOURCC_UUID = 0x75756964, FOURCC_UUID = 0x75756964,
FOURCC_VIDE = 0x76696465, FOURCC_VIDE = 0x76696465,
FOURCC_VMHD = 0x766d6864, FOURCC_VMHD = 0x766d6864,