Files
suaveplan/packages/media/video/video-thumbnails/src/runner/fluent-ffmpeg-runner.md
2026-05-27 23:47:53 +01:00

3.2 KiB
Raw Blame History

FluentFfmpegRunner

Purpose

Default FfmpegRunner implementation used by ThumbnailGenerator and SpriteSheetGenerator when no other runner is injected. It wraps fluent-ffmpeg and pins ffmpeg to the binary shipped by @ffmpeg-installer/ffmpeg, and ffprobe to @ffprobe-installer/ffprobe, so the package works on any host without requiring system ffmpeg/ffprobe to be on PATH. Every operation respects an optional AbortSignal by killing the underlying child process and rejecting with VIDEO_THUMBNAILS.ABORTED.

Features

  • Bundled ffmpeg + ffprobe binaries — zero system dependency.
  • Override-friendly: pass ffmpegPath and/or ffprobePath to point at a custom binary.
  • extract issues a single-frame ffmpeg pipeline with the canonical filter from buildScaleFilter and quality from buildQualityArgs.
  • tile issues the canonical fps=…,scale=…,tile=COLSxROWS sprite-sheet pipeline.
  • probe returns a strict ProbeResult with duration, dimensions, codec, fps, bitrate.
  • isAvailable spawns ffmpeg -version and resolves to true only on exit code 0.
  • Every call honours AbortSignal: command.kill("SIGKILL") on abort, then reject with ABORTED.

Usage: Basic

import { FluentFfmpegRunner } from "@suaveplan/video-thumbnails/runner";

const runner = new FluentFfmpegRunner();
const ok = await runner.isAvailable();

Usage: Advanced

import { FluentFfmpegRunner } from "@suaveplan/video-thumbnails/runner";

const runner = new FluentFfmpegRunner({
    ffmpegPath: "/usr/local/bin/ffmpeg-hwaccel",
    ffprobePath: "/usr/local/bin/ffprobe-hwaccel",
});
const controller = new AbortController();
setTimeout(() => controller.abort(), 250);
try {
    await runner.extract(
        {
            inputPath: "/data/big.mkv",
            outputPath: "/tmp/thumb.jpg",
            timestamp: "00:00:10",
            width: 640,
            height: 360,
            fit: "cover",
            format: "jpg",
            quality: 80,
        },
        controller.signal,
    );
} catch (error) {
    // VideoThumbnailsError { code: "VIDEO_THUMBNAILS.ABORTED" } when aborted.
}

API Reference

  • class FluentFfmpegRunner implements FfmpegRunner
    • constructor(options?: { ffmpegPath?: string; ffprobePath?: string })
    • isAvailable(signal?): Promise<boolean> — exit code 0 from ffmpeg -version.
    • extract(input, signal?): Promise<void> — single-frame extraction.
    • tile(input, signal?): Promise<void> — N×M sprite-sheet render.
    • probe(inputPath, signal?): Promise<ProbeResult> — ffprobe metadata.

Implementation Notes

run listens for end and error on the FfmpegCommand, tracks a settled flag so a late abort cannot double-resolve, and attaches the abort listener with { once: true } to keep event-emitter memory bounded. probe re-pins the ffprobe path on the module-level fluent-ffmpeg singleton before each call because ffmpeg.ffprobe (the top-level helper) does not consult per-instance state — without the re-pin the singleton would happily fall back to system ffprobe. The probe failure paths split into two: a real ffprobe crash (PROBE_FAILED) and a structurally invalid response (VIDEO_INVALID, raised when the file has no video stream or a non-positive duration).