Skip to content

Repository files navigation

trkbt10/isobmff

ISO Base Media File Format (ISO/IEC 14496-12) parser for MoonBit.

Extract duration, track information, and file type from MP4, 3GP, 3G2, MJ2, HEIF, F4V, DVB, DCF, M21, and other ISOBMFF-derived container formats.

Overview

This library provides a pure MoonBit implementation of an ISOBMFF metadata parser. It reads the box structure of media container files and extracts:

  • File type (ftyp) — major brand, minor version, compatible brands
  • Movie header (mvhd) — global duration and timescale
  • Track info (trak/tkhd/mdia/mdhd/hdlr) — per-track ID, duration, handler type, timescale
  • Format detection — classify files as MP4, 3GP, HEIF, etc. from the major brand

Large media data (mdat) boxes are skipped, making parsing efficient even for large files.

Package Structure

trkbt10/isobmff
├── types/       Core types (MediaInfo, TrackInfo, ParseError, FormatType, ...)
├── parser/      Synchronous byte-buffer parser and ByteReader
├── async/       Async file-based parser (native backend only)
├── cmd/main/    CLI tool (native backend only)
└── npm/         npm package for WebAssembly (wasm / wasm-gc)

Dependency Graph

graph LR
  types["types/"]
  parser["parser/"]
  async["async/"]
  cmd["cmd/main/"]
  npm["npm/"]

  parser --> types
  async --> types
  async --> parser
  cmd --> types
  cmd --> async
  npm --> types
  npm --> parser
Loading

Installation

MoonBit (mooncakes)

Add the dependency to your moon.mod.json:

{
  "deps": {
    "trkbt10/isobmff": "0.1.0"
  }
}

Then import the packages you need in your moon.pkg:

import {
  "trkbt10/isobmff/types" @types,
  "trkbt10/isobmff/parser" @parser,
}

npm (WebAssembly)

npm install @trkbt10/isobmff
import { init, parse } from "@trkbt10/isobmff";

await init();
const info = parse(uint8Array);

Getting Started

Quick Example

import {
  "trkbt10/isobmff/types" @types,
  "trkbt10/isobmff/parser" @parser,
}

fn main {
  let data : Bytes = ... // read file bytes
  let info = @parser.parse(data)
  let format = @types.detect_format(info.file_type.major_brand)
  println("Format: \{format}")
  println("Duration: \{info.duration_seconds}s")
  for i, track in info.tracks {
    println("Track \{i + 1}: \{track.handler_type} \{track.duration_seconds}s")
  }
}

Async File Parsing (Native)

For native applications, the async parser reads only metadata boxes and skips mdat, making it efficient for large files:

import {
  "trkbt10/isobmff/async" @async_parser,
}

async fn main {
  let info = @async_parser.parse_file("video.mp4") catch {
    err => { println("Error: \{err}"); return }
  }
  println("Duration: \{info.duration_seconds}s")
  println("Tracks: \{info.tracks.length()}")
}

CLI

moon run --target native cmd/main/ -- video.mp4
File: video.mp4
Format: MP4
Major Brand: isom
Compatible Brands: isom, iso2, mp41
Duration: 120.5s
Timescale: 90000
Tracks: 2
  Track 1: id=1 type=vide duration=120.5s timescale=90000
  Track 2: id=2 type=soun duration=120.5s timescale=48000

API Reference

@types — Core Types

Type Description
MediaInfo Top-level parse result: file type, duration, timescale, tracks
FileTypeInfo File type box data: major brand, minor version, compatible brands
TrackInfo Per-track data: track ID, duration, handler type, timescale
FormatType Enum: MP4, ThreeGP, ThreeG2, MJ2, HEIF, F4V, DVB, DCF, M21, Unknown(String)
BoxType 4-byte box type identifier
BoxHeader Parsed box header (type, size, header size)
ParseError Error type: InvalidBox, UnexpectedEof, UnsupportedVersion, NotISOBMFF

detect_format(major_brand: String) -> FormatType

Classify a major brand string into a known format category.

@parser — Parser

parse(data: Bytes) -> MediaInfo raise ParseError

Parse a complete ISOBMFF byte buffer. Extracts file type from ftyp, movie duration from mvhd, and per-track info from trak boxes.

ByteReader

Cursor-based big-endian binary reader. Public methods:

  • ByteReader::new(data: Bytes) -> ByteReader
  • ByteReader::read_u32be() -> UInt raise ParseError
  • ByteReader::read_u64be() -> UInt64 raise ParseError
  • ByteReader::read_ascii4() -> String raise ParseError

@async — Async File Parser

parse_file(path: String) -> MediaInfo raise Error (native only)

Reads box headers sequentially from a file, skips mdat, and parses only ftyp and moov for efficiency. Raises ParseError for invalid data or I/O errors for file access failures.

Supported Formats

Format Major Brands
MP4 isom, iso2iso6, mp41, mp42, avc1, dash
3GP 3gp43gp9, 3ge6, 3ge7
3G2 3g2a3g2c
MJ2 mjp2
HEIF heic, heix, mif1, msf1, hevc, hevx
F4V f4v
DVB dvb1
DCF odcf
M21 mp21

Supported Box Types

Box Purpose
ftyp File type identification
moov Movie metadata container
mvhd Movie header (duration, timescale)
trak Track container
tkhd Track header (track ID, duration)
mdia Media container
mdhd Media header (timescale, duration)
hdlr Handler reference (handler type)
mdat Media data (skipped)

License

Apache-2.0 - see LICENSE for details.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages