Skip to content

Commit fde0e31

Browse files
committed
improve mp4 parser by making it recursive
1 parent a534e2a commit fde0e31

File tree

1 file changed

+78
-120
lines changed

1 file changed

+78
-120
lines changed

patterns/mp4.hexpat

Lines changed: 78 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,51 @@ import std.io;
1010
import std.mem;
1111
import std.string;
1212

13+
// All known MP4/ISOBMFF container box types (boxes that contain other boxes)
14+
str CONTAINER_BOX_TYPES[28] = {
15+
"moov", // Movie
16+
"trak", // Track
17+
"edts", // Edit
18+
"mdia", // Media
19+
"minf", // Media Information
20+
"dinf", // Data Information
21+
"stbl", // Sample Table
22+
"mvex", // Movie Extends
23+
"moof", // Movie Fragment
24+
"traf", // Track Fragment
25+
"mfra", // Movie Fragment Random Access
26+
"udta", // User Data
27+
"meta", // Metadata
28+
"ilst", // Item List (iTunes metadata)
29+
"meco", // Additional Metadata Container
30+
"tref", // Track Reference
31+
"trgr", // Track Grouping
32+
"sinf", // Protection Scheme Information
33+
"schi", // Scheme Information
34+
"ipro", // Item Protection
35+
"iprp", // Item Properties
36+
"ipco", // Item Property Container
37+
"iref", // Item Reference
38+
"grpl", // Group List
39+
"clip", // Clipping (QuickTime)
40+
"matt", // Track Matte (QuickTime)
41+
"strk", // Sub Track
42+
"strd" // Sub Track Definition
43+
};
44+
1345
fn to_string(auto var) {
1446
return str(var);
1547
};
1648

49+
fn is_container_box(str type_str) {
50+
for (u32 i = 0, i < 28, i += 1) {
51+
if (CONTAINER_BOX_TYPES[i] == type_str) {
52+
return true;
53+
}
54+
}
55+
return false;
56+
};
57+
1758
fn format_string(auto string) {
1859
return string.value;
1960
};
@@ -40,6 +81,8 @@ struct string {
4081
char value[std::mem::find_sequence_in_range(0, $, std::mem::size(), 0x00) - $];
4182
} [[sealed, format("format_string")]];
4283

84+
using Box;
85+
4386
struct BaseBox {
4487
u64 boxSize = 0;
4588
u64 startOffset = $;
@@ -55,13 +98,19 @@ struct BaseBox {
5598
if (this.size == 1) {
5699
u64 largeSize;
57100
boxSize = largeSize;
58-
endOffset = startOffset + boxSize;
101+
if (startOffset + boxSize > std::mem::size())
102+
endOffset = std::mem::size();
103+
else
104+
endOffset = startOffset + boxSize;
59105
} else if (this.size == 0) {
60106
boxSize = std::mem::size() - startOffset;
61107
endOffset = std::mem::size();
62108
} else {
63109
boxSize = size;
64-
endOffset = startOffset + boxSize;
110+
if (startOffset + boxSize > std::mem::size())
111+
endOffset = std::mem::size();
112+
else
113+
endOffset = startOffset + boxSize;
65114
}
66115

67116
if (this.type == "uuid") {
@@ -150,19 +199,6 @@ struct DataReferenceBox : FullBox {
150199
DataEntryBox data_entries[this.entry_count];
151200
};
152201

153-
struct SubDataInformationBox {
154-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
155-
156-
match (str(type)) {
157-
("dref"): DataReferenceBox box [[inline]];
158-
(_): UnknownBox box [[inline]];
159-
}
160-
} [[name(std::format("DataInformationBox({})", box.type))]];
161-
162-
struct DataInformationBox : BaseBox {
163-
SubDataInformationBox box[while($ < endOffset)] [[inline]];
164-
};
165-
166202
struct HandlerBox : FullBox {
167203
u32 component_type;
168204
char handler_type[4];
@@ -213,19 +249,9 @@ struct Mp4aBox : BaseBox {
213249
u8 unk[while($ != endOffset)];
214250
};
215251

216-
struct SubSampleDescriptionBox {
217-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
218-
219-
match (str(type)) {
220-
("mp4a"): Mp4aBox box [[inline]];
221-
("avc1"): Avc1Box box [[inline]];
222-
(_): UnknownBox box [[inline]];
223-
}
224-
} [[name(std::format("SubSampleDescriptionBox({})", box.type))]];
225-
226252
struct SampleDescriptionBox : FullBox {
227253
u32 entry_count;
228-
SubSampleDescriptionBox box[while($ < endOffset)] [[inline]];
254+
Box box[while($ < endOffset)] [[inline]];
229255
};
230256

231257
struct SampleTimeToSampleEntry {
@@ -291,41 +317,6 @@ struct SampleSizeBox: FullBox {
291317
}
292318
};
293319

294-
struct SubSampleBoxTable {
295-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
296-
297-
match (str(type)) {
298-
("stsd"): SampleDescriptionBox box [[inline]];
299-
("stts"): SampleTimeToSampleBox box [[inline]];
300-
("stsc"): SampleToChunkBox box [[inline]];
301-
("stco"): ChunkOffsetBox box [[inline]];
302-
("stss"): SyncSampleBox box [[inline]];
303-
("ctts"): CompositionOffsetBox box [[inline]];
304-
("stsz"): SampleSizeBox box [[inline]];
305-
(_): UnknownBox box [[inline]];
306-
}
307-
} [[name(std::format("SubSampleBoxTable({})", box.type))]];
308-
309-
struct SampleBoxTable : BaseBox {
310-
SubSampleBoxTable box[while($ < endOffset)] [[inline]];
311-
};
312-
313-
struct SubMediaInformationBox {
314-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
315-
316-
match (str(type)) {
317-
("vmhd"): VideoMediaHeaderBox box [[inline]];
318-
("hdlr"): HandlerBox box [[inline]];
319-
("dinf"): DataInformationBox box [[inline]];
320-
("stbl"): SampleBoxTable box [[inline]];
321-
(_): UnknownBox box [[inline]];
322-
}
323-
} [[name(std::format("MediaInformationBox({})", box.type))]];
324-
325-
struct MediaInformationBox : BaseBox {
326-
SubMediaInformationBox box[while($ < endOffset)] [[inline]];
327-
};
328-
329320
struct MediaHeaderBox : FullBox {
330321
if (this.version == 1) {
331322
u64 creation_time;
@@ -342,21 +333,6 @@ struct MediaHeaderBox : FullBox {
342333
u16 quality;
343334
};
344335

345-
struct SubMediaBox {
346-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
347-
348-
match (str(type)) {
349-
("mdhd"): MediaHeaderBox box [[inline]];
350-
("hdlr"): HandlerBox box [[inline]];
351-
("minf"): MediaInformationBox box [[inline]];
352-
(_): UnknownBox box [[inline]];
353-
}
354-
} [[name(std::format("MediaBox({})", box.type))]];
355-
356-
struct MediaBox : BaseBox {
357-
SubMediaBox box[while($ < endOffset)] [[inline]];
358-
};
359-
360336
struct EditListEntry64 {
361337
u64 segment_duration;
362338
s64 media_time;
@@ -380,61 +356,43 @@ struct EditListBox : FullBox {
380356
}
381357
};
382358

383-
struct SubEditBox {
384-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
385-
386-
match (str(type)) {
387-
("elst"): EditListBox box [[inline]];
388-
(_): UnknownBox box [[inline]];
389-
}
390-
} [[name(std::format("EditBox({})", box.type))]];
391-
392-
struct EditBox : BaseBox {
393-
SubEditBox box[while($ < endOffset)] [[inline]];
394-
};
395-
396-
struct SubTrackBox {
397-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
398-
399-
match (str(type)) {
400-
("mdia"): MediaBox box [[inline]];
401-
("edts"): EditBox box [[inline]];
402-
("tkhd"): TrackHeaderBox box [[inline]];
403-
(_): UnknownBox box [[inline]];
404-
}
405-
} [[name(std::format("TrackBox({})", box.type))]];
406-
407-
struct TrackBox : BaseBox {
408-
SubTrackBox box[while($ < endOffset)] [[inline]];
359+
struct MediaDataBox : BaseBox {
360+
std::mem::Bytes<endOffset - $> data;
409361
};
410362

411-
struct SubMovieBox {
412-
u32 type = std::mem::read_unsigned($ + 4, 4, std::mem::Endian::Big);
413-
414-
match (str(type)) {
415-
("mvhd"): MovieHeaderBox box [[inline]];
416-
("trak"): TrackBox box [[inline]];
417-
(_): UnknownBox box [[inline]];
418-
// TODO: Add "iods" box
419-
}
420-
} [[name(std::format("MovieBox({})", box.type))]];
421-
422-
struct MovieBox : BaseBox {
423-
SubMovieBox box[while($ < endOffset)] [[inline]];
424-
};
363+
using Box;
425364

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

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

433372
match (str(type)) {
434373
("ftyp"): FileTypeBox box [[inline]];
435-
("moov"): MovieBox box [[inline]];
436374
("mdat"): MediaDataBox box [[inline]];
437-
(_): UnknownBox box [[inline]];
375+
("mvhd"): MovieHeaderBox box [[inline]];
376+
("mdhd"): MediaHeaderBox box [[inline]];
377+
("dref"): DataReferenceBox box [[inline]];
378+
("tkhd"): TrackHeaderBox box [[inline]];
379+
("mp4a"): Mp4aBox box [[inline]];
380+
("avc1"): Avc1Box box [[inline]];
381+
("stsd"): SampleDescriptionBox box [[inline]];
382+
("stts"): SampleTimeToSampleBox box [[inline]];
383+
("stsc"): SampleToChunkBox box [[inline]];
384+
("stco"): ChunkOffsetBox box [[inline]];
385+
("stss"): SyncSampleBox box [[inline]];
386+
("ctts"): CompositionOffsetBox box [[inline]];
387+
("stsz"): SampleSizeBox box [[inline]];
388+
("vmhd"): VideoMediaHeaderBox box [[inline]];
389+
("hdlr"): HandlerBox box [[inline]];
390+
("elst"): EditListBox box [[inline]];
391+
(_): if (is_container_box(str(type))) {
392+
ContainerBox box [[inline]];
393+
} else {
394+
UnknownBox box [[inline]];
395+
}
438396
}
439397
} [[name(std::format("Box({})", box.type))]];
440398

0 commit comments

Comments
 (0)