Let Claude (or any LLM) actually watch a video — scene-aware, deduplicated frames + transcript, from a URL or local file.
Project description
claude-real-video
Let Claude — or any LLM — actually watch a video.
Naming: crv is the short name for claude-real-video (the PyPI package). The paid add-on, crv Pro, is sold on Capafy under the listing name "llm-real-video Pro".
Same 58-second clip: fixed 1 fps sampling = 58 frames. crv keeps the 26 that actually differ — and
--gridpacks them into 3 contact sheets. Fewer tokens, nothing missed.
This free version lets your AI see the video. crv Pro lets it understand it — how it was shot (cut rhythm, camera moves) plus a timestamped timeline of what frames can't show: gestures, expressions, voice pitch shifts, emotion, sound events. One-time founder price $19 — get it on Capafy.
Most AI tools don't really see a video. Paste a YouTube link into ChatGPT and it reads the transcript, not the picture. Claude won't take a video file at all. Even Gemini, which can read video natively, has to send it up to Google and samples frames at a fixed interval (1 fps by default), so fast cuts slip past.
claude-real-video does it differently, and the processing runs locally: point it at a URL or a
file, and it pulls the frames that actually matter (every scene change, not a
fixed quota), throws away the near-duplicates, transcribes the audio, and hands
you a clean folder any LLM can read. All the processing happens on your own machine — what gets sent anywhere is only the frames/text you choose to paste into an LLM afterwards.
crv "https://www.youtube.com/watch?v=..."
# → crv-out/frames/*.jpg + frames.json (per-frame timestamps) + transcript.txt/.json + MANIFEST.txt
Then drop the frames + MANIFEST.txt into Claude / ChatGPT / Gemini and ask away.
No terminal needed — run crv-web and a local page opens (Traditional Chinese / Simplified Chinese / English): paste a YouTube or Reels link or a file path, click Analyze, open the result viewer. Video analysis and output generation run on your machine — the source video never gets uploaded. (If you then paste the extracted frames or transcript into a cloud LLM, that data goes to that provider.)
Want to eyeball what the model will see first? Add --viewer — it writes a local viewer.html (video + keyframe grid + transcript) you can double-click open. No network, no extra installs.
Slow-changing content (animation tutorials, gradual morphs, slow pans): add --adaptive — frames are picked against their rolling neighbourhood instead of a fixed threshold, so a 2-3s squash-and-stretch that never spikes any single frame still gets captured.
Text-heavy content (lecture slides, screen recordings, talking-head explainers): add --text-anchors — extra frames are forced at subtitle-cue timestamps, so each spoken segment gets a matching visual even when the scene barely changes. Needs a sidecar .srt/.vtt or an embedded subtitle track — captions burned into the pixels can't be detected. At most one forced frame per second; scene detection is untouched.
Not doing LLM work? It also works as a general-purpose video keyframe extractor — scene-change detection + dedup, no ML models to download.
Using Claude Code? Install it as a skill so Claude watches videos on its own
(the skills/ folder lives in the repo, not in the pip package — clone it first):
pip install "claude-real-video[whisper]"
git clone https://github.com/HUANGCHIHHUNGLeo/claude-real-video.git
mkdir -p ~/.claude/skills && cp -r claude-real-video/skills/claude-real-video ~/.claude/skills/
Then just paste a video link into Claude Code and ask about it.
New in 0.3.0 — tell it why you're watching, and keep what it finds:
crv "https://youtu.be/..." --why "find the pricing strategy" --kb ~/notes
--why makes the analysis focus on what you care about instead of a generic summary;
--kb saves the result as a dated note in your own notes folder, so it doesn't die in crv-out.
Why not just sample frames?
Most "let an LLM watch a video" scripts (and Gemini's own pipeline) grab frames
at a fixed interval — e.g. one per second. That over-samples a static
screencast and under-samples a fast-cut reel. claude-real-video is smarter:
| fixed-interval sampling | claude-real-video | |
|---|---|---|
| Frame selection | every N seconds | scene-change detection + density floor |
| Repeated shots (A-B-A cuts) | sent again every time | sliding-window dedup sends each shot once |
| Static slide (10 min) | ~600 near-identical frames | collapses to 1 (dedup) |
| Fast-cut reel | misses frames between samples | catches each visual change |
| Audio | often ignored | Whisper transcript w/ language detect |
| Where the processing happens | often in someone's cloud | on your machine (you choose what to share with an LLM afterwards) |
| Input | usually local file only | URL (yt-dlp) or local file |
You feed the model fewer, more meaningful frames — cheaper context, better understanding.
Install
pip install "claude-real-video[whisper]" # recommended: frames + dedup + audio transcription
pip install claude-real-video # core only (frames + dedup)
pip extras never install themselves — without [whisper] there is no speech-to-text
(videos that ship their own subtitles still get a transcript).
System requirement: ffmpeg
ffmpeg / ffprobe are used for frame extraction and audio, and aren't
pip-installable. Install them once:
| OS | command |
|---|---|
| macOS | brew install ffmpeg |
| Linux | sudo apt install ffmpeg (or your distro's package manager) |
| Windows | winget install Gyan.FFmpeg — or choco install ffmpeg — or download a build and add its bin\ folder to your PATH |
Verify it's on your PATH:
ffmpeg -version
Transcription uses the whisper CLI (installed by the [whisper] extra, or
pip install openai-whisper). Whisper also relies on ffmpeg.
Works on macOS, Windows, and Linux — Python 3.10+.
Usage
# A YouTube / Instagram / TikTok / ... link
crv "https://www.instagram.com/reel/XXXX/"
# A local file, English transcript, output to ./out
crv lecture.mp4 -o out --lang en
# Frames only, no transcription
crv clip.mp4 --no-transcribe
# A login-gated video (your own / authorised use): pass a Netscape cookie file
crv "https://..." --cookies cookies.txt
python -m claude_real_video ... works as an alias for crv too.
Options
| flag | default | meaning |
|---|---|---|
-o, --out |
crv-out |
output directory |
--overwrite |
off | replace a previous analysis living in the output directory (without this, a non-empty output dir is refused to avoid mixing videos) |
--scene |
0.30 |
scene-change sensitivity (lower = more frames) |
--fps-floor |
1.0 |
at least one frame every N seconds |
--max-frames |
150 |
hard cap on total frames |
--adaptive |
off | adaptive scene detection: catches slow morphs (2-3s squash/stretch, gradual pans) a fixed threshold misses, by comparing each frame against its rolling neighbourhood |
--text-anchors |
off | force extra frames at subtitle-cue timestamps (sidecar .srt/.vtt or embedded track) — for videos where meaning changes faster than pixels; at most one forced frame per second |
--lang |
auto |
Whisper language (en, zh, auto, ...) |
--whisper-model |
base |
Whisper model for transcription (tiny/base/small/medium/large/turbo — base is fast; want sharper transcripts? --whisper-model turbo is one flag away: close to large-v2 accuracy at ~8x the speed, one-time 1.6GB download, ~6GB memory) |
--dedup-threshold |
8 |
% of pixels that must change for a frame to count as new; higher = fewer frames (the settled-local detector's gate scales with it too) |
--dedup-window |
4 |
compare against the last N kept frames — a shot the model already saw doesn't come back after a cutaway (1 = consecutive-only) |
--report |
off | keep dropped frames in ./dropped + write report.html visualising every keep/drop decision |
--no-transcribe |
off | skip audio |
--keep-audio |
off | also save the full soundtrack (audio.m4a) so audio models can hear it |
--viewer |
off | also write viewer.html — browse the video, keyframes and transcript in one local page (double-click to open) |
--grid |
off | also tile the kept frames into 3x3 contact sheets (./grids) — consecutive frames side by side help the model follow motion and progression |
--why |
– | why you're watching, e.g. --why "find the pricing strategy" — written into MANIFEST.txt so the model analyses with that lens instead of a generic summary |
--kb |
– | also save the analysis as a dated markdown note into this folder (your Obsidian vault, notes dir, ...) — so it joins your knowledge base instead of dying in crv-out |
--cookies |
– | Netscape cookie file for login-gated sources |
--cookies-from-browser |
– | read login cookies straight from your own browser — chrome, safari, firefox or edge (your own account only) |
What --grid output looks like
One contact sheet = nine consecutive keyframes, in order, filenames on each cell — the model reads a sequence, not scattered stills:
Use it from Python
from claude_real_video import process
r = process("https://youtu.be/...", "out", lang="en")
print(r.frame_count, r.transcript_path)
How it works
- Fetch —
yt-dlpfor URLs (optional cookies), or copy a local file. - Extract — one chronological
ffmpeg selectpass grabs every scene change plus a density floor (at least one frame every--fps-floorseconds), so fast cuts and slow screencasts are both covered. - Dedup — two detectors against a sliding window of the last
--dedup-windowkept frames, so an A-B-A cutaway doesn't re-send a shot the model has already seen. A global channel measures real pixel difference (downscaled RGB, not a perceptual hash — hashes go blind on flat colours and equal-luma hue changes);--dedup-thresholdis the % of it that must change. A settled-local channel (v0.7.4) catches what the global one can't see: thin pen strokes, caption/text-card swaps and small UI updates that average out to ~0% globally. It looks, on a finer signature, for a region that differs strongly from every recent kept frame (with 1px shift tolerance, so film grain and frame jitter don't trigger) and is no longer changing — a settled new state, not motion mid-flight — with a cooldown so continuous motion that pauses every second (a waving flag, drifting smoke) can't keep re-firing. The final frame is evaluated even if still in motion (so a video's closing state is never lost), but it must clear both contrast gates like any other frame.--reportwritesreport.htmlshowing every keep/drop decision with its diff % (settled-local keeps are labelled), for tuning. - Text — if the video already has subtitles (a sidecar
.srt/.vttnext to a local file, or an embedded subtitle track), those are used as the transcript — faster and more accurate than re-transcribing. Only when there are no subtitles does it fall back to Whisper on the audio (skipped cleanly if there's no audio). - Audio (optional,
--keep-audio) — save the full original soundtrack (audio.m4a: music + speech + effects, copied losslessly when possible). The transcript only has the words; the audio file lets a model that can listen (Gemini, GPT-4o, …) actually hear the music and tone. - Timestamps — every kept frame's source-video time survives the whole
pipeline (extraction → dedup →
--max-framesthinning → renaming) and is written toframes.json(file/timestamp_sec/timestamp/selection_reason). Cite visual evidence asframe_012 @ 00:03:41, align frames withtranscript.jsonsegments, or feed the map to a video-RAG pipeline. Inviewer.html, click any keyframe → "play video from here". - Manifest —
MANIFEST.txtsummarises everything for the model.
So the model can see (key frames), read (transcript) and — with --keep-audio —
hear (full soundtrack) the video. The transcript is plain text any model can read;
the tool doesn't burn subtitles into the video — burning is a presentation choice,
not something needed to make a video AI-readable.
Notes
- Only download content you have the right to. The
--cookiesoption is for your own, authorised access — don't ship credentials in a repo. - Use one output folder per video. Re-running into a folder that already holds
an analysis is refused (so two videos never mix); pass
--overwriteto replace it.
crv Pro — understand how a video was shot
The free version tells your AI what's on screen. crv Pro tells it how it was shot — and why it works. Camera moves, editing rhythm, action bursts, plus a one-flag --breakdown report: hook analysis, pacing curve, camera language, Reels-algorithm lens, and a rubric your own LLM completes into a full video teardown.
This free tool tells an LLM what is on screen. A stack of keyframes can't tell it how the video moves — the camera work and the pacing.
crv Pro adds everything the free version can't hear or feel:
- Camera-move classification — every shot labelled static / pan / tilt / zoom / handheld (tested against a manually labeled internal sample set — public benchmark methodology is in progress)
- Editing rhythm — shot list, cuts per minute, and how pacing shifts across the video
- Perception timeline — the subtle things frames can't show: gestures and expressions (a smile, a hand raised, pointing), voice pitch rises and pauses, speaker emotion, and non-speech sound events — all timestamped
- A breakdown report — hook analysis, pacing curve, camera language, and a rubric your own LLM completes into a full teardown
- Three modes —
--mode watch(understand the content),--mode creator(reverse-engineer the making),--mode full
Recent Pro updates (July 2026): a music-state timeline (hear the score building, peaking, falling away — with BPM), voice emotion read from the isolated voice instead of the full mix, an interactive --viewer dashboard with a clickable synced timeline, and richer gesture narration ("hand raised — right hand, while walking toward frame right").
All as plain text in the same manifest, all computed on your machine. One-time founder price $19:
- Buy on Capafy (instant download, license key included): https://capafy.ai/agent/llm-real-video-pro-let-any-llm-watch-videos/5451082151
- Product page & demo: https://leoaido.com/crv-pro/
Following the build? I'm documenting the road from open-source tool to first paying customer, in public — @LeoAidoAI on X.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_real_video-0.7.6.tar.gz.
File metadata
- Download URL: claude_real_video-0.7.6.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ecf61930c3cd5523a7bfb40aaf29b471f73a4ec4a242f58139081f321b2fb66
|
|
| MD5 |
641a84a47bddac58d73ca0bf7826208c
|
|
| BLAKE2b-256 |
ce3d5a58e70668bbe717e332d9e9a38c98ac05b4a03c69e3c562381cff776668
|
File details
Details for the file claude_real_video-0.7.6-py3-none-any.whl.
File metadata
- Download URL: claude_real_video-0.7.6-py3-none-any.whl
- Upload date:
- Size: 34.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e20d604c636cece7f1de711785f7e7b1385910508c5bbbfe0819fe7b124159d1
|
|
| MD5 |
f879130569962ebf82d0d06fd9f827e0
|
|
| BLAKE2b-256 |
bd954bc9ebc401a69438a6b722626d9551a3a5cd015793441594fb331c10701c
|