关于 cut-video
Cut Video 是用于激进精简长视频录制的技能,可输出供 CapCut 使用的清理后 MP4。它结合 Whisper 转录文本与 Montreal Forced Aligner 的词级时间,并要求对照音频核实边界,尤其注意重复录制片段。
主要功能
- 01裁剪静音、填充词和重复内容
- 02使用 MFA 将文本与音频对齐
- 03通过重新转录核验剪辑边界
- 04支持选择剪辑语气
- 05输出清理后的 MP4
适用场景
- 01精简长时间录制内容
- 02删除面对镜头视频中的错误开头
- 03准备 CapCut 剪辑素材
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ louisedesadeleer/ cut-video --skill cut-video安装后在 Claude Code 中输入/cut-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdLICENSEmake_review.py详细介绍
剪辑视频
激进地精简长篇录制内容:去掉静音、填充词、模棱两可的表达、薄弱的过渡、不完整的开头和重复内容。保留笑声和喜剧停顿。输出清理后的 MP4,可直接导入 CapCut 添加布局、缩放和表情包。
**这项技能比单靠 Whisper 剪辑更准确。**剪辑点由 **Montreal Forced Aligner(MFA)**的词边界驱动(精度约为 10–20ms,并将实际词间静音作为明确区间处理),而不是使用 Whisper 时间戳(误差为 ±100–300ms,且停顿会包含在词语时长内)。Whisper 仅用于生成转录文本,再由 MFA 将文本与音频对齐。结果是:剪辑更精准,不会切掉词语的起始或尾音,并且能可靠地检测静音。
⚠️ 但 MFA 时间只是草稿,并非真实基准(2026-07-02 烧录,
AI is bad at jokes的 DJI 运行结果)。MFA 只能对齐 Whisper 提供的转录文本。对于有大量重录的素材,Whisper 会将重复台词合并,导致 MFA 将一个转录实例摊到多个口述版本上——该次运行后半段测得的漂移为 1–6 秒(“the average of all working code”:MFA 标记为 217.2s,实际起始时间为 225.4s;最后一次 “what this means”:MFA 标记为 114.7s,实际时间为 130.4s)。每个保留边界在渲染前都必须通过独立窗口重新转录(第 2.5 步)来核实真实基准。如果在那段视频上跳过此步骤,后半部分的剪辑就会全部变成垃圾。
风格目标(根据 AI mogging my dad.mp4 校准):
- 平均每 1.3–1.5 秒剪辑一次(剪辑时长中位数约为 1.1s)
- 总时长比原始素材缩短约 40–60%
- 在句子中间剪辑,而不仅仅是在句子之间
- 逐词精简——删掉填充词、模棱两可的表达和薄弱的开场白
输入
- 视频文件路径(由用户提供;否则询问)
- 可选:语气偏好(
aggressive/balanced/sentimental/documentary)——默认:aggressive
工作目录
/tmp/cut-video/<basename>/——开始时创建目录,并保留文件以便调试。
步骤 0 — 创建代理文件(最重要的提速方法)
如果源文件采用 HEVC 编码、大于 500MB,或分辨率为 4K 或更高,先转码为 1080p H.264 工作副本。后续每一步都针对代理文件运行,而非源文件。
先检查方向(ffprobe … width,height)——DJI/手机拍摄的素材通常为竖屏 9:16,硬编码 scale=1920:1080 会导致画面变形。仅横屏使用 scale=1920:1080;竖屏使用 scale=1080:1920(或不受方向影响的 scale=-2:1080 / scale=1080:-2)。
ffmpeg -y -hwaccel videotoolbox -i "$SRC" \
-vf scale=1920:1080 \ # portrait sources: scale=1080:1920
-c:v libx264 -preset fast -crf 20 -pix_fmt yuv420p \
-c:a aac -b:a 192k \
/tmp/cut-video/$NAME/proxy.mp4
关键标志:
- 在输入端使用
-hwaccel videotoolbox——以硬件解码 HEVC,在 Apple Silicon 上速度快约 5–10 倍。不使用它,就得等几分钟而不是几秒。 -preset fast——libx264 默认值为medium,在工作副本上速度慢约 3 倍,却没有实际的画质收益。
硬件编码替代方案(在 M 系列芯片上更快,但文件稍大):
-c:v h264_videotoolbox -b:v 8M
步骤 1 — 获取转录文本(whisper,作为 MFA 的输入)
MFA 是强制对齐器,不是转录器——它需要转录文本来进行对齐。Whisper 在这里唯一的任务就是生成这些文本;切分时不会使用 whisper 的词级时间戳(误差为 ±100–300ms,而且 turbo 会把停顿算进词语时长)。所有时间信息都由 MFA(步骤 1.5)提供。
ffmpeg -y -hwaccel videotoolbox -i /tmp/cut-video/$NAME/proxy.mp4 \
-vn -ac 1 -ar 16000 /tmp/cut-video/$NAME/audio.wav
whisper /tmp/cut-video/$NAME/audio.wav \
--model tiny.en --word_timestamps True --output_format json \
--output_dir /tmp/cut-video/$NAME --language en
模型选择(2026-07-02 修订——“我们只需要词语”这一说法是错的):转录文本就是对齐输入,因此转录错误会变成时间错误。在 AI is bad at jokes 这次运行中,tiny.en 漏掉的词正是旧警告所预测的(“bland”、“slop”),把“Compare this to”听成了“comparative is”,还合并了整句重录内容——而 MFA 对齐这些错误文本后,后半部分的时间偏移了 1–6s。tiny.en 只用于快速初筛,以了解录制内容的结构;如果转录文本显示存在重录/重复,或者素材有噪声/在户外拍摄,则第 2.5 步的分段真实内容校验会使用 small.en,并提供实际切分时间。(使用完整的 small.en 转录来作为 MFA 输入也是不错的升级方案——处理 5 分钟视频约需 1–2 min——但它也会合并重录内容,因此仍不能省去第 2.5 步。)对于非英语内容,使用 --model base 并去掉 --language。我们保留 --word_timestamps True,只是为了留存 whisper 的时间戳以供交叉检查/备用(参见步骤 1.5 的注意事项、2a-legacy)——绝不将其作为主要切分依据。
步骤 1.5 — 使用 MFA(Montreal Forced Aligner)将转录文本与音频对齐 — 计时引擎
这是此技能的核心。**MFA 会将 whisper 转录文本强制对齐到音频,并以约 10–20 毫秒的精度返回单词边界,同时将真正的词间静音表示为明确的空区间。**所有剪辑决策(间隙、填充词、说错后重说、重录)都使用 MFA 单词时间。
**自动安装 MFA(此技能会自行完成——不要让用户手动安装)。**每次运行开始时都执行此幂等引导;一切就绪后,该步骤不会执行任何操作(只需几秒),而在全新机器上首次安装则需要约 2–3 分钟。只有在确实安装了内容时,才告诉用户“正在安装 MFA(仅需一次)……”。
# 1. Ensure conda exists (MFA's only supported install path). Install miniforge via brew if missing.
if ! command -v conda >/dev/null 2>&1; then
echo "conda not found — installing miniforge (one-time)…"
brew install --cask miniforge || brew install miniforge
# make conda available in this shell
eval "$("$(brew --prefix)/bin/conda" shell.bash hook 2>/dev/null || conda shell.bash hook)"
fi
source "$(conda info --base)/etc/profile.d/conda.sh"
# 2. Ensure the mfa env exists with MFA installed
if ! conda env list | grep -q '^mfa\b'; then
echo "creating mfa conda env (one-time)…"
conda create -n mfa -c conda-forge montreal-forced-aligner -y
fi
# 3. Ensure the English acoustic model + dictionary are downloaded (idempotent; skips if present)
conda run -n mfa mfa model download acoustic english_mfa 2>/dev/null || true
conda run -n mfa mfa model download dictionary english_mfa 2>/dev/null || true
如果缺少 brew,就无法自动安装 MFA——请改用 whisper+silencedetect 路径(见下方的回退说明),并告诉用户,要启用 MFA 的高精度功能,需要运行这一行命令:brew install miniforge。
每次运行:
# corpus = a dir with audio.wav + audio.txt (the whisper transcript as PLAIN TEXT, no timestamps)
mkdir -p /tmp/cut-video/$NAME/corpus
cp /tmp/cut-video/$NAME/audio.wav /tmp/cut-video/$NAME/corpus/
python3 -c "import json;d=json.load(open('/tmp/cut-video/$NAME/audio.json'));open('/tmp/cut-video/$NAME/corpus/audio.txt','w').write(d['text'])"
conda run -n mfa mfa align --clean /tmp/cut-video/$NAME/corpus english_mfa english_mfa /tmp/cut-video/$NAME/aligned
# → aligned/audio.TextGrid — "words" tier: (start, end, word); EMPTY-label intervals = true silences
解析 TextGrid 的 words 层(使用 pip praatio,或编写一个 20 行的解析器——区间层是纯文本)。MFA 的优势:
- 真正的单词边界 → 剪辑留白可缩小到约 0.02 秒,不会切掉单词的起始或结尾。
- 真正的静音会表示为明确的空区间 → 2a 间隙表可直接基于 TextGrid 生成;whisper 将停顿嵌入文本的问题也随之消失。
- **注意事项:**MFA 对它收到的转录文本进行对齐。如果 whisper 将口语中的结巴重复合并了(“growth… growth marketer” → “growth marketer”),对齐会在其附近局部偏移——仍需保留
silencedetect检查(2a)作为交叉验证,并将偏差超过 0.3 秒的部分视为可疑区域,重新检查。对于重录较多的自拍素材,偏移并非局部问题——它会累积,可能达到数秒(参见顶部警告和步骤 2.5)。如果噪声底也导致 silencedetect 失效(动态范围过低保护),你就没有任何自动交叉验证——此时步骤 2.5 是必做项,而非可选项。 - **偏移预警——拉长的单词:**任何 MFA 或 whisper 时长约 ≥1 秒的短单词(在 2026-07-02 这次运行中,“like” 为 1.16 秒、“there's” 为 1.5 秒、“of” 为 2.4 秒、“the” 为 4.9 秒),都可能隐藏着停顿、口误或被完全合并的重录内容。预先收集所有拉长的单词;每个单词都标记一个真实内容未知的区域,必须重新选取窗口检查(步骤 2.5)。有一个拉长的 “the” 最终被发现包含整句完整、清晰的一次录制——并且最终保留的正是这段录制。
- **回退方案:**如果 MFA/conda 不可用,且用户不想安装,就改用 whisper 单词时间戳 + 音频 silencedetect(2a)——并在计划摘要中说明这一点。只有此路径会使用 whisper 时间戳来决定剪辑位置。
步骤 2 — 制定剪辑清单(默认采用激进剪辑)
根据MFA 单词区间计算要保留的(起始,结束)时间区间列表(仅在回退时使用 whisper JSON)。激进剪辑会删除以下四类内容:
2a. 静音间隙 — 优先使用 MFA 空白区间,并以音频静音检测交叉核验(更新于 2026-06-10)
使用 MFA(步骤 1.5)时,真正的静音是 TextGrid 中标签为空的区间——直接对这些区间应用下方的间隙表。使用音频静音检测进行交叉核验——但要根据录音本身的噪声底校准阈值;切勿将 -30dB 硬编码(2026-06-16 新增:在一次使用 DJI 麦克风录制的对镜拍摄中吃了亏,其噪声底约为 -24dB:固定的 -30dB 将整段录音都判为非静音,因此每个“静音”间隙都被测为“高于阈值 = 有内容,保留”,约 8 秒的空白停顿也留在了剪辑中):
# 1. Measure the noise floor F and speech level S from per-0.5s-window RMS
# (slice the wav into 0.5s windows, run volumedetect on each, collect mean_volume;
# F ≈ 10th-percentile window RMS (room tone), S ≈ 90th-percentile (speech))
# 2. Set the silence threshold RELATIVE to the floor, not absolute:
THRESH=$(python3 -c "print(f'{F + 6:.0f}')") # 6 dB above the measured floor
ffmpeg -i proxy.mp4 -af silencedetect=noise=${THRESH}dB:d=0.14 -f null - 2>&1 | grep silence_
⚠️ 低动态范围保护措施(2026-06-16 的真正教训):如果 S − F < ~8dB(麦克风噪声大——户外/DJI/领夹麦克风存在空调嗡嗡声,且每秒 RMS 在说话和静音期间读数相同),则任何能量阈值都无法区分说话和静音。此时完全不要相信 silencedetect/volumedetect——所有剪辑都要依据 MFA 词语边界;如果没有 MFA,则在备用方案中依据 small.en 词语起始点 + 拉长词语停顿检测(持续时间远长于正常词语的轻声词其实藏着一个停顿:保留其起始后的约 0.10 + 0.105·len(word) 秒,然后剪到下一个词的起始处)。在计划摘要中说明使用了哪条路径。
没有 MFA 时,只有在通过动态范围检查后,silencedetect 流程才是可靠的间隙来源:mlx_whisper/whisper-turbo(以及 tiny.en)会把停顿嵌入词语时长中——一个 3 秒的“词语”实际上是“词语 [长停顿]”,词间间隙读数约为 0.00,基于间隙的剪辑毫无作用。备用方案应使用 small.en(而非 tiny.en)——tiny 会更严重地将词语时长拉伸至静音期间,还会悄悄漏掉词语(“bland”“slop”)和整段重录内容。解析 silence_start/silence_end,移除这些区间(保留约 0.04 秒的边距;MFA 精确边界可使用约 0.02 秒)。对于“几乎没有停顿”的情况 → d=0.12,边距为 0.03。结合去重(2c/2d),通过移除 silences ∪ dropped-word-ranges 进行剪辑。这就是将中位数控制在约 1.1–1.3 秒的方法。
- **Whisper 会隐藏的结巴重复:**turbo 会将口头重复合并(“growth… growth marketer” → “growth marketer”),而且每次运行的结果都可能不同(漏掉/重新加回词语)。基于转录文本的剪辑无法发现这些问题——MFA 对齐偏移与 silencedetect 检测结果不一致时,说明该区域存在问题;请重新检查,或向用户询问时间码并剪掉精确片段。
2a-legacy. 词间静音间隙(严格阈值)
| 间隙 | aggressive(默认) | balanced | sentimental | documentary |
|---|---|---|---|---|
< 0.25s | 保留 | 保留 | 保留 | 保留 |
0.25–1s | 剪至 0.1s | 剪至 0.3s | 剪至 0.5s | 保留 |
1–3s | 剪至 0.2s | 剪至 0.8s | 剪至 1.5s | 剪至 2s |
> 3s | 剪至 0.2s | 剪至 0.5s | 剪至 1s | 剪至 3s |
aggressive 模式的阈值与参考视频的节奏相符(剪辑中位数为 1.13 秒)。
2b. 填充词 — 前后各留 50 毫秒
始终剪掉:um、uh、umm、uhh、er、erm、ah、mhm、hmm(单独出现时)
2c. 犹豫词与弱过渡语 — 默认模式下积极剪掉
这些词语用作填充语(而非表达实质性内容)时剪掉。标记为待剪,然后在审核步骤中结合上下文确认:
- 犹豫词:
like(用作填充语,而非表示比较)、you know、I mean、I guess、I think(表示犹豫,而非陈述观点时)、kind of、sort of、basically、literally、actually(用作填充语时) - 弱过渡语:
so(句首)、and so、and then、but um、but uh、okay so、right so、well - 冗余限定语:
kind of like、sort of like、or whatever、or something - 重新调整话题的短语:
anyway、so anyway、the thing is、what I'm saying is、to be honest、honestly
在 balanced / sentimental / documentary 模式下,只剪掉出现在重复表述之前的犹豫词(错误起句,见 2d)。在对话性较强的片段中予以保留。
2d. 错误起头和重复——大幅删减
通过以下方式检测:
- **自我纠正:**说话者在约 3 秒内重新说出相同的开头。模式示例:
"I want — I wanted to..."、"It's a — it's an interesting..."。删掉较早的尝试及中间的停顿。 - 重启式铺垫:
"so basically what I'm saying is..."、"the point is..."、"let me start over..."。删掉铺垫,保留实际要点。 - **逐字重复:**说话者连续两次说出相同的 3 个或更多单词。保留较流畅的一遍。
实现提示:对连续词语 n 元组建立滑动窗口模糊匹配。在 3 秒窗口内,若 3 元组相似度 > 0.8,则标记较早的一处以便删除。
2d-bis. 整句重录(自拍对镜录制,新增于 2026-06-10)
自拍式开场白/宣传片中会出现整句重录,间隔 5–60 秒(“The next person is Carmen who works. … The next person, the next guest I invited is Carmen who's social and content lead at Slate”)——远超 2d 的 3 秒窗口。检测并处理这些重录:
- 检测:在60 秒窗口内进行模糊 n 元组匹配(4 元组,相似度 > 0.7);也要匹配句子开头(前 3–5 个词),因为重录通常会重新起句。
- 默认保留最后一遍——说话者会反复录制,直到满意为止。例外:如果最后一遍不完整或说错,而较早的一遍完整无误,则保留完整无误的一遍,并在计划摘要中说明这一调整。
- 重录边界前通常会出现长停顿、吸气声、点击声或提示语(“okay”“again”“take two”)——停顿与开头匹配的组合是最强信号。
- 在第 3 步计划中列出每组重录(
line → takes at [t1, t2, t3] → keeping t3),以便用户指定保留哪一遍。
2e. 绝不可删减的内容——明确保护
- **笑声。**Whisper 会将笑声转录为静音。在应用任何静音删减之前,先检查音频振幅:
将窗口的 RMS 与测得的噪声底 F(2a)比较,而不是与固定 dB 值比较:如果窗口 RMS >ffmpeg -i audio.wav -af "volumedetect" -f null - 2>&1 | grep mean_volumeF + ~10dB,则其中有可听见的内容(笑声、呼吸声、反应声)——应予以保留。对噪声较大的麦克风使用硬编码的-30dB/-25dB阈值会出错,因为其噪声底本身可能已高于该值——这会把纯室内底噪“保护”成笑声,而这正是无声片段得以保留的原因。使用ffmpeg -i audio.wav -af "astats=metadata=1:reset=1,ametadata=print:key=lavfi.astats.Overall.RMS_level"获取每个窗口的 RMS。(还要记住 2a 中关于低动态范围的注意事项:当S − F < ~8dB时,RMS 同样无法区分笑声和室内底噪——应改用 MFA/词语起始时间,并在计划中标出所有模糊之处,供用户判断。) - **喜剧停顿。**包袱之后有意留出的停顿。在
aggressive模式下,也应将其缩短至 0.4–0.6 秒(不要删掉,只需压紧)。 - **反应声。**叹气、“ooh”、“wow”、倒吸气声——都属于内容。
- **单词式包袱。**如果一句话在停顿后以一个词的妙语收尾,应保留这段停顿。
2f. 严格检查——绝不容忍重复(Louise,2026-06-10:“清除所有重复内容”)
生成保留片段列表后,运行机器扫描——不要只靠眼睛检查转录:
- 扫描保留范围内的 MFA 单词,查找:(a) 连续重复的单词;(b) 跨片段边界重复的双词组合(口误重说可能跨越剪切点——曾有一次,“……meet her. And we're [口误] / And we're going to……”就这样漏了过去);(c) 相邻句子重复的句首(“So… So…” → 剪掉第二个)。
- 剪掉填充性口误,即使出现在统计数据中也要剪:“I believe”、句首的“Like”、“I guess”。保留修辞性重复(平行结构)——这是有意为之。
- 删除单词时,剪到 MFA 单词的完整结束位置(再加 0.01 秒)——残留 15 毫秒的元音听起来仍像这个单词。
- MFA OOV 陷阱(2026-06-10 的惨痛教训):MFA 词典中缺失的首字母缩略词/名称(“AI”、品牌名)会在对齐中悄然消失——该单词会被并入相邻单词;随后若将保留片段的结束位置对齐到“最后一个 MFA 单词”,就会截掉实际说出的单词。防护措施:如果 whisper 分段的结束时间比最后一个 MFA 单词的结束时间晚 0.2 秒以上,则对该边界采用较晚的时间(whisper 结束时间或下一处 silencedetect 起始时间);并使用单独片段转录核验该衔接处。
- 核验陷阱:对输出内容进行 whisper 转录会两次误导你。它会:(a) 合并保留下来的结巴重复(真实的“and we're… and we're”只转录一次——看起来干净,其实不然);(b) 在剪切点衔接处幻觉出上下文单词(“girls”+“Enjoy”的衔接会被转录成“So enjoy”——看起来有问题,其实没有)。因此要用两种方式核验:对保留范围进行 MFA 重复扫描(捕获真实的结巴重复),并对任何可疑的衔接处进行逐段单独转录(排除幻觉)。只有重复扫描结果为无重复时才能交付。
- **⭐ 跨 ASR 核验——最强的结巴重复检测器(2026-06-10 发现)。**MFA 重复扫描只能看到 WHISPER 转录出的单词——如果 whisper 合并了某段重说内容(“with the most recent video… with the most recent video” → 只转录一次),MFA 就无从得知,扫描也会让有问题的剪辑通过。解决办法:**使用第二个独立 ASR 转录剪辑并进行对比。**Tella 上传后的转录很适合此用途(采用不同模型 → 盲点不同):它一次就抓出了 5 处重复,而 whisper+MFA 流程却判定内容干净(一个重复短语、一个残留的“or, or”、两个词中片段“pers-”/“per-”、一个重复的“into”)。工作流程:将剪辑上传到 Tella(或任何第二个 ASR)→ 扫描其转录,查找重复单词/双词组合/短语和词中片段(“xyz-”)→ 将命中项映射回源时间点→剪切→重新核验。两个 ASR 结果不一致的部分,恰好标出需要修复或提醒用户注意的区域。
第 2.5 步 — 用独立窗口核实每个保留边界(新增于 2026-07-02 — 这一步挽救了整个流程)
MFA 能提供片段结构(说了什么、大致位置),但对于重录较多或有噪声的素材,它无法可靠地给出剪辑时间点。渲染前,使用 small.en 在独立的 ±几秒窗口中重新转录计划保留的每个片段——在较短的窗口内,whisper 的词语时间点准确,而且能听到完整转录遗漏的词(“bland”“slop”),也能识别完整转录合并的重录内容(“It turns out— it turns out…”)。
# windows: name:start:duration — start ≥0.5s BEFORE the expected onset
for n in "r1:5.5:8.4" "r2:17.0:6.0" "r3:30.5:6.0"; do
f=${n%%:*}; rest=${n#*:}; o=${rest%%:*}; t=${rest##*:}
ffmpeg -y -hide_banner -loglevel error -ss $o -t $t -i audio.wav gt/$f.wav
whisper gt/$f.wav --model small.en --word_timestamps True --output_format json --output_dir gt --language en >/dev/null 2>&1
python3 -c "
import json
d=json.load(open('gt/$f.json'))
print('=== $f (+$o) ===')
for s in d['segments']:
for w in s.get('words',[]):
print(f\"{$o+w['start']:7.2f}-{$o+w['end']:7.2f} {w['word']}\")"
done
(此循环兼容 zsh——不要使用 set -- $var,zsh 不会对未加引号的变量进行分词。)
读取这些窗口时的规则:
- 窗口边缘处的词会被拉长,不可信。 如果第一个词恰好从窗口起点开始,或最后一个词在窗口终点结束,说明它被截断了——真实起止点在窗口之外。使用该时间前,先将边界向外移动约 1 秒,重新截取窗口。
- 窗口内部被拉长的词也可能藏着未听到的音频——
small.en和完整转录一样,会合并窗口内的重复内容(跨越 93.1–97.9 的 “to” 中,包含了一整段被放弃的重录)。任何持续时间 ≳1 秒的词,都要通过更窄的窗口重新核查。有时其中其实有一段完整、干净的重录,完整转录的 ASR 都没有识别出来——用零散片段拼接前先检查。 - 两个窗口对相同的词可能有不同结果(一个窗口捕捉到了口误,另一个则把它截断了)。请调整第三个窗口的位置,让有争议的部分位于窗口中间,远离两端,以此解决分歧。
- 最终保留时间:起点提前 −0.03 秒,终点延后 +0.04–0.08 秒(要精确——20 个保留片段各自累加 +0.10 秒的余量,会增加 2 秒的杂音)。
- 也要剪掉保留片段内部的停顿(新增于 2026-07-02 — “更少静音”)。 仅移除重录和片段间隙还不够:流畅的录制也会在句中停顿(“……谋生,[0.3s] 我想知道……”),累积起来也会很长。扫描每个保留片段中经核实的词语,找出词间间隔 > 0.2 秒的地方,并将每处缩短至约 0.1 秒(剪掉
[gap_start+0.05, gap_end−0.05])。刻意设计的修辞停顿(“中位数……还是平均数”)不要缩短到约 0.15 秒以下。 - 保留片段中的拉长词陷阱(2026-07-02 踩过的坑): 在 ASR 中,拉长的口语词看起来与“词语 + 后续停顿”完全相同(“slooop” 被转录为
slop 285.08–286.32)。剪掉看似停顿的后半部分,可能会把词剪断在元音中间。若要在保留边界处剪入任何拉长的词,先用更窄的窗口重新检查,找出声音实际停止的位置——如果渲染后的核验转录中缺少原先存在的词,就说明剪辑把它删掉了:将边界往外移。
一段 5 分钟视频的成本:约 10–15 个窗口,每个窗口运行 small.en 几秒,合计约 2 分钟。这就是干净剪辑与返工整段后半部分之间的区别。
步骤 3 — 展示计划,立即渲染
不要等待批准——在同一轮中打印摘要并开始渲染(2026-07-09 更改:Louise 没注意到问题,审批关卡让她白白等待;渲染不会造成破坏,重新渲染成本也低,因此先渲染显然更好)。打印此摘要,然后直接进入步骤 4:
Original duration: 7m 25s
Cleaned duration: 3m 58s
Cut: 3m 27s (47%)
Total keep intervals: 312
Median cut duration: 1.2s (target: 1.1–1.5s)
Hard cuts (dead air > 3s removed): 23
Filler hits: 47
Hedge/transition cuts: 89
False-start drops: 12
Notable preserved long pauses: list timestamps + context (laughs, punchlines)
对照基准进行自检:
- 如果中位剪辑时长 > 2s → 不够激进。收紧间隔阈值或扩充犹豫词列表,然后重试。
- 如果中位剪辑时长 < 0.7s → 剪辑过度。可能破坏了呼吸或节奏。将 0.25–1s 阈值放宽到 0.3s。
- 压缩目标:激进模式下为 40–60%。
- **例外 — 重拍较多的素材(2026-07-02):**如果大部分素材时长都来自废弃的重拍片段,压缩主要通过删除整句实现,而非逐词切分——中位保留时长会达到 3–5s,压缩率为 65–75%,这是正确的。应改为根据压缩率和最终脚本的整洁度进行判断;不要为了达到 1.1–1.5s 的中位时长目标,就强行在流畅且保留的片段中间插入剪辑(该目标适用于填充词密集、没有重录的独白)。
自行运行自检,并在渲染前修正违规项——现在的质量关卡由你把关,而不是用户。然后立即渲染。用户会审核结果;如果某处剪掉了笑声或刻意停顿,就调整保留列表并重新渲染(很快——只需剪辑并拼接,无须重新转录)。
步骤 3.5 — 手动时间线编辑器(可选——仅在 Louise 要求时使用)
(自 2026-07-02 起不再默认启用:Louise 发现实际使用时编辑器操作繁琐,更希望流程自动剪得更紧凑——步骤 2.5 中的片段内停顿修剪正是因此而来。仅在她要求手动审查或调整时才生成编辑器。)
提供一个时间线编辑器,让她可以在渲染前(或渲染后)修剪静音并删除不需要的内容:
# keeps.json must be [start, end, "transcript text"] triplets in the working dir;
# needs proxy.mp4 (and ideally audio.wav) in the same dir. Generates wave.png once.
python3 ~/.claude/skills/cut-video/make_review.py /tmp/cut-video/$NAME
open /tmp/cut-video/$NAME/review.html
此页面提供的功能(独立的 HTML 文件,放在 proxy.mp4 旁边,无需服务器——波形峰值和静音建议都嵌入文件中,因此可通过 file:// 使用):
- 显示完整源素材的画布波形时间线,在任何缩放级别都清晰锐利。双指捏合或按住 ctrl/⌘ 滚动滚轮,可围绕光标缩放(连续缩放,范围为适应视图至 400px/s);鼠标滚轮用于平移;也可使用 +/−/适应视图按钮。点击可拖动播放位置;播放头与视频同步。
- 在波形上拖动以删除该范围——这是主要的静音移除操作:看到平坦区段后,划过它即可删除。跨区块边界也有效(修剪、拆分或删除覆盖的内容)。
- 琥珀色斜线带 = 保留区块内自动建议的静音(基于峰值,采用自适应阈值——由生成器计算并嵌入)。点击色带即可剪除(两侧各保留 0.1s 停顿),也可点击**“✂ 全部剪除”**,用最短时长滑块一次处理所有建议。在嘈杂的麦克风录音中,建议效果会变差——这些只是可视化候选项,由她自行判断。
- 拖动区块边缘进行修剪;拖动时视频会实时跳转,方便她听取剪切点。选中边缘后,可按 ±0.05s 微调(使用按钮或 ←/→,按住 shift 则为 0.25s)。
- 在播放头位置拆分(
S),丢弃/恢复区块(D/⌫,或点击对应卡片),双击间隙可恢复已剪掉的片段,撤销(Z,最多 60 步)。 - 下方的卡片列表包含每个片段的 ▶ 播放按钮和转录文本;点击**“预览最终剪辑”**即可连续播放保留区块并跳过已剪内容——无需渲染即可实时预览最终效果。
- **“为 Claude 复制编辑决定”**会复制
{"keeps": [[a,b], ...]}——以源代理素材秒数表示的完整编辑后保留列表。
应用她的编辑决定:粘贴的 keeps 数组会替换旧保留列表——按时间重叠情况,将转录文本从先前的 keeps.json 转移过来(她从间隙恢复的区块没有文本;将其标记为“(已恢复)”),然后重建 filter.txt 并重新渲染。代理素材已就绪,因此修改只需几秒钟。
边界处理:她手动拖动的边缘是有意设置的——不要再将其吸附到 MFA/ASR 词边界。只有当某个边缘落在实际词语中间时才发出警告,并指出具体词语及最近的干净边界。
步骤 4 — 使用 trim + concat 渲染,不要使用 select
**重要:**使用 trim+concat 滤镜图模式,不要使用 select/aselect。select 滤镜会压缩视频帧,但不会正确压缩音频 PTS,导致音画不同步。
为每个保留区间构建一组 trim+atrim,然后将它们 concat:
[0:v]trim=A1:B1,setpts=PTS-STARTPTS[v0];
[0:a]atrim=A1:B1,asetpts=PTS-STARTPTS[a0];
[0:v]trim=A2:B2,setpts=PTS-STARTPTS[v1];
[0:a]atrim=A2:B2,asetpts=PTS-STARTPTS[a1];
...
[v0][a0][v1][a1]...concat=n=N:v=1:a=1[outv][outa]
将滤镜图写入文件(文件会很长——积极剪辑时,7 分钟的源素材可能有 200–400 个区间),并使用 -filter_complex_script。渲染命令:
ffmpeg -y -hwaccel videotoolbox -i /tmp/cut-video/$NAME/proxy.mp4 \
-filter_complex_script /tmp/cut-video/$NAME/filter.txt \
-map "[outv]" -map "[outa]" \
-c:v libx264 -preset fast -crf 20 -pix_fmt yuv420p \
-c:a aac -b:a 192k \
/tmp/cut-video/$NAME/cleaned.mp4
**大量剪切时的更快替代方案:**如果滤镜图超过约 500 个 trim,则改为逐段提取并无损拼接:
- 将每个保留区间提取为单独的流复制片段
- 构建 concat demuxer 文件
ffmpeg -f concat -safe 0 -i concat.txt -c copy cleaned.mp4
这样在修剪阶段就完全无需重新编码。
第 5 步 — 交付
- 将最终文件保存到
<source_dir>/cut_out/<source_name>_cut.mp4(如目录不存在则创建) - 打印一行:原始时长 → 清理后时长、剪掉的百分比、剪辑中位时长、输出路径
open该文件,让用户立即查看- 修改成本很低:代理文件和经过实测校准的时间点都保留在工作目录中,因此“删掉第二段” / “收紧 X”只需几秒即可重新渲染。(如果她要求使用 Step 3.5 编辑器,提醒她该编辑器仍可使用,方便将决策粘贴回去。)
- 提供继续调整:重新调整间隔阈值、切换语气预设、标记要保留或剪掉的特定时刻
常见问题 — 切勿重犯(根据以往运行经验总结)
- 代理处理步骤不要跳过
-hwaccel videotoolbox。 对 7 分钟的 4K 源素材进行 HEVC 软件解码可能需要 5 分钟以上。使用该标记后约需 30 秒。 - 不要使用
select滤镜剪辑。 它会导致音频错位。请使用 trim+concat。 - 不要使用
-preset medium(libx264 的默认值)。 在工作副本上,它比-preset fast慢约 3 倍,画质却没有提升。 - 不要等用户批准后再渲染(2026-07-09 已修改——这一关卡浪费的时间比节省的还多)。打印计划后立即渲染。之前担心的情况(“无声”间隔里藏着笑声,或“填充语”其实是有意强调)由下方的振幅检查和摘要中的保留停顿列表处理——剪错了也只需快速重新渲染。
- 不检查振幅就不要剪掉较长的“静音”。 那通常是笑声、思考时的停顿,或铺垫与包袱之间的节拍。
- 有代理文件时,不要对整个原始源素材运行
whisper。 使用从代理文件中提取的audio.wav运行 whisper。 - 不要对音频重新编码两次。 如果只改了视频,请使用
-c:a copy,跳过不必要的 AAC 编码步骤。 - 不要畏手畏脚。 默认使用
aggressive。参考剪辑风格节奏很快——如果输出感觉“保守”,就不符合 Louise 的 CapCut 节奏。 - 对于重拍较多或噪声较大的素材,不要只依据 MFA 时间点渲染。 2026-07-02 的 DJI 运行实测出现了 1–6 秒的偏差。先用独立窗口(Step 2.5)校准每个保留片段的边界。
- 不要将纵向源素材缩放到 1920:1080。 先检查方向;DJI 和手机素材通常是 9:16。
- 不要信任独立转录中靠近窗口边缘的词语时间点。 碰到窗口边界的词会被截断或拉伸;用作剪辑点之前应重新划分窗口。
h264_videotoolbox -b:v 8M也适用于最终渲染,不只是代理文件——在 M 系列设备上,整个 4K-HEVC→代理文件→18 段渲染总共约 1 分钟即可完成。
基准参考
AI mogging my dad.mp4(2026-05-03,CapCut 项目 0501):
- 460 秒内剪切 335 次 = 每 1.37 秒剪切 1 次
- 中位数 1.13 秒,平均值 1.37 秒
- 41% 的剪辑时长 < 1 秒,12% < 0.5 秒
- 只有 3 次剪辑时长 > 5 秒
- 原始素材压缩约 60%
以此作为调校“aggressive”模式的基准真值。
本技能明确不做的事
- 添加缩放、布局或动态图形(属于独立任务——在 CapCut 中处理,或通过 [[tella-edit]] 处理)
- 添加梗图或 B-roll(由用户挑选;短视频剪辑请参见 [[clipify]])
- 烧录字幕(清理后单独处理)
- 上传到任何地方
让本技能专注于一件事:快速、激进地将长篇录制内容剪辑成更紧凑的 MP4。