Communitygithub.com

Developh/resolve-cut

全面剪辑人物出镜视频(课程、教程、访谈),在 DaVinci Resolve Studio 中完成端到端制作:包含逐词转录、每个镜头的档案、每个段落的最后完整镜头、帧精度的剪辑列表、按脚本编排时间线、预设渲染、质量控制(响度、帧数、重复词汇)及交付。请在需要进行 Resolve 脚本编写、装配、渲染、质量控制或视频交付工作之前加载此技能。

resolve-cut 是什么?

Developh/resolve-cut 是一款针对 DaVinci Resolve Studio 的专业 AI 技能,专为高效剪辑人物出镜(如教学课程、访谈)而设计。它提供端到端支持,从生成逐词转录和素材档案开始,通过外部脚本实现帧精度的剪辑列表、时间线自动组装、预设渲染、质量检测(含响度和重复词检查)以及最终交付。该技能遵循固定工作流程,将人性化决策(“保留什么”)与自动化执行分离,允许在反复修改过程中可持续地进行版本迭代并保持控制。它支持 macOS 上的 Resolve Studio,通过 `run.py` 执行脚本,并提供了详细的故障排除指南,记录了已知的 API 陷阱、导入问题以及特定平台(Instagram、YouTube、LinkedIn)的交付目标。脚本主要操作 JSON 格式的转录文件、元数据以及媒体文件,需配合 ffmpeg 和 Python 环境使用。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Developh/resolve-cut/tree/HEAD/skills/resolve-cut

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

resolve-cut 是做什么的?

你通过保存的带参数脚本在 DaVinci Resolve Studio 中执行编排、渲染和检查视频。你不会在每次会话中重写编排逻辑:而是调用脚本,读取其返回值,并通过数字和帧数验证结果。审美判断仍由人类保留:由人来决定保留哪些内容,你来执行和测量。

$SKILL 表示该技能文件夹(本文件所在的位置)。在 scripts/resolve/ 中的脚本通过 run.py 在 Resolve 内部运行;scripts/media/ 中的脚本是使用 ffmpeg 的普通 Python 脚本。每个脚本都有 --help。

开始前准备

  1. Resolve 响应测试:python3 "$SKILL/scripts/resolve/run.py" - '{}' <<< 'result = resolve.GetVersionString()'。 退出代码 2 表示 Resolve 已关闭、使用的是免费版、或者“偏好设置 > 系统 > 常规 > 外部脚本使用”未设置为“本地”。
  2. ffmpeg -version、python3 -c "import numpy, PIL" 以及 ELEVENLABS_API_KEY(环境变量或 ./.env 文件)。
  3. 如果项目有备注文件(VIDEO_NOTES.md 或类似文件),请阅读:了解之前用户批准和拒绝的内容。不要重复询问相同的修改。
  4. 工作文件夹:你创建的所有内容(转录、档案、帧、渲染输出)都要放入工作文件夹,切勿放入原始素材文件夹。

工作流程

1. 转写。 逐词级转录,每个剪辑一个 JSON 文件: python3 "$SKILL/scripts/media/transcribe.py" <clips 文件夹> --out work/transcripts [--language por]。 转录是一切的基础:用于选择镜头、在帧边界上剪辑以及检查最终混音。

2. 制作档案。 将所有素材紧凑地整合到一个文本文件中,只阅读一次: python3 "$SKILL/scripts/media/dossier.py" <clips 文件夹> --transcripts work/transcripts --out work/dossier.md [--sheets]。 它会列出每个句子及其时间码,并在某个句子开头与之前的句子相似时标记 «repeats C0076 20.2»,表示这是同一句台词的又一次尝试。有脚本的情况下,保留每个段落的最后一个完整镜头;删除犹豫、假开头和重复尝试。只有在需要做出决定时才打开剪辑: python3 "$SKILL/scripts/media/inspect_range.py" <clip> <t0> <t1> --words work/transcripts/<clip>.json(在一张图中显示帧、波形和词汇)。

3. 剪辑列表。 编写 work/plan.json,按顺序列出选中的镜头 ({"Lesson 01 v1": [["01a", "C0081", 1.9, 12.6], ["01b", "C0083", 5.4, 23.8], ...]}:镜头、剪辑、起始时间、结束时间(相对于剪辑的秒数)),然后: python3 "$SKILL/scripts/media/cut_list.py" work/plan.json work/transcripts <clips 文件夹> work/cuts.json。 剪辑点会落在词汇附近最安静的帧边界上,超过 1 秒的停顿会被缩短,并且片段会交替使用缩放 1 / 1.2,使得镜头间的切换不突兀。对于没有间隙的假开头(例如 "co- contar"),可以通过 {"in_frame": N} 或 {"out_frame": N} 强制指定帧。编辑器备注:add_markers.py。

