Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 79 additions & 120 deletions patterns/mp4.hexpat
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,52 @@ import std.io;
import std.mem;
import std.string;

// All known MP4/ISOBMFF container box types (boxes that contain other boxes)
const u32 CONTAINER_BOX_TYPES_COUNT = 28;
str CONTAINER_BOX_TYPES[CONTAINER_BOX_TYPES_COUNT] = {
"moov", // Movie
"trak", // Track
"edts", // Edit
"mdia", // Media
"minf", // Media Information
"dinf", // Data Information
"stbl", // Sample Table
"mvex", // Movie Extends
"moof", // Movie Fragment
"traf", // Track Fragment
"mfra", // Movie Fragment Random Access
"udta", // User Data
"meta", // Metadata
"ilst", // Item List (iTunes metadata)
"meco", // Additional Metadata Container
"tref", // Track Reference
"trgr", // Track Grouping
"sinf", // Protection Scheme Information
"schi", // Scheme Information
"ipro", // Item Protection
"iprp", // Item Properties
"ipco", // Item Property Container
"iref", // Item Reference
"grpl", // Group List
"clip", // Clipping (QuickTime)
"matt", // Track Matte (QuickTime)
"strk", // Sub Track
"strd" // Sub Track Definition
};

fn to_string(auto var) {
return str(var);
};

fn is_container_box(str type_str) {
for (u32 i = 0, i < CONTAINER_BOX_TYPES_COUNT, i += 1) {
if (CONTAINER_BOX_TYPES[i] == type_str) {
return true;
}
}
return false;
};

fn format_string(auto string) {
return string.value;
};
Expand All @@ -40,6 +82,8 @@ struct string {
char value[std::mem::find_sequence_in_range(0, $, std::mem::size(), 0x00) - $];
} [[sealed, format("format_string")]];

using Box;

struct BaseBox {
u64 boxSize = 0;
u64 startOffset = $;
Expand All @@ -55,13 +99,19 @@ struct BaseBox {
if (this.size == 1) {
u64 largeSize;
boxSize = largeSize;
endOffset = startOffset + boxSize;
if (startOffset + boxSize > std::mem::size())
endOffset = std::mem::size();
else
endOffset = startOffset + boxSize;
} else if (this.size == 0) {
boxSize = std::mem::size() - startOffset;
endOffset = std::mem::size();
} else {
boxSize = size;
endOffset = startOffset + boxSize;
if (startOffset + boxSize > std::mem::size())
endOffset = std::mem::size();
else
endOffset = startOffset + boxSize;
}

if (this.type == "uuid") {
Expand Down Expand Up @@ -150,19 +200,6 @@ struct DataReferenceBox : FullBox {
DataEntryBox data_entries[this.entry_count];
};

struct SubDataInformationBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("dref"): DataReferenceBox box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("DataInformationBox({})", box.type))]];

struct DataInformationBox : BaseBox {
SubDataInformationBox box[while($ < endOffset)] [[inline]];
};

struct HandlerBox : FullBox {
u32 component_type;
char handler_type[4];
Expand Down Expand Up @@ -213,19 +250,9 @@ struct Mp4aBox : BaseBox {
u8 unk[while($ != endOffset)];
};

struct SubSampleDescriptionBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("mp4a"): Mp4aBox box [[inline]];
("avc1"): Avc1Box box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("SubSampleDescriptionBox({})", box.type))]];

struct SampleDescriptionBox : FullBox {
u32 entry_count;
SubSampleDescriptionBox box[while($ < endOffset)] [[inline]];
Box box[while($ < endOffset)] [[inline]];
};

struct SampleTimeToSampleEntry {
Expand Down Expand Up @@ -291,41 +318,6 @@ struct SampleSizeBox: FullBox {
}
};

struct SubSampleBoxTable {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("stsd"): SampleDescriptionBox box [[inline]];
("stts"): SampleTimeToSampleBox box [[inline]];
("stsc"): SampleToChunkBox box [[inline]];
("stco"): ChunkOffsetBox box [[inline]];
("stss"): SyncSampleBox box [[inline]];
("ctts"): CompositionOffsetBox box [[inline]];
("stsz"): SampleSizeBox box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("SubSampleBoxTable({})", box.type))]];

