How to Extract Frames at Specific Timestamps with `--timestamps` in claude-video
The claude-video skill extracts exact frames at user-specified timestamps via the --timestamps flag, converting time strings like "4:32,7:10,9:55" into sorted, deduplicated seconds and invoking ffmpeg to capture JPEGs at each cue point.
The bradautomates/claude-video repository provides a frame extraction engine that supports precise timestamp-based sampling through its CLI and Python API. When you pass the --timestamps argument to the watch skill, the system parses your time cues, filters them against optional start/end windows, and generates individual frame files marked with "reason": "transcript-cue" for identification in the final output.
Understanding the Frame Engine Architecture
The timestamp extraction logic lives in skills/watch/scripts/frames.py, which orchestrates parsing, filtering, and image generation. The workflow moves through four distinct phases before merging results into the final frame set.
Parsing Time Strings with parse_timestamps()
At lines 95–103 of frames.py, the parse_timestamps() function handles the initial conversion of the raw CLI string. It accepts comma-separated values in formats like "4:32" or "7:10", converts each to floating-point seconds, and returns a sorted, deduplicated list.
from skills.watch.scripts.frames import parse_timestamps
# Converts "4:32,7:10,9:55" to [272.0, 430.0, 595.0]
timestamps = parse_timestamps("4:32,7:10,9:55")
Filtering and Sampling with extract_at_timestamps()
The extract_at_timestamps() function (lines 124–158) manages the core selection logic. This routine first validates each timestamp against user-provided --start and --end boundaries, dropping any cues that fall outside the active range. If the remaining count exceeds max_frames, the engine applies the _even_indices sampling strategy to evenly thin the list while preserving temporal distribution.
ffmpeg Integration for Frame Capture
For every retained timestamp t, the engine constructs and executes an ffmpeg command at lines 160–175. The command seeks to the exact second (-ss), extracts a single video frame (-frames:v 1), and writes it as a JPEG file named cue_*.jpg (e.g., cue_0000.jpg, cue_0001.jpg).
Merging Cue Frames into the Primary Set
After extraction, merge_frames() (lines 112–119) combines the timestamp-based frames with those generated by other detail engines (scene detection, keyframe analysis, or uniform sampling). This function preserves chronological order, re-indexes the combined list, and ensures cue frames are never dropped by subsequent sampling stages.
Using the --timestamps Flag from the Command Line
Invoke the watch.py entry point with the --timestamps argument to request specific frames from a video URL or local file. The skill downloads the video if necessary, processes your time cues, and includes the resulting frames in the final JSON payload.
# Assume $SKILL_DIR points to the skill directory
python3 "$SKILL_DIR/scripts/watch.py" "https://youtu.be/abc123" \
--detail balanced \
--timestamps 4:32,7:10,9:55
The execution flow performs four actions:
- Downloads the video to a temporary cache if not already present.
- Parses the three timestamps into seconds and sorts them.
- Extracts JPEGs for each cue point, naming them
cue_0000.jpg,cue_0001.jpg, andcue_0002.jpg. - Returns a JSON object where each frame dictionary contains
"reason": "transcript-cue".
Programmatic Frame Extraction with Python
You can bypass the CLI and call the frame engine directly from Python code. This approach is useful when integrating timestamp extraction into larger workflows or when you need fine-grained control over output directories and resolution.
from pathlib import Path
from skills.watch.scripts.frames import (
parse_timestamps,
extract_at_timestamps,
)
video_path = "/tmp/video.mp4"
out_dir = Path("/tmp/frames")
# Parse the timestamp string
timestamps = parse_timestamps("4:32,7:10,9:55")
# Extract frames at 512px resolution, keeping all cues
frames, meta = extract_at_timestamps(
video_path,
out_dir,
timestamps,
resolution=512,
max_frames=None, # Retain every requested timestamp
)
print(frames) # List of dicts with path, timestamp_seconds, reason
print(meta) # {'engine': 'timestamps', ...}
Combining Cue Frames with Scene Detection
To ensure timestamp frames appear alongside automatically selected scene frames, use the merge_frames() utility:
from skills.watch.scripts.frames import merge_frames
# scene_frames from extract_scene_or_uniform()
# cue_frames from extract_at_timestamps()
all_frames = merge_frames(scene_frames, cue_frames)
The merged list maintains chronological order and is the version rendered to users, guaranteeing that your explicitly requested timestamps are preserved even when scene-based sampling occurs.
Key Implementation Details
Time Format Flexibility. The parse_timestamps() implementation handles standard time notation and converts to floating-point seconds, enabling sub-second precision if your input includes decimal values.
Window Constraints. When using --start or --end flags in conjunction with --timestamps, the extract_at_timestamps() function filters cues before any sampling occurs. This ensures you only extract frames within your specified analysis window.
Even Sampling Fallback. If you request more timestamps than max_frames allows, the _even_indices logic evenly distributes the selected cues across your time range rather than simply truncating the list.
Documentation Reference. The SKILL.md file at lines 45–48 explicitly documents the --timestamps flag and its intended use as a transcript cue mechanism.
Summary
- The
--timestampsflag inbradautomates/claude-videoenables extraction of exact frames at user-specified times via thewatch.pyCLI. parse_timestamps()(lines 95–103) converts comma-separated time strings into sorted, deduplicated seconds.extract_at_timestamps()(lines 124–158) filters cues against--start/--endwindows and applies even sampling if frame limits are exceeded.- The engine invokes
ffmpegat lines 160–175 to generatecue_*.jpgfiles marked with"reason": "transcript-cue". merge_frames()(lines 112–119) integrates cue frames with scene or keyframe selections while preserving chronological order.
Frequently Asked Questions
What timestamp formats does the --timestamps flag accept?
The parse_timestamps() function accepts comma-separated time strings in standard notation like "4:32" (minutes:seconds) or "7:10". These are converted to floating-point seconds, allowing for precise positioning and optional sub-second decimal values.
How does the engine handle timestamps outside the --start or --end range?
The extract_at_timestamps() function automatically filters out any timestamps that fall before the --start value or after the --end value before extraction begins. This ensures you only generate frames within your specified analysis window, preventing unnecessary ffmpeg invocations.
Can I combine timestamp-based frames with scene detection?
Yes. Use the merge_frames() function (lines 112–119) to combine the list from extract_at_timestamps() with frames from extract_scene_or_uniform(). The merge preserves chronological order and guarantees that your explicitly requested cue frames are included in the final output.
What file naming convention is used for timestamp frames?
The engine generates JPEG files named cue_0000.jpg, cue_0001.jpg, etc., corresponding to the sorted order of your input timestamps. Each frame dictionary in the output JSON includes "reason": "transcript-cue" to distinguish these from scene-selected or keyframe-selected frames.
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 →