# How Claude-Video's Frame Budget Scales With Video Duration: A Technical Deep Dive

> Discover how Claude Video's frame budget scales with video duration. Learn about its dynamic FPS adjustment and hard frame cap to optimize video processing.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: deep-dive
- Published: 2026-08-02

---

**Claude-Video uses a budget-aware algorithm that dynamically adjusts frames-per-second based on video duration, ensuring the total frame count never exceeds a hard cap of approximately 300 frames regardless of video length.**

This article examines how the `bradautomates/claude-video` repository implements scalable video frame extraction. The system intelligently balances visual coverage against processing constraints through a ceiling-based approach that adapts to any input duration.

## The Frame Budget Architecture

Claude-Video's frame extraction system centers on three core constants defined in the configuration layer. These values govern how the tool responds to videos of varying lengths.

- **MAX_FRAMES**: Hard upper limit (default ~300 frames)
- **DEFAULT_FPS**: Preferred extraction rate (typically 30 fps)
- **duration_secs**: Runtime detected via ffprobe

The scaling logic lives primarily in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py), with duration detection handled by [`skills/watch/scripts/download.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/download.py) and configuration values stored in [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py).

## Duration Detection With ffprobe

Before any frame extraction occurs, the system must determine video length. The [`download.py`](https://github.com/bradautomates/claude-video/blob/main/download.py) script invokes ffprobe to retrieve precise duration metadata.

```python

# Simplified representation of duration detection

import subprocess
import json

def get_video_duration(path):
    out = subprocess.check_output([
        "ffprobe", "-v", "error",
        "-show_entries", "format=duration",
        "-of", "json", path
    ])
    return float(json.loads(out)["format"]["duration"])

```

This duration value feeds directly into the dynamic fps calculation that follows.

## Dynamic FPS Calculation Formula

The heart of Claude-Video's scaling mechanism is a single mathematical operation that computes the target extraction rate. From [`frames.py`](https://github.com/bradautomates/claude-video/blob/main/frames.py), the formula executes as:

\[
\text{target\_fps} = \min(\text{DEFAULT\_FPS},\; \frac{\text{MAX\_FRAMES}}{\text{duration\_secs}})
\]

This cap-and-floor approach produces two distinct behavioral modes:

**Short videos** (e.g., 10 seconds): MAX_FRAMES / duration_secs yields 30 fps or higher, so extraction proceeds at DEFAULT_FPS—capturing maximum detail without exceeding the budget.

**Long videos** (e.g., 5 minutes / 300 seconds): The division drops to 1 fps or lower, forcing sparse sampling that preserves visual coverage across the full timeline while respecting the 300-frame ceiling.

## FFmpeg Execution With Computed Rate

The calculated `target_fps` passes directly to ffmpeg's fps video filter. This filter transparently drops or duplicates frames to achieve the desired rate, guaranteeing the output never surpasses MAX_FRAMES.

```python

# Representative extraction logic from frames.py

import subprocess
import pathlib

MAX_FRAMES = 300
DEFAULT_FPS = 30

def extract_frames(video_path, output_dir):
    # Duration detection

    duration_secs = get_video_duration(video_path)
    
    # Budget-aware fps calculation

    target_fps = min(DEFAULT_FPS, MAX_FRAMES / duration_secs)
    
    # Directory preparation

    pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True)
    
    # Frame extraction with computed rate

    subprocess.run([
        "ffmpeg", "-i", video_path,
        "-vf", f"fps={target_fps}",
        "-q:v", "2",
        f"{output_dir}/%05d.jpg"
    ], check=True)

```

## Performance Implications

The scaling strategy creates predictable performance characteristics:

- **Frame count remains bounded** at ~300 frames maximum regardless of input duration
- **Processing time grows roughly linearly** with video length due to ffmpeg's sequential decoding
- **Memory usage stays constant** since the pipeline streams frames rather than buffering

This bounded behavior protects downstream components—such as captioning models or Whisper transcription—from resource exhaustion when processing arbitrarily long videos.

## Practical Usage Example

```bash

# Running the watch skill on a 2-minute video

# The skill automatically computes ~2.5 fps to stay under budget

$ claudecode /watch https://example.com/long-video.mp4

# For a 2-minute (120s) video:

# target_fps = min(30, 300 / 120) = min(30, 2.5) = 2.5 fps

# Result: approximately 300 frames extracted across full duration

```

## Summary

- **MAX_FRAMES** (~300) acts as an inviolable ceiling on total frame output
- **ffprobe duration detection** enables duration-aware parameter adjustment
- **min(DEFAULT_FPS, MAX_FRAMES/duration)** formula guarantees budget compliance
- **ffmpeg fps filter** executes the computed rate with frame dropping/duplication
- Processing resources scale predictably without hard duration limits on input videos

## Frequently Asked Questions

### What is the maximum number of frames Claude-Video will extract from any video?

Claude-Video enforces a hard **MAX_FRAMES** limit of approximately 300 frames, defined in [`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py). This ceiling applies universally regardless of video duration, ensuring consistent downstream processing loads.

### Why does frame extraction slow down for longer videos?

The system intentionally reduces **frames-per-second** for lengthy inputs. A 10-second video extracts at 30 fps, while a 5-minute video drops to ~1 fps. This maintains representative visual coverage across the full timeline without exceeding the 300-frame budget.

### Can I customize the MAX_FRAMES or DEFAULT_FPS values?

Both constants reside in **[`skills/watch/scripts/config.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/config.py)** and can be modified before deployment. Adjusting **MAX_FRAMES** upward increases visual granularity at the cost of downstream processing time, while changing **DEFAULT_FPS** alters the baseline extraction rate for short videos.

### How does Claude-Video handle videos with variable frame rates?

The **ffprobe duration detection** in [`skills/watch/scripts/download.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/download.py) reports total runtime in seconds, which drives the fps calculation. The **ffmpeg fps filter** then normalizes output to the computed constant rate, smoothing any source variabilities into a uniform extraction pattern.