How Claude Video Calculates Auto-FPS for Frame Extraction
Claude Video calculates auto-FPS using duration-based tiered logic in skills/watch/scripts/frames.py, capping extraction at 2 FPS and respecting a configurable frame budget to balance detail against token limits.
The bradautomates/claude-video repository implements an intelligent auto-FPS calculation system that dynamically adapts frame extraction rates based on video duration and user-defined focus windows. Rather than using a fixed sampling rate, the algorithm selects a target frame count from predefined tiers, then derives the appropriate FPS while enforcing safety limits. This approach ensures dense sampling for short videos and prevents token limit exhaustion for long content.
The Auto-FPS Algorithm Overview
The auto-FPS mechanism consists of two primary strategies implemented in skills/watch/scripts/frames.py. The system chooses between full-video scans and focused range extractions depending on whether the user specifies start/end timestamps.
Both strategies rely on a frame budget (defaulting to 100 frames maximum) and a maximum FPS ceiling of 2.0. The helper function _clamp_fps() enforces these constraints, ensuring the final extraction never exceeds hardware or token processing capabilities.
Full-Video Scan Logic: auto_fps()
When processing an entire video without user-specified ranges, the auto_fps() function applies duration-based tiers to determine the target frame count:
- ≤ 30 seconds:
max(12, round(duration))frames - ≤ 60 seconds: 40 frames
- ≤ 180 seconds: 60 frames
- ≤ 600 seconds: 80 frames
- > 600 seconds:
max_frames(default 100)
After selecting the target, the function divides by duration to calculate the raw FPS, then passes through _clamp_fps() for safety enforcement.
from skills.watch.scripts.frames import auto_fps
# 45-second video with default 100-frame budget
fps, target = auto_fps(45)
# Returns: (0.89, 40)
# 0.89 FPS yields exactly 40 frames, respecting the ≤60s tier
Focused Range Logic: auto_fps_focus()
For focused extractions where --start and --end flags define a specific window, the auto_fps_focus() function applies tighter sampling budgets to capture fine-grained detail in short segments:
- ≤ 5 seconds: Up to 6× duration (capped by budget)
- ≤ 15 seconds: Up to 4× duration (capped by budget)
- ≤ 30 seconds: 60 frames
- ≤ 60 seconds: 80 frames
- ≤ 180 seconds:
max_frames - > 180 seconds:
max_frames
This aggressive up-sampling for short windows ensures critical moments receive adequate visual representation without exceeding the global frame budget.
from skills.watch.scripts.frames import auto_fps_focus
# 8-second focused clip
fps, target = auto_fps_focus(8)
# Returns: (2.0, 16)
# Clamped to MAX_FPS of 2.0, yielding 16 frames for the segment
Safety Limits and Frame Budget Enforcement
The _clamp_fps() helper function in skills/watch/scripts/frames.py serves as the gatekeeper for extraction parameters:
def _clamp_fps(fps: float, duration_seconds: float, max_frames: int) -> tuple[float, int]:
fps = min(fps, MAX_FPS) # never exceed 2 fps
target = min(max_frames, max(1, int(round(fps * duration_seconds))))
return fps, target
This implementation guarantees three critical constraints:
- Maximum FPS: Never exceeds 2.0 FPS to prevent overwhelming downstream token limits
- Minimum frames: Always returns at least 1 frame
- Budget compliance: Hard caps total frames at the
max_framesparameter
Integration in the Watch Pipeline
The skills/watch/scripts/watch.py module orchestrates the selection logic. After parsing video metadata and determining the effective duration, it selects the appropriate auto-FPS strategy:
if focused:
fps, target = auto_fps_focus(effective_duration, max_frames=budget_cap)
else:
fps, target = auto_fps(effective_duration, max_frames=budget_cap)
Users can override the automatic calculation by providing an explicit --fps argument. When specified, the system clamps the user value to MAX_FPS but still applies the frame budget cap:
if args.fps is not None:
fps = min(args.fps, MAX_FPS)
target = max(1, int(round(fps * effective_duration)))
Summary
- Claude Video's auto-FPS calculation resides in
skills/watch/scripts/frames.pywithin thebradautomates/claude-videorepository - Two distinct algorithms exist:
auto_fps()for full videos andauto_fps_focus()for time-restricted ranges - Duration-based tiers determine target frame counts, favoring denser sampling for shorter content
- The
_clamp_fps()helper enforces a 2.0 FPS maximum and respects the configurable frame budget (default 100) - Explicit user
--fpsvalues override automatic calculations but remain subject to safety limits
Frequently Asked Questions
What is the maximum FPS Claude Video will extract?
Claude Video enforces a hard limit of 2.0 FPS through the MAX_FPS constant in skills/watch/scripts/frames.py. Even if the duration-based tier logic suggests a higher rate, or if the user specifies an aggressive --fps value, the _clamp_fps() function caps the extraction at 2 frames per second to protect downstream token budgets.
How does Claude Video handle very short video clips?
For videos under 30 seconds, the auto_fps() function uses the formula max(12, round(duration)) to ensure adequate visual coverage. When using focused ranges under 5 seconds, auto_fps_focus() can sample up to 6× the duration (capped by the frame budget), extracting up to 30 frames for a 5-second clip while respecting the 2.0 FPS ceiling.
Can I override the automatic FPS calculation?
Yes. Providing the --fps argument in the CLI bypasses the tiered auto-selection logic. The system applies min(args.fps, MAX_FPS) to respect the safety ceiling, then calculates the target frame count as max(1, int(round(fps * effective_duration))). However, this manual override still respects the maximum frame budget cap to prevent system overload.
What file contains the auto-FPS calculation logic?
The core auto-FPS functions are implemented in skills/watch/scripts/frames.py. This module contains auto_fps() for full-video processing, auto_fps_focus() for restricted time windows, and the _clamp_fps() helper that enforces safety limits. The orchestration logic that selects between these strategies lives in skills/watch/scripts/watch.py.
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 →