mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
442 lines
11 KiB
Rust
442 lines
11 KiB
Rust
#pragma description MPEG-4 Part 14 digital multimedia container (MP4)
|
|
|
|
#pragma endian big
|
|
|
|
#pragma MIME audio/mp4
|
|
#pragma MIME video/mp4
|
|
#pragma MIME application/mp4
|
|
|
|
import std.io;
|
|
import std.mem;
|
|
import std.string;
|
|
|
|
fn to_string(auto var) {
|
|
return str(var);
|
|
};
|
|
|
|
fn format_string(auto string) {
|
|
return string.value;
|
|
};
|
|
|
|
fn format_fixed32(auto fp32) {
|
|
return fp32.integer + fp32.fraction / 65536.0;
|
|
};
|
|
|
|
fn format_fixed16(auto fp16) {
|
|
return fp16.integer + fp16.fraction / 256.0;
|
|
};
|
|
|
|
struct FixedPoint16 {
|
|
u8 integer;
|
|
u8 fraction;
|
|
} [[format("format_fixed16")]];
|
|
|
|
struct FixedPoint32 {
|
|
u16 integer;
|
|
u16 fraction;
|
|
} [[format("format_fixed32")]];
|
|
|
|
struct string {
|
|
char value[std::mem::find_sequence_in_range(0, $, std::mem::size(), 0x00) - $];
|
|
} [[sealed, format("format_string")]];
|
|
|
|
struct BaseBox {
|
|
u64 boxSize = 0;
|
|
u64 startOffset = $;
|
|
u64 endOffset = 0;
|
|
|
|
u32 size;
|
|
char type[4];
|
|
|
|
// Calculate the size of the current box
|
|
// 1. If the size is equal to 1 -> the box size is equal to 'largeSize' attribute.
|
|
// 2. If the size is equal to 0 -> The box extends to the end of the file.
|
|
// 3. Otherwise, size is equaly to the 'size' attribute.
|
|
if (this.size == 1) {
|
|
u64 largeSize;
|
|
boxSize = largeSize;
|
|
endOffset = startOffset + boxSize;
|
|
} else if (this.size == 0) {
|
|
boxSize = std::mem::size() - startOffset;
|
|
endOffset = std::mem::size();
|
|
} else {
|
|
boxSize = size;
|
|
endOffset = startOffset + boxSize;
|
|
}
|
|
|
|
if (this.type == "uuid") {
|
|
char usertype[16];
|
|
}
|
|
};
|
|
|
|
struct FullBox : BaseBox {
|
|
u8 version;
|
|
u24 flags;
|
|
};
|
|
|
|
struct UnknownBox : BaseBox {
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
using brand = u32 [[format("to_string")]];
|
|
struct FileTypeBox : BaseBox {
|
|
brand major_brand;
|
|
u32 minor_version;
|
|
brand compatible_brands[(endOffset - $) / sizeof(brand)];
|
|
};
|
|
|
|
struct MovieHeaderBox : FullBox {
|
|
if (this.version == 1) {
|
|
u64 creation_time;
|
|
u64 modification_time;
|
|
u32 timescale;
|
|
u64 duration;
|
|
} else { // version == 0
|
|
u32 creation_time;
|
|
u32 modification_time;
|
|
u32 timescale;
|
|
u32 duration;
|
|
}
|
|
FixedPoint32 rate;
|
|
FixedPoint16 volume;
|
|
u8 reserved[10] [[sealed]];
|
|
u32 matrix[9];
|
|
u32 preview_time;
|
|
u32 preview_duration;
|
|
u32 poster_time;
|
|
u32 selection_time;
|
|
u32 selection_duration;
|
|
u32 current_time;
|
|
u32 next_track_id;
|
|
};
|
|
|
|
struct TrackHeaderBox : FullBox {
|
|
if (this.version == 1) {
|
|
u64 creation_time;
|
|
u64 modification_time;
|
|
u32 track_id;
|
|
u32 reserved;
|
|
u64 duration;
|
|
} else { // version == 0
|
|
u32 creation_time;
|
|
u32 modification_time;
|
|
u32 track_id;
|
|
u32 reserved;
|
|
u32 duration;
|
|
}
|
|
u32 reserved_2[2] [[sealed]];
|
|
s16 layer;
|
|
s16 alternate_group;
|
|
s16 volume;
|
|
u16 reserved_3;
|
|
s32 matrix[9];
|
|
FixedPoint32 width;
|
|
FixedPoint32 height;
|
|
};
|
|
|
|
struct DataEntryBox : FullBox {
|
|
if (std::string::contains(this.type, "url")) {
|
|
string location;
|
|
} else if (std::string::contains(this.type, "urn")) {
|
|
string name;
|
|
string location;
|
|
} else {
|
|
std::error("Invalid DataEntryBox");
|
|
}
|
|
};
|
|
|
|
struct DataReferenceBox : FullBox {
|
|
u32 entry_count;
|
|
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];
|
|
u32 reserved[3];
|
|
char name[endOffset - $];
|
|
};
|
|
|
|
struct VideoMediaHeaderBox : FullBox {
|
|
u16 graphicsmode;
|
|
u16 opcolor[3];
|
|
};
|
|
|
|
struct Avc1Box : BaseBox {
|
|
u48 reserved;
|
|
u16 data_reference_index;
|
|
u16 version;
|
|
u16 revision_level;
|
|
u32 max_packet_size;
|
|
if (this.version == 0 || this.version == 1) {
|
|
u32 temporal_quality;
|
|
u32 spatial_quality;
|
|
u16 width;
|
|
u16 height;
|
|
FixedPoint32 horizontal_resolution;
|
|
FixedPoint32 vertical_resolution;
|
|
u32 data_size;
|
|
u16 frame_count;
|
|
char compressor_name[32];
|
|
u16 depth;
|
|
s16 color_table_id;
|
|
}
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
struct Mp4aBox : BaseBox {
|
|
u48 reserved;
|
|
u16 data_reference_index;
|
|
u16 version;
|
|
u16 revision_level;
|
|
u32 max_packet_size;
|
|
if (this.version == 0) {
|
|
u16 num_audio_channels;
|
|
u16 sample_size;
|
|
u16 compression_id;
|
|
u16 packet_size;
|
|
FixedPoint32 sample_rate;
|
|
}
|
|
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]];
|
|
};
|
|
|
|
struct SampleTimeToSampleEntry {
|
|
u32 sample_count;
|
|
u32 sample_delta;
|
|
};
|
|
|
|
struct SampleTimeToSampleBox: FullBox {
|
|
u32 entry_count;
|
|
SampleTimeToSampleEntry entry_list[this.entry_count];
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
struct SampleToChunkEntry {
|
|
u32 first_chunk;
|
|
u32 samples_per_chunk;
|
|
u32 sample_description_index;
|
|
};
|
|
|
|
struct SampleToChunkBox: FullBox {
|
|
u32 entry_count;
|
|
SampleToChunkEntry entry_list[this.entry_count];
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
struct ChunkOffsetBox: FullBox {
|
|
u32 entry_count;
|
|
u32 chunk_offset[this.entry_count];
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
struct SyncSampleBox: FullBox {
|
|
u32 entry_count;
|
|
u32 sample_number[this.entry_count];
|
|
u8 unk[while($ != endOffset)];
|
|
};
|
|
|
|
struct CompositionOffsetEntryV0 {
|
|
u32 sample_count;
|
|
u32 sample_offset;
|
|
};
|
|
|
|
struct CompositionOffsetEntryV1 {
|
|
u32 sample_count;
|
|
s32 sample_offset;
|
|
};
|
|
|
|
struct CompositionOffsetBox: FullBox {
|
|
u32 entry_count;
|
|
if(this.version == 0) {
|
|
CompositionOffsetEntryV0 entry_list[this.entry_count];
|
|
}
|
|
else if (this.version == 1) {
|
|
CompositionOffsetEntryV1 entry_list[this.entry_count];
|
|
}
|
|
};
|
|
|
|
struct SampleSizeBox: FullBox {
|
|
u32 sample_size;
|
|
u32 sample_count;
|
|
if(this.sample_size==0) {
|
|
u32 entry_size[this.sample_count];
|
|
}
|
|
};
|
|
|
|
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;
|
|
u64 modification_time;
|
|
u32 timescale;
|
|
u64 duration;
|
|
} else { // version==0
|
|
u32 creation_time;
|
|
u32 modification_time;
|
|
u32 timescale;
|
|
u32 duration;
|
|
}
|
|
u16 language [[comment("ISO-639-2/T language code")]];
|
|
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;
|
|
s16 media_rate_integer;
|
|
s16 media_rate_fraction;
|
|
};
|
|
|
|
struct EditListEntry32 {
|
|
u32 segment_duration;
|
|
s32 media_time;
|
|
s16 media_rate_integer;
|
|
s16 media_rate_fraction;
|
|
};
|
|
|
|
struct EditListBox : FullBox {
|
|
u32 entry_count;
|
|
if (this.version == 1) {
|
|
EditListEntry64 entry_list[this.entry_count];
|
|
} else { // version 0
|
|
EditListEntry32 entry_list[this.entry_count];
|
|
}
|
|
};
|
|
|
|
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 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]];
|
|
};
|
|
|
|
struct MediaDataBox : BaseBox {
|
|
std::mem::Bytes<boxSize - sizeof(size) - sizeof(type)> data;
|
|
};
|
|
|
|
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]];
|
|
}
|
|
} [[name(std::format("Box({})", box.type))]];
|
|
|
|
Box mp4[while(!std::mem::eof())] @ 0x0;
|