Skip to content

Rust development guide

This page covers getting started with the VMAFX Rust bindings.

Overview

The repository ships a Rust workspace at the repo root (Cargo.toml). Its first member is bindings/rust/vmafx-sys, the low-level FFI crate.

Crate Description
vmafx-sys Auto-generated raw FFI bindings + thin safe wrappers.

A higher-level vmafx crate is planned for a future PR.

Prerequisites

Rust toolchain

Install the stable toolchain via rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rustfmt clippy

The crate targets Rust 2021 edition. Any stable release from 1.65+ is sufficient.

libvmaf

vmafx-sys links against libvmaf.so at runtime and uses its headers at build time. You must have a compatible install of libvmaf before running cargo build.

# From the repo root:
meson setup build -Denable_cuda=false -Denable_sycl=false
ninja -C build
sudo ninja -C build install   # installs to /usr/local by default
sudo ldconfig                 # refresh the dynamic linker cache

Verify the install:

pkg-config --modversion libvmaf  # should print the library version
ls /usr/local/lib/libvmaf.so     # should exist

Option B — non-standard prefix

If you install to a prefix other than /usr/local, set:

export LIBVMAF_PREFIX=$HOME/.local
export PKG_CONFIG_PATH=$LIBVMAF_PREFIX/lib/pkgconfig
export LD_LIBRARY_PATH=$LIBVMAF_PREFIX/lib:$LD_LIBRARY_PATH

build.rs reads LIBVMAF_PREFIX to locate both the headers (used by bindgen) and the shared library (used by the linker).

Using vmafx-sys as a dependency

Add to your crate's Cargo.toml:

[dependencies]
vmafx-sys = { path = "<path-to-repo>/bindings/rust/vmafx-sys" }

Once the crate is published to crates.io, you will instead write:

[dependencies]
vmafx-sys = "0.1"

The safe vs sys API split

vmafx-sys exposes two layers.

Raw layer (use vmafx_sys::*)

Auto-generated by bindgen from libvmaf.h. Every C type, constant, and function is available. Use this layer when you need access to functionality not yet wrapped by the safe layer.

use vmafx_sys::{vmaf_version, CStr};
let v = unsafe { CStr::from_ptr(vmaf_version()) };

Safe layer (use vmafx_sys::safe::*)

Thin RAII wrappers that:

  • Manage object lifetimes automatically (VmafContext closes on drop, VmafModel destroys on drop).
  • Convert negative C error codes into Result<T, VmafxError>.
  • Confine unsafe to the actual FFI call sites only.
  • Mark all types Send.
use vmafx_sys::safe::{VmafContext, VmafModel, alloc_yuv420p_8bit, unref_picture};

let mut ctx = VmafContext::new()?;
let mut model = VmafModel::from_path("/usr/local/share/model/vmaf_v0.6.1.json")?;
ctx.use_features_from_model(&mut model)?;

// Queue frames...
let mut ref_pic = alloc_yuv420p_8bit(576, 324)?;
let mut dist_pic = alloc_yuv420p_8bit(576, 324)?;
// ... fill pic.data[0..3] with YUV plane bytes ...
ctx.read_pictures(&mut ref_pic, &mut dist_pic, 0)?;

ctx.flush()?;
let score = ctx.score_pooled(&mut model, 0, 0)?;

Building

# From repo root:
cargo build -p vmafx-sys

Running the smoke test

VMAFX_REPO=$(git rev-parse --show-toplevel) \
    LD_LIBRARY_PATH=/usr/local/lib \
    cargo run --example score

Expected output:

vmafx-sys version: 3.x.y-lusoris.N
Reference:  .../python/test/resource/yuv/src01_hrc00_576x324.yuv
Distorted:  .../python/test/resource/yuv/src01_hrc01_576x324.yuv
Model:      .../model/vmaf_v0.6.1.json
Frames processed: 240
Mean VMAF score:  76.6680
Score assertion PASSED (expected 76.6680)

Running tests

VMAFX_REPO=$(git rev-parse --show-toplevel) \
    LD_LIBRARY_PATH=/usr/local/lib \
    cargo test -p vmafx-sys --all-features

The integration test (tests/integration_test.rs) scores the Netflix golden YUV pair and asserts the mean VMAF equals 76.668 (places=4). If the YUV files are not present (e.g. a CI environment without test fixtures), the test skips gracefully.

Linting

cargo fmt -p vmafx-sys --check
cargo clippy -p vmafx-sys --all-targets -- -D warnings

These two gates run in CI on every PR touching bindings/rust/.

Environment variables reference

Variable Default Description
LIBVMAF_PREFIX /usr/local libvmaf install prefix. Used by build.rs.
VMAFX_REPO auto-detected from CARGO_MANIFEST_DIR Repo root; used to resolve test fixtures.
VMAFX_YUV_REF <VMAFX_REPO>/python/test/resource/yuv/src01_hrc00_576x324.yuv Reference YUV override.
VMAFX_YUV_DIST <VMAFX_REPO>/python/test/resource/yuv/src01_hrc01_576x324.yuv Distorted YUV override.
VMAFX_MODEL <VMAFX_REPO>/model/vmaf_v0.6.1.json Model path override.

Troubleshooting

error: could not find native library 'vmaf'

The linker cannot find libvmaf.so. Fix:

sudo ldconfig
# or
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

error: failed to run custom build command for vmafx-sys

bindgen failed to parse the header. Check that:

  1. LIBVMAF_PREFIX points to a directory containing include/libvmaf/libvmaf.h.
  2. clang / libclang-dev is installed.

cargo: error[E0425]: cannot find function ...

The installed libvmaf version is older than expected. Build from source (Option A above) rather than using the distro package.