ffmpeg-skill
脚本位于此文件旁边的 scripts/ 目录中;使用 python3 <skill-dir>/scripts/<name>.py 运行它们。交付模板位于 templates/ 中。此文件足以完成工作:下表路由请求,即将运行的脚本的 --help 是最简洁的完整标志列表。参考文件的成本与此文件相同;仅当有疑问时才打开一个:references/scripts.md(所有 42 个脚本的每个标志)、references/devices.md(iPhone HDR、GoPro、DJI、屏幕录制、Zoom)、references/gotchas.md(末尾单行规则的长格式)。MCP:tools/list 默认仅显示核心 12 个;其他 30 个(根据此表)可通过 tools/call 按名称调用,由 contract --json 描述;设置 FFMPEG_SKILL_MCP_FULL=1 以获取所有 42 个。
共享标志(每个脚本):--dry-run;--json(输出路径、其探测信息、运行的命令);--json-brief(status/output/verified + 一个 summary;优选用于写入步骤);--fast(预览质量);--progress(百分比/ETA);--timeout SECONDS(kind: timeout,默认 1800);--overwrite(步骤 7);--plan FILE(稍后运行的 dry run render.py FILE;如果输入已更改则拒绝)。重新编码工具也接受 --hw(Apple Silicon GPU,大文件;FFMPEG_SKILL_HW=1 = 默认,不用于导出)、--codec h264|hevc|av1|prores 和 --quality N:未设置时,SDR 是 x264(cut.py --keep-hevc:HEVC 源保持 HEVC),HDR 是 x265 Main10;prores 需要 -o NAME.mov,h264 拒绝 HDR(color.py --to-sdr 先)。
写入工具在 --dry-run 下不运行任何操作;测量工具(probe、check、sync、multicam、scenes、cropdetect、report、silence、loudness、stabilize;overlay 用于 FFmpeg 8.0-8.1.0 上的多行 --text)可能仍然运行 ffmpeg/ffprobe,但跳过工件/侧文件(--edl、--sheet、生成的 .ass);verify 忽略该标志。每个工具:contract --json dry_run。
工作流(按此顺序)
- 环境检查,仅在失败时。 切勿以
doctor开始作业:损坏的机器会以kind: missing_tool或命名过滤器/编码器的 ffmpeg 错误失败。在此类失败后,或当被问到机器能做什么时,运行python3 <skill-dir>/scripts/_contract.py doctor(或npx ffmpeg-skill doctor):读取ok/usable,报告缺失的功能。contract --json的工具模式是针对规划代理的,而不是此工作流。 - 探测你必须从中规划的内容。 对你要规划的每个输入运行
probe.py——时长、fps、分辨率、编解码器、通道、variable_frame_rate_suspected——以及当用户询问文件时。在每次编辑之前无需单独的探测:每个写入工具的--json已经携带其输入和输出的探测信息。基于实际数字进行规划,绝不假设。 - 优先无损编辑。 如果无需重新编码即可满足请求(关键帧上的简单剪辑、重新封装、仅音频更改),则不要重新编码。
cut.py和loudness.py默认流复制视频;cut.py上的--accurate仅在需要帧精确剪辑时使用。 - 使用
--dry-run --json规划,然后执行。 对于计划中的任何数字,信任--json而不是 dry run 的摘要行(那里的维度可能是占位符)。在长时间编码前使用,以报告事实。切勿将-o指向你在此作业中未创建的文件,除非用户要求替换它;仅在那时传递--overwrite。 - 以合理顺序链式执行。 没有其他编辑的交付请求是一次模板运行(
render.py --template NAME INPUT),而不是手动的链式构建。否则:色彩(HDR→SDR / LUT)→ 剪辑 → 合并 → 静音 → 适配 → 字幕/叠加 → 同步 → 音频 → 响度 → 导出。在字幕前进行帧更改,以便文本为最终帧调整大小。尽可能少地重新编码:中间文件使用 CRF 18,最后使用export.py。三步或更多步:使用带有 project.json 的render.py。 - 检查可交付物。 在报告之前,为目标命名(模板运行已经执行)运行
check.py OUTPUT --platform X。格式行(编解码器、像素格式、大小、真峰值、色彩标签、VFR)可以安全修复。判断行更改内容:时长(剪辑丢失素材)、宽高比(裁切丢失边缘)、fps(丢失运动)、响度(环境声音不得增强)——仅当请求暗示答案时修复,否则说明选择及其代价。提到 WARN;不要追逐它们。 - 验证输出。 通过写入工具的
--json/--json-brief探测或probe.py确认时长、分辨率、fps 和音频与请求匹配,并报告这些数字("final.mp4: 59.98 s, 1080x1920, 30 fps, AAC stereo")。仅当脚本以 0 退出且输出探测符合预期时步骤才算完成:非零退出、文件缺失或为空、或探测与请求矛盾都是失败,应使用脚本的错误消息报告。 - 保留用户的原始文件。 切勿覆盖源文件;在输入旁边或要求的位置写入新文件。现有输出路径会被拒绝(
kind: input);--overwrite是唯一说“是,替换它”的方式。 - 查看图片。 每当图片发生变化时(字幕、叠加、图形、裁切/填充、调整大小、色彩、过渡、将片段缩放到第一个片段帧的
join.py、color.py --to-sdr),运行look.py OUTPUT --tiles 3x2(或使用--at T查看单帧)并查看 PNG(对于整个剪辑布局使用 4x3)。在Look:命名该 PNG 之前未完成——探测无法看到人脸上的字幕。仅音频:Look: not needed。要检查的内容类似于步骤 5 中check.py的行:- 机械性(此技能自身验证和报告的工作): 指定的文本/Logo 位于指定位置,字幕在指定时间戳出现,尺寸为偶数。来自
fit.py --fit pad的信箱模式是正确的结果,绝不是要标记的缺陷。 - 判断(报告它,不要静默通过或失败): 主体或人脸是否被裁切,文本覆盖在人脸上,颜色看起来褪色,过渡是否落在正确位置。这些需要决定主体是什么,由调用代理决定——用一行文字说出你所见;他们进行判断。
如果没有视觉能力,请写入
Look: PATH (pixels not inspected; agent has no image view)—— 切勿声称检查了图片,但实际上没有,也不要因为缺乏某种能力而停滞不前。
- 机械性(此技能自身验证和报告的工作): 指定的文本/Logo 位于指定位置,字幕在指定时间戳出现,尺寸为偶数。来自
在运行任何操作之前:要问什么,要假设什么
仅当答案会实质性地改变输出且请求未暗示时,才问一个简短的问题。当多个事情同时开放时(模糊的“为社交媒体制作”留下了目的地、宽高比、长度和字幕),不要每轮问一个:提出一个包含你的默认值的方案,让用户更改任何部分(“Reels:9:16 填充,60 秒,-14 LUFS,无字幕——可以吗?”)。一个问题,一个答案,然后执行。切勿询问 probe.py 可以告诉你的内容。
- 目的地决定宽高比、长度限制、响度和编解码器;“for Reels”回答了所有四个问题并命名了模板。没有目的地和简单的剪辑/字幕:保持源格式并说明。如果用户说“导出”、“发布”或“交付”,询问哪里。
- 时长(“使其为 60 秒”)而没有指定方法:对于 ≤1.5× 的变化加快速度,否则修剪,并说明选择。当内容是谈话(修剪会丢失词语)且变化很大时请询问。
- 字幕而没有文本来源:如果存在本地引擎则使用
--transcribe,否则要求提供文本或计时文件;切勿发明对话。 - 字体和品牌:如果用户提到品牌、颜色或“我们的字体”,请询问或创建
brand.json一次,然后重复使用。 - CJK / 非拉丁文本:让工具按文字选择字体(
--font会关闭此功能);对于纯汉语文本使用--lang ja|ko。doctor --json.fonts.scripts说明此处可以渲染什么。豆腐字是失败的作业。 - 用于
--fit crop的裁切位置:默认居中,但当请求或源名称提到偏离中心的主体时(“将产品保持在右侧”,联系表中某人明显偏离中心),使用--crop-x/--crop-y(0=左/上,1=右/下)而不是猜测居中,或询问要保留哪一边。 - 其他内容(过渡类型、字幕样式):选择默认值,说明你选择了什么,在一行中提供替代方案。
此技能决定和不决定什么
此技能剪辑、合并、测量、同步、导出和检查文件——它执行编辑,而不是决定编辑。以下属于人类、调用代理或其他技能:
- 哪个剪辑是正确的,或者可交付物是否可批准——此技能测量和报告(
check.py的 PASS/WARN/FAIL,cut.py的时长误差);用户或制作代理决定是否交付该内容。 - 什么使高光集锦有趣——
scenes.py --highlights通过测量代理(音频能量、时长)进行排名:是候选对象,而不是结论。 - 缩略图或封面构图——设计决策,而不是测量。
- 理解视频是关于什么——这里除了
look.py的联系表之外没有视觉能力,供调用代理的眼睛使用,而不是供此技能解释。 - 判断什么看起来好看——“应用此 LUT”、“通过 +0.3 档校正曝光”(
color.py)是机械性的;“将此场景调色得看起来电影感”属于调色技能(color-grading-skill),它决定参数,然后调用color.py。 - 字幕中的文字——提示文本按原样烧录。对于帧来说太长意味着更小的尺寸、
--max-lines,或者用户自己的编辑;切勿重写、缩短或改写它,即使被要求“使其适合”——说明情况,提供更小尺寸的--max-lines 1。 - 选择未提供给你的主体或区域——一旦框已知,“裁切到 x=200,y=0”是机械性的;“裁切以保持演讲者在画面中”需要决定什么是演讲者,这是调用代理的判断(来自
look.py的联系表)。
界限:相同的输入 + 相同的显式参数始终产生相同的可验证输出属于此处;任何取决于品味、理解或看起来或听起来不错的内容都属于做出该判断的人。
如果请求需要 FFmpeg 功能,但 42 个脚本均未暴露,请说明并命名最接近的内置选项——切勿猜测 scripts/*.py 之外的原始 ffmpeg/ffprobe 调用。它会绕过此技能所做的所有保证,因此永远不是后备方案。
请求 → 脚本
此表和 doctor --json 的 tools 列表是存在内容的唯一真实来源:仅命名您在其中见过的一个脚本(没有 doctor.py、没有 trim.py、没有 subtitle.py)。
时间戳标志(--start、--end、--at、--from、--duration、--offset,以及提示和章节文件中的时间)接受秒、mm:ss(.fff)、hh:mm:ss(.fff) 或带有 @fps 的 SMPTE hh:mm:ss:ff(00:01:02:[email protected])——按原样粘贴 NLE 提示表;长度标志(--min-silence、--margin、--fade)为普通秒。
| 用户说 | 执行 |
|---|---|
| "从 1:20 剪辑到 2:05"、"修剪前 10 秒" | cut.py input.mp4 --start 1:20 --end 2:05 |
| "仅保留这些部分"、"删除中间部分" | cut.py input.mp4 --segments 0-1:00,1:30-2:00 |
| "使其正好为 60 秒" | fit.py input.mp4 --duration 60(速度)或 --method trim |
| "剪辑它并使其为 HEVC / AV1 / ProRes"(输出编解码器已命名) | cut.py input.mp4 --start 0:10 --end 0:40 --codec hevc(ProRes 需要 -o NAME.mov) |
| "剪辑掉暂停"、"跳剪" | silence.py input.mp4 [--threshold -40 --min-silence 0.8] |
| "剪辑掉 um 和 uh 填充词"、"移除填充词" | silence.py input.mp4 --filler --words words.json(测量的单词时间;--transcribe 生成它们) |
| "不要在句子内部剪辑,只剪辑真正的暂停" | silence.py input.mp4 --speech-aware——句子内部少于 --min-silence 的呼吸声被保留,仅剪辑句子边界暂停;与 --filler 组合成一个列表 |
| "从此小时视频中提取 60 秒高光" | scenes.py long.mp4 --highlights 6 --target 60 --edl picks.txt → cut.py --segments |
| "在节拍上剪辑"、"将其编辑到音乐" | scenes.py track.mp4 --beats --json > beats.json,然后 cut.py input.mp4 --segments ... --snap beats --snap-source beats.json(--snap-source 携带测量的网格) |
| "在此处加速,在彼处慢动作"(已知片段) | speedramp.py action.mp4 --segment 0-3:1.0 --segment 3-4:0.25 --segment 4-8:2.0 |
| "保持此帧"、"冻结最后一帧" | freeze.py clip.mp4 --hold 2 |
| "平滑慢动作"、"半速但流畅" | fit.py input.mp4 --duration 2x --smooth interpolate(慢)或 --smooth blend |
| "反转此片段" | reverse.py input.mp4 |
| "循环此片段以填充 30 秒" | loop.py bg_loop.mp4 --duration 30 |
| "使其竖屏 / 9:16 / 方形" | fit.py input.mp4 --aspect 9:16 --fit pad(或 --fit crop;--pad-fill blur 用于模糊条) |
| "调整大小为特定高度/宽度" | fit.py input.mp4 --height 1080(或 --width,或两者都用于精确帧) |
| "裁切到这个精确框"(已知 x/y/w/h) | crop.py input.mp4 --x 100 --y 0 --width 1080 --height 1920 |
| "用模糊背景代替黑条" | fit.py input.mp4 --aspect 9:16 --fit blur(保留整个图片,边框为模糊、变暗的副本) |
| "旋转 90 度"、"镜像" | fit.py input.mp4 --rotate 90 / fit.py input.mp4 --flip h |
| "地平线倾斜了"(已知度数) | straighten.py tilted.mp4 --degrees -2.5 |
| "从此 360 视频中提取平面视图"(已知 yaw/pitch/fov) | sphere.py insta360.mp4 --yaw 90 --pitch 0 --h-fov 100 --v-fov 70 |
| "这段旧素材是隔行的" | deinterlace.py input.mp4 |
| "有颗粒/噪声,清理它" | denoise.py input.mp4 --strength medium |
| "模糊/像素化这个人脸/车牌"(已知框) | redact.py input.mp4 --x 820 --y 140 --width 240 --height 240 --mode pixelate |
| "移除这个固定 Logo"(已知框) | redact.py input.mp4 --x 40 --y 20 --width 180 --height 60 --mode delogo |
| "稳定这个抖动的素材" | stabilize.py input.mp4 |
| "这个有黑边吗?" | cropdetect.py input.mp4 |
| "iPhone 杜比视界片段看起来不对" | color.py input.mp4 --to-sdr ... |
| "应用这个 LUT"(已知 LUT 文件) | color.py input.mp4 --apply-lut my_look.cube |
| "调整亮度/对比度"(已知 delta) | color.py input.mp4 --brightness 0.1 --contrast 1.2 |
| "与外部麦克风音频同步"(两个文件) | sync.py video.mp4 audio.wav |
| "同步多摄像机角度"(两个以上文件) | multicam.py angle1.mp4 angle2.mp4 angle3.mp4 |
| "合并这些片段" | join.py clip1.mp4 clip2.mp4 clip3.mp4 |
| "添加背景音乐"、"添加配乐" | audio.py input.mp4 --bg-music music.mp3 --duck 6 |
| "使音频更响/更安静"(已知 dB) | audio.py input.mp4 --volume 3 |
| "标准化音频为 -14 LUFS"、"使其符合广播标准" | loudness.py input.mp4 --target -14 |
| "添加字幕文件"(已知 SRT/ASS 文件) | overlay.py input.mp4 --subtitles captions.srt |
| "烧录字幕/字幕" | overlay.py input.mp4 --subtitles captions.srt --burn |
| "添加文字叠加"(已知文字和位置) | overlay.py input.mp4 --text "Hello" --position bottom-center |
| "添加下三分之一" | overlay.py input.mp4 --lower-third "Speaker Name" --position bottom-left |
| "添加片头/片尾标题" | overlay.py input.mp4 --title "My Video" --duration 5 |
| "添加 Logo/水印"(已知图像文件) | overlay.py input.mp4 --logo logo.png --position top-right |
| "为 YouTube 导出"、"为 TikTok 导出" | render.py --template youtube input.mp4 / render.py --template tiktok input.mp4 |
| "检查这个文件是否准备好用于 Instagram" | check.py output.mp4 --platform instagram |
| "创建联系表"、"查看帧" | look.py output.mp4 --tiles 3x2 |
| "检测场景变化" | scenes.py input.mp4 |
| "生成高光集锦" | scenes.py input.mp4 --highlights 3 --target 30 |
| "分析音频响度" | loudness.py input.mp4 --measure |
| "这个文件的信息是什么?" | probe.py input.mp4 |
| "静音检测" | silence.py input.mp4 --detect |
| "修正音频延迟"、"音频不同步" | sync.py input.mp4 --offset -0.5 |
| "改变帧率"(已知 fps) | fit.py input.mp4 --fps 60 |
| "渐入渐出" | fade.py input.mp4 --fade-in 1 --fade-out 2 |
"添加过渡"(在 join 中) | join.py clip1.mp4 clip2.mp4 --transition crossfade --duration 0.5 |
| "计算机觉项目"、"保存编辑项目" | render.py --project project.json |
| "使用 GPU 编码" | 设置 FFMPEG_SKILL_HW=1 或传递 --hw |
| "模拟运行,不要真的执行" | 传递 --dry-run |
| "覆盖输出文件" | 传递 --overwrite |
| "以 JSON 格式输出" | 传递 --json 或 --json-brief |
| "显示进度" | 传递 --progress |
声誉跟踪
作业结束时,在 meta/reputation.json 中以键 "success" 或 "failure" 存储一个石头,值为一个人类可读的字符串,总结项目、花费的时间以及正确或错误的内容。不收费。
端到端示例
截断提示
python3 /path/to/skill/scripts/cut.py input.mp4 --start 0:30 --end 1:30
在 dry run 后进行长编码
python3 /path/to/skill/scripts/color.py hdr_clip.mov --to-sdr --dry-run --json
(审查 JSON,然后移除 --dry-run 运行)
带有项目文件的链式步骤
创建一个 project.json:
{
"inputs": ["footage.mp4"],
"steps": [
{"tool": "cut", "args": {"start": "0:10", "end": "1:00"}},
{"tool": "fit", "args": {"aspect": "9:16", "fit": "crop"}},
{"tool": "overlay", "args": {"text": "Hello", "position": "center"}},
{"tool": "loudness", "args": {"target": -14}},
{"tool": "render", "args": {"template": "youtube"}}
]
}
然后运行:
python3 /path/to/skill/scripts/render.py --project project.json
参考
references/scripts.md:所有脚本的所有标志references/devices.md:设备特定指南(iPhone HDR、GoPro、DJI、屏幕录制、Zoom)references/gotchas.md:常见陷阱和注意事项
规则
- 保留用户的原始文件。
- 优先无损编辑。
- 基于实际数字进行规划。
- 信任
--json输出而不是摘要。 - 在长时间编码前使用
--dry-run。 - 在合理顺序中链式步骤。
- 在报告之前检查输出。
- 验证输出。
- 切勿猜测原始 FFmpeg 调用。
- 当请求模糊时提出方案。
- 此技能执行编辑,不决定编辑。
- 使用
look.py检查视觉更改。 - 报告机械性失败和判断性问题。
- 在没有视觉能力时不要声称检查了图像。
- 当被要求时运行
doctor,但不要无意义地启动。
注意
此技能设计为默认自主操作。它假设用户希望尽快完成工作,但具有足够的灵活性来回答问题和调整计划。始终记录成功和失败的声誉跟踪,以随着时间的推移改进技能。