FFmpeg adapter for the mediadecode abstraction
layer, built on top of
ffmpeg-next.
Implements mediadecode's VideoAdapter / AudioAdapter /
SubtitleAdapter traits and the matching push-style *StreamDecoder
traits. Frame payloads are zero-copy refcounted views over FFmpeg's
AVBufferRef via the [FfmpegBuffer] type — receiving a frame does
not memcpy the pixel data.
FfmpegVideoStreamDecoder mirrors the send_packet / receive_frame
shape of ffmpeg::decoder::Video, auto-probes the host's HW backends,
and falls through to a software decoder when none open. Audio and
subtitles use parallel FfmpegAudioStreamDecoder /
FfmpegSubtitleStreamDecoder types.
Backends
FfmpegVideoStreamDecoder::open walks this probe order, opening the
first backend that accepts the stream:
| Target | Probe order |
|---|---|
| macOS / iOS / tvOS | VideoToolbox → software |
| Linux | VAAPI → CUDA → software |
| Windows | D3D11VA → CUDA → software |
| other | software |
Output frames are CPU-side, downloaded with av_hwframe_transfer_data
(NV12 for 8-bit, P010/P012/P016/P210/P212/P216/P410/P412/P416 for
10/12/16-bit). Pixel-format conversion is intentionally out of scope
— downstream
colconv handles it.
If every HW backend opens but later fails at decode time and the
software backend is also unavailable, the error surfaces as
VideoDecodeError::Decode(Error::AllBackendsFailed(p)) carrying any
packets the decoder had already accepted from the demuxer (accessible
via p.unconsumed_packets() / p.into_unconsumed_packets()) — so
non-seekable callers (live streams, pipes, network sources) can replay
them through their own software decoder without re-demuxing.
Usage
use ffmpeg_next as ffmpeg;
use ;
use ;
use ;
Audio and subtitle decoding share the shape — see
examples/decode_via_trait.rs and
tests/audio_subtitle_via_trait.rs
for end-to-end demuxer-driven runs that cover all three streams.
Public surface map
- Decoders:
FfmpegVideoStreamDecoder,FfmpegAudioStreamDecoder,FfmpegSubtitleStreamDecoder. Plus their error types:VideoDecodeError,AudioDecodeError,SubtitleDecodeError. - Type aliases:
VideoPacket,AudioPacket,SubtitlePacket,VideoFrame,AudioFrame,SubtitleFrame— themediadecodegeneric types pre-parameterized with this crate's adapter / buffer / extras, so you don't have to spell them out. - Buffer:
FfmpegBuffer— refcounted view over anAVBufferRefwith safe constructors (empty,from_packet,try_*panic-free counterparts). - Boundary helpers:
video_packet_from_ffmpeg,audio_packet_from_ffmpeg,subtitle_packet_from_ffmpeg— convert a borrowedffmpeg::Packetinto the matchingmediadecodepacket without copying the compressed payload. - Empty-frame builders:
empty_video_frame,empty_audio_frame,empty_subtitle_frame— well-formed destinations forreceive_frame.
Running tests and benches
The fixture-gated tests and the benchmark expect real media files,
named by five environment variables. The unit tests run
unconditionally; the gated ones are #[ignore]d, so --ignored
is what opts into them.
| Variable | Feeds |
|---|---|
HWDECODE_SAMPLE_VIDEO |
tests/decode.rs, tests/hw_smoke.rs, benches/decode.rs, and the three decoder::tests backend cases |
MEDIADECODE_SAMPLE_VIDEO |
tests/decode_via_trait.rs |
MEDIADECODE_SAMPLE_AUDIO |
the audio-through-trait case (any container with an audio track) |
MEDIADECODE_SAMPLE_SUBTITLE |
the subtitle-through-trait case (needs a container that really carries a subtitle track) |
MEDIADECODE_FX3_SAMPLE |
the Sony FX3 H.264 High 4:2:2 10-bit mid-stream HW→SW fallback case |
HWDECODE_SAMPLE_VIDEO=/path/to/clip.mp4
HWDECODE_SAMPLE_VIDEO=/path/to/clip.mp4
# The whole fixture-gated set at once.
HWDECODE_SAMPLE_VIDEO=/path/to/clip.mp4 \
MEDIADECODE_SAMPLE_VIDEO=/path/to/clip.mp4 \
MEDIADECODE_SAMPLE_AUDIO=/path/to/clip.mp4 \
MEDIADECODE_SAMPLE_SUBTITLE=/path/to/subtitled.mkv \
MEDIADECODE_FX3_SAMPLE=/path/to/12_sony_fx3_xavc.mp4 \
A variable left unset is not always a quiet skip: the FX3 case prints
a notice and returns, but the trait cases panic on a missing path
once --ignored has opted into them.
Build requirements
- A system FFmpeg ≥ 5.1 linkable via
pkg-config(we referenceAV_PIX_FMT_P212LE/AV_PIX_FMT_P412LE, which were added in 5.1). Tested against 9.0. Verify withffmpeg -hwaccelsthat your build has the backends you expect compiled in (e.g.videotoolboxon macOS,vaapi/cudaon Linux,d3d11va/cudaon Windows). - Rust ≥ 1.95, edition 2024.
License
mediadecode-ffmpeg 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.