4. 在 Resolve 中装配。 每次调用执行一个重量级操作,并在下一次调用前读取每个 result:

R="$SKILL/scripts/resolve/run.py"
python3 "$R" "$SKILL/scripts/resolve/project.py" '{"name": "Lesson 01", "width": 1920, "height": 1080, "fps": "25"}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "import", "bin": "Raw", "media": "/abs/clips", "files": ["C0081.MP4"]}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "timeline", "bin": "Raw", "cuts": "/abs/work/cuts.json", "timeline": "Lesson 01 v1", "zoom": {"center": [0.45, 0.37]}, "voice_isolation": 50}'

zoom.center 是人脸在画面中的位置(以帧的分数表示),因此放大镜头可以保持人脸位置不变。检查 frames == expected 且 failures 为空。

5. 渲染前查看。 frames.py 可以在一秒内直接从时间线导出帧 ({"timeline": "Lesson 01 v1", "frames": [100, 500], "folder": "/abs/work/frames", "max": 960})。查看一个普通帧和一个放大帧。

6. 渲染。 python3 "$R" "$SKILL/scripts/resolve/render.py" '{"phase": "start", "timeline": "Lesson 01 v1", "folder": "/abs/out", "name": "lesson-01", "preset": "reel", "width": 1920, "height": 1080, "mark": [0, <frames - 1>]}' 然后每 10 秒轮询 {"phase": "status", "job": "<id>"} 直到 JobStatus 变为 Complete。在渲染完成之前不要回答:如果无头运行在“渲染开始”时结束轮次,将无人检查渲染状态。

7. 验证。 python3 "$SKILL/scripts/media/qc.py" out/lesson-01.mp4 --expected <frames> --transcribe (添加 --ref 比对上一个批准的版本,--frames 生成表格,--simulate 模拟 Instagram)。阅读最终混音的转录,在每个剪辑点检查:重复词汇("decide, decide")、被剪掉的词汇以及位置错误的词汇是剪辑列表最容易产生的缺陷。在移动剪辑点前,在波形上确认可疑的剪辑(inspect_range.py),修复剪辑列表,装配新版本(v2)并再次渲染。最多进行 3 轮,每个缺陷需注明其精确时间。永远不要因为“看起来正确”就认为完成:必须引用数字。

8. 交付。 当混音偏离目标时使用 loudness.py(线性增益加限制器,绝不使用 loudnorm),然后使用 deliver.py export.mp4 clean.mp4 [--no-editlist] [--copy <folder>]:无时间码轨道、无元数据、moov 优先,逐字节比较复制结果。

9. 复查,待用户批准后。 在备注文件中记录用户批准和拒绝的内容,使用用户的原始措辞,每行一条;记录每个新陷阱及其日期;以及任何你手动执行超过一次的操作,都成为旁边的带参数脚本。

在 Resolve 中运行脚本

  • run.py 连接到打开的 Resolve 实例,并运行定义了 resolve、project、P(JSON)和 __file__ 的脚本,然后将 result 打印为 JSON。这比通过 MCP 编写相同脚本消耗的 token 少得多。
  • 如果使用 MCP 服务器(官方 run_script_unsafe): P = {...}; __file__ = "<脚本的绝对路径>"; exec(open(__file__, encoding="utf-8").read())。沙盒在未指定 encoding 时以 ASCII 读取文件,且变量名在调用间持久存在:脚本需要为其变量添加前缀。
  • 在写入前后都要保存 (GetProjectManager().SaveProject());没有撤销功能。每次创建新版本时,都要在时间线的副本上进行操作 (DuplicateTimeline,此操作也会复制 Fusion 合成)。
  • 查找 API 而非猜测:使用官方 MCP 的 search_scripting_api、get_scripting_docs 和 get_whats_new(每个会话一次),或者查阅 Resolve 的 Developer/Scripting 文件夹中的 Blackmagic README(帮助 > 文档 > 开发者)。
  • 有需要重复的新操作?一次性编写为带有 P 字典和 result 的脚本,放在这些脚本旁边。

交付目标

