oxideav-mkv
Pure-Rust Matroska (MKV) and WebM container — demuxer + muxer built on the EBML primitives from RFC 8794. Zero C dependencies.
Part of the oxideav framework but usable standalone.
Installation
[]
= "0.1"
= "0.1"
= "0.1"
= "0.0"
Quick use
Register both containers ("matroska" and "webm") and let the probe
pick which DocType the file carries:
use ContainerRegistry;
let mut containers = new;
register;
let input: = Boxnew;
let mut dmx = containers.open_demuxer?;
for s in dmx.streams
loop
# Ok::
The demuxer returns raw Packet bytes — pair it with a decoder crate
(e.g. oxideav-opus,
oxideav-flac,
oxideav-vp9) or go through
the unified oxideav aggregator to wire decoding automatically.
What's implemented
Demuxer (demux::open)
- EBML header parse, DocType validation (
matroska/webm). - Segment walk:
Info,Tracks,Tags,Cues,Cluster. Known- and unknown-size Segment/Cluster both supported. - Clusters:
SimpleBlockandBlockGroup -> Block, all three lacing modes (Xiph, fixed, EBML-signed-delta). - Metadata lift: title, muxer, encoder, date (Matroska
DateUTC-> ISO-8601), TagsSimpleTagname/value pairs. - Duration:
Segment\Info\Durationtranslated to microseconds. - Seek:
seek_to(stream, pts)uses the Cues index. Handles Cues at either end of the Segment, and walks an unknown-size final Cluster to find Cues that sit past it. - An unknown-size Cluster is terminated cleanly when a sibling Segment- child element follows it (no more "Cues silently eaten as payload").
Muxer (mux::open and mux::open_webm)
- EBML header + Segment (unknown size) for a streaming-friendly layout.
Info(1 msTimecodeScale),Tracks, rolling ~5 sClusters withSimpleBlockpayload.Cueselement emitted inwrite_trailer- index entries for every video keyframe and every audio cluster-start, so the resulting file is seekable without a second pass.- Codec-specific fields:
CodecPrivatenormalisation for FLAC (fLaCmagic prepended), OpusCodecDelayderived from theOpusHeadpre-skip plus an 80 msSeekPreRollper the WebM spec. - WebM profile:
mux::open_webmpinsDocType="webm"and rejects any stream whose codec isn't VP8/VP9/AV1 video or Vorbis/Opus audio withError::Unsupported.
Codec ID mapping (codec_id module)
Matroska CodecID string <-> oxideav CodecId. Both directions are
implemented for roundtrip:
- Audio:
A_FLAC,A_OPUS,A_VORBIS,A_PCM/INT/LIT,A_PCM/INT/BIG,A_PCM/FLOAT/IEEE,A_AAC(+MPEG4/LC/MPEG2/LCaliases),A_MPEG/L3,A_AC3,A_EAC3. - Video:
V_VP8,V_VP9,V_AV1,V_MPEG4/ISO/AVC,V_MPEGH/ISO/HEVC,V_FFV1,V_THEORA, plusV_MS/VFW/FOURCCwith BITMAPINFOHEADER fourcc extraction (e.g.FFV1).
Unknown MKV codec IDs fall back to a pass-through mkv:<raw-id> form
so the demuxer never hides an unrecognised track.
Probes + registration
- Registers both
"matroska"and"webm"with the container registry. - Extensions:
.mkv,.mka,.mks->matroska;.webm->webm. - Probe scoring: DocType=webm scores 100 on
probe_webmand 0 onprobe_matroska(so.mkvnever masquerades aswebm). DocType= matroska scores 100 onprobe_matroskaand 0 onprobe_webm. Files with an ambiguous DocType fall through to the matroska entry.
What's NOT implemented
- No
SeekHeadon write (players scan the file head for Info/Tracks, then find Cues past the last Cluster - the existing interop test confirms ffmpeg accepts this layout). - No block lacing on write; every frame becomes a standalone SimpleBlock. The read side handles all three lacing modes.
- No
Attachments,Chapters,ChapterDisplaybeyond skipping them. - CRC-32 elements are parsed (skipped) but not validated.
- Subtitle tracks pass through as opaque packets with
MediaType::Data.
License
MIT - see LICENSE.