用途
capture-video-frames 用于从 YouTube 视频中按固定的时间间隔截取画面,生成一份将文件名映射到时间戳的清单(manifest),并借助 LLM 为每一帧生成文字描述。适用于需要对演讲、演示类视频做逐帧内容梳理与去重挑选的场景。
主要能力
- 按指定间隔(默认 30 秒)从 YouTube 视频截取帧,保存为以时间戳秒数零填充四位命名的 PNG(如 frame_0000.png、frame_0030.png)。
- 生成 frames_manifest.md,逐行列出文件、时间戳,并预留 Description 描述列。
- 通过 describe-frame 子代理逐帧生成纯文本描述;若某帧与前一帧基本相同,则返回 (same as previous)。
- 在清单中即时更新每帧描述。
- 对连续 (same as previous) 的重复帧分组去重,只保留演讲者面部质量最佳的一帧。
- 在最佳帧中演讲者仍闭口时,可在附近时间点重新截取画面并替换。
使用方式
第一步:截取帧。运行脚本:
uv run .agents/skills/capture-video-frames/capture_video_frames.py <youtube_url> <output_dir> [--interval SECONDS]
参数说明:
- youtube_url(必填):YouTube 视频 URL(与 extract-transcript 技能接受相同格式)。
- output_dir(必填):保存帧与清单文件的目录,不存在会自动创建。
- --interval(可选):帧间隔秒数,默认 30。
输出:frame_0000.png、frame_0030.png 等 PNG 图片,以及 frames_manifest.md。清单示例:
| File | Timestamp | Description |
|---|---|---|
| frame_0000.png | [00:00] | |
| frame_0030.png | [00:30] | |
| frame_0060.png | [01:00] |
前置依赖:
- yt-dlp:brew install yt-dlp 或 pip install yt-dlp
- ffmpeg:brew install ffmpeg 或 apt-get install ffmpeg
第二步:使用 describe-frame 子代理描述帧。describe-frame 代理定义于 .github/agents/describe-frame.md。每次子代理调用获得独立上下文,避免帧图片累积耗尽上下文窗口。流程:
- 从输出目录读取 frames_manifest.md 获取全部帧列表。
- 对每一帧,以子代理方式运行 describe-frame,提示中包含当前帧图片的绝对路径、前一帧图片的绝对路径(若存在)、前一帧的描述文本(若存在)。
- 子代理返回纯文本描述(若与前一帧基本相同则返回 (same as previous))。
- 每次返回后立即更新清单中该行的 Description 列,直到全部描述完成。
子代理提示模板:
Describe the current frame image at: [CURRENT_FRAME_ABSOLUTE_PATH]
[若存在前一帧,包含以下两行:] The previous frame image is at: [PREVIOUS_FRAME_ABSOLUTE_PATH] The previous frame was described as: "[PREVIOUS_DESCRIPTION]"
描述完成后的清单示例:
| File | Timestamp | Description |
|---|---|---|
| frame_0000.png | [00:00] | Title slide introducing "Building RAG apps with Python" |
| frame_0030.png | [00:30] | Speaker showing the agenda with four main topics |
| frame_0060.png | [01:00] | (same as previous) |
| frame_0090.png | [01:30] | Architecture diagram of a retrieval-augmented generation pipeline |
第三步:去重并挑选最佳演讲者面部。连续为 (same as previous) 的行代表同一画面内容在不同时刻的捕获,组内演讲者面部可能不同(睁眼/闭眼、张口/闭口、面向镜头/转向别处)。
目标:每组重复帧只保留一帧面部质量最佳者,删除其余。
最佳面部标准(按优先级):
- 当前演讲者口型张开(说话中);如从转录稿得知该时间戳的说话人,优先该演讲者。
- 睁眼,非眨眼瞬间。
- 面向镜头,而非侧脸或低头。 若无可视演讲者(如全屏演示或无摄像头画面),组内所有帧等价,保留第一帧。
流程:
- 找出所有连续 (same as previous) 的行组。每组以“锚点”帧(有真实描述的那一帧)开头,后跟一个或多个 (same as previous) 行。
- 对每组运行 describe-frame 子代理比较面部,使用提示模板:
Compare these two frames focusing ONLY on the speaker faces visible in webcam feeds. Which frame has better speaker faces — eyes open, facing camera, mouth open (mid-speech), not mid-blink or turned away?
Frame A: [ANCHOR_FRAME_ABSOLUTE_PATH] Frame B: [DUPLICATE_FRAME_ABSOLUTE_PATH]
Reply with ONLY one of:
- "A BETTER" if the anchor frame has better speaker faces
- "B BETTER" if the duplicate frame has better speaker faces
- "EQUAL" if both are equivalent
- "NO SPEAKERS" if no speaker faces are visible in either frame
Then add a brief reason.
- 将组内所有重复帧与锚点(及当前最佳)比较后确定唯一最佳帧。
- 若最佳帧不是锚点:将锚点描述移到最佳帧行;在描述中加面部质量备注,如 (better speaker faces than frame_XXXX: eyes open, facing camera);从清单中删除其余 (same as previous) 行。若锚点已是最佳,仅删除重复行。
为闭口帧重新截取:去重后若组内最佳帧演讲者仍闭口(两位演讲者都闭口),尝试在附近时间戳重新截取:
若视频尚未下载: yt-dlp -f "bestvideo[height<=720]" --no-playlist -o "<output_dir>/video.%(ext)s" "<youtube_url>"
在该帧时间戳 +2s、+5s、+8s、+10s 偏移处截取备选帧: ffmpeg -ss <SECONDS> -i <output_dir>/video.mp4 -frames:v 1 -q:v 2 <output_dir>/alt_<FRAME>_<SECONDS>.png -y
用 describe-frame 子代理检查备选帧中演讲者是否张口,且幻灯片/演示内容是否仍相同。若找到更优备选,替换帧文件(cp alt_XXXX.png frame_XXXX.png)。清理:rm -f <output_dir>/alt_*.png <output_dir>/video.mp4
适用场景
适用于对含摄像头画面的演讲、演示类 YouTube 视频做帧级梳理、内容摘要与关键帧挑选,尤其是需要去除重复帧、保留演讲者表情质量最佳画面的情况。
限制
需要预先安装 yt-dlp 与 ffmpeg。依赖 YouTube 视频来源及 describe-frame 子代理的可用性。其他具体限制资料未提供。