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 "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"
namespace media {
class BufferReader;
namespace mp4 {
enum TrackType {
@ -22,33 +26,42 @@ enum TrackType {
kHint
};
#define DECLARE_BOX_METHODS(T) \
T(); \
virtual ~T(); \
virtual bool Parse(BoxReader* reader) OVERRIDE; \
virtual FourCC BoxType() const OVERRIDE; \
class BoxBuffer;
#define DECLARE_BOX_METHODS(T) \
T(); \
virtual ~T(); \
virtual bool ReadWrite(BoxBuffer* buffer) OVERRIDE; \
virtual FourCC BoxType() const OVERRIDE; \
virtual uint32 ComputeSize() OVERRIDE;
struct FileType : Box {
DECLARE_BOX_METHODS(FileType);
FourCC major_brand;
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);
std::vector<uint8> system_id;
std::vector<uint8> data;
std::vector<uint8> raw_box;
};
struct SampleAuxiliaryInformationOffset : Box {
struct SampleAuxiliaryInformationOffset : FullBox {
DECLARE_BOX_METHODS(SampleAuxiliaryInformationOffset);
std::vector<uint64> offsets;
};
struct SampleAuxiliaryInformationSize : Box {
struct SampleAuxiliaryInformationSize : FullBox {
DECLARE_BOX_METHODS(SampleAuxiliaryInformationSize);
uint8 default_sample_info_size;
@ -62,14 +75,14 @@ struct OriginalFormat : Box {
FourCC format;
};
struct SchemeType : Box {
struct SchemeType : FullBox {
DECLARE_BOX_METHODS(SchemeType);
FourCC type;
uint32 version;
};
struct TrackEncryption : Box {
struct TrackEncryption : FullBox {
DECLARE_BOX_METHODS(TrackEncryption);
// Note: this definition is specific to the CENC protection type.
@ -92,7 +105,7 @@ struct ProtectionSchemeInfo : Box {
SchemeInfo info;
};
struct MovieHeader : Box {
struct MovieHeader : FullBox {
DECLARE_BOX_METHODS(MovieHeader);
uint64 creation_time;
@ -104,7 +117,13 @@ struct MovieHeader : Box {
uint32 next_track_id;
};
struct TrackHeader : Box {
struct TrackHeader : FullBox {
enum TrackHeaderFlags {
kTrackEnabled = 0x000001,
kTrackInMovie = 0x000002,
kTrackInPreview = 0x000004,
};
DECLARE_BOX_METHODS(TrackHeader);
uint64 creation_time;
@ -125,7 +144,7 @@ struct EditListEntry {
int16 media_rate_fraction;
};
struct EditList : Box {
struct EditList : FullBox {
DECLARE_BOX_METHODS(EditList);
std::vector<EditListEntry> edits;
@ -137,7 +156,7 @@ struct Edit : Box {
EditList list;
};
struct HandlerReference : Box {
struct HandlerReference : FullBox {
DECLARE_BOX_METHODS(HandlerReference);
TrackType type;
@ -188,11 +207,11 @@ struct VideoSampleEntry : Box {
AVCDecoderConfigurationRecord avcc;
};
struct ElementaryStreamDescriptor : Box {
struct ElementaryStreamDescriptor : FullBox {
DECLARE_BOX_METHODS(ElementaryStreamDescriptor);
uint8 object_type;
AAC aac;
ESDescriptor es_descriptor;
};
struct AudioSampleEntry : Box {
@ -208,7 +227,7 @@ struct AudioSampleEntry : Box {
ElementaryStreamDescriptor esds;
};
struct SampleDescription : Box {
struct SampleDescription : FullBox {
DECLARE_BOX_METHODS(SampleDescription);
TrackType type;
@ -222,7 +241,7 @@ struct DecodingTime {
};
// stts.
struct DecodingTimeToSample : Box {
struct DecodingTimeToSample : FullBox {
DECLARE_BOX_METHODS(DecodingTimeToSample);
std::vector<DecodingTime> decoding_time;
@ -232,13 +251,13 @@ struct CompositionOffset {
uint32 sample_count;
// If version == 0, sample_offset is uint32;
// 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.
int32 sample_offset;
};
// ctts. Optional.
struct CompositionTimeToSample : Box {
struct CompositionTimeToSample : FullBox {
DECLARE_BOX_METHODS(CompositionTimeToSample);
std::vector<CompositionOffset> composition_offset;
@ -251,14 +270,14 @@ struct ChunkInfo {
};
// stsc.
struct SampleToChunk : Box {
struct SampleToChunk : FullBox {
DECLARE_BOX_METHODS(SampleToChunk);
std::vector<ChunkInfo> chunk_info;
};
// stsz.
struct SampleSize : Box {
struct SampleSize : FullBox {
DECLARE_BOX_METHODS(SampleSize);
uint32 sample_size;
@ -267,27 +286,27 @@ struct SampleSize : Box {
};
// stz2.
struct CompactSampleSize : SampleSize {
struct CompactSampleSize : FullBox {
DECLARE_BOX_METHODS(CompactSampleSize);
};
// stco.
struct ChunkOffset : Box {
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;
uint8 field_size;
std::vector<uint32> sizes;
};
// co64.
struct ChunkLargeOffset : ChunkOffset {
struct ChunkLargeOffset : FullBox {
DECLARE_BOX_METHODS(ChunkLargeOffset);
std::vector<uint64> offsets;
};
// stco.
struct ChunkOffset : ChunkLargeOffset {
DECLARE_BOX_METHODS(ChunkOffset);
};
// stss. Optional.
struct SyncSample : Box {
struct SyncSample : FullBox {
DECLARE_BOX_METHODS(SyncSample);
std::vector<uint32> sample_number;
@ -302,12 +321,13 @@ struct SampleTable : Box {
SampleToChunk sample_to_chunk;
// Either SampleSize or CompactSampleSize must present. Store in SampleSize.
SampleSize sample_size;
// Either ChunkOffset or ChunkLargeOffset must present. Store in ChunkOffset.
ChunkOffset chunk_offset;
// Either ChunkOffset or ChunkLargeOffset must present. Store in
// ChunkLargeOffset.
ChunkLargeOffset chunk_large_offset;
SyncSample sync_sample;
};
struct MediaHeader : Box {
struct MediaHeader : FullBox {
DECLARE_BOX_METHODS(MediaHeader);
uint64 creation_time;
@ -318,10 +338,48 @@ struct MediaHeader : Box {
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 {
DECLARE_BOX_METHODS(MediaInformation);
DataInformation dinf;
SampleTable sample_table;
// Exactly one specific meida header shall be present, vmhd, smhd, hmhd, nmhd.
VideoMediaHeader vmhd;
SoundMediaHeader smhd;
};
struct Media : Box {
@ -340,13 +398,13 @@ struct Track : Box {
Edit edit;
};
struct MovieExtendsHeader : Box {
struct MovieExtendsHeader : FullBox {
DECLARE_BOX_METHODS(MovieExtendsHeader);
uint64 fragment_duration;
};
struct TrackExtends : Box {
struct TrackExtends : FullBox {
DECLARE_BOX_METHODS(TrackExtends);
uint32 track_id;
@ -366,41 +424,64 @@ struct MovieExtends : Box {
struct Movie : Box {
DECLARE_BOX_METHODS(Movie);
bool fragmented;
MovieHeader header;
MovieExtends extends;
std::vector<Track> tracks;
std::vector<ProtectionSystemSpecificHeader> pssh;
};
struct TrackFragmentDecodeTime : Box {
struct TrackFragmentDecodeTime : FullBox {
DECLARE_BOX_METHODS(TrackFragmentDecodeTime);
uint64 decode_time;
};
struct MovieFragmentHeader : Box {
struct MovieFragmentHeader : FullBox {
DECLARE_BOX_METHODS(MovieFragmentHeader);
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);
uint32 track_id;
uint32 sample_description_index;
uint32 default_sample_duration;
uint32 default_sample_size;
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);
uint32 sample_count;
@ -429,6 +510,50 @@ struct MovieFragment : Box {
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
} // namespace mp4

View File

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