# How the `--max-frames` Flag Overrides Detail-Mode Frame Caps in Claude Video

> Discover how the --max-frames flag overrides Claude Video's detail-mode frame caps. Learn to control and limit extracted frames effectively for efficient video analysis.

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

---

**The `--max-frames` argument sets a hard ceiling that supersedes any internal detail-mode or uniform-mode budget calculations, ensuring the final extracted frame count never exceeds the user-specified limit regardless of video duration.**

In the `bradautomates/claude-video` repository, the [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) script orchestrates all frame-extraction strategies. When processing video content, the engine normally calculates an optimal frame budget based on detail modes, but the `--max-frames` override interacts with these detail mode caps by taking precedence at every enforcement point in the pipeline.

## How `--max-frames` Interacts with Detail Mode Caps

The `--max-frames` command-line option provides an absolute upper bound that takes precedence over every internal "detail-mode" cap the engine would otherwise apply. When a user specifies this flag, the value propagates through the extraction pipeline and **overrides** the duration-based budget calculations normally performed by `auto_fps()` (uniform mode) or `auto_fps_focus()` (detail mode).

According to the source code in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py), this override occurs at multiple stages: during initial FPS calculation, at the ffmpeg execution layer, and during post-processing sampling. This ensures that regardless of how the detail-mode logic calculates the "ideal" frame density, the output never exceeds the user-defined ceiling.

## The Frame Budget Calculation Pipeline

### CLI Parsing and Argument Propagation

In the CLI entry point (lines 1000–1012), the argument parser stores the `--max-frames` value in the `max_frames` variable. This value is then supplied to all extraction functions, including `auto_fps()`, `auto_fps_focus()`, and the various extraction helpers.

```python

# Conceptual flow from frames.py L1000-L1012

max_frames = args.max_frames  # User-specified ceiling

extract(video_path, max_frames=max_frames, ...)

```

### FPS Clamping Logic in `_clamp_fps`

Both `auto_fps()` and `auto_fps_focus()` ultimately invoke the `_clamp_fps()` helper function (lines 49–53) to finalize the frame budget. This function explicitly **clamps the target frame count to the supplied `max_frames`**:

```python
def _clamp_fps(fps: float, duration_seconds: float, max_frames: int) -> tuple[float, int]:
    fps = min(fps, MAX_FPS)                         # never exceed MAX_FPS

    target = min(max_frames, max(1, int(round(fps * duration_seconds))))
    return fps, target

```

Here, the `target` calculation uses `min(max_frames, ...)` to ensure that even if the detail-mode logic calculates a higher frame budget based on video duration, the final target is capped at the user-supplied value.

## Enforcement Points Throughout the Extraction Pipeline

The `max_frames` limit is enforced at three critical stages to guarantee compliance:

### Early Enforcement During FPS Calculation

Before any frames are extracted, the `_clamp_fps()` function applies the first layer of enforcement. Whether the engine is operating in uniform mode (`auto_fps`) or focused detail mode (`auto_fps_focus`), the calculated target is immediately constrained by the `--max-frames` value.

### FFmpeg Output Limits (lines 94–100)

The `max_frames` value is passed directly to the ffmpeg command via the `-frames:v` flag in the `extract()` function (lines 95–96). This hard limit at the codec level ensures that even if the frame selection logic fails, the output file count cannot exceed the specified maximum.

```python

# From extract() in frames.py L94-L100

command = [
    "ffmpeg",
    "-i", video_path,
    "-frames:v", str(max_frames),  # Hard limit at ffmpeg level

    ...
]

```

### Scene Candidate Extraction (lines 58–60)

For scene-based extraction strategies, the `extract_scene_candidates()` function (lines 58–60) also receives the `max_frames` parameter, ensuring that the initial candidate pool generation respects the user ceiling.

### Post-Processing Caps After Deduplication

For scene and keyframe engines, the script discovers candidate frames, optionally deduplicates them, then applies an **even-sample cap** using `_even_sample()`. This final filtering step (referenced in `extract_scene_or_uniform` at lines 44–46 and `extract_keyframes` at lines 74–76) again respects the `max_frames` argument, ensuring that the final delivered frame count stays within bounds even after content analysis.

## Practical Examples

These examples demonstrate how `--max-frames` overrides the default detail-mode budgets:

**Uniform mode with default caps:**

```bash

# 30-second video defaults to ~12 frames (detail-mode budget)

python -m skills.watch.scripts.frames video.mp4 out/

```

**Override with strict cap:**

```bash

# Forces exactly 5 frames regardless of video duration

python -m skills.watch.scripts.frames video.mp4 out/ --max-frames 5

```

In this case, `_clamp_fps()` forces the target to 5, ffmpeg receives `-frames:v 5`, and post-processing sampling respects the 5-frame ceiling.

**Focused detail mode with range limits:**

```bash

# Detail mode would normally select ~30 frames for a 3-second clip

python -m skills.watch.scripts.frames video.mp4 out/ --start 00:01 --end 00:04 --max-frames 10

```

Here, `auto_fps_focus()` would calculate a dense budget of approximately 30 frames, but `_clamp_fps()` limits the final count to 10 before extraction begins.

## Summary

- The `--max-frames` flag provides a **hard ceiling** that supersedes duration-based budgets calculated by detail mode (`auto_fps_focus`) or uniform mode (`auto_fps`).
- The limit is enforced at **three stages**: during FPS calculation via `_clamp_fps()` (lines 49–53), at the ffmpeg extraction step via `-frames:v` (lines 94–100), and during post-processing through `_even_sample()` (lines 44–46, 74–76).
- Both **uniform extraction** and **focused detail extraction** respect the same override mechanism, ensuring consistent behavior across all processing modes.
- The override is **idempotent**—specifying a `--max-frames` value higher than the calculated budget has no effect, while lower values forcibly constrain the output.

## Frequently Asked Questions

### Does `--max-frames` affect both uniform and detail modes?

Yes. The flag is passed to both `auto_fps()` (uniform mode) and `auto_fps_focus()` (detail mode) in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py). Both functions rely on `_clamp_fps()` to enforce the limit, meaning the override applies regardless of which extraction strategy the engine selects.

### At what stage does the max-frames limit apply?

The limit is applied at **three distinct stages**: first during the FPS budget calculation inside `_clamp_fps()` (lines 49–53), second at the ffmpeg command level via the `-frames:v` argument (lines 94–100), and third during post-processing when `_even_sample()` caps the final frame list (lines 44–46 and 74–76).

### What happens if `--max-frames` is higher than the detail-mode budget?

If the user-specified limit exceeds the calculated detail-mode budget, the budget calculation takes precedence. The `min(max_frames, ...)` logic in `_clamp_fps()` ensures that the lower of the two values is used, so the engine extracts only what the detail-mode logic deems necessary, never exceeding the calculated budget unless forced by the user cap.

### Does the limit apply before or after deduplication?

The `--max-frames` limit applies **both before and after** deduplication. The initial ffmpeg extraction is capped at the limit (pre-deduplication), and the final `_even_sample()` step (lines 44–46, 74–76) applies an even-sample cap to the deduplicated candidate set, ensuring the final output never exceeds the specified ceiling even if duplicate frames are removed from the initial pool.