Skip to main content
Glama
  ╔══════════════════════════════════════════════════════╗
  ║                                                      ║
  ║   ████████ ████████ ██    ██ ██████  ████████  ████  ║
  ║   ██       ██       ███  ███ ██   ██ ██       ██     ║
  ║   ██████   ██████   ██ ██ ██ ██████  ██████   ██  ██ ║
  ║   ██       ██       ██    ██ ██      ██       ██  ██ ║
  ║   ██       ██       ██    ██ ██      ████████  ████  ║
  ║                                                      ║
  ║   ██████  ████████ ██    ██ ██████  ████████ ██████  ║
  ║   ██   ██ ██       ███   ██ ██   ██ ██       ██   ██ ║
  ║   ██████  ██████   ██ ██ ██ ██   ██ ██████   ██████  ║
  ║   ██   ██ ██       ██  ████ ██   ██ ██       ██   ██ ║
  ║   ██   ██ ████████ ██    ██ ██████  ████████ ██   ██ ║
  ║                                                      ║
  ║        ██████  ██████   ████                         ║
  ║        ██   ██ ██   ██ ██  ██                        ║
  ║        ██████  ██████  ██  ██                        ║
  ║        ██      ██   ██ ██  ██                        ║
  ║        ██      ██   ██  ████                         ║
  ║                                                      ║
  ║  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░ 8 WRKRS    ║
  ║  GPU: AUTO   DASHBOARD: LIVE   CONCAT: INSTANT       ║
  ╚══════════════════════════════════════════════════════╝

ffmpeg-render-pro

npm version License: MIT Platform: Cross-platform Node.js MCP Server

Parallel video rendering with live dashboard, GPU auto-detection, checkpoint system, and stream-copy concat. Includes an MCP server, a Claude Code skill, and a CLI.

Built by Beeswax Pat · Free and open source forever

Features

  • Parallel rendering: Split frames across N worker threads, concat with zero re-encoding

  • GPU auto-detection: Probes NVENC, VideoToolbox, AMF, VA-API, QSV with 1-frame validation

  • Live dashboard: Auto-opens in your browser with per-worker progress, FPS chart, ETA

  • Checkpoint system: 93% reduction in fast-forward overhead for long renders

  • Color grading: 5 built-in presets (noir, warm, cool, cinematic, vintage) plus custom filters

  • Audio merge: Combine video + audio with loudness normalization, no video re-encode

  • Deterministic output: Seeded RNG ensures parallel workers produce identical results to sequential

  • MCP server: Model Context Protocol server with 6 tools, works with Claude Code, Claude Desktop, and any MCP client

  • Cross-platform: Windows, macOS, Linux. Any GPU or CPU-only. Requires Node.js >= 18 plus ffmpeg.

Related MCP server: ffmpeg-mcp

What's new in v1.4.0

A Claude Fable 5 review pass. Fully backward-compatible: every CLI command, API signature, MCP tool name, and worker contract from 1.3.x works unchanged.

  • GPU detection fixed on modern ffmpeg. The validation probe frame was below NVENC's minimum resolution, so NVIDIA systems silently fell back to CPU encoding. If detect-gpu told you "NO (CPU fallback)" and you have a GPU, run it again on 1.4.0.

  • Example worker frame generation is 3.1x faster (13.1ms to 4.2ms per 1080p frame), with byte-identical output.

  • Concurrent renders into the same output directory no longer collide on temp files

  • mergeAudio always keeps the NEW audio track, even when the video already had one

  • New CLI flags: --no-dashboard, --no-open, --port, --linger-ms; --seed=0 and fractional --duration now work

  • colorGrade can keep the soundtrack (keepAudio: true / MCP keep_audio)

  • New optional MCP params: max_workers, dashboard_port, linger_ms, crf, keep_audio

  • New end-to-end suite renders real videos and verifies them with ffprobe + framemd5; 49 tests grew to 81

See CHANGELOG.md for the complete list.

