The read faces of the mediaio family: the decoders and the demuxer, no_std-friendly.
The read faces of the mediaio family: the push-style decoder traits,
the pull-style frame sources, the one-shot image decoder, the
Demuxer session, and their async mirrors under future. A backend
implements them; a consumer programs against them and never names the
backend.
The vocabulary the faces speak — frames, packets, subtitles, the push
rhythm's Sent and Received, the demuxer's track types, the adapter
traits, the resampler face, the time primitives — is
mediaspine's. This crate
re-exports it under the module names it has always used
(mediadecode::frame, mediadecode::packet, mediadecode::demuxer,
mediadecode::Received, …), so every path a consumer wrote still
resolves, to the same item a mediaspine:: path names. The write
faces are mediaencode's.
This crate ships no decoder code and no FFmpeg dependency. It
is no_std-clean (with optional alloc / std features). Adapter
implementations live in sibling crates:
mediadecode-ffmpeg and
mediadecode-webcodecs.
What's in the box
- Decoder traits —
VideoStreamDecoder,AudioStreamDecoder,SubtitleDecoder,ImageDecoder. The two*Stream*faces are push-style (send_packet/receive_frame/send_eof/flush), mirroring FFmpeg's decoder API while staying backend-agnostic; the other two are not, and their names say so — a subtitle cue and a still image each come out of exactly the packet that went in.VideoStreamDecoderalso states whether it can decode to a smaller size (ScaledOutputCapability). - Frame sources —
VideoFrameSource,AudioFrameSource: the pull-style faces of clip-oriented SDKs (R3D, BRAW, ARRIRAW, X-OCN, Canon Cinema RAW Light), which hand out frames by index. - The demux face —
Demuxer, the pull session over an opened container (tracks()/next_packet()/seek(), with the chapter table, the container duration and the measured end provided). Opening is each backend's own, so the trait covers only the opened session. A session keeps its track table for life:tracks()hands outTrackHandles — the backend's own row carrier,Arc/Rc/ a plain borrow — so a consumer that needs a row past the pull loop clones a refcount rather than taking the table away from the session. - Async faces — under the
futurefeature, every decoder face again withasync fnmethods, in a!Sendand aSend-bounded variant. - The vocabulary, re-exported — everything above is written against
mediaspine's types, re-exported here:PixelFormatand the color and CFA vocabulary frommediaframe, the packet and frame households, the carrier amputation contract every backend's buffer type obeys (on theadaptermodule), the demuxer'sTrackInfo/TrackParams/DemuxedPacket, the resampler face, andTimebase/Timestamp/TimeRangewith the rest ofmediatimeasmediadecode::mediatime.
Cargo features
| Feature | Default | Effect |
|---|---|---|
std |
yes | The standard library, here and in mediaspine. |
alloc |
— | Owning collections without std, here and in mediaspine. |
future |
— | The async faces under mediadecode::future. |
serde |
— | mediaspine's wire formats. |
arbitrary |
— | mediaspine's Arbitrary impls, for fuzzing. |
quickcheck |
— | mediaspine's quickcheck impls. |
no_std builds: disable defaults and pick alloc if you need
Vec-backed payloads:
[]
= { = "0.19", = false, = ["alloc"] }
Usage
This crate defines the surface; concrete decoding happens in adapter
crates. A backend-agnostic consumer programs against the traits, and
both faces answer states: send_packet answers Sent — accepted or
must drain — and receive_frame answers Received — produced,
needs input, or ended. Err means a fault and nothing else:
use ;
type Frame<D> = ;
/// Feeds one packet and delivers every frame it made ready.
/// Answers `true` once the stream is over.
The compiler is what makes this correct: a consumer that forgets end-of-stream does not compile, a receive-side failure can no longer be mistaken for a drained decoder, and back pressure no longer has to be guessed at by offering every packet twice.
For an end-to-end example using the FFmpeg adapter, see
mediadecode-ffmpeg.
Build requirements
- Rust ≥ 1.95, edition 2024.
- No system dependencies —
mediadecodeis FFmpeg-free and builds anywhere Rust does, includingno_stdtargets with optionalalloc.
License
mediadecode is under the terms of both the MIT license and the
Apache License (Version 2.0).
See LICENSE-APACHE, LICENSE-MIT for details.
Copyright (c) 2026 FinDIT Studio authors.