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

> Learn how to extract frames from a video at specific timestamps using Claude Video's watch skill. Easily capture exact frames with the --timestamps flag and FFmpeg.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: how-to-guide
- Published: 2026-07-11

---

**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`](https://github.com/bradautomates/claude-video/blob/main/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`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py), invoked from the `watch` entry point in [`skills/watch/scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/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.

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

```

The [`watch.py`](https://github.com/bradautomates/claude-video/blob/main/watch.py) entry point parses this string through `parse_timestamps()` → `parse_time()` in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/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.

```python
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.

```python
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:

```python
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`](https://github.com/bradautomates/claude-video/blob/main/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.

```bash
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:

```python
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`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/watch.py) | Entry point parsing `--timestamps` and orchestrating extraction |
| [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) | Core `extract_at_timestamps()` implementation with FFmpeg logic |
| [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py) | Default detail levels and frame caps |
| [`skills/watch/scripts/download.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/download.py) | URL handling via YT-DLP |
| [`skills/watch/scripts/transcribe.py`](https://github.com/bradautomates/claude-video/blob/main/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`](https://github.com/bradautomates/claude-video/blob/main/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`](https://github.com/bradautomates/claude-video/blob/main/download.py) module handles retrieval via YT-DLP before frame extraction proceeds:

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

```