@gao_sean/mv-editor

AI自动生成曲目 MV

G@Gao_Sean·latest·↓ 4·updated 2026-05-11·MIT
music

AI 音乐 MV 制作流水线

把「音频 + 参考图」做成完整 MV,covers 4 个核心阶段。

When to load

  • 用 InfiniteTalk / Wan I2V 跑 lip-sync 音乐视频
  • 把多段视频按歌词时间轴拼接 + 加智能过场 + 烧字幕
  • 多平台输出 (B 站 16:9 / 抖音 9:16 / 小红书 4:3)
  • 排查 MV 剪辑常见坑 (口型漂移、过场时间累积、xfade chain bug、必剪/剪映工程不互通)

4 阶段流水线

阶段 1: 音频对齐 & 段位划分

import stable_whisper
m = stable_whisper.load_model("base", device="cpu")
r = m.align(MP3, text=lyrics_txt, language="zh", original_split=True)
r.to_srt_vtt(SRT, segment_level=True)
# 找关键段起点 (Intro / Hook / Verse / Bridge / Outro)
for s in r.segments:
    if "副歌金句" in s.text: print(s.start)

输出: srt + 段位时间表 (锚段需要哪些段位的精确时间)。

阶段 2: 视频生成 (ComfyUI 远程 GPU)

两种 clip:

类型工具长度跟音频
锚段 (口型)Wan 2.1 InfiniteTalk Single5-19s是 (输入 mp3 片段)
短镜 (氛围)Wan 2.2 I2V + KJ wrapper (G01_basic.json)4-7s否 (只输入图)

关键坑 (踩过):

  1. AudioCrop.widgets_values 必须整数秒, "0:18.5" 报错 → 用 "0:18"
  2. Wan I2V 的 G05 模板 (LightX2V x3 LoRA) 风格保持极弱, 经常跑成"白衣古风+电光鸟"。必须用 G01 (KJ WanVideo wrapper, lightx2v 只 1 个 LoRA on high)
  3. KSamplerAdvanced.widgets_values 中 seed 在 index 1 不是 3 (index 3 是 steps)
  4. Wan I2V 末尾 1-2 帧有 "倒走" bug → 每段 trim 末尾 1s
  5. 锚段视频末尾有 ~1s padding → trim 到精确音频长度
  6. ui2api_v2.py 已处理 SetNode/GetNode 链 + Anything Everywhere

双卡分配: 段长平均分到 GPU 6006 / 6010, 长度大致均衡。

阶段 3: 时间轴拼接 (MoviePy, 防漂移核心)

永远用 MoviePy CompositeVideoClip + with_start(精确时间), 不用 ffmpeg xfade chain (xfade 必漂移, ffmpeg 8.1+ chain 还有 truncation bug)。

from moviepy import VideoFileClip, CompositeVideoClip, vfx
clips = []
for path, start, dur in plan:
    c = VideoFileClip(path).subclipped(0, dur).with_start(start)
    if prev_was_crossfade: c = c.with_effects([vfx.CrossFadeIn(0.3)])
    clips.append(c)
final = CompositeVideoClip(clips, size=(832,1480)).with_audio(audio)

防漂移原理: 每段 with_start(t) 把段位置锚定在 timeline 绝对时间, 不依赖前段长度。锚段(口型)位置永远精确 = mp3 中对应歌词时间。

阶段 4: 智能过场 + 字幕

过场分配: | 场景 | 过场 | 时长 | |---|---|---| | 同细节链 / 锚段连续 | hard cut | 0 | | 跨场景 (大部分接缝) | CrossFadeIn | 0.25-0.4s | | 大景别变化 (wide↔close) | zoom + crossfade | 0.4s | | Hook→Bridge 戏剧停顿 | FadeOut+FadeIn (黑场) | 0.4s | | 夜→黎明 / 重要爆点 | ColorClip(white) overlay + fade | 0.5-0.6s |

字幕: stable-whisper SRT → ASS (PingFang SC 52pt 白字黑边半透明黑底) → ffmpeg -vf ass=... 烧制。

已踩坑的固定规则

  1. xfade chain 漂移: 30+ 段 × 0.3s 累积 9s, 锚段口型必偏 → 用 MoviePy
  2. ffmpeg 8.1.1 xfade chain bug: 多段 chain 后输出被截到 ~20s → 用 MoviePy
  3. 必剪 / 剪映工程文件私有: 无法生成 .ce/.draft, 只能拖单文件素材 → 输出按时间编号 01.mp4...33.mp4 + manifest.txt
  4. MoviePy 2.x API: with_start 不是 set_start, with_effects([vfx.CrossFadeIn(d)]) 不是 crossfadein(d)
  5. DaVinci Resolve / Final Cut 用户: 生成 FCPXML 让他们打开 (用 opentimelineio)

Reference

  • 模板路径: templates/v16_moviepy.py (主拼接含智能过场) / templates/v15_simple_crossfade.py (简化版)
  • AutoDL 远程: ~/.ssh/config Host autodl, ComfyUI 双卡 6006/6010
  • 工作流: /root/zealman-app/comfyui-workflows/J视频-对口型/J04- (InfiniteTalk) + G视频-Wan图生/G01- (Wan I2V)
  • ui2api 转换器: /tmp/ui2api_v2.py (重启后需 re-scp)

Anti-patterns

  • ❌ ffmpeg xfade chain 串多个 transition (漂移 + 截断)
  • ❌ MoviePy concatenate_videoclips 期望保持时间精确 (overlap 会引发漂移)
  • ❌ 锚段时间分配靠"累计上段长度"算 (每段实际长度 ≠ manifest 长度)
  • ❌ 假设歌词不同版本节奏一样 (Suno 同首歌的不同 take 段间过门会变 5-10s,全部锚段必须按新音频重对齐时间窗后重跑 InfiniteTalk)
  • ❌ 用堆叠多个 LightX2V LoRA 的工作流跑短镜 (风格保持极弱, 模型自由发挥跑成完全不相关的内容如古风/魔法/电光鸟)
  • ❌ 跳过和 user 对齐主角身份就开 brief: 同一个中文词可能有多种解读 (如 "X 班"="工作班次" 还是 "X 场"="表演场所"), 先跟 user 确认主角是工人 / 表演者 / 路人, 避免做完整套 MV 后气质割裂返工

Featured in 0 collections

See how others combine this skill with their stack

Not yet featured in any collection.

No reviews yet

Use it and be the first to leave a review

Version history

v0.0.0-202605110555latest
2026-05-11