oxideav-mp4
Pure-Rust MP4 / ISO Base Media File Format container — demuxer
(probe + sample-table expansion + seek) and muxer (moov-at-end by
default, optional faststart rewrite). Three brand presets share one
implementation: mp4, mov (QuickTime), and ismv (Smooth Streaming
ftyp, non-fragmented layout). Zero C dependencies.
Part of the oxideav framework but usable standalone.
Installation
[]
= "0.1"
= "0.1"
= "0.1"
= "0.0"
Quick use
Demux an MP4 and feed packets into a codec
use CodecRegistry;
use ContainerRegistry;
let mut codecs = new;
let mut containers = new;
register;
// ... register whichever codecs you care about (aac, flac, h264, mjpeg, ...)
let input: =
Boxnew;
let mut dmx = containers.open?;
// Sample entries are resolved to concrete codec ids. For `mp4a`/`mp4v`
// tracks the esds `objectTypeIndication` is honoured, so MP3-in-mp4
// comes out as "mp3", MPEG-1 video as "mpeg1video", AAC as "aac", etc.
let stream = &dmx.streams;
let mut dec = codecs.make_decoder?;
loop
# Ok::
Mux packets into an MP4
use WriteSeek;
let f = create?;
let ws: = Boxnew;
let mut mux = open?;
mux.write_header?;
for pkt in packets
mux.write_trailer?;
# Ok::
Faststart (moov-at-front) layout
use ;
let opts = Mp4MuxerOptions ;
let mut mux = open_with_options?;
In faststart mode the muxer buffers mdat in memory and writes
[ftyp][moov][mdat] at write_trailer time, patching chunk offsets so
the file is streamable from the first byte.
Scope
Demuxer
Sample-entry FourCCs resolve to these codec ids:
| FourCC | Codec id |
|---|---|
mp4a |
aac (default); esds OTI refines to mp3 (0x69/0x6B), ac3 (0xA5), eac3 (0xA6), dts (0xA9) |
mp4v |
mpeg4video (default); esds OTI refines to mpeg1video, mpeg2video, h264, h265, mjpeg |
alac |
alac |
fLaC / flac |
flac |
Opus / opus |
opus |
ac-3 / AC-3 |
ac3 (Dolby Digital, ETSI TS 102 366 Annex F) |
ec-3 / EC-3 |
eac3 (Dolby Digital Plus, ETSI TS 102 366 Annex G) |
dtsc / dtsh / dtsl / dtse |
dts (DTS Coherent Acoustics / DTS-HD HR / DTS-HD MA / DTS Express, ETSI TS 102 114) |
ulaw / alaw |
pcm_mulaw / pcm_alaw (G.711) |
avc1 / avc3 |
h264 |
hvc1 / hev1 |
h265 |
vp08 |
vp8 |
vp09 |
vp9 |
av01 |
av1 |
jpeg / mjpa / mjpb |
mjpeg |
s263 / h263 |
h263 |
lpcm / sowt / twos |
pcm_s16le (endianness of twos is not re-swapped) |
| any other | mp4:<fourcc> — callers can register their own decoder |
- Codec-specific config records (
avcC,hvcC,av1C,vpcC,dfLa,dOps,dac3,dec3, esds DSI) are forwarded asextradata. - Sample-table expansion:
stts,stsc,stsz/stz2,stco/co64,stss.next_packetserves samples in file-offset order. - Fragmented MP4 (DASH / HLS / Smooth Streaming / CMAF):
mvex/trexper-track defaults plus zero or more trailingmoof+mdatpairs (mfhd,traf,tfhd,tfdt,trun) are stitched onto the initial sample table.default-base-is-moof, per-sample size/duration/flags/composition-time-offset overrides, andtfhd.base_data_offsetare all honoured.styp,sidx, andmfrasegment-index boxes are skipped (segment-precision seek hint consumption is a follow-up). - Seek:
seek_to(stream, pts)lands on the nearest sync-sample ≤ pts (or the first keyframe of the stream if none qualify). - Metadata: 3GPP
udtaboxes (titl/auth/…) and iTunes-stylemeta/ilstare surfaced viaDemuxer::metadata().
Muxer
Only codecs with an mp4 sample-entry packaging are accepted. Codec
knowledge is confined to sample_entries::sample_entry_for; the rest
of the muxer appends opaque packet bytes.
Supported encode codec ids (produced sample entry FourCC in parentheses):
pcm_s16le→sowtflac→fLaCwithdfLaconfig (requires STREAMINFO extradata)aac→mp4awithesds(requires AudioSpecificConfig extradata)h264→avc1withavcC(requires AVCConfigurationRecord extradata)mjpeg→jpeg
Other codec ids fail with Error::Unsupported at open, never at
write_packet time.
Chunk offsets auto-promote from stco (32-bit) to co64 (64-bit) when
any offset exceeds 4 GiB. The mdat box header stays 32-bit — files
whose mdat payload exceeds 4 GiB fail at write_trailer.
Not (yet) supported
- Fragmented-MP4 muxing — the demuxer reads
moof+mdatsegments, but the muxer only emits a single moov-at-end (or faststart) shape. mfra/tfrarandom-access index consumption (the demuxer skips these; sequential demux works without them).sidxsegment-index seek-time mapping (skipped; sequential demux works without it).- Edit lists on the muxer.
- Sample groups (
sbgp/sgpd), subtitle tracks, DRM (sinf/pssh). - Multiple sample descriptions per track (only the first entry of
stsdis used;tfhd.sample_description_indexoverrides are ignored). - mdat payloads larger than 4 GiB (the 32-bit box header is not
promoted to
largesize).
Container registry
let mut reg = new;
register;
Registers:
- Demuxer
"mp4"(also serving.mp4,.m4a,.m4v,.3gp,.mov,.ismv). - Muxers
"mp4","mov","ismv". - A content probe that recognises
ftyp/wide+ftyp/moov.
License
MIT — see LICENSE.