关于 video-frames
Video Frames 是一项从视频提取 JPEG 帧供大模型视觉分析的技能。它支持按固定帧率、场景变化或目标帧数选帧,并提供质量预设和适配模型的尺寸调整。
主要功能
- 01按帧率、场景变化或目标数量提取帧
- 02选择图像质量与处理预设
- 03按指定视觉模型调整帧尺寸
- 04为文字处理应用灰度、增强对比度和锐化
- 05叠加源文件名与时间戳
- 06在 JSON 输出中估算图像 Token 用量
适用场景
- 01在帧数限制内抽取长视频画面
- 02按演示文稿的场景变化提取画面
- 03读取屏幕录制或文档视频中的文字
- 04为指定模型的图像输入准备视频帧
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mugnimaestra/ video-frames-skill --skill video-frames安装后在 Claude Code 中输入/video-frames确认已加载。
附带文件references/llm-image-specs.mdscripts/extract_frames.py
详细介绍
视频帧
使用 ffmpeg 从视频文件中提取帧,并生成针对大模型视觉分析优化的 JPEG 图像。支持多种帧选择策略(固定 FPS、场景检测、目标帧数)、质量预设、针对模型优化尺寸,以及 OCR 增强。
先决条件
必须安装 ffmpeg 和 ffprobe,并将其添加到 PATH 中:
brew install ffmpeg # macOS
工作流
- 接收用户提供的视频文件路径
- 运行
scripts/extract_frames.py提取 JPEG 帧 - 解析 JSON 输出,获取帧路径、分辨率和令牌估算值
- 将提取的帧作为图像附件读取并进行分析
- 回答用户关于视频内容的问题
- 完成后清理临时目录
快速入门
最简单的调用方式——以均衡质量每秒提取 1 帧:
python3 scripts/extract_frames.py video.mp4
大多数情况下,使用 --max-frames 让脚本自动计算 FPS:
python3 scripts/extract_frames.py video.mp4 --max-frames 30
与手动设置 --fps 相比,更推荐这种方式,因为它能适应任意视频时长,并使帧数保持可预测。
预设
四种质量预设用于控制分辨率、JPEG 质量和图像处理:
| 预设 | 最大尺寸 | 质量 | 附加处理 | 适用场景 |
|---|---|---|---|---|
efficient | 768px | 5 | -- | 批量帧、长视频 |
balanced | 1024px | 3 | -- | 常规分析(默认) |
detailed | 1568px | 2 | -- | 精细细节、小物体 |
ocr | 1568px | 1 | 灰度 + 高对比度 + 锐化 | 文本/文档提取 |
# Long video, keep costs low
python3 scripts/extract_frames.py long_video.mp4 --max-frames 20 --preset efficient
# Need to read text in a screencast
python3 scripts/extract_frames.py screencast.mp4 --max-frames 40 --preset ocr
质量(1 = 最佳,31 = 最差)和最大尺寸可分别覆盖:
python3 scripts/extract_frames.py video.mp4 --preset balanced --quality 1 --max-dimension 1568
场景变化检测
不按固定频率提取帧,而是检测视觉场景变化,并为每个场景提取一帧。这适用于具有明显分段的视频(演示文稿、剪辑视频、教程)。
python3 scripts/extract_frames.py video.mp4 --scene-threshold 0.3
--scene-threshold(浮点数,0.0-1.0):灵敏度。数值越低,灵敏度越高,可检测较小的变化。建议从0.3开始(使用此标志时的默认值)。--min-scene-interval(浮点数,默认值:1.0):检测到的场景之间的最小间隔秒数。可避免快速剪切时连续触发检测。
注意: --fps 和 --scene-threshold 不能同时使用。--max-frames 只能用于 --fps 模式,不能用于场景检测。
# Presentation with clear slide transitions
python3 scripts/extract_frames.py presentation.mp4 --scene-threshold 0.2
# Action footage -- less sensitive, min 2s apart
python3 scripts/extract_frames.py action.mp4 --scene-threshold 0.5 --min-scene-interval 2.0
针对模型优化
使用 --target-model 将帧调整为与特定模型的图块边界对齐的尺寸,以尽量减少浪费的令牌:
| 模型 | 最大尺寸 | 原因 |
|---|---|---|
claude | 1568px | 自动调整尺寸前的最大原生分辨率 |
openai | 768px | 与 512px 图块网格对齐(短边为 768) |
gemini | 768px | 与 768px 图块边界对齐 |
universal | 768px | 适用于所有模型的理想尺寸(默认) |
# Optimized for Claude -- maximum detail
python3 scripts/extract_frames.py video.mp4 --max-frames 30 --target-model claude
# Optimized for GPT-4o -- efficient tile packing
python3 scripts/extract_frames.py video.mp4 --max-frames 30 --target-model openai
除非明确提供 --max-dimension,否则 --target-model 会设置最大尺寸(CLI 覆盖优先)。
有关各模型的详细令牌公式、图块计算和最佳尺寸表,请参阅 references/llm-image-specs.md。
OCR 和灰度模式
适用于包含文本的视频(屏幕录制、演示文稿、文档、终端录制):
# Full OCR pipeline via preset
python3 scripts/extract_frames.py screencast.mp4 --preset ocr --max-frames 40
# Manual OCR flags (can combine with any preset)
python3 scripts/extract_frames.py video.mp4 --grayscale --high-contrast
--grayscale:将帧转换为灰度。文件大小可减少约 60%,且不会降低 OCR 准确率。--high-contrast:应用contrast=1.3, brightness=0.05,提升文本与背景的区分度。ocr预设会启用这两个标志,并且在 1568px、质量 1 下应用反遮罩锐化(最佳 JPEG)。
高级选项
FPS 选择指南
直接使用 --fps 而非 --max-frames 时:
| 视频时长 | 建议 FPS | 原因 |
|---|---|---|
| < 30s | 2-5 | 短片段,捕捉细节 |
| 30s - 5min | 1 | 在覆盖范围与帧数之间取得良好平衡 |
| 5min - 30min | 0.5 | 避免帧数过多 |
| > 30min | 0.1 - 0.2 | 仅采样关键时刻 |
为优化大模型上下文使用,将总帧数控制在约 50 帧以内。公式:duration_seconds * fps = frame_count。
优先使用 --max-frames,而不是手动设置 FPS——它会自动计算合适的帧率,并将其限制在 0.05-30.0 FPS。
时间戳叠加
python3 scripts/extract_frames.py video.mp4 --timestamps --max-frames 30
在每帧右下角叠加源文件名和 hh:mm:ss 时间戳(半透明黑色方框上的白色文字)。当用户需要引用视频中的特定时刻时使用。
CLI 选项完整参考
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
video_path | pos. | (必填) | 视频文件路径 |
--fps | float | 1.0 | 每秒帧数(不能与 --scene-threshold 同时使用) |
--scene-threshold | float | -- | 场景变化灵敏度 0.0-1.0(不能与 --fps 同时使用) |
--min-scene-interval | float | 1.0 | 场景变化帧之间的最小秒数 |
--max-frames | int | -- | 自动计算 FPS,以生成约 N 帧 |
--preset | choice | balanced | efficient / balanced / detailed / ocr |
--max-dimension | int | -- | 覆盖最大像素尺寸(最长边) |
--quality | int | -- | JPEG 质量 1-31(1=最佳,31=最差) |
--target-model | choice | -- | claude / openai / gemini / universal |
--grayscale | flag | off | 转换为灰度图 |
--high-contrast | flag | off | 增强对比度,提高文字可读性 |
--timestamps | flag | off | 在帧上叠加文件名和时间戳 |
--output-dir | string | temp dir | 提取帧的输出目录 |
输出 JSON 结构
脚本会将以下结构的 JSON 打印到 stdout:
{
"output_dir": "/tmp/video_frames_abc123/",
"frames": ["/tmp/video_frames_abc123/frame_00001.jpg", "..."],
"preset": "balanced",
"resolution": { "width": 1024, "height": 576 },
"token_estimate": {
"frame_count": 30,
"per_frame": {
"claude": 787,
"openai_high": 765,
"openai_low": 85,
"openai_patch": 934,
"gemini": 258
},
"total": {
"claude": 23610,
"openai_high": 22950,
"openai_low": 2550,
"openai_patch": 28020,
"gemini": 7740
}
},
"summary": {
"video_duration_seconds": 120.5,
"extraction_method": "max_frames",
"scene_changes_detected": null,
"frames_extracted": 30,
"estimated_total_tokens": {
"claude": 23610,
"openai_high": 22950,
"openai_low": 2550,
"openai_patch": 28020,
"gemini": 7740
}
}
}
将帧附加到提示词之前,使用 token_estimate.total 确认这组帧符合模型上下文限制。
注意:
openai_high和openai_low用于旧版模型(GPT-4o、GPT-4.1)。openai_patch用于较新的模型(gpt-5.4+、gpt-5-mini、o4-mini)。详情请参阅references/llm-image-specs.md。
发生错误时,会将包含 "error" 键的 JSON 打印到 stderr,并且脚本以代码 1 退出。
提取后
- 解析 JSON 输出,从
frames获取帧路径列表 - 检查
token_estimate.total,确保这些帧符合上下文限制 - 使用 Read 工具读取每张帧图像(它们是 JPEG 文件)
- 分析这些帧,以回答用户的问题
- 清理:完成后,如果输出目录是临时目录,则将其删除