A safe, high-level Rust API over FFmpeg for building media applications: decode, encode, filter, compose, and stream.
avio is a family of Rust crates over FFmpeg, from decode and encode up to timeline composition, real-time preview, and GPU rendering. The public API is safe: every unsafe FFmpeg call is encapsulated, so application code never needs unsafe.
The goal is to be a foundation for video delivery services and video editing applications written in Rust. It does not try to cover every FFmpeg feature.
use ff_probe::open;
use ff_decode::VideoDecoder;
use ff_encode::{VideoEncoder, VideoCodec, AudioCodec, BitrateMode};
// Inspect a media file
let info = open("input.mp4")?;
if let Some(v) = info.primary_video() {
println!("{}x{} @ {:.2} fps", v.width(), v.height(), v.fps());
}
// Decode frames
let mut decoder = VideoDecoder::open("input.mp4").build()?;
while let Some(frame) = decoder.decode_one()? {
// process frame.planes() ...
}
// Re-encode
let mut encoder = VideoEncoder::create("output.mp4")
.video(1920, 1080, 30.0)
.video_codec(VideoCodec::H264)
.bitrate_mode(BitrateMode::Crf(23))
.audio(48000, 2)
.audio_codec(AudioCodec::Aac)
.build()?;
encoder.finish()?;Add the facade crate, or just the member crates you need:
[dependencies]
avio = "0.15"
# Or pick individual crates
ff-probe = "0.15"
ff-decode = "0.15"
ff-encode = "0.15"FFmpeg 7.x development libraries must be installed on your system.
vcpkg install ffmpeg:x64-windows
$env:VCPKG_ROOT = "C:\vcpkg"brew install ffmpegsudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-devuse ff_decode::{VideoDecoder, AudioDecoder, SeekMode};
use ff_format::{PixelFormat, SampleFormat};
use std::time::Duration;
// Video
let mut decoder = VideoDecoder::open("video.mp4")
.output_format(PixelFormat::Rgba)
.build()?;
while let Some(frame) = decoder.decode_one()? {
// frame.planes() contains pixel data
}
// Seek and decode a single frame
decoder.seek(Duration::from_secs(30), SeekMode::Exact)?;
let frame = decoder.decode_one()?;
// Audio
let mut decoder = AudioDecoder::open("audio.mp3")
.output_format(SampleFormat::F32)
.output_sample_rate(48000)
.build()?;
while let Some(frame) = decoder.decode_one()? {
// frame.planes() contains audio samples
}use ff_encode::{VideoEncoder, VideoCodec, AudioCodec, BitrateMode, Preset};
// Automatically selects an LGPL-compatible encoder (hardware or VP9/AV1 fallback)
let mut encoder = VideoEncoder::create("output.mp4")
.video(1920, 1080, 30.0)
.video_codec(VideoCodec::H264)
.bitrate_mode(BitrateMode::Crf(23))
.preset(Preset::Fast)
.audio(48000, 2)
.audio_codec(AudioCodec::Aac)
.build()?;
for frame in video_frames {
encoder.push_video(&frame)?;
}
encoder.finish()?;use ff_decode::{VideoDecoder, HardwareAccel};
use ff_encode::{VideoEncoder, HardwareEncoder};
// Decode with GPU
let decoder = VideoDecoder::open("video.mp4")
.hardware_accel(HardwareAccel::Auto)
.build()?;
// Encode with GPU
let encoder = VideoEncoder::create("output.mp4")
.video(1920, 1080, 60.0)
.hardware_encoder(HardwareEncoder::Auto)
.build()?;See docs.rs/avio for the full API.
| Crate | Description | crates.io | docs.rs |
|---|---|---|---|
ff-probe |
Media metadata extraction | ||
ff-decode |
Video and audio decoding | ||
ff-encode |
Video and audio encoding | ||
ff-filter |
Filter graph operations | ||
ff-pipeline |
Decode, filter, encode pipeline | ||
ff-stream |
HLS/DASH streaming output | ||
ff-preview |
Real-time A/V preview and proxy workflow | ||
ff-render |
GPU compositing pipeline (wgpu) | ||
ff-format |
Shared type definitions | ||
ff-common |
Common traits and buffer pooling | ||
ff-sys |
Low-level FFmpeg FFI bindings | ||
avio |
Facade crate that re-exports all member crates |
The avio facade re-exports the member crates behind cargo features:
| Feature | Default | Enables |
|---|---|---|
probe |
yes | Metadata extraction |
decode |
yes | Video and audio decoding |
encode |
yes | Video and audio encoding |
hwaccel |
yes | Hardware encoders (NVENC, QSV, AMF, VideoToolbox, VA-API) |
filter |
libavfilter graph operations | |
pipeline |
Decode, filter, encode pipeline | |
stream |
HLS/DASH output | |
preview |
Real-time preview | |
preview-proxy |
Proxy generation | |
render |
CPU compositing | |
render-gpu |
GPU compositing via wgpu | |
tokio |
Async decode/encode API | |
gpl |
GPL codecs (libx264, libx265) | |
srt |
SRT protocol input and output | |
serde |
serde derives for filter types |
| Platform | Status | Hardware acceleration |
|---|---|---|
| Windows | ✅ | NVENC/NVDEC, QSV, AMF |
| macOS | ✅ | VideoToolbox |
| Linux | ✅ | VAAPI, NVENC/NVDEC, QSV |
A terminal media player that renders video as colored ASCII art with synchronized audio. It was migrated from ffmpeg-next / ffmpeg-sys-next to avio, with no direct unsafe FFmpeg code in the application. It uses:
VideoDecoderwithPixelFormat::Rgb24for per-pixel luminance mappingAudioDecoderwith PCM conversion (SampleFormat::F32) feeding rodio- Synchronized audio and video across two threads via
crossbeam-channel
A non-linear video editor and the main driver of the library's API. It exercises the full decode, timeline compose, preview, and export path, and is where most bugs and API changes originate. It uses:
Timeline/Clipmulti-track composition with per-clip colour correction and transitions- A real-time preview that matches the exported result
- The
ff-previewproxy workflow, plus scene/silence detection, waveform, and EBU R128 loudness analysis
Pull requests, bug reports, and feature requests are welcome. See CONTRIBUTING, and look for issues labeled good first issue or help wanted.
avio-editor-demo drives most API changes, so it is a good place to see what is needed next.
Rust 1.93.0 (edition 2024).
Dual-licensed under either MIT or Apache-2.0 at your option.
avio links against FFmpeg, which is LGPL 2.1+ by default. The gpl feature of ff-encode enables GPL-licensed codecs (libx264, libx265); see ff-encode.
The audio fixture used in integration tests is provided by Music Atelier Amacha (甘茶の音楽工房), composed by Amacha. Used with permission under the site's free-use terms.