- name
- extract-frames-skill
- description
- Extract frames from a video at a fixed sample rate using ffmpeg, saving them as timestamp-named image files. Use when asked to capture stills, extract frames, sample frames, or turn a video into a sequence of images.
# Extract Frames
Sample frames from a video at a constant rate with ffmpeg and save each frame
named by its timestamp in seconds (zero-padded so filenames sort correctly).
## Defaults
- fps: `3`
- format: `jpg` (quality `-q:v 2`)
- output dir: `./frames` (created if missing)
- filename pattern: `SSSSS.mmm.ext` — seconds, zero-padded to cover the video's
duration, with 3 decimal places (milliseconds), e.g. `08177.333.jpg`
Ask the user before running if any of these should differ:
1. **fps** — how many frames per second to sample (default 3)
2. **format** — `jpg` or `png` (default jpg; use png for lossless/transparency)
3. **output directory** — default `./frames`
4. Optionally: a specific time range (`-ss` / `-to`) instead of the whole video
If the user doesn't specify, use the defaults without prompting further.
## Workflow
1. Confirm the input video path exists (`ls` or `ffprobe`).
2. Get the video duration to determine zero-padding width:
```
ffprobe -v error -select_streams v:0 -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 input.mp4
```
Integer-seconds digit count = `len(str(int(duration)))`, minimum 5 digits.
Total printf width = digits + 1 (decimal point) + 3 (decimals).
3. Create the output directory: `mkdir -p frames`
4. Extract frames sequentially with the fps filter (this guarantees frames land
at exact `index/fps` second boundaries):
```
ffmpeg -hide_banner -loglevel error -i input.mp4 \
-vf fps=<FPS> -q:v 2 frames/tmp_%06d.<ext>
```
(Drop `-q:v 2` for png.)
5. Rename each `tmp_NNNNNN.ext` to its timestamp. For 0-indexed frame `i`,
timestamp = `i / FPS` seconds. Example bash loop (adjust width `W` from
step 2, default 9 for `%09.3f`):
```bash
cd frames
for f in tmp_*.<ext>; do
n=$(echo "$f" | sed -E 's/tmp_0*([0-9]+)\.<ext>/\1/')
idx=$((10#$n - 1))
ts=$(awk -v i="$idx" -v fps="<FPS>" 'BEGIN{printf "%0<W>.3f", i/fps}')
mv "$f" "${ts}.<ext>"
done
```
6. Report frame count and a sample of filenames (first/last few, sorted).
## Notes
- Never use ffmpeg's `-frame_pts` for this — it emits pts in the container's
internal timebase, not seconds, and isn't human-readable.
- The `fps` filter (not `-r` on output alone) is what guarantees evenly spaced,
deterministic sample points regardless of the source frame rate.
- For very long videos, extraction can take a while; run with a generous or no
timeout.
Ver no GitHub