目标平台画面音频
Reels, Stories, Shorts, TikTok1440x2560,拍摄帧率,H.264 High 约 20 Mbps 实际码率,Rec.709 标记 (1-1-1),faststart-14 LUFS,真峰值低于 -1.5 dBTP
课程和教程原始分辨率(1920x1080 或 3840x2160)-16 LUFS,真峰值最高 -1 dBTP
YouTube4K 母版(1080p 上传会损失画质),MP4 不含编辑列表母版的混音
LinkedIn1920x1080 和 1080x1920 16 Mbps,带 SRT母版的混音

已验证的陷阱

在 macOS 上使用 Resolve Studio 21.1.1 和 21.1.2 测量,2026 年 10 月和 11 月。

机器方面

  • 每次只运行一个 ffmpeg,使用 nice -n 15 和 -threads 2:96 个并行 ffmpeg 进程会使 Mac 死机并强制重启。
  • 在 zsh 中,$var 不会分割成单词 (ffmpeg $args 会出错):在 Python 中构建参数列表。
  • 将输出写入工作文件夹:如果辅助脚本将图像保存到剪辑旁边,则会写入原始素材驱动器。

Resolve 设置与 API

  • Resolve 21.1 将 Python 脚本功能转移到了 Studio:run.py 和两个 MCP 服务器都需要 DaVinci Resolve Studio。
  • 必须将“外部脚本使用”设置为“本地”(偏好设置 > 系统 > 常规),否则 scriptapp("Resolve") 返回 None。
  • StartRendering 是脚本的最后一次调用:在此之后所有内容都返回 None,直到渲染结束。
  • 项目帧率在创建第一个时间线时锁定:之前设置好 (project.py)。
  • 分辨率设置:SetSetting 一次设置一个键,先设置 useCustomSettings。
  • MCP 超时(默认 10 秒,最多 60 秒)会返回错误,但脚本会在 Resolve 内部继续运行:再次运行前需检查状态。
  • 没有修剪、移动或滑动操作:删除该项目并使用 startFrame、endFrame(不包含)和 recordFrame 重新添加。
  • startFrame 从文件的第一个帧开始计数,即使有摄影机时间码。
  • GetSourceStartFrame 有时会读取早一帧(866 读取为 865),但放置位置是正确的:使用 GetLeftOffset 读取切入点。
  • AddMarker 每个帧只保留一个标记。
  • ReplaceClip 会清除剪辑的元数据。
  • SetTrackEnable 在某些时间线上返回 True 但实际上不生效:使用 SetClipEnabled 禁用剪辑,并在导出的帧上确认。
  • 在非当前时间线上调用 SetClipEnabled 返回 False:先调用 SetCurrentTimeline,然后使用 GetClipEnabled 确认。
  • DeleteClips(items, True) 会影响所有轨道:先删除跨越该剪辑点的内容(对白、字幕)而不进行波纹编辑。
  • 语音隔离可通过脚本实现:TimelineItem.SetVoiceIsolationState({"isEnabled": True, "amount": 100}) 可将房间混响降低 3 到 4 dB;Timeline.SetVoiceIsolationState(track, {...}) 设置整个轨道的一个控制。
  • API 无法设置 ResolveFX 参数(面部美化、去瑕疵):由人工设置,或通过无障碍功能驱动 UI。
  • 当屏幕锁定或 Resolve 最小化时,窗口会从无障碍功能中消失,但 API 仍可工作:通过导出的帧验证。
  • Super Scale 是媒体池属性:SetClipProperty("Super Scale", 2);替换文件需要重新设置。
  • Graph.SetLUT 的 LUT 放在 Resolve 的系统 LUT 文件夹的子文件夹中,在 RefreshLUTList() 后通过相对路径传递。
  • 在 Resolve 播放时切换页面会导致挂起;item.GetFusionCompByIndex(1).Execute(lua) 可以在不打开 Fusion 页面的情况下编辑合成。

导入与媒体

  • 每次导入只调用一个 ProRes 文件:在一次调用中导入多个 ProRes 4444(以及一次两个新的 ProRes 422)导致 Resolve 21.1 崩溃(UiMpController,std::out_of_range)。相机 MP4 文件,一次 22 个,没有问题。
  • 崩溃后,会有一个残留的 ResolvePython 进程使得 MCP 的 launch_resolve 报告 Resolve 正在运行:杀死该进程并重新打开 Resolve。
  • ImportMedia 使用路径列表时,在 21.1 版本上使用字典形式对 MP4 返回 None。
  • Resolve 根据路径缓存解码:重新渲染的文件需要新名称。
  • MOV 中的 PCM 24 位小端格式被读取为白噪声:请使用 pcm_s24be。
  • iPhone HEVC 导致 macOS 解码器崩溃:从 ProRes 进行编辑。
  • iPhone HDR (HLG, Dolby Vision):我们自己的色调映射看起来褪色,被拒绝了两次。一开始就要求 SDR 导出。
  • 1 帧的 .mov 被导入为 150 帧的静止图像:至少提供 3 帧,然后在时间线上修剪。
  • 直通 Alpha:Resolve 以未预乘的方式读取 Alpha,因此在透明画布上使用 ffmpeg overlay 创建的叠加层会变暗;使用 pad=W:H:x:y:[email protected] 定位。

