ff-render
GPU compositing pipeline for real-time video preview, built on [wgpu]. Apply per-frame visual effects — colour grading, blending, masking, chroma key, YUV upload — in a linear render graph wired directly to ff-preview's PlayerRunner.
Project status (as of 2026-04-20): This crate is in an early phase. The high-level API is designed and reviewed by hand; AI is used as an accelerator to implement FFmpeg bindings efficiently. Code contributions are not expected at this time — questions, bug reports, and feature requests are welcome. See the main repository for full context.
Installation
[]
= "0.14"
# Enable GPU processing (requires wgpu-compatible hardware)
= { = "0.14", = ["wgpu"] }
Feature Flags
| Feature | Description | Default |
|---|---|---|
wgpu |
GPU processing via wgpu (Metal / Vulkan / DX12 / WebGPU) | no |
Without wgpu only the CPU fallback path is available via RenderGraph::process_cpu. The CPU path is suitable for unit tests, CI, and software-only environments.
CPU Path (no wgpu required)
All built-in nodes implement RenderNodeCpu, which processes raw RGBA bytes without any GPU dependency.
use ;
// Build a pipeline: boost brightness then multiply-blend with an overlay.
let overlay_rgba: = /* ... */ vec!;
let graph = new_cpu
.push_cpu
.push_cpu;
let input_rgba: = /* decoded frame */ vec!;
let output: = graph.process_cpu;
GPU Path (wgpu feature)
When the wgpu feature is enabled, nodes run on the GPU via RenderGraph::process_gpu. The same nodes implement both RenderNode (GPU) and RenderNodeCpu (CPU fallback).
use Arc;
use ;
async
Integration with ff-preview
GpuFrameSink implements ff_preview::FrameSink, wiring the render graph directly into a PlayerRunner pipeline.
use Arc;
use ;
use ;
async
Multi-Layer Compositor (wgpu feature)
Compositor is a stateful high-level compositor that accepts a Vec<FrameLayer>, sorts layers by z_order, applies per-layer transforms and blend modes, and returns the composited wgpu::Texture.
use Arc;
use ;
async
Built-in Nodes
| Node | CPU | GPU | Description |
|---|---|---|---|
ColorGradeNode |
✓ | ✓ | Brightness, saturation, contrast, hue shift, colour temperature |
ScaleNode |
passthrough | ✓ | Resize to target dimensions (Bilinear / Nearest) |
OverlayNode |
✓ | ✓ | Alpha-composite a static overlay image over the base |
CrossfadeNode |
✓ | ✓ | Linear crossfade between base and a target image |
BlendModeNode |
✓ | ✓ | Photoshop-style blend modes with per-node opacity |
TransformNode |
passthrough | ✓ | Translate, rotate, and scale the frame in UV space |
ChromaKeyNode |
✓ | ✓ | Chroma key (green screen) — removes a specified colour range |
ShapeMaskNode |
✓ | ✓ | Binary alpha mask from an RGBA mask image |
LumaMaskNode |
✓ | ✓ | Luma-derived alpha mask — bright = keep, dark = cut |
AlphaMatteNode |
✓ | ✓ | Alpha-composite foreground over a background using fg alpha |
YuvUploadNode |
✓ | ✓ | Upload native YUV planes (4:2:0 / 4:2:2 / 4:4:4) without sws_scale |
Blend Modes
BlendModeNode supports the following modes via BlendMode:
Normal · Multiply · Screen · Overlay · Darken · Lighten · ColorDodge · ColorBurn · HardLight · SoftLight · Difference · Exclusion
YUV Upload
YuvUploadNode accepts planar YUV data directly, bypassing sws_scale:
use ;
let mut node = new;
node.set_planes;
let graph = new_cpu.push_cpu;
let rgba = graph.process_cpu;
Supported formats: Yuv420p, Yuv422p, Yuv444p.
Error Handling
All fallible operations return RenderError:
use RenderError;
match result
Crate stack
ff-sys → ff-common → ff-format → ff-preview → ff-render
ff-render depends on ff-preview for the FrameSink trait and VideoFrame type. It has no direct dependency on ff-decode or ff-filter — frames can come from any source.