struct SampleBoxTable : BaseBox {
SubSampleBoxTable box[while($ < endOffset)] [[inline]];
};

struct SubMediaInformationBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("vmhd"): VideoMediaHeaderBox box [[inline]];
("hdlr"): HandlerBox box [[inline]];
("dinf"): DataInformationBox box [[inline]];
("stbl"): SampleBoxTable box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("MediaInformationBox({})", box.type))]];

struct MediaInformationBox : BaseBox {
SubMediaInformationBox box[while($ < endOffset)] [[inline]];
};

struct MediaHeaderBox : FullBox {
if (this.version == 1) {
u64 creation_time;
Expand All @@ -342,21 +334,6 @@ struct MediaHeaderBox : FullBox {
u16 quality;
};

struct SubMediaBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("mdhd"): MediaHeaderBox box [[inline]];
("hdlr"): HandlerBox box [[inline]];
("minf"): MediaInformationBox box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("MediaBox({})", box.type))]];

struct MediaBox : BaseBox {
SubMediaBox box[while($ < endOffset)] [[inline]];
};

struct EditListEntry64 {
u64 segment_duration;
s64 media_time;
Expand All @@ -380,61 +357,43 @@ struct EditListBox : FullBox {
}
};

struct SubEditBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("elst"): EditListBox box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("EditBox({})", box.type))]];

struct EditBox : BaseBox {
SubEditBox box[while($ < endOffset)] [[inline]];
};

struct SubTrackBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("mdia"): MediaBox box [[inline]];
("edts"): EditBox box [[inline]];
("tkhd"): TrackHeaderBox box [[inline]];
(_): UnknownBox box [[inline]];
}
} [[name(std::format("TrackBox({})", box.type))]];

struct TrackBox : BaseBox {
SubTrackBox box[while($ < endOffset)] [[inline]];
struct MediaDataBox : BaseBox {
std::mem::Bytes<endOffset - $> data;
};

struct SubMovieBox {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("mvhd"): MovieHeaderBox box [[inline]];
("trak"): TrackBox box [[inline]];
(_): UnknownBox box [[inline]];
// TODO: Add "iods" box
}
} [[name(std::format("MovieBox({})", box.type))]];

struct MovieBox : BaseBox {
SubMovieBox box[while($ < endOffset)] [[inline]];
};
using Box;

struct MediaDataBox : BaseBox {
std::mem::Bytes<boxSize - sizeof(size) - sizeof(type)> data;
struct ContainerBox : BaseBox {
Box children[while($ < endOffset)] [[inline]];
};

struct Box {
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);

match (str(type)) {
("ftyp"): FileTypeBox box [[inline]];
("moov"): MovieBox box [[inline]];
("mdat"): MediaDataBox box [[inline]];
(_): UnknownBox box [[inline]];
("mvhd"): MovieHeaderBox box [[inline]];
("mdhd"): MediaHeaderBox box [[inline]];
("dref"): DataReferenceBox box [[inline]];
("tkhd"): TrackHeaderBox box [[inline]];
("mp4a"): Mp4aBox box [[inline]];
("avc1"): Avc1Box box [[inline]];
("stsd"): SampleDescriptionBox box [[inline]];
("stts"): SampleTimeToSampleBox box [[inline]];
("stsc"): SampleToChunkBox box [[inline]];
("stco"): ChunkOffsetBox box [[inline]];
("stss"): SyncSampleBox box [[inline]];
("ctts"): CompositionOffsetBox box [[inline]];
("stsz"): SampleSizeBox box [[inline]];
("vmhd"): VideoMediaHeaderBox box [[inline]];
("hdlr"): HandlerBox box [[inline]];
("elst"): EditListBox box [[inline]];
(_): if (is_container_box(str(type))) {
ContainerBox box [[inline]];
} else {
UnknownBox box [[inline]];
}
}
} [[name(std::format("Box({})", box.type))]];

Expand Down
Loading