渲染

  • 使用 SelectAllFrames 时,StartRendering 有时返回 False:设置 MarkIn/MarkOut(render.py 的 mark),这也能剪掉延长时间线的音频尾音。
  • 在仅音频任务之后立即创建的 H.264 任务输出不带视频:在 SetRenderSettings 之前加载预设,并用 ffprobe 检查视频流。
  • H.264 的 VideoQuality 是上限而非平均值:20000 在 1440x2560 下给出 14.7 Mbps,27300 给出 20.7 Mbps。
  • "Force sizing to highest quality" 不是 SetRenderSettings 的键,但它包含在渲染预设中 (ForceHighestQualitySizing)。
  • ExportRenderPreset(name, path) 将 path 视为文件夹;ImportRenderPreset 以文件名命名预设。
  • 预设存储帧率:从时间线设置 FrameRate,否则 29.97 的时间线会被转换(render.py 会处理)。
  • ExportFrame (21.1.2) 在 0.75 秒内给出 1440x2560 的 4 帧,与渲染的差异在 41 到 46 dB 之间:无需渲染即可检查帧。

音频与转录

  • 两个镜头之间的剪辑可能连接一个重复的词汇("decide, decide"):转录最终混音并查找重复内容。修复而不改变长度:在词汇之前结束第一段,在优秀镜头的停顿中更早开始第二段。
  • 转录听不到低语和呼吸声:剪辑点来自相机自带音频 (cut_list.py)。
  • 有一次 Scribe 将一个词提前了 3 秒放置(在一声拍手和低语之后):在移动剪辑点前确认波形。
  • MP3 音效会延迟约 60 毫秒(编码器延迟未补偿):对于需要精确到帧的音频使用 WAV。
  • loudnorm 在单遍模式下是动态的,会改变已批准的混音;在两遍模式下会静默回退到动态模式:使用 loudness.py。

素材与平台

  • Instagram 上的 25 fps:以 25 fps 服务(2026 年 11 月对服务文件的 ffprobe 测试)。卡顿来自 ProMotion iPhones,这些手机没有 25 或 50 Hz 模式。保持 25 fps 素材为 25 fps(转换为 30 会每五帧重复一帧);拍摄新素材时使用 1/50 快门的 29.97 fps。
  • 50 Hz 灯光下的闪烁取决于快门而非帧率:1/50 和 1/100 不闪烁;30 fps 下的 1/60 会闪烁。
  • Instagram 在手机上和服务端都会重新编码:基础交付约为 720x1280 在 1.4 Mbps,音频归一化到约 -14 LUFS,因此高于 -14 的母版没有增益。qc.py --simulate 显示哪些会留存。
  • ffmpeg 的 CRF 会使暗色背景码率不足:一个 Reel 的码率只有 6.8 Mbps。在交付前检查实际码率。
  • 无头运行的 claude -p 在渲染开始时结束轮次,除非提示要求等待渲染完成。

脚本

脚本功能
scripts/media/transcribe.py每个剪辑的 Scribe 逐词 JSON(密钥通过 stdin 传入,绝不在进程列表中显示)
scripts/media/dossier.py每个剪辑的紧凑文本:带时间的句子、停顿、重复尝试,可选的帧表格
scripts/media/inspect_range.py范围的一张图像:帧、波形、带时间的词汇
scripts/media/cut_list.py镜头选择与剪辑
scripts/media/add_markers.py为编辑器添加标记
scripts/resolve/run.py在 Resolve 中执行 Python 脚本的入口
scripts/resolve/project.py创建或打开项目
scripts/resolve/assemble.py导入媒体并装配时间线
scripts/resolve/render.py渲染时间线
scripts/resolve/frames.py导出时间线中的特定帧
scripts/media/qc.py质量控制:检查帧数、转录、响度
scripts/media/loudness.py调整音频响度(线性增益和限制器)
scripts/media/deliver.py最终交付版本清理

提示:所有脚本的详细用法请使用 --help 参数查看。

相关技能