How to Extract Frames at Specific Timestamps Using the --timestamps Flag in Claude-Video
Claude-Video's watch command can extract exact frames at user-specified timestamps using the --timestamps flag with comma-separated time values in HH:MM:SS, MM:SS, or seconds format.
The claude-video repository provides a powerful video analysis toolkit that includes precise frame extraction capabilities. When you need to capture specific moments from a video rather than relying on automatic sampling, the --timestamps flag allows you to extract frames at exact temporal coordinates. This functionality integrates seamlessly with the tool's transcript analysis and detail-level framing systems, storing output as cue_*.jpg files alongside regular frames.
Understanding the --timestamps Flag
The --timestamps flag accepts a comma-separated string of time values that specify exactly where in the video to capture frames. According to the source code in skills/watch/scripts/watch.py, the entry point parses this input using parse_timestamps() between lines 81-86, converting human-readable time strings into seconds for processing.
Supported timestamp formats include:
- Seconds only:
12or12.5 - Minutes and seconds:
01:30or01:30.250 - Hours, minutes, and seconds:
00:05:00or00:05:00.500
When you invoke the watch skill with this flag, the system validates each timestamp against optional --start and --end boundaries before proceeding to extraction.
The Frame Extraction Pipeline
The core extraction logic resides in skills/watch/scripts/frames.py within the extract_at_timestamps() function. This routine handles the heavy lifting from lines 44-90, orchestrating FFmpeg subprocesses to pull exact frames without re-encoding the entire video.
Directory Preparation and Cleanup
Before extraction begins, the function prepares the output directory at lines 44-48. It creates the directory if missing and removes any existing cue_*.jpg files to prevent conflicts with previous runs:
out_dir.mkdir(parents=True, exist_ok=True)
for existing in out_dir.glob("cue_*.jpg"):
existing.unlink()
Focus Window Clamping
If you specify --start or --end parameters alongside --timestamps, the system clamps the requested timestamps to this focus window (lines 48-52). Timestamps falling outside the range are tracked in the dropped_out_of_window metadata count rather than being extracted.
The logic uses:
lo = start_seconds or 0.0
hi = end_seconds if end_seconds is not None else float("inf")
Frame Cap and Even Sampling
When the number of requested timestamps exceeds the --max-frames limit, the system applies intelligent sampling at lines 54-57. The _even_indices helper selects evenly distributed timestamps from your list, always preserving the first and last cues while dropping intermediate frames to meet the cap.
FFmpeg Extraction Process
For each validated timestamp, the system executes FFmpeg via subprocess.run() (lines 60-73). The command seeks to the specified time using -ss and extracts a single frame:
cmd = [
"ffmpeg", "-y", "-ss", str(t), "-i", str(video_path),
"-frames:v", "1", "-q:v", "2",
"-vf", f"scale={resolution}:-1",
str(out_path)
]
Each extracted frame is saved as cue_####.jpg in the <work-dir>/frames/ directory, with zero-padded numbering to maintain chronological order.
Command-Line Usage Examples
Extract specific moments from a YouTube video:
watch "https://youtu.be/ABC123" \
--timestamps "00:05,00:30,02:15" \
--detail transcript
This command downloads the video, extracts frames at 5 seconds, 30 seconds, and 2 minutes 15 seconds, and includes only these cue frames in the final report.
Combine cue frames with balanced sampling on a local file:
watch /path/to/video.mp4 \
--timestamps "00:10,01:00,01:30,02:00" \
--detail balanced \
--max-frames 50
Here, the four specified timestamps are extracted alongside automatically selected balanced frames, with the total frame count capped at 50.
Programmatic API Usage
You can invoke the extraction logic directly from Python without using the CLI:
from pathlib import Path
from skills.watch.scripts.frames import extract_at_timestamps
video = "/tmp/video.mp4"
out_dir = Path("/tmp/frames")
timestamps = [12.0, 30.5, 125.0] # seconds as floats
frames, meta = extract_at_timestamps(
video_path=video,
out_dir=out_dir,
timestamps=timestamps,
resolution=512,
max_frames=10,
)
print("Extracted frames:", frames)
print("Metadata:", meta)
# meta contains: requested_count, selected_count, dropped_out_of_window
The function returns a tuple containing the list of extracted frame paths and a metadata dictionary tracking how many timestamps were requested, selected, and dropped due to window constraints.
Integration with Detail Levels
After extraction, skills/watch/scripts/watch.py merges the cue frames with regular detail-engine frames (lines 27-31) using the merge_frames() function. This ensures that timestamp-specific frames appear alongside auto-generated frames in the final markdown report, each annotated with their timestamp and reason (transcript-cue).
The cue frames use a distinct cue_ prefix to avoid filename collisions with the standard frame_*.jpg naming convention used by the detail engine.
Summary
- Pass timestamps to the
watchcommand using--timestamps "00:01,00:30,02:15"with flexible formatting support. - Source files: Parsing occurs in
skills/watch/scripts/watch.py(lines 81-86); extraction logic lives inskills/watch/scripts/frames.py(lines 44-90). - Window clamping: Combine
--timestampswith--startand--endto restrict extraction to specific video segments. - Frame capping: When requests exceed
--max-frames, the system evenly samples your timestamp list while preserving endpoints. - Output: Frames are saved as
cue_*.jpgin the work directory'sframes/folder and merged into the final report.
Frequently Asked Questions
What timestamp formats does claude-video support?
Claude-video accepts timestamps in several formats: plain seconds (45 or 45.5), minutes and seconds (01:30), or full hours-minutes-seconds (00:05:00). Fractional seconds are supported in all formats (e.g., 01:30.250). The parse_time() function in skills/watch/scripts/frames.py (lines 95-104) handles these conversions, normalizing all inputs to float seconds for FFmpeg processing.
How does the --timestamps flag interact with --start and --end?
When you specify --start or --end alongside --timestamps, the system filters your timestamp list to include only values within that window. Timestamps outside the range are counted in the dropped_out_of_window metadata field but are not extracted. This allows you to specify a broad list of interesting moments while restricting actual extraction to a specific segment of interest.
What happens if I request more timestamps than --max-frames allows?
If your comma-separated timestamp list contains more entries than the --max-frames limit, the system applies even sampling via _even_indices in skills/watch/scripts/frames.py (lines 54-57). It preserves the first and last timestamps from your list and selects evenly spaced intermediate timestamps to stay within the limit, ensuring temporal distribution across your requested moments.
Where are the extracted frames saved and how are they named?
Extracted timestamp frames are saved in the <work-directory>/frames/ directory with the naming pattern cue_####.jpg, where #### is a zero-padded index. This distinguishes them from automatically generated detail frames (frame_*.jpg). After extraction, watch.py merges these cue frames into the final analysis report, listing each frame's path, exact timestamp, and extraction reason.
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 →