ISO Base Media File Format (MP4 / .mov) parser for Standard ML. Builds the
recursive box tree (with byte offsets), and decodes the common metadata
boxes: ftyp brands, FullBox version/flags, and the mvhd/tkhd/mdhd
timescale + duration — including overall movie duration in seconds.
datatype box = Box of
{ kind : string, size : int, offset : int, dataOffset : int, children : box list }
(* accessors *)
val kind/size/offset/dataOffset/children : box -> ...
val payloadLength : box -> int
(* tree *)
val parse : Word8Vector.vector -> box list
val isContainer : string -> bool
val findAll : string -> box list -> box list
val find : string -> box list -> box option
val path : string list -> box list -> box option (* e.g. ["moov","trak","mdia"] *)
val payload : Word8Vector.vector -> box -> Word8Vector.vector
(* typed boxes *)
val ftyp : Word8Vector.vector -> box -> { major:string, minor:int, compatible:string list } option
val fullBox : Word8Vector.vector -> box -> { version:int, flags:int }
val mvhd : Word8Vector.vector -> box -> { timescale:int, duration:int } option
val tkhd : Word8Vector.vector -> box -> { trackId:int, duration:int } option
val mdhd : Word8Vector.vector -> box -> { timescale:int, duration:int } option
val movieDuration : Word8Vector.vector -> box list -> real option (* seconds *)
val toString : box list -> stringval boxes = Mp4.parse data
(* navigate by path *)
val mdia = Mp4.path ["moov","trak","mdia"] boxes
(* read brands *)
val SOME ft = Mp4.ftyp data (valOf (Mp4.find "ftyp" boxes))
(* { major = "isom", minor = 512, compatible = ["isom","avc1"] } *)
(* overall duration in seconds *)
val secs = Mp4.movieDuration data boxes (* SOME 5.0 *)
(* raw payload bytes of a leaf box *)
val raw = Mp4.payload data (valOf (Mp4.find "mdat" boxes))
print (Mp4.toString boxes) (* indented box-tree dump *)Recognized container boxes (descended into): moov, trak, mdia, minf,
stbl, udta, dinf, edts, mvex, moof, traf.
Breaking change:
Boxnow carriesoffsetanddataOffsetfields (so payloads and typed boxes can be sliced from the original vector). Pattern matches that named only{kind, size, children}must add the new fields or use the accessor functions.
- Decodes the box framing layer (32-bit
size, the 64-bit large-size form,size == 0box-to-EOF) plus the metadata boxes listed above. Other payloads (sample tables, codec config,uuidtypes) are left as raw bytes. mvhd/tkhd/mdhdhandle FullBox version 0 and version 1 layouts.- 64-bit sizes/durations are read into the platform
int; extremely large files may exceed a narrowintrange.
smlpkg add github.com/sjqtentacles/sml-mp4
smlpkg syncReference from your .mlb:
lib/github.com/sjqtentacles/sml-mp4/mp4.mlb
make test # MLton
make test-poly # Poly/ML
make all-tests # both
make cleansml.pkg
Makefile
lib/github.com/sjqtentacles/sml-mp4/
mp4.sig
mp4.sml box-tree parser + ftyp/FullBox/mvhd/tkhd/mdhd + find/path/payload
mp4.mlb
test/
test.sml framing, nesting, largesize, find/path, brands, timescale/duration, payload
MIT. See LICENSE.