Created
November 25, 2022 07:37
-
-
Save summivox/b511db55f36f39f2dd424866f1273b7b to your computer and use it in GitHub Desktop.
MP4 & GPMF ImHex Pattern definitions (partial)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma eval_depth 50 | |
#pragma endian big | |
#include <std/io.pat> | |
enum GpmfElemType : char { | |
CONTAINER = '\x00', | |
COMPLEX = '?', | |
I8 = 'b', | |
U8 = 'B', | |
I16 = 's', | |
U16 = 'S', | |
I32 = 'l', | |
U32 = 'L', | |
F32 = 'f', | |
I64 = 'j', | |
U64 = 'J', | |
F64 = 'd', | |
CHAR = 'c', | |
FOURCC = 'F', | |
GUID = 'G', | |
Q15_16 = 'q', | |
Q31_32 = 'Q', | |
DATETIME = 'U', | |
}; | |
fn GpmfPayloadSize(u8 elem_size, u16 num_elems) { | |
return (le u32(elem_size) * le u32(num_elems)); | |
}; | |
using GpmfBox; | |
struct GpmfContainer<auto size> { | |
GpmfBox children[while($ < addressof(parent) + size + 8)]; | |
}; | |
struct Array<T, auto n> { | |
T elem[n]; | |
}; | |
struct GpmfBox { | |
char fourcc[4]; | |
GpmfElemType data_type; | |
u8 elem_size; | |
u16 num_elems; | |
if (data_type == GpmfElemType::CONTAINER) { | |
GpmfContainer<GpmfPayloadSize(elem_size, num_elems)> children; | |
} else if (data_type == GpmfElemType::I8) { | |
if (elem_size == 1) { | |
s8 a[num_elems]; | |
} else { | |
Array<s8, elem_size/1> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::U8) { | |
if (elem_size == 1) { | |
u8 a[num_elems]; | |
} else { | |
Array<u8, elem_size/1> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::I16) { | |
if (elem_size == 2) { | |
s16 a[num_elems]; | |
} else { | |
Array<s16, elem_size/2> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::U16) { | |
if (elem_size == 2) { | |
u16 a[num_elems]; | |
} else { | |
Array<u16, elem_size/2> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::I32 || data_type == GpmfElemType::Q15_16) { | |
if (elem_size == 4) { | |
s32 a[num_elems]; | |
} else { | |
Array<s32, elem_size/4> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::U32) { | |
if (elem_size == 4) { | |
u32 a[num_elems]; | |
} else { | |
Array<u32, elem_size/4> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::I64 || data_type == GpmfElemType::Q31_32) { | |
if (elem_size == 8) { | |
s64 a[num_elems]; | |
} else { | |
Array<s64, elem_size/8> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::U64) { | |
if (elem_size == 8) { | |
u64 a[num_elems]; | |
} else { | |
Array<u64, elem_size/8> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::F32) { | |
if (elem_size == 4) { | |
float a[num_elems]; | |
} else { | |
Array<float, elem_size/4> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::F64) { | |
if (elem_size == 8) { | |
double a[num_elems]; | |
} else { | |
Array<double, elem_size/8> a[num_elems]; | |
} | |
} else if (data_type == GpmfElemType::CHAR && elem_size == 1) { | |
char a[num_elems]; | |
} else if (data_type == GpmfElemType::FOURCC && elem_size == 4) { | |
char a[num_elems * 4]; | |
} else { | |
u8 payload[GpmfPayloadSize(elem_size, num_elems)]; | |
} | |
$ = ($ - addressof(fourcc) + 3) / 4 * 4 + addressof(fourcc); | |
}; | |
// GpmfBox root @ 0; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma endian big | |
#pragma eval_depth 100 | |
#include <std/ctype.pat> | |
#include <std/core.pat> | |
#include <std/mem.pat> | |
#include <std/io.pat> | |
#include <std/string.pat> | |
#include <std/ptr.pat> | |
struct Mp4BoxHeader { | |
u32 len; | |
char fourcc[4]; | |
if (len == 1) { | |
u64 len64; | |
} | |
}; | |
fn Probe(auto base) { | |
u32 x = std::mem::read_unsigned(base, 4, 0x00000000); | |
// assuming we are on little endian system --- builtin endianness conversion did not work somehow... | |
u32 len = | |
(((x >> 0) & 0xFF) << 24) | | |
(((x >> 8) & 0xFF) << 16) | | |
(((x >> 16) & 0xFF) << 8) | | |
(((x >> 24) & 0xFF) << 0); | |
str fourcc = std::mem::read_string(base + 4, 4); | |
// std::print("probe @ {:08x} => len={}, fourcc={}", base, len, fourcc); | |
if (len < 8) { | |
return false; | |
} | |
for (u8 i = 0, i < 4, i = i + 1) { | |
if (!std::ctype::isalpha(std::string::at(fourcc, i))) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
fn ProbeLimit(auto base, auto pbase, auto len) { | |
std::print("ProbeLimit(base={:08x}, pbase={:08x}, len={:08x})", base, pbase, len); | |
if (base >= pbase + len) { | |
return false; | |
} | |
return Probe(base); | |
}; | |
bitfield TkhdFlags { | |
enabled : 1; | |
in_movie : 1; | |
in_preview : 1; | |
in_poster: 1; | |
padding : 20; | |
}; | |
struct Tkhd { | |
u8 version; | |
TkhdFlags flags; | |
u32 creation_time; | |
u32 modification_time; | |
u32 track_id; | |
padding[4]; | |
u32 duration; | |
padding[8]; | |
u16 layer; | |
u16 alternate_group; | |
u16 volume; | |
padding[2]; | |
u32 matrix[9]; | |
u32 track_width; | |
u32 track_height; | |
}; | |
struct Mdhd { | |
u8 version; | |
u24 flags; | |
u32 creation_time; | |
u32 modification_time; | |
u32 time_scale; | |
u32 duration; | |
u16 language; | |
u16 quality; | |
}; | |
struct SttsEntry { | |
u32 sample_count; | |
u32 sample_duration; | |
}; | |
struct SttsTable { | |
u8 version; | |
u24 flags; | |
u32 num_entries; | |
SttsEntry entries[num_entries]; | |
}; | |
struct StscEntry { | |
u32 first_chunk; | |
u32 samples_per_chunk; | |
u32 sample_description_id; | |
}; | |
struct StscTable { | |
u8 version; | |
u24 flags; | |
u32 num_entries; | |
StscEntry entries[num_entries]; | |
}; | |
struct StszTable { | |
u8 version; | |
u24 flags; | |
u32 size; | |
u32 num_samples; | |
if (size == 0) { | |
u32 sizes[num_samples]; | |
} | |
}; | |
struct StcoTable { | |
u8 version; | |
u24 flags; | |
u32 num_chunks; | |
u32 chunk_offsets[num_chunks]; | |
}; | |
using Mp4Box; | |
struct Mp4Children<auto L> { | |
Mp4Box children[while(ProbeLimit($, addressof(parent), L))]; | |
}; | |
struct Mp4Box : Mp4BoxHeader { | |
if (Probe($)) { | |
Mp4Children<len> children; | |
} else if (fourcc == "tkhd") { | |
Tkhd tkhd; | |
} else if (fourcc == "mdhd") { | |
Mdhd mdhd; | |
} else if (fourcc == "stts") { | |
SttsTable stts; | |
} else if (fourcc == "stsc") { | |
StscTable stsc; | |
} else if (fourcc == "stsz") { | |
StszTable stsz; | |
} else if (fourcc == "stco") { | |
StcoTable stco; | |
} else { | |
// std::print("{:x}", $); | |
if (len == 0) { | |
} else { | |
u8 payload[len - 8]; | |
} | |
} | |
$ = addressof(len) + len; | |
}; | |
struct Mp4 { | |
Mp4Box root[while(Probe($))]; | |
}; | |
Mp4 mp4 @ 0; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment