Skip to content

itsakeyfut/avio

avio

A safe, high-level Rust wrapper around FFmpeg for building video editors — decode, encode, filter, compose, and stream.

Crates.io Docs.rs License

Note

First of all, thank you for finding this project. I would like to briefly share the current state of things.

AI agents have been evolving remarkably in recent times, and large projects such as Rust and Bevy have declared any issue, comment, or code generated by AI to be a violation of their contribution guidelines. I believe this is because whether copyright can apply to AI-generated content — and whether the engineer who directed the AI can bear full accountability — are still actively being debated. For now, most projects are erring on the side of caution and treating AI contributions as guideline violations.

At the same time, when an engineer designs the structs, traits, functions, variables, and overall architecture — deciding how to separate module responsibilities, how to connect them, which APIs to expose, and what to test — and then gives detailed instructions to an AI to generate code efficiently, the result is a dynamic where the engineer does the thinking and the AI does the work. I find this analogous to the relationship between an architect and a mid-level engineer. Of course, being the architect requires commensurate experience, technical depth, and judgment — but the structure of the relationship is similar.

Current phase (as of 2026-06-10): The library foundation is in place. Active development continues through avio-editor-demo — a real-world video editing application built on avio — which remains the primary vehicle for surfacing bugs and driving API improvements. Pull requests are welcome. While the contributor base is small, or whenever rapid iteration is needed, AI assistance may be used to accelerate development — always with the engineer in the architectural role, reviewing and taking responsibility for every change. Questions, bug reports, and feature requests are equally welcome.

The goal of this project is to serve as the core foundation for video delivery services and video editing applications built in Rust — not to cover every FFmpeg feature. The fundamental motivation was simply a desire to build a video editing application in Rust.

New contributors are very welcome — see CONTRIBUTING, and look for issues labeled good first issue or help wanted to get started.

If you have any questions or suggestions, I would be happy to hear them. Feel free to ask.

Overview

avio is a family of Rust crates for building video-editing and media applications — a safe, ergonomic toolkit over FFmpeg. It spans low-level decode/encode up through timeline composition, real-time preview, and GPU rendering. All public APIs are safe — unsafe internals are fully encapsulated, so you never need to write unsafe code in your application.

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()?;

Crate Family

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 — re-exports all member crates

Features

  • Safe API — No unsafe code required in user code
  • Probe — Extract metadata (codec, resolution, duration, bitrate, HDR info) from any media file
  • Decode — Frame-by-frame video/audio decoding with Iterator pattern, seeking, and thumbnail generation
  • Encode — Video/audio encoding with hardware acceleration and LGPL-compliant defaults
  • Hardware Acceleration — NVENC/NVDEC, Intel QSV, AMD AMF, Apple VideoToolbox, VA-API
  • Filter Graph — Trim, scale, crop, overlay, and more via libavfilter
  • HLS/DASH Streaming — Adaptive bitrate output via ff-stream
  • Async — Tokio-backed async decode/encode with back-pressure (tokio feature)
  • Cross-platform — Windows, macOS, Linux

Installation

Add the crates you need to your Cargo.toml:

[dependencies]
ff-probe  = "0.15"
ff-decode = "0.15"
ff-encode = "0.15"

# Or use the facade crate for everything
avio = "0.15"

Prerequisites

FFmpeg development libraries must be installed on your system.

Windows

vcpkg install ffmpeg:x64-windows
$env:VCPKG_ROOT = "C:\vcpkg"

macOS

brew install ffmpeg

Linux (Debian/Ubuntu)

sudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev

Quick Start

Probe

use ff_probe::open;

let info = open("video.mp4")?;

if let Some(video) = info.primary_video() {
    println!("{}x{} @ {:.2} fps ({:?})", video.width(), video.height(), video.fps(), video.codec());
}
if let Some(audio) = info.primary_audio() {
    println!("{} Hz, {} ch ({:?})", audio.sample_rate(), audio.channels(), audio.codec());
}

Decode

use 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
}

Encode

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()?;

Hardware Acceleration

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()?;

Showcase

The best way to see avio in action is to run these projects. If either interests you, contributions to them are very welcome too — they are where new requirements and rough edges surface first.

ascii-term — Terminal ASCII Art Video Player

A full-featured terminal media player built entirely on avio. It renders video as colored ASCII art in the terminal with synchronized audio playback, and was fully migrated from ffmpeg-next / ffmpeg-sys-next to avio.

What it demonstrates:

  • VideoDecoder with PixelFormat::Rgb24 output for per-pixel luminance mapping
  • AudioDecoder with custom PCM conversion (SampleFormat::F32) feeding rodio for playback
  • Synchronized audio/video across two threads via crossbeam-channel
  • 10 selectable ASCII character maps, per-character RGB coloring, real-time terminal resize

This is a real-world proof that avio can replace ffmpeg-next / ffmpeg-sys-next in decode-heavy applications without any direct unsafe FFmpeg code in the application layer.

avio-editor-demo — Non-Linear Video Editor

A real-world non-linear video editor built on avio, and the primary driver of the library's API. It exercises the full decode → timeline compose → real-time preview → export path, and is where most bugs and API improvements originate.

What it demonstrates:

  • Timeline / Clip multi-track composition with per-clip effects (colour correction, LUT, transitions)
  • Real-time monitor preview that matches the exported result (same yuv420p pipeline)
  • ff-preview proxy workflow and ff-render GPU compositing

Give it a try — and if you'd like to help shape a real Rust video editor, jump in.

Platform Support

Platform Status Hardware Acceleration
Windows NVENC/NVDEC, QSV, AMF
macOS VideoToolbox
Linux VAAPI, NVENC/NVDEC, QSV

Minimum Supported Rust Version

Rust 1.93.0 or later (edition 2024).

License

Licensed under either of:

at your option.

FFmpeg License

This project links against FFmpeg, which is licensed under LGPL 2.1+ by default. The gpl feature of ff-encode enables GPL-licensed codecs (libx264, libx265) — see ff-encode for details.

Test Assets

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.

About

A safe, high-level Rust wrapper around FFmpeg for building video editors — decode, encode, filter, compose, and stream.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages