v0.9.0
0.9.0
A correctness-focused overhaul that also adds non-destructive editing,
fragmented-MP4 support, tolerant parsing, and DRM/DASH decoders. The library now
depends only on anyhow + serde for parse-only builds.
Added
- Non-destructive box editing (
editmodule,mp4editCLI — on by default).- Extent-tree design: unmodified boxes stay as byte-range references into the
source; serializing an unedited tree reproduces the file byte-for-byte, and
mdatis streamed rather than held in memory. - Ancestor box sizes are recomputed bottom-up (correct by construction);
stco/co64offsets are remapped through an exact old→new extent map — no
heuristics. - Commands:
Remove/RemoveAll/Insert/Replace/Set/SetTag/
Faststart, addressed by slash paths with[n]indexing and©fourccs. Setpatches named fields in place (mvhd/tkhd/mdhd timestamps, timescale,
duration, rate, volume, track_id, layer, width/height, language) with
version-aware offsets — no re-encoding.SetTagbuilds themoov/udta/meta/ilstchain (ffmpeg-compatiblehdlr)
when missing.- Faststart: move
moovbeforemdatfor progressive playback (like
qt-faststart/ffmpeg -movflags +faststart); idempotent.
- Extent-tree design: unmodified boxes stay as byte-range references into the
- Fragmented MP4 (fMP4 / DASH / CMAF) sample extraction.
track_samples_from_reader/_from_pathnow walkmoof/traf/trun,
implementing the ISO 14496-12 §8.8 defaulting chain (trun → first_sample_flags
→ tfhd → trex), with decode times fromtfdt(running-DTS fallback across
fragments) and byte offsets fromtfhdbase or the enclosingmoof. - Tolerant parsing.
parse_boxes_tolerant/get_boxes_tolerantreturn the
partial tree plus locatedParseIssues (offset + description); damage is
contained to the enclosing container.mp4dumpis now tolerant by default
(partial tree, issues on stderr, exit code 2);--strictrestores fail-fast. - Typed structured decoders for movie/fragment boxes:
MovieHeader,
EditList,SegmentIndex,TrackFragmentHeader,TrackFragmentDecodeTime,
TrackExtends(elst/sidx include full entry lists with SAP info). - DRM/DASH decoders:
pssh(Widevine/PlayReady/FairPlay/ClearKey/Marlin
recognition, v1 KIDs),tenc,emsg,senc,schm,frma— verified
end-to-end against a real CENC-encrypted file. - AAC:
esdsnow decodesAudioSpecificConfig(object type, profile,
core/extension sample rates, channels, SBR/PS) — HE-AAC and HE-AAC v2 now
report correctly instead of as AAC-LC. - New decoders:
stz2,avcC,hvcC. - New cargo features:
edit(default, no extra deps) andcli(default; gates
clap + serde_json). - New examples:
edit.rs,fragments.rs,media_info.rs.
Fixed
- FullBox decoding: mvhd/tkhd/elst/sidx no longer re-parse already-stripped
version/flags (every field was shifted 4+ bytes — mvhd reported garbage
timescale/duration, tkhd alwaystrack_id=0). - tkhd v0 now reads 4-byte timestamps; mdhd honors v1 64-bit times.
- New
FullContainernode kind fixesmeta/iref/trep/stsdchildren
previously parsed as garbage; QuickTime-stylemetais auto-detected. stsdnow recurses into sample entries and their codec-config children, making
the esds/dOps/colr/pasp/btrt decoders reachable on real files.- Box classification fixes (dinf/tref/schi as containers; schm/tenc/senc/emsg/…
as FullBoxes; accept the specOpusfourcc). tfhdflag mixup fixed (0x010000is duration_is_empty, not
default_base_is_moof).- Sample tables:
track_samples_*work again on v0-tkhd files; sample building
is a single O(n) pass;mp4samplesprints real stts/ctts/stsc/stco/stsz
instead of values scraped from Debug strings.
Changed
- Dependencies slimmed 7 → 2 for library consumers (transitive tree 33 → 11
crates): droppedbyteorder(smallReadExttrait),thiserror
(hand-written impls), andhex(unused). clap and serde_json are gated behind
the default-onclifeature; parse-only builds use
default-features = false, features = ["edit"]. - MSRV set to Rust 1.88; refreshed crate metadata (description, keywords,
categories); added MIT LICENSE file.