How Auto-FPS Is Calculated Based on Video Length and Budget Caps in Claude-Video
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, 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):
MAX_FPS = 2.0— the absolute frame rate ceiling regardless of video lengthMAX_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:
- Receives a proposed fps, video duration, and
max_framesbudget - Clamps the fps to
MAX_FPSif exceeded - Computes target frames as
fps × duration - Returns the lesser of calculated frames or
max_frames, with a minimum of 1
# 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) |
# 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.
# 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:
- Metadata extraction —
get_metadata()callsffprobeto obtainduration_seconds - Function selection —
scripts/watch.pychoosesauto_fpsorauto_fps_focusbased on whether a time range was specified - Rate calculation — The selected function returns
(fps, target_frames) - Frame extraction —
extract()invokesffmpegwith-vf fps={fps}, writing at mosttarget_framesframes
# 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:
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.0caps absolute frame rate regardless of durationauto_fps()applies tiered targets for full videos: 12–40–60–80–budgetauto_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
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 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →