mcpField
V
video-cut

video-cut

github.com/whitetowerai创意与媒体1778 次安装3 周前更新
代码仓库

关于 video-cut

Video Cut 是将未经剪辑的长视频制作成紧凑初剪的技能,面向需要压缩内容并保留重点的剪辑流程。它结合人工判断取舍内容与脚本精确处理边界、静音和渲染,并在交付前执行校验。

主要功能

  1. 01根据转录和分析制定保留方案
  2. 02将剪辑边界对齐句子或静音处
  3. 03回收停顿并调整语速
  4. 04渲染连续剪辑片段
  5. 05复查画面、接点及音画同步

适用场景

  1. 01压缩未经剪辑的长视频
  2. 02删去离题内容和长时间停顿
  3. 03生成并核验视频初剪

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/whitetowerai/cut-as-code --skill video-cut

安装后在 Claude Code 中输入/video-cut确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
edit_coarse.json
edit_final.json
reference/
edit_coarse.schema.md
pitfalls.md
scripts/
analyze.py
assign_speed.py
build_edit.py
check_project_protocol.py
cut_render.py
inspect_bounds.py
selfcheck_frames.py
transcribe.py
verify_cut.py
tests/
test_inspect_bounds.py

详细介绍

Video Cut

将一段未经编辑的长视频变成精简、易看的第一版剪辑——果断、理解内容,并经过自我验证。由人类(你,即模型)决定哪些内容值得保留;随附脚本负责机械精度(边界对齐、回收静音片段、内存安全渲染、自检)。

适用场景

  • 需要将原始/未经编辑的视频(YouTube URL 或本地文件)剪得更紧凑。
  • 需求是“剪掉一半”“删掉无聊的部分”“做一个第一版/粗剪”。
  • 不适用于:逐字逐句地微调口头填充词、多机位 B-roll 拼接、色彩/音频润色——这些属于后续 P1/P2 润色阶段。本技能属于 P0:验证诊断并产出扎实的剪辑。

依赖项

/video-understand 是前置条件。先运行它,并在本技能中使用其验证过的媒体、转录文本、分析结果和时间线,不要重新创建这些内容。 开始前,请确认该工具已安装。如果没有安装,请告知用户缺少此项前置条件,并在处理媒体前停止。

激活包含以下内容的任意环境(不要假定特定的 conda 环境名称):

  • PATH 中的 yt-dlp(下载)、ffmpeg/ffprobe(剪辑/渲染/探测)
  • 带有 faster-whisper 的 Python(CPU 可用:device=cpu, compute_type=int8) 先检查:yt-dlp --version、ffmpeg -version、python -c "import faster_whisper"。

项目协议工作流

使用以下持久项目文件:

work/cut/edit-plan.json          # hand-authored keep/drop decisions only
work/timeline.json               # generated precision ranges + source/program mapping
review/01-cut/cut-summary.md
review/01-cut/timeline-map.png
review/01-cut/boundary-review.mp4
review/01-cut/full-proxy.mp4  # optional whole-program pacing review

每项规范决策都有稳定的 id、action(keep 或 drop)、start_s、end_s、reason 和语义/转录证据 evidence_refs。按时间顺序排列保留决策;V1 不支持对源片段重新排序或重复使用。

复用共享证据层,而不是重新转录或诊断:

python skills/video-understand/scripts/transcribe.py work/cache/audio16k.wav work/understand/transcript
python skills/video-understand/scripts/analyze.py work/understand/transcript.json work/understand/analysis.json

现有精度脚本接受规范计划。扩展边界以确保词语完整,可选分配线性变速,然后生成共享时间线:

python skills/video-cut/scripts/build_edit.py work/cut/edit-plan.json work/understand/transcript.json work/cache/edit-final.json
python skills/video-cut/scripts/assign_speed.py work/cache/edit-final.json work/understand/transcript.json
python skills/video-understand/scripts/build_timeline.py work/cache/edit-final.json work/timeline.json --fps-num SOURCE_FPS_NUM --fps-den SOURCE_FPS_DEN

使用 work/understand/media.json 中的精确有理数帧率;绝不要将 30000/1001 四舍五入为 30/1。检查 timeline-map.png 和较短的 boundary-review.mp4。只有在需要检查整段节目的节奏时,才生成 full-proxy.mp4。将结果写入 cut-summary.md,并在操作检查报告中指向该文件。

记录时间线贡献及其所需的源输入,更新操作整数 revision,并将 based_on 设为所使用的确切理解版本:

"render": {
  "kind": "timeline-transform",
  "input": "../input/original-video.mp4",
  "plan": "timeline.json"
}

通过所有版本检查后,共享交付渲染器会对当前序列进行编码。

独立兼容工作流

迁移期间仍支持以下旧版文件和命令。build_edit.py 同时接受 edit_coarse.json 和规范的 decisions[];cut_render.py 同时接受 edit_final.json 和 timeline.json;本技能的 transcribe.py 是对 ../video-understand/scripts/transcribe.py 的兼容包装器。

将所有中间文件保存在 work/ 下,交付文件放在项目根目录:

work/source.mp4            # downloaded original
work/audio16k.wav          # 16k mono audio for whisper
work/transcript.json/.srt  # word-level timestamps
work/analysis.json         # diagnosis (silences/fillers/runs)
work/edit_coarse.json      # *** YOUR editorial decision (hand-written) ***
work/edit_final.json       # expanded tight render segments (generated; carries per-segment speed)
work/selfcheck/            # cut re-transcript + join frames
first_cut.mp4              # THE DELIVERABLE
first_cut_report.md        # edit + self-check report

流程(6 步)

1. 下载

下载可获取的最高画质及音频。默认播放器客户端经常失败(视频不可用/DRM/需要登录)。可靠的备用方案是 android 客户端:

yt-dlp --extractor-args "youtube:player_client=android" \
       -o work/source.mp4 "<URL>"

如果不登录只能获取合并封装的 360p(格式 18),则接受该画质并记录限制——HD DASH 经常受 DRM 或登录限制。然后提取音频:

ffmpeg -y -i work/source.mp4 -ac 1 -ar 16000 work/audio16k.wav
2. 转录(词语级)
python scripts/transcribe.py work/audio16k.wav work/transcript [base.en]

生成 work/transcript.json(包含片段和每个词的起止时间)及 .srt。 使用 faster-whisper、CPU/int8、启用 VAD、设置 word_timestamps=True。 **非英语:**传入多语言模型和 --lang,例如: python scripts/transcribe.py work/audio16k.wav work/transcript medium --lang zh .en 模型仅支持英语。先用一段简短样本验证语言。 **注意:**Whisper 会去除大多数发声填充词(如“嗯”“呃”)——无法仅根据转录文本测量这些词,因此填充词检测必须结合下方的词语搜索和静音间隔分析,不能只依赖转录文本。

3. 诊断(“看”+“读”)
python scripts/analyze.py work/transcript.json work/analysis.json

展示内容:开头和结尾的冷场、词间静音 ≥0.8s(归到其前面的词)、填充词计数、wpm、speaking_ratio、近似重复、>40s 的独白片段(可能在絮叨)。

要看画面,每隔约 2s 抽取一帧,制作联系表并自行查看;确认场景结构/检查黑屏或无用帧:

ffmpeg -y -i work/source.mp4 -vf "fps=1/2,scale=240:-1,tile=10x10" -frames:v 1 work/contact.png
ffmpeg -i work/source.mp4 -vf "blackdetect=d=0.1:pic_th=0.98" -an -f null -

如果是单一的静态对镜讲话镜头,就不会有场景切换——这是预期情况;请注意,后面的跳切很正常,并非故障。

4. 决定剪辑 — 手动编写 edit_coarse.json

这是编辑的核心。阅读转录文本和分析结果,然后编写粗剪计划,将整个时间线完整划分为保留片段和删除区间,不留空隙或重叠,每项都包含 in、out 和一行 reason。将缓慢的开场压缩成少量高价值内容;实质性内容保留为较大的片段;删除明显的离题内容/絮叨。保留时间顺序;规范的 V1 时间线不允许重新排序。 目标是将时长大致缩短一半。

  • 格式规范和完整示例:reference/edit_coarse.schema.md。
  • 每个片段边界都要对齐到句子/分句结尾——绝不要在句中或口吃处开始/停止。使用:
    python scripts/inspect_bounds.py work/edit_coarse.json work/transcript.json
    
    它同时接受旧版 keep[] 和规范的 decisions[] 计划,并打印每个边界处被截断的词,方便你将边界微调到干净的位置。
5. 扩展 → 自动调整语速 → 渲染

将粗略区块细分为紧凑、无冷场的渲染片段,统一语速,然后渲染:

python scripts/build_edit.py   work/edit_coarse.json work/transcript.json work/edit_final.json 1.5
python scripts/assign_speed.py work/edit_final.json   work/transcript.json   # adds per-segment speed
python scripts/cut_render.py    work/edit_final.json   work/source.mp4 first_cut.mp4
  • build_edit.py 会在每个区块内部的停顿超过 SPLIT_GAP(第 4 个参数,例如 1.5s)时拆分区块,并将每个边界裁入静音部分(前导 0.10s / 尾随 0.30s),以免截断词语并收回冷场时间。SPLIT_GAP 越小,切分越紧凑,但也越零碎;对于语速缓慢、表达从容的说话者,建议使用约 1.5,而不是 0.6(避免频繁进行细碎剪切)。
  • assign_speed.py(自动变速)——按 decision_ref 对渲染片段分组,测量每个人工编写的保留决策对应的语速,并将一个共享的 speed 因子以及每个片段计算出的 out_dur 写回 edit_final.json。语速已经处于舒适区间时保持 1.0;超出区间时,仅调整至最近的死区边缘。相邻决策区块的语速差异最多为 0.08x,以避免连接处出现“忽快忽慢”的感觉。 此工具只改变语速,不会改变保留的内容。渲染前请阅读输出的表格:
    • 指标:每分钟词数(英语)——对 CJK(zh/ja/ko)自动切换为每分钟字符数。
    • 默认值是首次运行的起始值,并非经过验证的固定常量:死区为 145–185 WPM,速度限制在 1.0–1.3。此功能只会加速:语速较慢的决策区块可以加快,而自然语速较快的内容则保持 1.0。较短的决策区块(<3.5s / <6 个词)难以准确测量,会沿用全局因子。
    • 语速是在收回冷场时间后测量的,因此数值会高于按总时长计算的 WPM,也更接近发音语速。审核输出表格至关重要:渲染前请仔细查看,并根据说话者调整 deadband,不要盲目相信默认值。
    • 参数(k=v):mode=segment|global|off(默认 segment;global=整段视频使用一个因子,off=禁用)、deadband=lo,hi、min_speed=/max_speed=、min_seg=/min_words=、lang=auto|en|cjk。若要完全跳过此功能,只需不运行这一步——cut_render.py 会将缺少的 speed 视为 1.0。
  • cut_render.py 使用 N 个独立的定位输入 + concat 滤镜,只重新编码一次。这是必需的:如果从一个解码后的输入中裁剪 N 次,ffmpeg 会缓存整个解码流(长视频可能达到数十 GB)。参见 reference/pitfalls.md。 当片段带有 speed 时,它会重新调整每个输入的时间(视频使用 setpts / 音频使用 atempo),并在拼接前统一每个输入的帧率、时间基和采样率,从而保持音视频同步;如果没有 speed,则会回退到完全相同的原始处理图。
  • 最终对比:video-edit-compare 会读取标准时间线和实际的最终成片。它会将最终画面映射回源视频时间,将变速片段延展至其源视频时长,并将删除的范围显示为黑色。
6. 自检——通过检查前不得宣告完成
# protocol precision regression check (run from the repository root)
python skills/video-cut/scripts/check_project_protocol.py
# re-transcribe the finished cut
ffmpeg -y -i first_cut.mp4 -ac 1 -ar 16000 work/selfcheck/cut_audio16k.wav
python scripts/transcribe.py work/selfcheck/cut_audio16k.wav work/selfcheck/cut_transcript
# content + filler + boundary check
python scripts/verify_cut.py work/edit_final.json work/transcript.json work/selfcheck/cut_transcript.json
# frame / black / join check (join times use post-speed out_dur, so they stay accurate)
python scripts/selfcheck_frames.py work/edit_final.json first_cut.mp4 work/selfcheck
# A/V sync + no residual dead air
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of csv=p=0 first_cut.mp4
ffprobe -v error -select_streams a:0 -show_entries stream=duration -of csv=p=0 first_cut.mp4
ffmpeg -i first_cut.mp4 -af silencedetect=noise=-32dB:d=1.5 -f null -

通过标准:

检查项通过条件
黑帧无
拼接帧干净——仅有自然的画面跳变,无黑帧、冻结帧或撕裂帧
音视频同步视频与音频时长相差不超过约 1 帧(≈30ms);启用变速时,总时长约为 final_duration_s_after_speed
≥1.5s 的冷场0(speaking_ratio 应明显升高)
丢失/重复片段无——所有关键内容均保留(difflib 约 0.90 可以接受;比例更低通常是口齿不清的语音在第二轮转录时产生的噪声,并非内容丢失——在归咎于剪辑前,请通过关键词确认内容是否存在)
截断的半句话无——边界应落在静音处或句尾

**关于语气词的客观说明:**按段落剪辑无法实现“几乎没有语气词”。每分钟语气词密度甚至可能上升,因为保留下来的内容仍带有对话特征。请如实说明;按词语级别删除语气词属于 P1/P2(并且会让单镜头对谈画面明显变得零碎)。

最后

编写 first_cut_report.md:包括源文件摘要、删掉了哪些内容及原因、自检表格, 以及任何如实说明的注意事项(360p 源文件带来的质量上限、填充词密度等)。 如果应用了变速,请披露:有多少个片段经过了重新调速,以及速度范围 (参照 assign_speed.py 的表格 / speed_params),让读者知道剪辑并非与实时速度 1:1 对应。还要说明,提速后 verify_cut.py 的每分钟填充词数量略高——这是报告中的统计偏差,并非添加了填充词。

核心原则(来之不易的经验)

  • 内容由你决定;帧由脚本决定。 手动编写 edit_coarse.json; 让 build_edit.py 负责精确处理,让 assign_speed.py 负责节奏。
  • 变速只影响节奏,不改变内容。 自动变速会为来自同一个 decision_ref 的所有渲染片段设置相同速度,只将超出范围的节奏调整到最近的死区边缘,将相邻决策之间的速度差限制在 0.08x,并将输出速度限制在 1.0–1.3。 atempo 会保留音高。查看表格;设置 mode=off 或跳过此步骤即可停用变速。
  • 绝不截断词语。 边界始终落在静音处。
  • 仅使用内存安全的渲染方式(N 个定位输入 + concat)。绝不对同一个输入执行多次 trim。
  • 果断行事。 做出合理判断并继续;不要过度追问。
  • 自检不容妥协。 在声称完成之前,重新转录并检查帧。
  • 完整的陷阱与修复方法请参阅 reference/pitfalls.md。

评论

支持 Markdown