Requirements

  • Node.js >= 18

  • ffmpeg installed and on PATH

Install

# Global install gives you the ffmpeg-render-pro + ffmpeg-render-pro-mcp binaries
npm install -g ffmpeg-render-pro

# Or clone the repo directly
git clone https://github.com/beeswaxpat/ffmpeg-render-pro.git
cd ffmpeg-render-pro

Quick Start

# System info (workers, RAM, CPU, ffmpeg version)
ffmpeg-render-pro info

# Probe hardware encoders
ffmpeg-render-pro detect-gpu

# 5s benchmark render (dashboard auto-opens at http://127.0.0.1:8080)
ffmpeg-render-pro benchmark

# Longer render, custom resolution
ffmpeg-render-pro benchmark --duration=30 --width=1080 --height=1920 --fps=30

# Force CPU / GPU encoding
ffmpeg-render-pro detect-gpu --cpu
ffmpeg-render-pro detect-gpu --gpu

CLI

ffmpeg-render-pro info                # System snapshot
ffmpeg-render-pro detect-gpu          # Probe hardware encoders
ffmpeg-render-pro render <worker.js>  # Render with your worker script
ffmpeg-render-pro benchmark           # Quick 5s test render
ffmpeg-render-pro version             # Print the installed version

Dashboard control flags for render and benchmark: --no-dashboard (disable entirely), --no-open (serve but don't open a browser), --port=8080, and --linger-ms=30000 (how long the dashboard stays up after completion; 0 exits immediately). Run ffmpeg-render-pro with no arguments for the full flag reference.

API

const {
  renderParallel,    // Core: parallel rendering engine
  createEncoder,     // Pipe raw frames to ffmpeg
  detectGPU,         // Cross-platform GPU detection
  getConfig,         // Auto-tune workers, codec selection
  concatSegments,    // Stream-copy segment joining
  colorGrade,        // Apply color grades (presets or custom)
  mergeAudio,        // Combine video + audio
  startDashboard,    // Live progress dashboard
  saveCheckpoint,    // Checkpoint serialization
  loadCheckpoint,    // Checkpoint restoration
} = require('ffmpeg-render-pro');

renderParallel(options)

The main entry point. Splits a render across workers, shows a live dashboard, and produces a final MP4.

await renderParallel({
  workerScript: './my-worker.js',  // Your frame generator
  outputPath: './output.mp4',
  width: 1920,
  height: 1080,
  fps: 60,
  duration: 60,         // seconds
  title: 'My Render',
  autoOpen: true,       // auto-open dashboard in browser
  maxWorkers: 8,        // cap for auto worker count (override with workerCount)
  dashboardLingerMs: 0, // 0 = resolve immediately; CLI default keeps it up 30s
});

Width and height must be even (the pipeline encodes yuv420p). For library use, set dashboardLingerMs: 0 so the call resolves without holding the process open. renderParallel resolves with { outputPath, elapsed, totalFrames, avgFps }. Set FFMPEG_RENDER_PRO_DEBUG=1 in the environment for full stack traces on error.

Writing a Worker

Workers receive frame ranges via workerData and pipe raw BGRA frames to ffmpeg:

const { workerData, parentPort } = require('worker_threads');
const { spawn } = require('child_process');

const { width, height, fps, startFrame, endFrame, segmentPath, workerId } = workerData;

// Spawn ffmpeg encoder
const ffmpeg = spawn('ffmpeg', [
  '-y', '-f', 'rawvideo', '-pixel_format', 'bgra',
  '-video_size', `${width}x${height}`, '-framerate', String(fps),
  '-i', 'pipe:0',
  '-c:v', 'libx264', '-preset', 'fast', '-crf', '20',
  '-pix_fmt', 'yuv420p', '-movflags', '+faststart',
  segmentPath,
], { stdio: ['pipe', 'pipe', 'pipe'] });

const buffer = Buffer.alloc(width * height * 4);

for (let f = startFrame; f < endFrame; f++) {
  // Fill buffer with your frame data (BGRA format)
  renderMyFrame(f, buffer);

  // Write with backpressure
  const ok = ffmpeg.stdin.write(buffer);
  if (!ok) await new Promise(r => ffmpeg.stdin.once('drain', r));

  // Report progress
  parentPort.postMessage({ type: 'progress', workerId, pct: ..., fps: ..., frame: ..., eta: ... });
}

ffmpeg.stdin.end();
ffmpeg.on('close', () => parentPort.postMessage({ type: 'done', workerId }));

See examples/basic-worker.js for a complete working example.

Worker data (injected via worker_threads workerData): width, height, fps, seed, startFrame, endFrame, segmentPath, workerId, totalFrames, duration, plus anything you pass in renderParallel({ workerData }).

Messages a worker posts to the parent via parentPort.postMessage(...):

Message

When

Fields

{ type: 'progress' }

periodically while encoding

workerId, pct, fps, frame, eta

{ type: 'fast-forward-start' }

before replaying state up to startFrame (optional)

workerId, frames

{ type: 'done' }

after the segment is fully written (required)

workerId

{ type: 'error' }

on failure

workerId, error

Each worker writes its frame range to segmentPath; the renderer stream-copy concats the segments in order.

Post-processing API

Use these directly, or via the CLI and MCP tools. Video is stream-copied where possible, so there is no quality loss.

const { colorGrade, mergeAudio, concatSegments } = require('ffmpeg-render-pro');

// Color grade with a built-in preset (noir, warm, cool, cinematic, vintage)
await colorGrade({ inputPath: 'raw.mp4', outputPath: 'graded.mp4', preset: 'cinematic' });

// ...or a custom ffmpeg -vf filter chain
await colorGrade({ inputPath: 'raw.mp4', outputPath: 'graded.mp4', filter: 'eq=contrast=1.08:saturation=0.9', crf: 18 });

// Keep the soundtrack through the grade (default strips audio)
await colorGrade({ inputPath: 'final.mp4', outputPath: 'graded.mp4', preset: 'noir', keepAudio: true });

// Merge audio: video is stream-copied, audio encoded to AAC. loop + loudnorm are optional.
await mergeAudio({ videoPath: 'graded.mp4', audioPath: 'track.mp3', outputPath: 'final.mp4', bitrate: 320, loop: true, normalize: true });

// Concatenate same-codec, same-resolution segments with stream copy (instant)
await concatSegments(['part-000.mp4', 'part-001.mp4'], 'joined.mp4');

Checkpoints (long renders)

For multi-hour renders, pre-generate state snapshots so each worker replays only the frames since the nearest checkpoint instead of from frame 0.

const { generateCheckpoints, loadCheckpoint, restoreCheckpoint } = require('ffmpeg-render-pro');

// One-time update-only pass: advance your systems and snapshot every `interval` frames
generateCheckpoints({ systems, totalFrames: 432000, fps: 60, checkpointDir: './.checkpoints', interval: 60000 });

// Inside a worker: jump to the nearest snapshot at or below startFrame
const cp = loadCheckpoint('./.checkpoints', startFrame);
if (cp) {
  const resumeFrame = restoreCheckpoint(cp, systems); // returns the snapshot's frame number
  // fast-forward systems from resumeFrame to startFrame, then render
}

systems is an object of named modules, each implementing getState() and setState() (plus update(dt) for generateCheckpoints).

Modules

Module

Purpose

parallel-renderer

N-worker thread pool with progress tracking

encoder

Raw frame pipe to ffmpeg with backpressure

gpu-detect

Cross-platform hardware encoder discovery + validation

config

Auto-tune workers based on resolution, RAM, CPU

concat

Stream-copy segment joining (instant)

color-grade

ffmpeg video filter presets + custom chains

audio-merge

Video + audio merge with loudnorm support

dashboard-server

Zero-dep HTTP server with auto-open browser

progress

Per-worker terminal + JSON progress tracking

checkpoint

State serialization for long renders

Benchmarks

Run your own:

node examples/render-test.js --duration=5
node examples/render-test.js --duration=30
node examples/render-test.js --duration=60 --width=1080 --height=1920

Tests

npm test           # smoke suite + MCP stdio handshake + end-to-end renders
npm run test:smoke # smoke suite only
npm run test:mcp   # MCP server handshake only
npm run test:e2e   # real renders verified with ffprobe + framemd5

A zero-dependency suite (81 tests) covering module exports, input validation (including odd-dimension and worker-count math), dashboard path-safety (traversal + null-byte + double-encoding vectors), checkpoint round-trip and corruption fallback, and the MCP server stdio handshake. The e2e suite renders real videos and checks codec, dimensions, exact frame counts, same-seed determinism (framemd5), concat, color grades, and audio merges; it skips itself cleanly on machines without ffmpeg.

MCP Server

ffmpeg-render-pro includes a Model Context Protocol (MCP) server with 6 tools. Works with Claude Code, Claude Desktop, and any MCP client.

Add to Claude Code

# After `npm install -g ffmpeg-render-pro` the MCP binary is on your PATH:
claude mcp add --transport stdio ffmpeg-render-pro -- ffmpeg-render-pro-mcp

# Or without global install (uses npx):
claude mcp add --transport stdio ffmpeg-render-pro -- npx --yes --package=ffmpeg-render-pro ffmpeg-render-pro-mcp

Add to Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "ffmpeg-render-pro": {
      "command": "ffmpeg-render-pro-mcp"
    }
  }
}

Or, if you prefer not to install globally:

{
  "mcpServers": {
    "ffmpeg-render-pro": {
      "command": "npx",
      "args": ["--yes", "--package=ffmpeg-render-pro", "ffmpeg-render-pro-mcp"]
    }
  }
}

MCP Tools

Tool

Description

detect_gpu

Probe hardware encoders (NVENC, VideoToolbox, AMF, VA-API, QSV)

system_info

Show CPU cores, RAM, recommended workers, ffmpeg version

render_video

Parallel render with live dashboard

color_grade

Apply presets (noir, warm, cool, cinematic, vintage) or custom filters

merge_audio

Combine video + audio with loudness normalization

concat_videos

Stream-copy join multiple videos (instant, no re-encode)

Each tool's full input schema (parameter names, types, defaults) is advertised by the server at runtime via the MCP tools/list method, so an agent can introspect it directly. render_video also accepts dashboard, auto_open, max_workers, dashboard_port, and linger_ms for headless or tuned use; color_grade accepts crf and keep_audio.

Claude Code Skill

This repo includes a ready-to-use Claude Code skill. To install it, copy the skill folder into your Claude skills directory:

# macOS / Linux
cp -r .claude/skills/ffmpeg-render-pipeline ~/.claude/skills/

# Windows
xcopy .claude\skills\ffmpeg-render-pipeline %USERPROFILE%\.claude\skills\ffmpeg-render-pipeline\ /E /I

Once installed, Claude Code will automatically use the skill when you ask it to render video or audio with ffmpeg.

Security Notes

  • Dashboard server binds to 127.0.0.1 only. It is never reachable from other machines on your network.

  • No telemetry, no phone-home, no CDN loads. Dashboard runs entirely from local files using system fonts.

  • MCP server is a local-filesystem tool. When wired into an AI agent, it will render, read, and write files anywhere the current user has access. Treat it like any other filesystem-enabled tool: only run it with a trusted agent, and consider restricting the process's working directory if you use it with untrusted prompts.

  • Stream-copy concat uses temp files under os.tmpdir(). Output paths you pass are still written as-is, so make sure your output path is where you want it.

Changelog

See CHANGELOG.md for the full release history.

License

MIT

Author

Beeswax Pat

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/beeswaxpat/ffmpeg-render-pro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server