关于 ffmpeg-skill
ffmpeg-skill 是面向需要可重复、可验证媒体处理的 Agent 的音视频编辑技能。它提供 42 个脚本,用于编辑、测量、导出和检查输出,并规定了从探测输入到验证结果的流程。
主要功能
- 0142 个媒体处理脚本
- 02视频与音频编辑
- 03试运行和可复用计划
- 04输出检查与验证
- 05用于目视审查的预览图
适用场景
- 01剪切和拼接视频片段
- 02将 HDR 素材转换为 SDR
- 03为指定平台准备媒体文件
- 04按要求检查导出文件
MCP 相关
它将脚本作为 MCP 工具公开:默认在 tools/list 中显示 12 个;设置 FFMPEG_SKILL_MCP_FULL=1 可启用全部 42 个。其他工具可通过 tools/call 按名称调用。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kajisho5/ ffmpeg-skill --skill ffmpeg-skill安装后在 Claude Code 中输入/ffmpeg-skill确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.npmignore.gitignoreCONTRIBUTING.mdCHANGELOG.mdLICENSE.claude-plugin/plugin.json.claude/skills/ci-pipeline-synthesizer/assets/github-actions-nodejs.ymlgithub-actions-rust.ymlgithub-actions-python.ymlgithub-actions-go.yml.claude/skills/code-review/references/review-checklist.mdresult-honesty.mdsurfaces.md.github/FUNDING.ymlpull_request_template.mddependabot.ymlrelease-drafter.yml.github/ISSUE_TEMPLATE/bug_report.mdconfig.ymlfeature_request.md.github/scripts/bump_roadmap_md.pyresolve_version.pybump_contract_md.py.github/workflows/codeql.ymldependabot-auto-merge.ymlrelease.ymlci.ymlrelease-drafter.ymldemos/CI.mdbuild.py详细介绍
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(状态/输出/验证结果,以及一个 summary;写入步骤优先使用此标志);--fast(预览质量);--progress;--timeout SECONDS(kind: timeout,默认值为 1800);--overwrite(步骤 7);--plan FILE(将试运行结果保存为计划,之后可通过 render.py FILE 运行;如果输入内容已更改则会拒绝运行)。重新编码工具还支持 --codec h264|hevc|av1|prores 和 --quality N:未设置时,SDR 使用 x264,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)仍可能运行 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的工具架构是给规划 Agent 用的,不适用于此工作流。 - 探测规划所需的信息。 对每个用于规划的输入运行
probe.py,获取时长、fps、分辨率、编解码器、声道数、variable_frame_rate_suspected;用户询问文件信息时也要运行。无需在每次编辑前单独探测:每个写入工具的--json都会包含输入信息和输出探测结果。根据实际数值规划,切勿凭假设。 - 优先无损处理。 如果无需重新编码即可满足请求(关键帧上的直接剪切、重新封装、仅更改音频),就不要重新编码。
cut.py和loudness.py默认会对视频进行流复制;cut.py仅在需要精确到帧的剪切时才使用--accurate。 - 先用
--dry-run --json规划,再执行。 规划中的任何数值都以--json为准,不要信任 dry run 的摘要行(其中的尺寸可能只是占位值)。长时间编码前使用此选项,以便报告实际情况。--fast用于预览质量,--progress会在 stderr 输出百分比/预计剩余时间。除非用户要求替换文件,否则切勿将-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 立体声”)。只有脚本以 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的检查行相同:- 机械检查(本技能必须验证并报告): 指定的文本/徽标位于指定位置,字幕出现在指定时间戳,尺寸为偶数。
fit.py --fit pad产生的黑边是该模式下的正确结果,绝不能将其标记为缺陷。 - 判断类检查(报告情况,不要擅自判定通过或失败): 主体或人脸是否被截断,文字是否覆盖人脸,颜色是否显得褪色,转场是否落在合适的位置。这些需要判断主体是什么,应由调用 Agent 作出判断——用一行说明所见,由其决定。
- 如果不具备视觉能力,写
Look: PATH (pixels not inspected; agent has no image view)——绝不要声称检查过画面;也不要因缺少此能力而停滞。
- 机械检查(本技能必须验证并报告): 指定的文本/徽标位于指定位置,字幕出现在指定时间戳,尺寸为偶数。
运行任何操作前:该询问什么,该默认什么
只有当答案会显著影响输出,且请求中没有明确说明时,才简短提问。多个问题同时未确定时(比如含糊地说“做成社交媒体用”时,目标平台、画面比例、时长和字幕都未确定),不要每轮问一个问题:把你的默认选项打包提出,让用户可以更改任意一项(“Reels:填充至 9:16,60 s,-14 LUFS,不加字幕——可以吗?”)。问一个问题,得到一个回答,然后执行。不要询问 probe.py 能告诉你的内容。
- 目标平台决定画面比例、时长限制、响度和编码格式;“用于 Reels”这句话就能确定全部四项,并指定一个模板。如果没有说明目标平台,且请求只是剪辑或加字幕:保留源格式并说明这一点。如果用户说“导出”“发布”或“交付”,询问要用于哪个平台。
- 时长(“做成 60 s”)但未指定处理方式时:变化幅度 ≤1.5× 时加速,否则裁剪,并说明采用哪种方式。如果内容是演讲(裁剪会丢失话语)且变化幅度较大,则先询问。
- 字幕没有文本来源时:如果本地有 whisper,则使用
--transcribe;否则询问用户提供文本或带时间码的文件;绝不编造对话。 - 字体和品牌:如果用户提到品牌、颜色或“我们的字体”,询问用户提供或创建
brand.json,之后重复使用。 - CJK / 非拉丁文本:让工具按文字所属的文字体系选择字体(
--font会关闭此功能);纯汉字文本使用--lang ja|ko。doctor --json中的.fonts.scripts会说明这里支持渲染哪些文字。出现方框字形即表示任务失败。 - 裁剪位置对于
--fit crop:默认居中,但如果请求或源素材指出主体不在中心(例如“让产品留在右侧”,或画面中人物明显偏离中心),使用--crop-x/--crop-y(0=左侧/顶部,1=右侧/底部),不要猜测居中,或者询问要保留哪一侧。 - 其他事项(转场类型、字幕样式):选择常规默认值,说明你的选择,并用一句话提供其他选项。
此技能决定什么、不决定什么
此技能负责剪切、拼接、测量、同步、导出和检查文件——它执行编辑,不负责决定如何编辑。以下事项由用户、调用它的 Agent 或其他技能负责:
- 选择哪个剪辑合适,或判断交付内容是否可以批准——此技能负责测量并报告(
check.py的 PASS/WARN/FAIL、cut.py的时长误差);是否交付由用户或制作 Agent 决定。 - 什么样的精彩片段才有意思——
scenes.py --highlights根据测量得出的代理指标(音频能量、时长)排序;这些只是候选片段,不是结论。 - 缩略图或封面的构图——这是设计决策,不是测量。
- 理解视频 讲的是什么——此处没有视觉理解能力,只有
look.py生成的联系表,供调用它的 Agent 查看,而不是供此技能解读。 - 判断画面效果是否好看——“应用此 LUT”“将曝光校正 +0.3 档”(
color.py)属于机械操作;“将此场景调色得更有电影感”则属于调色技能 (color-grading-skill),由它决定参数,再调用color.py。 - 字幕的文字内容——提示文本会按原样烧录到视频中。若文字对于画面而言太长,应缩小字号、使用
--max-lines,或由用户自行编辑;绝不要改写、缩短或转述,即使用户要求“让它适配”也不行——应说明情况,并建议使用较小字号的--max-lines 1。 - 选择未提供的主体或区域——已知边界框后,“裁剪到 x=200,y=0”属于机械操作;“裁剪以确保说话者留在画面中”则需要先判断说话者是谁,这项判断应由调用它的 Agent 根据
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 s” | 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(任何重新编码工具都可使用 --codec/--quality;ProRes 需要 -o NAME.mov) |
| “剪掉停顿”,“跳切” | silence.py input.mp4 [--threshold -40 --min-silence 0.8] |
| “剪掉嗯啊之类的口头语”,“删掉填充词” | silence.py input.mp4 --filler --words words.json(测量词语时间;使用 --transcribe 生成) |
| “不要在句子中间剪,只剪真正的停顿” | silence.py input.mp4 --speech-aware — 句子中的短促呼吸若短于 --min-silence,则保留;只剪句子边界处的停顿;与 --filler 组合后输出一个列表 |
| “从这段一小时的视频中剪出 60 s 精华片段” | 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 |
| “稳定这段抖动的素材” | stabilize.py input.mp4 |
| “这里有黑边吗?” | cropdetect.py input.mp4 |
| “iPhone Dolby Vision 视频看起来不对” | color.py clip.mov --to-sdr 或 --strip-dovi(保留 HDR,移除 DV 图层) |
| “颜色看起来褪色了 / iPhone HDR” | color.py input.mov --to-sdr(探测结果显示 hdr: true) |
| “应用这个 LUT”,“转换 S-Log 素材” | color.py input.mp4 --lut grade.cube [--lut-strength 0.7] |
| “颜色标记错了” | color.py input.mp4 --retag bt709(流复制;只有复制无法保留标记时才重新编码 — 参见 reencoded) |
| “调亮 / 增强对比度 / 校正白平衡” | color.py input.mp4 --correct --exposure 0.3 --contrast 1.1 --saturation 1.05 --temperature 5600 --tint -0.05 |
| “根据这个 SRT 添加字幕”,“烧录字幕” | caption.py input.mp4 --srt subs.srt |
| “用这些台词加字幕”(带时间的文本) | caption.py input.mp4 --text cues.txt |
| “保留可开关的字幕”,“将 SRT 封装进去” | caption.py input.mp4 --srt subs.srt --mode mux;多个语言可重复使用 --srt file:lang,超过两种语言时使用 .mkv |
| “字幕太小了 / Short 里有三行字幕”,“不要截断句子” | caption.py 会在拆分字幕前缩小字号,直到字幕适配 --max-lines(--fit-size off 会保留 --size 并改为拆分,--min-size 可设置最小字号)。保留模板的 --max-lines(竖屏为 2)并允许字号缩小;为了避免缩小而调高此值,会导致每行堆叠两个词。若一个词在最小字号下仍宽于栏宽,则会在边缘拆开(优先使用连字符),不会改写词语;此操作自动完成;JSON 中的 broken_inside_word 会统计拆词次数 |
| “转录并加字幕” | caption.py input.mp4 --transcribe --animate pop --karaoke(需要本地 whisper;否则使用 --text) |
| “添加 TikTok 风格的跳字字幕” | caption.py input.mp4 --text cues.txt --animate pop --karaoke |
| “在右上角放我们的 Logo”,“加水印” | overlay.py input.mp4 --image logo.png --position top-right --scale 200 |
| “前 4 秒显示标题” | overlay.py input.mp4 --text "Title" --position top --start 0 --end 4 --fade 0.4 |
| “在角落显示网络摄像头画面”,“画中画” | overlay.py input.mp4 --video webcam.mp4 --position bottom-right --scale 480 |
| “移除绿幕” | overlay.py bg.mp4 --video greenscreen.mp4 --chromakey 0x00ff00 |
| “带我名字的下三分之一字幕”,“倒计时片头”,“进度条” | graphics.py input.mp4 --template lower-third --name "..." --title "..." --start 2 --end 8 |
| “贴纸”,“前 3 s 的吸睛卡片”,“梗图文字” | graphics.py input.mp4 --template sticker --text "NEW" --platform tiktok / --template hook --title "..." --duration 3 / --template meme --top "..." --bottom "..." |
| “使用我们的品牌字体/颜色/Logo” | 在 caption/overlay/graphics 中使用 --brand brand.json,或在 project.json 中设置 "brand" |
| “同步领夹麦克风”,“对齐两台摄像机” | sync.py camera.mp4 mic.wav --replace-audio / sync.py camA.mp4 camB.mp4 --trim-second;第三台及更多录音设备作为其他位置参数传入(sync.py ref.mp4 mic.wav cam2.mp4),一个 offsets JSON |
| “修正音量”,“标准化到 -14 LUFS” | loudness.py input.mp4(播客使用 -I -16 --tp -1.5,广播使用 -I -23;使用 --lra N 设置范围) |
| “清理音频”,“去除嘶嘶声” | audio.py input.mp4 --voice(语音;--voice light|medium|strong)或 --denoise |
| “在讲话声下方添加背景音乐” | audio.py input.mp4 --music bed.mp3 --duck --fade-out 3(--effects sfx.wav 会添加第三层音轨,不会触发闪避;项目音量设置:audio.stems) |
| “让音乐闪避更明显 / 更快恢复” | 添加 --duck-amount 18 --duck-threshold -30 --duck-release 250(也可添加 --duck-attack) |
| “混音听起来太窄”,“加宽立体声” | audio.py band.wav --stereo-widen 0.5(需要真正的立体声源;5.1 音频需要使用 --downmix) |
| “将 5.1 声道转为立体声” | audio.py input.mov --downmix |
| “替换为旁白音轨” | audio.py input.mp4 --replace narration.wav |
| “提取音频”,“把声音保存为 WAV” | audio.py input.mp4 -o input.wav(使用音频扩展名会移除画面;使用 --audio-stream 1 选择音轨) |
| “压缩人声”,“限制峰值”,“抑制房间噪声” | audio.py input.mp4 --compress --comp-threshold -20 --comp-ratio 4 / --limit --limit-ceiling -1 / --gate --gate-threshold -45 |
| “一小时内音频逐渐不同步” | sync.py camera.mp4 recorder.wav --fix-drift --replace-audio |
| “将这个播客转换成视频”,“音频图” | render.py --template audiogram ep.m4a --image cover.png — 在静态图或纯色背景上显示波形;不会获取任何内容 |
| “制作 TikTok / Reel / Short / YouTube / X / LinkedIn / 播客版本” | render.py --template tiktok|reels|shorts|youtube-shorts|youtube|x|linkedin|facebook|podcast input.mp4 [--cues cues.txt] [--title "..."] — 用一条命令完成画幅、字幕、响度、导出和检查(--list-templates;可先用 --write-project 进行编辑) |
| “发布到所有平台”,“为每个平台剪一版” | render.py --template all input.mp4 --cues cues.txt(或使用逗号分隔的列表)→ 每个目标平台生成一个文件,另附 <name>_pack.md(report.py --pack 会生成 HTML) |
| “导出 YouTube / Reels / X 版本”,“ProRes 母版” | export.py input.mp4 --preset youtube|reels|tiktok|shorts|linkedin|facebook|x|prores|h265(--normalize 会在同一次调用中达到响度规格;youtube-hdr 保留 HDR,youtube-av1 输出 AV1) |
| “生成 GIF 预览” | export.py input.mp4 --preset gif |
| “小型代理文件 / 低成本预览文件” | proxy.py input.mp4 [--width 640 --no-audio] — 不是交付预设(交付预设请使用 export.py) |
| “这个文件可以上传吗?” | check.py final.mp4 --platform reels |
| “带章节的播客单集” | loudness.py ep.wav -I -16 --tp -1.5 → metadata.py ep.m4a --chapters chapters.txt → check.py ep.m4a --platform podcast(章节和声道行) |
| “给我一份操作摘要” | report.py --before raw.mov --after final.mp4 --platform youtube -o report.html |
| “将这张图片转成片段”,“标题卡片” | insert.py title.png --duration 3 |
| “让照片缓慢缩放”,“Ken Burns 效果” | insert.py photo.jpg --duration 6 --zoom in --pan right --width 1920 --height 1080 |
| “制作空白/纯色背景视频片段” | background.py -o bg.mp4 --duration 3 --width 1920 --height 1080 --color 0x101010 |
| “将这些编号帧转成视频” | sequence.py --dir frames --pattern "frame_%04d.png" --fps 24 |
| “为这段音轨生成波形/频谱视频” | waveform.py podcast.wav -o waveform.mp4 |
| “在开头添加黑场” | pad.py clip.mp4 --start 1.5 |
| “切到 0:12-0:16 的产品镜头”,“在这段上叠加 B-roll” | broll.py talk.mp4 --insert product.mp4 --at 12 --end 16(可重复使用 --insert/--at;--audio b|mix) |
| “添加章节”,“为 YouTube 添加章节标记” | metadata.py episode.mp4 --chapters chapters.txt(每行使用 TIME TITLE;流会被复制;在项目中使用 "chapters")。--auto-chapters 会根据测得的停顿/场景切换提出章节建议(Chapter N) |
| “设置标题 / 艺术家 / 评论” | metadata.py episode.mp4 --title "Episode 12" --artist "Studio" |
| “把这些视频放进 4x2 网格” | grid.py t1.mp4 ... t8.mp4 --cols 4 --rows 2 |
| “拼接这些片段”,“添加交叉淡化” | join.py a.mp4 b.mp4 c.mp4 --transition fade --duration 0.5(TTS:--list parts.txt、--on-missing skip、--on-silent fail) |
| “对一次剪辑进行多项更改”,3 步及以上 | render.py --init project.json,编辑后运行 render.py project.json |
| “我改了一个阶段,不要重新处理其余部分” | render.py project.json --cache DIR — 相同的阶段会复用(--from STAGE 从指定阶段开始) |
| “在 Premiere / Resolve / Final Cut 中打开” | render.py project.json --export-timeline edit.fcpxml|.edl|.otio — 不会渲染;查看 not_exported;没有项目?使用 --write-project |
| “对文件夹中的每个文件都执行此操作”,“使用所有核心” | batch.py FOLDER --recipe batch.json --jobs auto(步骤或渲染项目;带缓存) |
| “三台摄像机,镜头间切换” | multicam.py camA.mp4 camB.mp4 camC.mp4 --switch "0-20:0,20-40:1,40-60:2"(手动)或 --switch energy(--min-shot);--edl = 剪辑列表;编辑器:--write-project p.json → --export-timeline |
| “这个文件里有什么”,“时长是多少” | probe.py input.mp4 |
| “看看效果如何”,“字幕是否易读” | look.py output.mp4 --tiles 3x2,然后查看 PNG |
| “你会运行什么命令?”,“先不要渲染” | 任意脚本都可使用 --dry-run |
| “哪些镜头是静止的、哪些在移动”,“每秒的音量峰值”,“这是语音还是音乐” | scenes.py input.mp4 --shots(逐镜头标记静止/摇摄/运动,并测量光流)/ --audio-peaks(dBFS 列表)/ --speech(语音与音乐的比率,并非分类结果)— 可组合使用,也可单独使用 |
| “主体在哪里移动,这样我就能自己裁剪” | cropdetect.py input.mp4 --motion-centre — 每秒的运动质心,仅生成报告;由调用方 Agent 选择裁剪区域 |
| “它看起来像 Log / S-Log 吗?” | probe.py clip.mp4 --analyze(looks_like_log),然后运行 color.py --lut |
| “在我的实际文件上测试工具” | verify.py ~/Footage --report verify.md |
| “显示进度”,“先快速预览” | 任何编码脚本都可使用 --progress 和/或 --fast |
| “这是使用可变帧率的手机视频” | 无需额外操作:重新编码时会将 VFR 转为恒定帧率;fit.py --fps 30 可选择帧率 |
仅音频文件
音频是一等输入:probe、cut、silence、loudness、audio、sync、check --platform podcast、render --template podcast 支持 WAV、FLAC、MP3、M4A/AAC、OGG、Opus;输出格式由扩展名决定。需要画面的脚本(fit、caption、overlay、graphics、color、export、scenes、look)会拒绝音频,并提示“input has no video stream”——不要强行套用视频封装。操作指南:references/gotchas.md#audio-only-files。
报告格式
使用用户请求所用的语言回复——即使字幕使用其他语言,也仍使用请求所用的语言进行报告。标签(Done:、Steps:、Check:、Look:、Notes:)保留英文;其余内容使用用户的语言。无论任务多短或是否失败,都不要改变格式:即使只需回复一行“文件不存在”也一样。对话中途切换语言时,以用户最新消息为准。
每项任务都以如下格式结束(数字取自 --json 或 probe.py/check.py,不要凭记忆填写):
Done: final.mp4 — 59.98 s, 1080x1920, 30 fps, H.264, AAC stereo, -14.1 LUFS
Steps: cut 0:12-1:12 (lossless) -> fit 9:16 crop -> captions (pop, karaoke) -> loudness -14 -> export reels
Check: reels — all 12 checks pass (verified: true)
Look: final_sheet.png (captions inside the safe area, logo top-right)
Notes: source was VFR, conformed to 30 fps; audio was mono, made stereo
日语请求也使用相同的五行格式:
Done: final.mp4 — 59.98 秒、1080x1920、30 fps、H.264、AAC ステレオ、-14.1 LUFS
Steps: 0:12-1:12 をカット(無劣化)-> 9:16 にクロップ -> 字幕(ポップ、カラオケ)-> ラウドネス -14 -> Reels 書き出し
Check: reels — 12 項目すべて合格(verified: true)
Look: final_sheet.png(字幕はセーフエリア内、ロゴは右上)
Notes: 元は VFR だったので 30 fps に揃えた。音声はモノラルだったのでステレオにした
报告仅限这五行,以及用户必须决定的事项。没有输出探测结果,绝不要报告成功;绝不要描述未实际执行的修复。
某个步骤失败时,将 Done: 替换为 Failed:,其余内容如实填写:
Failed: color.py --lut grade.cube exited 1 — ffmpeg: "Unable to parse LUT file" (the .cube is not a valid LUT)
Steps: probe -> color (failed); nothing written
Check: nothing to verify
Look: not needed
Notes: send a valid .cube, or say if you want the clip left as is
这些填充行是句子,不是标签:日语请求的同一报告以
Check: 検証するものなし / Look: 不要
结尾。
拒绝请求时也使用相同格式:Failed: 说明拒绝的事项及原因,Steps: 列出实际执行的步骤,Look: not needed。最简短的失败报告也必须包含全部五个标签,不能使用标题。部分完成时使用 Done:,并在 Notes: 中简要说明未完成之处;若拒绝请求但仍提供了部分内容,则使用 Failed:——绝不要使用 Done (partially): 之类的第三种标签。在 Notes: 中引用失败信息的 error.hint——也就是重试时需要更改的标志。
每个脚本在使用 --json 时都会输出 {"status": "failed", "error": {"kind": input | ffmpeg | output | missing_tool | timeout | verification | interrupted, "message": ...}} 并以非零状态码退出;引用其中的消息,切勿转述。
看起来正确但实际有误
每项一行;如果当前任务涉及该领域,请打开链接的 references/gotchas.md 章节。
- HDR(iPhone、HDR10)经 SDR 路径重新编码后会变平;这些脚本会保留 HDR;
hdr: true表示真实的 PQ/HLG/DV 信号,bt2020_or_hdr: true也包括 BT.2020 SDR。 -> #hdr-and-colour - Log 素材(S-Log/V-Log/C-Log)被标记为 SDR,因此看起来发灰:先运行
probe.py --analyze,然后运行color.py --lut。 -> #log-footage - 使用
-c copy剪辑可能会从错误或冻结的帧开始;cut.py会在 0.5 s 对齐点之后重新编码,请尊重这一点。 -> #keyframe-cuts - VFR 手机/屏幕录制:重新编码时会转换为 CFR,
cut.py会切换到--accurate;如果帧率异常,请用fit.py --fps选择帧率。 -> #variable-frame-rate - 同步/多机位的
confidence低于 0.3(或偏移量很大)时结果可疑——请检查每台摄像机;这些工具对齐的是音频,不是唇形同步。 -> #sync-multicam-and-drift - 音频即使经过“标准化”仍可能削波(请检查真峰值);-40 LUFS 或更低的环境音绝不能提高到语音目标响度。 -> #loudness-and-ambience
- 在裁剪/调整大小之前烧录的字幕会偏离画面;先以小尺寸烧录,再由
export.py放大,字幕会变模糊。 -> #captions-fonts-and-text-order - Emoji 需要通过
--emoji-assets DIR(每个字形对应一个 PNG)才能以彩色渲染;没有这些资源时会以单色显示,并报告此问题。 -> #emoji - 非拉丁文字会按书写系统选择字体(
graphics.py通过 libass 排版天城文、孟加拉文、泰米尔文和泰文;drawtext 无法做到);没有字体会导致任务失败。 -> #fonts-by-script --fit crop将 16:9 转为 9:16 时会舍弃 70% 的画面宽度;按速度实现“60 秒”和按剪辑实现“60 秒”是不同的结果——请说明采用哪种方式及原因。 -> #reframing-fps-and-duration- TikTok/Reels 的界面会遮挡底部五分之一和右侧栏——模板会让文字避开这些区域;运行
look.py --safe tiktok可查看。 -> #platform-safe-zones scenes.py --highlights按响度(或时长)排序,而不是按含义排序:请先检查表格,再决定是否采纳结果。 -> #highlights- 重新编码使用 x264
medium;在一个render.py项目中串联 3 个或更多步骤。 -> #chaining-and-speed