| name | vlog-editor |
| description | 本地 AI 驱动的端到端视频剪辑流水线,让 Claude Code 自己把原始素材剪成成片——引擎是 FFmpeg(不依赖 DaVinci/Blender/任何付费 MCP)。覆盖:下载素材、探测、从长连续镜头里抽帧选高光(B-roll 内容选取,替代 shot detection)、mlx_whisper 语音转写 + 卡拉OK/普通字幕、librosa 音乐节拍卡点(downbeat 硬切)、暖色电影感调色、交叉转场/硬切/Ken-Burns 推镜、竖屏模糊填充、标题与下字幕、配乐淡入淡出、渲染后自检循环、project.md 跨会话记忆。Use whenever the user wants to EDIT or ASSEMBLE video from footage — 触发词:剪辑视频 / 剪个 vlog / 把素材剪成片 / 做个 montage / 旅游vlog / 卡点 / 节拍卡点 / 踩点 / 语音字幕 / 自动字幕 / 给视频加字幕 / 视频调色 / 自动剪辑 / 选素材 / edit my video / make a montage / travel vlog / beat sync / cut to the beat / auto captions / burn subtitles / color grade footage。也适用于用户给一个素材目录并希望产出一支剪好的片子。不要用于:生成全新 AI 视频(文生视频)、纯音频处理、或仅转录不剪辑(那用 audio-transcribe)。 |
vlog-editor — 本地 AI 视频剪辑流水线
你是一个能端到端剪视频的助手。核心理念(来自社区 video-use 等 coding-agent 剪辑器的共识):
你看不到视频/听不到音频信号,所以把"感知"外包给工具(ffprobe/抽帧/whisper/librosa),它们吐出结构化数字,你在数字+按需图像上做剪辑决策,再交给 FFmpeg 渲染。
原则:Text + on-demand visuals, no frame-dumping —— 只在决策点抽几帧看,不要 dump 整片。
引擎是 FFmpeg。不要建议 DaVinci/Blender/OTIO MCP:它们的剪辑调色 API 被封,OTIO 也不渲染像素。
0. 环境(开工先体检 —— 一条命令搞定)
python3 bin/doctor.py
脚本(bin/_env.py)自动探测 ffmpeg/ffprobe/字体/编码器,不需要手填路径。可用环境变量覆盖:FFMPEG · FFPROBE · VLOG_FONT。
依赖分层:
- 🔴 CORE(出片最小集)= 一个带 drawtext 的 ffmpeg + ffprobe + 任意 python3(纯标准库,零 pip)
drawtext 需 libfreetype:Homebrew 版常缺 → 用 conda install -c conda-forge ffmpeg(推荐,带 drawtext+libass+VideoToolbox)或完整 brew install ffmpeg。doctor 会自动挑带 drawtext 的那个。
- 编码器自动回落:有 VideoToolbox(Apple) 用硬件加速,否则
libx264,再否则 mpeg4。
- 字体自动选:macOS=Futura、Linux=DejaVu/Noto/Liberation;
VLOG_FONT=/path/to/font.ttf 覆盖。EDL 里的 font 字段可省略(自动探测)或写绝对路径。
- 🟡 可选模块(各自的 python 里
pip install):
- 卡点
beats.py → librosa
- 语音字幕
transcribe.py → Apple Silicon 用 mlx-whisper;其他平台自动回落 faster-whisper(CPU/CUDA 跨平台)
- 下载
yt-dlp · 去静默 auto-editor
- 双 python 提醒:
beats/transcribe 要用装了 librosa/whisper 的解释器(如 conda whisper 环境的 python);其余脚本任意 python3 即可。doctor.py 会告诉你各模块在哪个 python 里可用——按它给的解释器路径调用。
不卡点、不做语音字幕时,只要一个带 drawtext 的 ffmpeg 就能出片(核心链路零 pip 依赖)。
1. 工作流总览
摄入 → 选取 → 决策(写 EDL) → [卡点] → 组装渲染 → 自检循环 → 更新 project.md
probe scan/transcribe 你 beats assemble qc 记忆
先读项目里的 project.md(若存在)续上历史;没有就从 project.md.template 建一份。
2. 摄入 & 选取
探测
python3 bin/probe.py footage/*.mp4 > work/probe.json
素材分两类,选取方式不同:
B-roll(空镜/风景/无人说话)——用 scan.py,不要用 shot detection
连续长镜头几乎没有硬切,PySceneDetect/TransNetV2 找不到东西。正解是抽帧让你看:
python3 bin/scan.py footage_real/hawaii.mp4 --interval 3
然后 Read 那张 work/scan/<name>_sheet00.jpg,认出好窗口(光线/构图/主体/有没有动作),避开过曝/偏暗/静止段。在决策点对候选窗口中点抽全分辨率帧复核:
$FFMPEG -ss <t> -i clip.mp4 -frames:v 1 -vf scale=560:-1 work/scan/pick.jpg
A-roll(口播/人物说话)——用 transcribe.py
$WHISPER_PY bin/transcribe.py narration.wav > work/transcript.json
读转写,标出要保留的句子、删掉 "umm/uh"/重复/静默。把保留段写进 EDL。
3. 决策:写 EDL(edl.json)
EDL 是唯一的"创作"文件,assemble.py 读它出片。Schema:
{
"output": "output/final.mp4",
"width": 1920, "height": 1080, "fps": 30,
"font": "/System/Library/Fonts/Supplemental/Futura.ttc",
"xfade_transition": "fade",
"xfade_duration": 0.8,
"kenburns": false, "kenburns_max": 1.06,
"grade": "eq=...,curves=...,vignette=...,unsharp=...",
"end_fade_to_black": 1.0,
"title": {"text":"WANDERLUST","subtitle":"...","in":0.6,"hold_until":5.0},
"music": {"path":"footage/music.mp3","start":0,"fade_in":1.5,"fade_out":2.8,"gain_db":-1},
"segments": [
{"clip":"footage/a.mp4","in":20.0,"dur":8.0,"role":"open","caption":""},
{"clip":"footage/b.mp4","in":2.0,"dur":7.0,"portrait":true,"caption":"ON THE ROAD"},
{"clip":"footage/c.mp4","in":3.0,"dur":8.0,"role":"close","caption":"UNTIL NEXT TIME"}
]
}
role:"open" 段叠大标题;portrait:true 竖屏素材自动模糊背景填充;caption 是下字幕(留空则无)。
- 直接复制
presets/cinematic.json(舒缓) 或 presets/beat.json(踩点) 当起点,改 segments 即可。
python3 bin/assemble.py edl.json
4. 卡点(可选,节奏感强)
$WHISPER_PY bin/beats.py footage/music.mp3 > work/beats.json
让每段 dur = 相邻 downbeat 之差(视频从 0 起、音乐从 0 起)→ 硬切正好落在小节线。xfade_transition:"cut" + kenburns:true。
5. 语音字幕(口播片)
$WHISPER_PY bin/subtitles.py work/transcript.json work/captions.ass --style karaoke
$FFMPEG -i base.mp4 -vf "ass=work/captions.ass" -c:a copy out.mp4
6. 自检循环(渲染后必做)
python3 bin/qc.py output/final.mp4 --edl edl.json
Read work/qc/<name>_qcsheet.jpg 视觉确认标题/字幕/调色都对。verdict=WARN 或印相表有问题 → 改 edl.json 重渲(最多 ~3 轮),别把有问题的片子给用户。
7. 更新记忆
渲染通过后,在 project.md 的 Render Log 追加一行(日期/EDL/输出/时长/QC),并把新决策、新踩坑记下来。
关键踩坑(违反必出 bug)
- drawtext 字幕全部消失:① ffmpeg 没 libfreetype → 用 conda 完整版;②
-ss 必须在 -i 之前(输入端定位、重置时间轴)——放之后保留源 PTS,高 in 点片段的字幕 alpha 淡入淡出窗口永不命中、alpha 恒 0。assemble.py 已正确处理,自己写临时命令时注意。
- 亮背景字幕看不见 → 白字必须配黑色描边
borderw=4:bordercolor=black@0.9 + 加强底板。
- 连续素材别用 shot detection → 用
scan.py 抽帧选取。
- 混合帧率/分辨率/横竖屏 →
assemble.py 已统一到目标 width/height/fps、竖屏走模糊填充。
快速上手(最短路径)
python3 bin/doctor.py
python3 bin/probe.py footage/*.mp4 > work/probe.json
python3 bin/scan.py footage/<longclip>.mp4
cp presets/cinematic.json edl.json
python3 bin/assemble.py edl.json
python3 bin/qc.py output/final.mp4 --edl edl.json
工具清单:doctor.py(环境体检) probe.py(探测) scan.py(B-roll选取) transcribe.py(转写) subtitles.py(字幕) beats.py(卡点) assemble.py(渲染) qc.py(自检) · _env.py(共享环境探测,被其他脚本 import,非入口)。