ff-sys 0.17.0

Low-level FFmpeg FFI bindings and owned RAII safe wrappers for the ff-* crate family
Documentation

ff-sys

Why ff-sys?

Crates like ffmpeg-sys-next, ffmpeg-next, and rsmpeg already wrap FFmpeg well. ff-sys does not try to replace them; it is the purpose-built FFI base for the ff-* / avio family, optimised for that one job:

  • Version and ABI control: it targets FFmpeg 7.x / 8.x directly and owns exactly which versions and ABI quirks it supports (for example the SWS_* flag change between libswscale 8 and 9, handled via the ffmpeg8 cfg).
  • Self-contained build detection: the build script locates FFmpeg per platform on its own (vcpkg via VCPKG_ROOT on Windows, pkg-config on Linux, Homebrew on macOS) and drives bindgen through LIBCLANG_PATH, so the family is not bound to another crate's build-script assumptions.
  • An implementation detail, not a public API: application code uses the safe ff-* crates, never ff-sys directly, so "mature vs. new" matters less for a base you are not meant to depend on.

Building your own project on FFmpeg directly? The crates above are excellent choices. Building on avio? You already get ff-sys transitively; reach for the safe ff-* crates.

Installation Prerequisites

FFmpeg 7.x or 8.x development libraries must be available on your system before building any crate in this workspace. FFmpeg 6.x is not supported (the SWS_* flags differ in API shape); 8.x is detected automatically via the SwsFlags enum (the ffmpeg8 cfg).

Windows

Install FFmpeg via vcpkg:

vcpkg install ffmpeg:x64-windows

The build script reads VCPKG_ROOT to locate the installation (defaulting to C:\vcpkg) and expects FFmpeg under <VCPKG_ROOT>\installed\x64-windows. bindgen also requires libclang: set LIBCLANG_PATH to your LLVM bin directory (containing libclang.dll) if it is not in a standard location such as C:\Program Files\LLVM\bin.

Linux

Detected via pkg-config:

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

If FFmpeg is installed in a non-standard location, set PKG_CONFIG_PATH to its lib/pkgconfig directory.

macOS

brew install ffmpeg

Platform Support

Platform Detection Notes
Windows vcpkg (VCPKG_ROOT) ffmpeg:x64-windows triplet; LIBCLANG_PATH for bindgen
Linux pkg-config Dev packages (-dev) must be installed
macOS Homebrew, pkg-config Auto-detects /opt/homebrew or /usr/local, falls back to pkg-config

Safe layer

Alongside the raw bindgen output, ff-sys ships a hand-written safe layer that isolates the most error-prone FFmpeg call sequences. It is built from owned RAII types: each wraps a NonNull<T>, is neither Copy nor Clone, and frees its FFmpeg resource exactly once on Drop, so a leak or double-free is not expressible in safe code (ADR-0003):

Owned type Wraps
Frame AVFrame (owned; drops once)
Packet AVPacket (owned; drops once)
CodecContext AVCodecContext, codec open/close + send/receive drain-flush
FormatContext AVFormatContext, demux/mux lifecycle
ScaleContext SwsContext, pixel-format conversion
ResampleContext SwrContext, sample-format / channel-layout conversion
HwDeviceContext Hardware-acceleration device context
AvError A typed error over FFmpeg's c_int return codes

The owned types expose no raw pointers across their public API: the as_ptr / as_mut_ptr accessors are pub(crate), sealed so only the ff-* crates in this workspace reach the raw handle (guarded by tests/seal.rs, #1506). As a result the entire ff-* family is raw-pointer-free at its boundaries. Free functions grouped under the avcodec, avformat, swscale, and swresample modules cover the remaining stateless helpers.

Everything here is public (pub) but meant for use by the higher-level ff-* crates rather than for direct consumption.

Usage

ff-sys is normally consumed transitively through the safe ff-* crates. A few of the safe helpers are self-contained, however, and can be called directly:

use ff_sys::{av_error_string, avformat, error_codes};

fn main() {
    // Convert an FFmpeg error code into a readable message.
    let msg = av_error_string(error_codes::ENOMEM);
    println!("ENOMEM: {msg}");

    // Query the linked FFmpeg build for optional protocol support.
    let has_srt = avformat::srt_available();
    println!("libsrt available: {has_srt}");
}

Most of the surface is raw FFI and therefore unsafe; the safe wrappers above and the ff-* crates exist so that application code never has to touch it directly.

MSRV

Rust 1.93.0 (edition 2024).

License

MIT OR Apache-2.0