first commit
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# `SpriteSheetGenerator`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`SpriteSheetGenerator` renders an N×M grid of thumbnails into a single image using ffmpeg's
|
||||
`tile` filter. A sprite sheet is the canonical artefact for video scrubbers and timeline
|
||||
previews — one HTTP fetch, one decode, then arbitrary in-page hovers slide a `background-
|
||||
position`. The generator delegates the actual ffmpeg invocation to an injectable
|
||||
`FfmpegRunner` (default: `FluentFfmpegRunner` with bundled ffmpeg/ffprobe binaries) and
|
||||
auto-detects video duration via the runner's `probe` when the caller does not pass one
|
||||
explicitly.
|
||||
|
||||
## Features
|
||||
|
||||
- Configurable grid: `columns`, `rows`, `thumbnailWidth`, `thumbnailHeight`, `interval`,
|
||||
`format`.
|
||||
- Auto-detection of video duration via `runner.probe` when caller omits `duration`.
|
||||
- Frame count is capped at `columns × rows` and at `floor(duration / interval)` — whichever
|
||||
is smaller — so short videos do not produce padded grids.
|
||||
- Zod boundary validation with code-specific failures (`INVALID_DIMENSIONS`,
|
||||
`FORMAT_UNSUPPORTED`, `INVALID_OPTIONS`).
|
||||
- OTel: `video_thumbnails.sprite_sheet.duration_ms{outcome,format}` plus
|
||||
`video_thumbnails.sprite_sheet.frames{format}`.
|
||||
- `AbortSignal` propagated through every call; aborts surface as `VIDEO_THUMBNAILS.ABORTED`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { SpriteSheetGenerator } from "@suaveplan/video-thumbnails/sprite-sheet";
|
||||
|
||||
const generator = new SpriteSheetGenerator();
|
||||
const result = await generator.generate("/data/clip.mp4", "/tmp/sprite.jpg");
|
||||
console.log(result.frameCount, result.columns, result.rows);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { SpriteSheetGenerator } from "@suaveplan/video-thumbnails/sprite-sheet";
|
||||
|
||||
const generator = new SpriteSheetGenerator({
|
||||
columns: 8,
|
||||
rows: 6,
|
||||
thumbnailWidth: 192,
|
||||
thumbnailHeight: 108,
|
||||
interval: 2,
|
||||
format: "jpg",
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
const result = await generator.generate(
|
||||
"/data/long-movie.mp4",
|
||||
"/tmp/movie-sprite.jpg",
|
||||
7200,
|
||||
controller.signal,
|
||||
);
|
||||
// result.width === 8 * 192, result.height === 6 * 108, result.frameCount === 48
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class SpriteSheetGenerator`
|
||||
- `constructor(config?: SpriteSheetConfigInput, runner?: FfmpegRunner)`
|
||||
- `generate(inputPath, outputPath, duration?, signal?): Promise<SpriteSheetResult>`
|
||||
|
||||
Throws `VideoThumbnailsError` on `INVALID_DIMENSIONS`, `FORMAT_UNSUPPORTED`,
|
||||
`INVALID_OPTIONS`, `VIDEO_INVALID`, `EXTRACT_FAILED`, `PROBE_FAILED`, or `ABORTED`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`rows` is recomputed against the actual `frameCount` (rather than blindly using the configured
|
||||
upper bound) so a 5-second clip with a 10-frame grid does not produce four trailing black
|
||||
cells. The generator never directly invokes ffmpeg — every call routes through the supplied
|
||||
runner so consumers can swap in a hardware-accelerated or hosted variant without touching
|
||||
this class. OTel records before throwing on failure so dashboards distinguish counts from
|
||||
timings even on errors. `duration` is validated when passed explicitly: non-finite or
|
||||
non-positive values are rejected with `VIDEO_INVALID`, mirroring the probe path.
|
||||
Reference in New Issue
Block a user