用途:从本地视频中提取“出现新内容”的关键帧,而非固定间隔或逐帧抽取,输出 frames/*.jpg 与 timeline.json(一个精简的、先读后看图的摘要)。适用于用户想知道屏幕上出现了什么,例如“把幻灯片抽出来”“4:20 时屏幕上是什么”“截取他运行的命令”“读一下这张图”。不适用于只要语音内容(用 video-transcribe)或要文字笔记(用 video-notes,它会调用本技能)。纯语音视频(播客、访谈、口播)不值得抽帧,先判断类型。
输入为本地文件,本技能不下载任何内容。若为 URL,需先获取: yt-dlp -f "bv*[height<=720]+ba/b[height<=720]" -o video.mp4 "<url>" 720p 基本足够回答视频能回答的问题。
工作流:1) 提取:python3 "${CLAUDE_SKILL_DIR}/scripts/extract_frames.py" video.mp4 --out <workdir> [--transcript <workdir>/transcript.json] [--start MM:SS --end MM:SS] [--max-frames N]。有转写时传入 --transcript,每个镜头会带上覆盖它的语音。2) 先读 timeline.json:每行一个镜头,含 start/start_ms、帧路径、ocr 文本、motion 和 speech;多数镜头 OCR 加语音已能回答,无需打开图片。3) 仅在证据需要时细看:一次调用多个精确时刻 python3 "${CLAUDE_SKILL_DIR}/scripts/extract_frames.py" frame-at video.mp4 --out <workdir> 1:02 1:15 4:20;或按范围采样 python3 "${CLAUDE_SKILL_DIR}/scripts/extract_frames.py" clip video.mp4 6:00 6:30 --out <workdir> --fps 2。
阈值选择:ffmpeg 场景分数并非变化像素比例,普通浅色幻灯片整页切换约 0.03,因此常见的 gt(scene,0.4) 甚至 0.05 都检测不到。脚本会先做一次廉价降采样测量真实分布,再选取大致符合帧预算的阈值,不要硬编码。若场景检测留下超过两分钟未观察的片段,脚本会切换为间隔采样并在 stderr 说明;timeline.json 的 strategy 记录所用策略,应报告给用户以说明覆盖完整度。
输出:<workdir>/frames/*.jpg 与 timeline.json(含 duration_s、strategy、scene_threshold、frames_kept、frame_budget、shots)。
注意事项:OCR 会弄错命令参数,Tesseract 常把 --maxfail 识别成 —-maxfail,并混淆 l/1/I、O/0;把 ocr 当搜索索引而非事实来源,要复现的命令需从图像本身读取。感知去重仅基于亮度,按钮变红或数字变绿不可见,UI 流程可能塌缩为单帧;脚本会固定等距帧,若仍缺中间过程可用 clip 重采样。首帧被刻意保留,因为场景检测不会在第 0 帧触发。ffmpeg 8 移除了 -vsync 并会硬报错,脚本探测 -fps_mode 并仅在旧版本回退。无 tesseract 也可运行,OCR 降级为无文本帧。阈值测量、预算层级与去重细节见 references/frame-selection.md。