How to Extract Frames from a Video at Specific Timestamps Using Claude Video

Claude Video's watch skill extracts exact frames at any timestamp you specify using the --timestamps flag, which calls extract_at_timestamps() in skills/watch/scripts/frames.py to perform FFmpeg-based seek and capture.

You can extract frames from a video at specific timestamps using Claude Video's watch skill, which supports local files and URLs with flexible time formatting. The workflow centers on the extract_at_timestamps() function in skills/watch/scripts/frames.py, invoked from the watch entry point in skills/watch/scripts/watch.py.

Passing Timestamps to the Watch Command

Use the --timestamps flag to supply a comma-separated list of times when running the watch command.

watch "https://youtu.be/ABC123" --timestamps "00:05,00:30,02:15"

The watch.py entry point parses this string through parse_timestamps()parse_time() in skills/watch/scripts/frames.py, converting human-readable times into seconds before extraction begins.

How Frame Extraction Works Internally

The extract_at_timestamps() function performs five sequential operations to generate frame images.

1. Prepare Output Directory

The function clears any existing cue_*.jpg files from the target directory to prevent collisions.

out_dir.mkdir(parents=True, exist_ok=True)
for existing in out_dir.glob("cue_*.jpg"):
    existing.unlink()

2. Clamp to Focus Window

Timestamps outside optional --start/--end ranges are filtered out. The logic uses lo = start_seconds or 0.0 and hi = end_seconds if end_seconds is not None else float("inf") to define valid windows.

3. Apply Frame Cap

When max_frames is set and more timestamps exist than the limit, the function calls _even_indices to evenly sample while preserving the first and last cues.

if max_frames is not None and len(in_window) > max_frames:
    indices = _even_indices(len(in_window), max_frames)
    selected = [in_window[i] for i in indices]

4. Execute FFmpeg Extraction

For each selected timestamp, the function builds and runs an FFmpeg command:

cmd = [
    "ffmpeg",
    "-ss", str(t),
    "-i", video_path,
    "-frames:v", "1",
    "-q:v", "2",
    "-y",
    str(out_path)
]
subprocess.run(cmd, check=True, capture_output=True)

This writes JPEG files prefixed with cue_ (e.g., cue_0001.jpg) to avoid conflicts with regular detail frames.

5. Return Metadata

The function returns a metadata dictionary containing counts of requested, selected, and dropped timestamps.

Supported Timestamp Formats

Claude Video accepts multiple time formats in the --timestamps argument:

  • Seconds only: 12 or 12.5
  • Minutes:Seconds: 01:30 or 01:30.250
  • Hours:Minutes:Seconds: 00:05:00 or 00:05:00.500

Fractional seconds are supported for precise frame alignment.

Combining Cue Frames with Detail Frames

After extraction, watch.py merges cue frames with regular detail frames through merge_frames() so both appear in the final markdown report. Cue frames retain their transcript-cue reason code, distinguishing them from automatically selected frames.

watch /path/to/video.mp4 \
  --timestamps "00:10,01:00,01:30,02:00" \
  --detail balanced \
  --max-frames 50

Programmatic API Usage

Import extract_at_timestamps directly for custom Python workflows:

from pathlib import Path
from skills.watch.scripts.frames import extract_at_timestamps

video = "/tmp/video.mp4"
out_dir = Path("/tmp/frames")
timestamps = [12.0, 30.5, 125.0]

frames, meta = extract_at_timestamps(
    video_path=video,
    out_dir=out_dir,
    timestamps=timestamps,
    resolution=512,
    max_frames=10
)

print("Extracted frames:", frames)
print("Metadata:", meta)

Key Source Files

File Purpose
skills/watch/scripts/watch.py Entry point parsing --timestamps and orchestrating extraction
skills/watch/scripts/frames.py Core extract_at_timestamps() implementation with FFmpeg logic
skills/watch/scripts/config.py Default detail levels and frame caps
skills/watch/scripts/download.py URL handling via YT-DLP
skills/watch/scripts/transcribe.py Subtitle parsing for transcript-derived timestamps

Summary

  • Use --timestamps "time1,time2,time3" to extract specific frames from any video source
  • Timestamps support seconds, MM:SS, or HH:MM:SS formats with optional decimals
  • The extract_at_timestamps() function in skills/watch/scripts/frames.py handles FFmpeg execution and file naming
  • Cue frames are prefixed with cue_ and merged with detail frames in final reports
  • Optional --start/--end windows and --max-frames caps control extraction scope

Frequently Asked Questions

What timestamp formats does Claude Video accept?

Claude Video accepts raw seconds (45.5), MM:SS (01:30), or HH:MM:SS (00:05:00) formats. Fractional seconds are supported for millisecond-precision frame extraction.

Where are extracted frames saved?

Frames are written to <work-dir>/frames/ alongside regular detail frames, using the cue_*.jpg naming convention to prevent clashes with automatically extracted frames.

Can I limit how many cue frames are extracted?

Yes. Pass --max-frames N to cap the total. When more timestamps are supplied than the cap, the system evenly samples across your list while preserving the first and last timestamps.

How do I extract frames from a YouTube video?

Provide the URL as the first argument to watch. The download.py module handles retrieval via YT-DLP before frame extraction proceeds:

watch "https://youtu.be/ABC123" --timestamps "00:30,01:15"

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →