1 unstable release
Uses new Rust 2024
| 0.1.0 | Jul 19, 2025 |
|---|
#135 in Video
34 downloads per month
Used in 4 crates
(3 directly)
57KB
1.5K
SLoC
FFmpeg Suite Rust Wrappers
Safe, idiomatic, and performant Rust wrappers for FFmpeg, FFprobe, and FFplay.
Overview
This workspace provides three separate crates that wrap the FFmpeg suite of tools:
rust_ffmpeg- Video/audio transcoding, filtering, and manipulationrust_ffprobe- Media file inspection and metadata extractionrust_ffplay- Media playback with various display optionsffmpeg-common- Shared types and utilities
Features
- Type-safe - Strongly typed APIs prevent common mistakes
- Async - Built on Tokio for non-blocking execution
- Zero-copy - Efficient handling of large files
- Cross-platform - Works on Linux, macOS, and Windows
- Progress tracking - Real-time progress updates for long operations
- Hardware acceleration - Support for VAAPI, NVENC, QSV, etc.
- Comprehensive - Covers most FFmpeg functionality
Installation
Add the crates you need to your Cargo.toml:
[dependencies]
rust_ffmpeg = "0.1"
rust_ffprobe = "0.1"
rust_ffplay = "0.1"
tokio = { version = "1", features = ["full"] }
Quick Start
FFmpeg - Transcoding
use rust_ffmpeg::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Simple conversion
FFmpegBuilder::convert("input.mp4", "output.webm")
.run()
.await?;
// Complex transcoding with filters
FFmpegBuilder::new()?
.input(Input::new("input.mp4").seek(Duration::from_secs(10)))
.output(
Output::new("output.mp4")
.video_codec_opts(presets::h264::youtube_1080p())
.audio_codec(Codec::aac())
.metadata("title", "My Video")
)
.video_filter(VideoFilter::scale(1920, 1080))
.on_progress(|p| println!("Progress: {:?}", p))
.run()
.await?;
Ok(())
}
FFprobe - Media Inspection
use rust_ffprobe::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Probe media file
let info = FFprobeBuilder::probe("video.mp4").run().await?;
// Access format info
if let Some(format) = &info.format {
println!("Duration: {} seconds", info.duration().unwrap_or(0.0));
println!("Bitrate: {} bps", format.bit_rate.as_deref().unwrap_or("unknown"));
}
// Access stream info
for stream in &info.streams {
match stream.codec_type.as_deref() {
Some("video") => {
println!("Video: {}x{} @ {} fps",
stream.width.unwrap_or(0),
stream.height.unwrap_or(0),
stream.frame_rate().unwrap_or(0.0)
);
}
Some("audio") => {
println!("Audio: {} Hz, {} channels",
stream.sample_rate.as_deref().unwrap_or("?"),
stream.channels.unwrap_or(0)
);
}
_ => {}
}
}
Ok(())
}
FFplay - Media Playback
use rust_ffplay::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Simple playback
let mut player = FFplayBuilder::play("video.mp4").spawn().await?;
player.wait().await?;
// Advanced playback with options
let mut player = FFplayBuilder::new()?
.input("video.mp4")
.size(1280, 720)
.window_title("My Player")
.seek(Duration::from_secs(30))
.volume(75)
.spawn()
.await?;
// Stop after 10 seconds
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
player.kill().await?;
Ok(())
}
Advanced Examples
Batch Processing
use rust_ffmpeg::prelude::*;
use futures::future::try_join_all;
async fn batch_convert(files: Vec<&str>) -> Result<()> {
let tasks = files.into_iter().map(|file| {
let output = file.replace(".mp4", ".webm");
FFmpegBuilder::convert(file, output)
.video_codec_opts(presets::vp9::youtube())
.run()
});
try_join_all(tasks).await?;
Ok(())
}
Live Streaming
use rust_ffmpeg::prelude::*;
async fn stream_to_rtmp() -> Result<()> {
FFmpegBuilder::new()?
.input(DeviceInput::screen_capture().into_input())
.input(DeviceInput::webcam("/dev/video0").into_input())
.output(
Output::new("rtmp://live.example.com/stream/key")
.for_streaming()
.video_codec_opts(presets::h264::streaming())
.audio_codec_opts(presets::audio::aac_standard())
)
.filter_complex("[0:v][1:v]overlay=W-w-10:10")
.run()
.await?;
Ok(())
}
Extract Frames
use rust_ffmpeg::prelude::*;
async fn extract_thumbnails() -> Result<()> {
FFmpegBuilder::new()?
.input("video.mp4")
.output(
ImageSequenceOutput::new("thumb_%04d.jpg")
.quality(2)
.framerate(1.0)
.into_output()
)
.video_filter(VideoFilter::scale(320, -1))
.run()
.await?;
Ok(())
}
Hardware Acceleration
use rust_ffmpeg::prelude::*;
use rust_ffmpeg::codec::hardware;
async fn transcode_with_gpu() -> Result<()> {
FFmpegBuilder::new()?
.input(Input::new("input.mp4").hwaccel_device("0"))
.output(
Output::new("output.mp4")
.video_codec_opts(hardware::nvenc_h264())
)
.hwaccel("cuda")
.run()
.await?;
Ok(())
}
Architecture
The crates follow a builder pattern for constructing commands:
FFmpegBuilder/FFprobeBuilder/FFplayBuilder
├── Input specifications
├── Output specifications
├── Filters and processing
├── Global options
└── Execution
Key design principles:
- Type safety - Invalid combinations are compile-time errors
- Ergonomics - Common tasks are simple, complex tasks are possible
- Performance - Zero-copy where possible, efficient command building
- Flexibility - Raw arguments can be added for unsupported features
Error Handling
All operations return Result<T, Error> with detailed error information:
use ffmpeg_common::{Error, ResultExt};
match FFmpegBuilder::convert("input.mp4", "output.mp4").run().await {
Ok(_) => println!("Success!"),
Err(Error::ExecutableNotFound(name)) => {
eprintln!("{} not found in PATH", name);
}
Err(Error::ProcessFailed { message, stderr, .. }) => {
eprintln!("Process failed: {}", message);
if let Some(stderr) = stderr {
eprintln!("stderr: {}", stderr);
}
}
Err(e) => eprintln!("Error: {}", e),
}
Testing
Run the test suite:
cargo test --workspace
Safety
These wrappers are designed with safety in mind:
- Path validation prevents command injection
- Proper escaping of filter strings
- Resource cleanup on drop
- Timeout support for all operations
- Graceful process termination
Platform Support
- Linux: Full support including hardware acceleration (VAAPI, VDPAU)
- macOS: Full support including VideoToolbox acceleration
- Windows: Full support including DXVA2/D3D11VA acceleration
Contributing
Contributions are welcome! Please ensure:
- Code follows Rust idioms and passes
cargo clippy - New features include tests and documentation
- Public APIs have doc comments with examples
- Changes maintain backward compatibility
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
at your option.
Acknowledgments
Built on top of the excellent FFmpeg project. These wrappers would not be possible without the hard work of the FFmpeg community.
Dependencies
~5–10MB
~173K SLoC