# `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 ```ts import { FluentFfmpegRunner } from "@suaveplan/video-thumbnails/runner"; const runner = new FluentFfmpegRunner(); const ok = await runner.isAvailable(); ``` ## Usage: Advanced ```ts 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` — exit code 0 from `ffmpeg -version`. - `extract(input, signal?): Promise` — single-frame extraction. - `tile(input, signal?): Promise` — N×M sprite-sheet render. - `probe(inputPath, signal?): Promise` — 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).