When Does the Frame Cap Apply in claude-video After Deduplication?

The frame cap (max_frames) is enforced only after the deduplication process removes visually similar frames, ensuring the final budget is spent on unique content rather than duplicates.

The bradautomates/claude-video repository provides a robust frame extraction pipeline for video processing. Understanding exactly when the frame cap applies is critical for optimizing your video analysis budget and ensuring you capture the most diverse visual content. According to the source code in skills/watch/scripts/frames.py, the cap is imposed as a final filtering step, not during the initial candidate generation.

Frame Cap Timing in the Extraction Pipeline

The extraction logic follows a strict three-phase sequence to maximize content diversity while respecting user-defined limits. The frame cap acts as the final gatekeeper, operating only on the deduplicated set.

Step 1: Candidate Extraction

First, the engine gathers all potential frames using methods like extract_scene_candidates() or extract_keyframes(). This phase returns an unfiltered list of every scene change, key frame, or uniform sample detected in the video, often numbering in the hundreds regardless of your target budget.

Step 2: Perceptual Deduplication

Next, the system runs dedupe_perceptual() (or the internal helper _dedupe_by_deltas) to eliminate near-identical frames. This step compares visual hashes or frame deltas to drop redundant content, preventing wasted tokens on duplicate visual information.

Step 3: Cap Enforcement via Even Sampling

Finally, the surviving frames are passed to _even_sample(), which trims the list down to the max_frames limit. This is where the frame cap is actually applied. As implemented in skills/watch/scripts/frames.py lines 44–50, the logic first deduplicates, then calculates the cap, then samples:


# From extract_scene_or_uniform (lines 44-50)

deduped, n_dropped = dedupe_perceptual(scene_frames) if dedup else (scene_frames, 0)
cap = len(deduped) if max_frames is None else max_frames
selected = _even_sample(deduped, cap)

The same pattern appears in the key-frame engine at lines 70–75, confirming this is the canonical behavior across extraction modes.

Code Implementation in frames.py

The skills/watch/scripts/frames.py file contains the core logic that dictates this order. The critical insight is that max_frames is evaluated against the deduped list length, not the original candidate list.

In the scene-based extraction path:

deduped, n_dropped = dedupe_perceptual(scene_frames) if dedup else (scene_frames, 0)
cap = len(deduped) if max_frames is None else max_frames
selected = _even_sample(deduped, cap)

In the key-frame extraction path:

deduped, n_dropped = dedupe_perceptual(candidates) if dedup else (candidates, 0)
cap = len(deduped) if max_frames is None else max_frames
selected = _even_sample(deduped, cap)

Both paths demonstrate that deduplication always precedes the cap. If max_frames is set to None, the cap defaults to the length of the deduplicated list, effectively returning all unique frames.

Practical Examples

Using Scene or Uniform Extraction

When calling extract_scene_or_uniform, the max_frames parameter acts as a post-dedup limit:

from pathlib import Path
from skills.watch.scripts.frames import extract_scene_or_uniform

video_path = "sample.mp4"
out_dir = Path("./frames")

# Request 100 frames, but only after removing duplicates

frames, meta = extract_scene_or_uniform(
    video_path,
    out_dir,
    fps=2.0,
    target_frames=100,
    max_frames=100,
    dedup=True,
)

print(f"Returned {len(frames)} frames (cap applied after dedup)")
print(meta)

Even if the video contains 300 scene changes, the engine first removes visual duplicates, then selects an evenly distributed sample of 100 from the remaining unique frames.

Using Key-Frame Extraction

The same behavior applies to extract_keyframes:

from pathlib import Path
from skills.watch.scripts.frames import extract_keyframes

frames, meta = extract_keyframes(
    "sample.mp4",
    Path("./keyframes"),
    max_frames=20,
    dedup=True,
)

print(f"Key-frames after dedup and capping: {len(frames)}")

If the video yields 150 distinct key-frames before deduplication, but only 80 remain after removing near-duplicates, the final cap of 20 is applied to those 80, resulting in 20 evenly spaced frames.

Why This Order Matters

Applying the frame cap after deduplication ensures that your max_frames budget is never consumed by redundant visual data. If the cap were applied first, you risk retaining multiple near-identical frames while discarding unique content from later in the video. By deduplicating first, claude-video guarantees that every frame in the final output represents distinct visual information, with _even_sample() providing temporal coverage across the entire deduplicated set.

Summary

  • The frame cap (max_frames) is enforced in skills/watch/scripts/frames.py only after the dedupe_perceptual() step completes.
  • Initial candidate extraction generates an uncapped list of potential frames.
  • Deduplication removes visual duplicates before the budget constraint is applied.
  • The _even_sample() function performs the final trimming to meet the max_frames limit.
  • This sequence ensures optimal use of your frame budget on unique visual content.

Frequently Asked Questions

Does the frame cap apply before or after deduplication?

The frame cap applies after deduplication. According to the source code in skills/watch/scripts/frames.py, the dedupe_perceptual() function runs first, and its output is then passed to _even_sample() along with the max_frames value. This ensures that only unique frames are counted toward your budget.

What happens if there are fewer frames than max_frames after deduplication?

If the deduplication process yields fewer frames than the specified max_frames value, the _even_sample() function returns all remaining frames without error. The cap acts as a ceiling, not a requirement, so you will never receive more frames than exist in the deduplicated set.

Which function handles the final frame sampling?

The _even_sample() function in skills/watch/scripts/frames.py handles the final sampling. It receives the deduplicated frame list and the calculated cap (either max_frames or the length of the deduplicated list), then returns an evenly distributed subset that respects the limit.

Can I apply the frame cap without deduplicating frames?

Yes. You can disable deduplication by setting dedup=False in functions like extract_scene_or_uniform or extract_keyframes. When deduplication is disabled, the frame cap is applied directly to the raw candidate list via _even_sample(), meaning duplicates may be included in your final frame count if they exist in the initial extraction.

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 →