# How Auto-FPS Is Calculated Based on Video Length and Budget Caps in Claude-Video

> Learn how Claude-Video calculates auto-fps using video length and budget caps. Discover the frame rate mapping and limits applied for optimal video generation.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-08-10

---

**The `claude-video` repository automatically determines frame rates by mapping video duration to preset target frame counts, then clamping the result against a user-defined `max_frames` budget and a global `MAX_FPS` limit of 2.0.**

The **auto-fps calculation** is a core feature of the `bradautomates/claude-video` project, designed to balance visual coverage with downstream LLM token costs. In [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py), the system implements duration-aware heuristics that prioritize dense sampling for short videos while respecting strict upper bounds on total frames extracted.

## Core Constants and Constraints

The auto-fps system operates within hard limits defined at the module level in [[`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py)](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py):

- `MAX_FPS = 2.0` — the absolute frame rate ceiling regardless of video length
- `MAX_READ_DIMENSION` — constrains resolution during extraction

These constants ensure predictable performance and prevent excessive frame generation that would overwhelm vision-language models.

## The `_clamp_fps` Helper Function

All fps calculations flow through `_clamp_fps()`, which enforces the budget cap. This function:

1. Receives a proposed fps, video duration, and `max_frames` budget
2. Clamps the fps to `MAX_FPS` if exceeded
3. Computes target frames as `fps × duration`
4. Returns the lesser of calculated frames or `max_frames`, with a minimum of 1

```python

# From skills/watch/scripts/frames.py, lines 49-52

def _clamp_fps(fps, duration_seconds, max_frames):
    fps = min(fps, MAX_FPS)
    target = int(fps * duration_seconds)
    return fps, min(target, max_frames)

```

## Full-Video Auto-FPS: `auto_fps()`

For processing entire videos, `auto_fps(duration_seconds, max_frames)` selects target frames based on duration tiers:

| Duration | Target Frames (before budget cap) |
|----------|-----------------------------------|
| ≤ 30 seconds | `max(12, round(duration))` |
| ≤ 60 seconds | **40** |
| ≤ 3 minutes | **60** |
| ≤ 10 minutes | **80** |
| > 10 minutes | `max_frames` (full budget) |

```python

# Example: 2-minute video with 100-frame budget

from skills.watch.scripts.frames import auto_fps

fps, target = auto_fps(duration_seconds=120, max_frames=100)

# Returns: fps=0.67, target=80

```

For invalid durations (≤ 0), the function falls back to **1 fps** and **1 frame**.

## Focused-Range Auto-FPS: `auto_fps_focus()`

When users specify time ranges (e.g., `00:01:00-00:01:30`), the system applies denser sampling via `auto_fps_focus()`:

| Duration | Target Frames (before budget cap) |
|----------|-----------------------------------|
| ≤ 5 seconds | `max(10, round(duration × 6))` |
| ≤ 15 seconds | `max(30, round(duration × 4))` |
| ≤ 30 seconds | **60** |
| ≤ 60 seconds | **80** |
| > 60 seconds | `max_frames` (full budget) |

This prioritizes granular detail for brief segments that users explicitly flag as important.

```python

# Example: 8-second focused clip with 100-frame budget

from skills.watch.scripts.frames import auto_fps_focus

fps, target = auto_fps_focus(duration_seconds=8, max_frames=100)

# Returns fps=6.0 initially, but _clamp_fps reduces to MAX_FPS=2.0

# target becomes min(16, 100) = 16 frames

```

## End-to-End Execution Flow

The auto-fps calculation integrates into the video processing pipeline as follows:

1. **Metadata extraction** — `get_metadata()` calls `ffprobe` to obtain `duration_seconds`
2. **Function selection** — [`scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/scripts/watch.py) chooses `auto_fps` or `auto_fps_focus` based on whether a time range was specified
3. **Rate calculation** — The selected function returns `(fps, target_frames)`
4. **Frame extraction** — `extract()` invokes `ffmpeg` with `-vf fps={fps}`, writing at most `target_frames` frames

```bash

# Command-line usage with explicit budget

python -m skills.watch.scripts.watch path/to/video.mp4 --budget 50

```

## Budget Cap Behavior in Practice

The `max_frames` parameter acts as a hard ceiling. Consider a 30-minute video with default settings:

```python
fps, target = auto_fps(duration_seconds=1800, max_frames=100)

# Duration > 600s triggers "else" branch: target = max_frames = 100

# fps = min(100/1800, MAX_FPS) = 0.056 → effectively sampling every ~18 seconds

```

Without the budget cap, long videos would generate prohibitive frame counts. The tiered heuristics ensure short videos receive adequate coverage while scaling gracefully to arbitrarily long content.

## Summary

- **`MAX_FPS = 2.0`** caps absolute frame rate regardless of duration
- **`auto_fps()`** applies tiered targets for full videos: 12–40–60–80–budget
- **`auto_fps_focus()`** applies denser sampling for user-specified ranges: 10–30–60–80–budget
- **`_clamp_fps()`** enforces both the fps ceiling and frame budget in all cases
- **Duration ≤ 0** triggers safe fallback to 1 fps, 1 frame
- **All logic is deterministic** and located in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py)

## Frequently Asked Questions

### What happens if my video is shorter than 1 second?

The `auto_fps` function detects `duration_seconds ≤ 0` and falls back to **1 fps with 1 frame** output. This prevents division errors and ensures at least one representative frame is extracted.

### Why is MAX_FPS capped at 2.0 instead of higher values?

According to the `claude-video` source code, the 2 fps limit balances temporal resolution against vision-language model token costs. Higher rates rarely improve understanding for most video content while significantly increasing processing overhead.

### How do I force a specific frame rate instead of auto-fps?

The current implementation does not expose manual fps override in the CLI. You would need to modify [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) to bypass `auto_fps`/`auto_fps_focus` and pass a hardcoded value directly to `extract()`.

### Does the budget cap affect video quality or resolution?

No. The `max_frames` budget and `MAX_FPS` limit control **quantity of frames only**. Resolution constraints are handled separately via `MAX_READ_DIMENSION` during the ffmpeg extraction phase.