How Auto-FPS Is Calculated for Different Video Durations in Claude-Video

The auto_fps logic in bradautomates/claude-video assigns dynamic frame budgets based on video length, capping extraction at 2 FPS to balance visual coverage with token costs.

The watch skill in the bradautomates/claude-video repository adaptively calculates frame rates to optimize Claude’s vision model usage. By varying the number of extracted frames according to duration, the tool ensures short clips receive dense sampling while long videos stay within token limits.

Full-Video Frame Budgets (auto_fps)

For complete video scans, the auto_fps function in skills/watch/scripts/frames.py (lines 22-38) implements a tiered frame allocation strategy:

  • ≤ 30 seconds: Targets max(12, round(duration)) frames, ensuring even brief clips capture at least 12 frames
  • 30s < duration ≤ 60s: Fixed target of 40 frames
  • 1 minute < duration ≤ 3 minutes: Fixed target of 60 frames
  • 3 minutes < duration ≤ 10 minutes: Fixed target of 80 frames
  • > 10 minutes: Targets max_frames (default 100)

After calculating the raw frame count, the function divides by duration to derive the extraction FPS, then passes this value to _clamp_fps for enforcement of hard limits.

Focused Range Density (auto_fps_focus)

When users specify a time range via --start and --end flags, the auto_fps_focus function (lines 41-60) applies denser sampling under the assumption that the selected segment requires higher detail:

  • ≤ 5 seconds: Uses duration × 6 frames per second (aggressive sampling for brief moments)
  • 5s < duration ≤ 15s: Uses duration × 4 frames, capped at max_frames
  • 15s < duration ≤ 30s: Fixed target of 60 frames
  • 30s < duration ≤ 60s: Fixed target of 80 frames
  • > 1 minute: Targets max_frames (default 100)

This function is invoked in skills/watch/scripts/watch.py (lines 55-58) instead of auto_fps whenever a custom range is detected.

Frame Rate Clamping and Safety Limits

Both calculation paths rely on the _clamp_fps helper (lines 49-53) which enforces two critical constraints:

  1. Maximum FPS: Hard-capped at MAX_FPS (2.0) to prevent excessive token consumption per second of video
  2. Frame Budget: The final target count never exceeds the supplied max_frames parameter

The clamping logic computes the target as int(round(fps * duration)), ensuring the actual extracted frame count respects both the duration-based target and absolute ceiling.

Code Examples

Here is how the calculation behaves across different scenarios:

from skills.watch.scripts.frames import auto_fps, auto_fps_focus

# Example 1: Full scan of a 45-second video

duration = 45.0
fps, target = auto_fps(duration)

# fps = 0.89 (40 frames / 45s), target = 40

print(f"fps={fps:.2f}, target={target}")

# Example 2: Focused 12-second segment

duration = 12.0
fps, target = auto_fps_focus(duration)

# fps = 2.0 (clamped from 4.0), target = 24 (12s × 2 FPS)

print(f"fps={fps:.2f}, target={target}")

# Example 3: 20-minute video with default max_frames=100

duration = 20 * 60
fps, target = auto_fps(duration)

# fps = 0.08, target = 100 (capped)

print(f"fps={fps:.2f}, target={target}")

Summary

  • auto_fps allocates 12–100 frames based on video length tiers, prioritizing higher density for short content
  • auto_fps_focus multiplies frame budgets by 4×–6× for user-specified ranges, assuming detailed analysis is needed
  • MAX_FPS (2.0) acts as a hard ceiling to control Claude vision API token costs
  • Implementation resides in skills/watch/scripts/frames.py, with function selection logic in watch.py

Frequently Asked Questions

What is the maximum frame rate the tool will ever use?

The absolute maximum is 2 FPS, defined by the MAX_FPS constant in skills/watch/scripts/frames.py. Even if the duration-based calculation suggests a higher rate (e.g., 5 FPS for a focused 5-second clip), the _clamp_fps helper forces the value down to 2.0 to maintain predictable token costs.

Why does focused range extraction use different logic than full-video?

Focused ranges assume the user has identified a specific moment requiring detailed inspection. Therefore, auto_fps_focus applies multipliers (4×–6×) that would be prohibitively expensive across an entire video but are acceptable for short segments. This approach balances coverage with cost only where precision matters most.

How can I adjust the total number of frames extracted?

Modify the max_frames parameter passed to either function (default 100). In watch.py, this value controls the upper bound for both auto_fps and auto_fps_focus, allowing you to increase density for high-detail analysis or decrease it for cost-sensitive processing of long content.

What happens if a video exceeds 10 minutes?

Videos longer than 10 minutes automatically target the max_frames value (100 by default). The resulting FPS becomes approximately 0.08–0.17 depending on exact duration, ensuring the total token spend remains bounded regardless of input length.

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 →