mcpField
M
moviepy

moviepy

github.com/digitalsamba创意与媒体2.4k1.1k 次安装今天更新
代码仓库

关于 moviepy

面向 moviepy 视频制作的技能,用于给 AI 生成的画面添加准确、可控的文字,也可构建短篇 Python 视频项目。适合需要可靠标签和字幕且不使用 Remotion 工具链的编辑者。

主要功能

  1. 01使用 PIL 添加确定性文字叠层
  2. 02合成视频与数据驱动视觉内容
  3. 03以音频为基准的场景时间线
  4. 04混合旁白并降低背景音乐音量
  5. 05可运行的短视频示例

适用场景

  1. 01为 AI 生成画面添加准确名称和字幕
  2. 02用 Python 制作短广告视频
  3. 03为图表叠加标题和来源标注
  4. 04按场景旁白时长对齐视频

安装

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

$npx skills add https://github.com/digitalsamba/claude-code-video-toolkit --skill moviepy

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

详细介绍

用于视频制作的 moviepy

moviepy 是工具包中用于在 AI 生成的视频上添加确定性的文字,以及在不使用 Remotion 工具链的情况下构建短小、单文件 Python 视频项目的首选库。

更深层的原则是可信赖的文字:凡是文字必须清晰可读、准确且一致的类型(无论是在法律、编辑还是商业方面),都不能接受由 AI 在画面内生成文字,而使用 moviepy 叠加文字是自然的解决方案。姓名必须拼写正确。价格必须准确。来源署名必须做到像素级精准。AI 生成模型无法保证这些。

何时使用 moviepy,何时使用 Remotion

适合使用 moviepy 的场景……适合使用 Remotion 的场景……
在 LTX-2 或 SadTalker 的输出上叠加文字/标签构建长篇冲刺回顾或产品演示
在单个 build.py 中制作 30 秒以内的广告风格短片多模板、多品牌、设计要求较高的工作
合成数据驱动的视觉效果(matplotlib FuncAnimation → mp4)任何需要 React 组件或复用设计系统的场景
对现有视频文件进行一次性转换任何需要关注项目生命周期(规划 → 渲染)的场景
希望完全避免 Node.js/React 带来的心智负担希望在 Remotion Studio 中热重载预览

本技能的 examples/ 中提供了两个可运行的参考示例:

  • examples/quick-spot/build.py — 15 秒广告风格短片。以音频为锚点的时间线、文字叠加、可选画外音 + 自动降低背景音乐音量。无需外部素材,开箱即可渲染无声视频。
  • examples/data-viz-chart/build.py — 带有确定性标题和来源署名的动态时间序列图表。展示 matplotlib(数据)+ moviepy(可信赖的文字)的分工。

两个示例都可通过 uv run build.py 运行,并立即生成真正的 out.mp4。请结合本技能阅读这两个示例——下文介绍的每种模式都能在那里找到可运行的实现。

依赖项。 moviepy、Pillow 和 matplotlib 已在根目录的 pyproject.toml 中声明,并通过工具包的一行式 Python 安装命令安装:uv sync。如果运行示例时遇到 Missing dependency,请在仓库根目录运行该命令——示例中的 build.py 文件也会在错误消息中提示同一操作,并正常退出,而不是只打印一段回溯信息。

主要用例:在 AI 生成的视频上添加文字

LTX-2 和 SadTalker 输出的都只是纯画面:

  • LTX-2 无法可靠地渲染可读文字(模型会幻觉出字形——请参阅 ltx2 技能中的“Bad Prompts”)。
  • SadTalker 输出的是没有字幕、标签、下三分之一字幕条或背景信息的说话人头部视频。

解决方法是先干净地生成画面,再用 moviepy 以确定性的方式在其上合成文字。这是本工具包中的典型模式:

from moviepy import VideoFileClip, ImageClip, CompositeVideoClip

# 1. AI-generated visual (LTX-2 or SadTalker output)
bg = VideoFileClip("lugh_ltx.mp4").without_audio()

# 2. Text rendered via PIL → ImageClip (see "Text rendering" below)
title = (
    ImageClip("text_cache/intro_title.png")
    .with_duration(2.0)
    .with_start(0.5)
    .with_position(("center", 880))
)

# 3. Composite
final = CompositeVideoClip([bg, title], size=(1920, 1080))
final.write_videofile("lugh_with_caption.mp4", fps=30, codec="libx264")

常见形式如下:

形式LTX-2 用法SadTalker 用法
主视觉画面上的标题卡在电影感的 LTX-2 辅助镜头上叠加“INTRODUCING LONGARM”不适用
下三分之一字幕条/姓名牌不适用在说话人头部视频下方显示“Lugh — Ancient Warrior God”
引语字幕在 LTX-2 人物客串画面上叠加“I am going home.”同样适用,叠加在 SadTalker 说话人头部视频上
品牌署名在最后一秒淡入徽标 + URL同样适用
用于增强对比度的色调叠加层在文字后添加半透明深海军蓝图层同样适用

适用的类型

“AI 视觉 + 确定性文字叠加”模式是多种视频风格的自然制作流程。如果需求符合以下某种类型,默认选择 moviepy:

类型叠加内容moviepy 是合适选择的原因
新闻 / 访谈新闻发言人姓名牌、地点栏、突发新闻横幅、来源署名、引用语姓名必须拼写正确(编辑 / 法律要求)。按数量计算,这是最大的类别。
纪录片片段受访者下三分之一字幕、章节标题、档案来源署名、地点标记与新闻一样,必须确保可信度。
预告片 / 宣传短片标题卡、演职员表叠加(“导演作品……”)、日期特效、引用卡、行动号召时间点要求精准、文字内容多,每一帧都很重要。q2-townhall-longarm-ad 示例就是这种情况。
社交媒体短视频(Reels、TikTok、Shorts)可在静音播放时准确呈现的字幕、标签叠加大多数社交媒体视频都是静音播放;字幕必不可少。
带标注的产品演示价格提示、功能标签、屏幕录制上的“点击此处”指示、前后对比标签价格和产品名称必须准确无误。
教程 / 讲解视频步骤编号叠加、终端命令字幕、键盘快捷键提示步骤编号必须连续,命令必须可直接复制粘贴。

也适用但较少见的类型:音乐视频(歌词叠加)、反应视频(来源署名)、体育赛事集锦(比分叠加)、房地产导览(价格 / 平方英尺)、会议演讲(发言人 + 会议环节信息牌)。

对于完整的 SRT 字幕(长视频、带时间码、多语言),moviepy 可以胜任,但并非理想选择——建议使用带 subtitles 滤镜的 ffmpeg,或专用字幕工具。moviepy 最适合手动放置叠加内容,而非批量处理字幕轨。

文字渲染——使用 PIL,而非 TextClip

**关键问题:**moviepy 2.x 的 TextClip(method='label') 存在紧框边界框(tight-bbox)错误,会裁掉字母的上伸部和下伸部(大写字母的顶部,以及 g/p/y 的尾部)。在 Apple Silicon 上,你会看到字符边缘被切掉,却可能花上好几个小时都没发现问题所在。

**解决方法:**通过 PIL 将文字渲染为透明 PNG,然后将其加载为 ImageClip。按内容哈希缓存结果,这样重新构建就无需额外开销。

import hashlib
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont

ARIAL_BOLD = "/System/Library/Fonts/Supplemental/Arial Bold.ttf"

def render_text_png(txt, size, hex_color, cache_dir="./text_cache"):
    cache = Path(cache_dir); cache.mkdir(parents=True, exist_ok=True)
    key = hashlib.sha1(f"{txt}|{size}|{hex_color}".encode()).hexdigest()[:16]
    path = cache / f"{key}.png"
    if path.exists():
        return str(path)

    font = ImageFont.truetype(ARIAL_BOLD, size)
    bbox = ImageDraw.Draw(Image.new("RGBA", (1, 1))).textbbox((0, 0), txt, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    pad = max(20, size // 4)

    img = Image.new("RGBA", (tw + pad * 2, th + pad * 2), (0, 0, 0, 0))
    rgb = tuple(int(hex_color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4))
    ImageDraw.Draw(img).text((pad - bbox[0], pad - bbox[1]), txt, font=font, fill=(*rgb, 255))
    img.save(path)
    return str(path)

完整辅助函数(含粗体、位置、淡入淡出等关键字参数,使用体验也更好)位于 examples/quick-spot/build.py——直接复制使用,不要重新实现。

以音频为锚点的时间线模式

对于每一帧都很重要的广告风格剪辑,先生成每个场景的 VO,再将所有画面锚定到已知的绝对时间戳。这样可以彻底消除时间漂移。完整模式请参阅 CLAUDE.md → Video Timing → Audio-Anchored Timelines。简要版如下:

# Audio-anchored timeline (25s):
#   Scene 1 tired      0.3 → 3.74  (audio 3.44s)
#   Scene 2 worries    4.0 → 8.88  (audio 4.88s)

text_clip("TIRED OF",     start=0.5,  duration=1.2)
text_clip("THIRD-PARTY",  start=1.0,  duration=1.8)
vo_clip("01_tired.mp3",   start=0.3)
vo_clip("02_worries.mp3", start=4.0)

常用配方

在单个 AI 生成的视频片段上添加文字
from moviepy import VideoFileClip, ImageClip, CompositeVideoClip

bg = VideoFileClip("ltx_hero.mp4").without_audio()
caption = (
    ImageClip(render_text_png("THE FUTURE OF AGENTS", 140, "#FFFFFF"))
    .with_duration(bg.duration)
    .with_position(("center", 880))
)
CompositeVideoClip([bg, caption], size=bg.size).write_videofile("captioned.mp4", fps=30)
在 SadTalker 访谈画面上添加下三分之一字幕
from moviepy import VideoFileClip, ImageClip, ColorClip, CompositeVideoClip

talking = VideoFileClip("narrator_sadtalker.mp4")
W, H = talking.size

# Semi-transparent bar across the bottom for contrast
bar = (
    ColorClip((W, 140), color=(20, 24, 38))
    .with_duration(talking.duration)
    .with_opacity(0.75)
    .with_position(("center", H - 160))
)
name = (
    ImageClip(render_text_png("LUGH", 72, "#F06859"))
    .with_duration(talking.duration)
    .with_position((80, H - 150))
)
title = (
    ImageClip(render_text_png("Ancient Warrior God", 36, "#FFFFFF"))
    .with_duration(talking.duration)
    .with_position((80, H - 80))
)
CompositeVideoClip([talking, bar, name, title]).write_videofile("with_lower_third.mp4", fps=30)
为繁杂画面上的文字添加有色叠加层,增强对比度

LTX-2 的 b-roll 画面往往过于繁杂,文字难以辨认。在视频和文字之间添加半透明的藏青色图层:

from moviepy import ColorClip

tint = (
    ColorClip((W, H), color=(20, 24, 38))
    .with_duration(duration)
    .with_opacity(0.55)
)
# Composite order: bg → tint → text
CompositeVideoClip([bg, tint, text_clip])
并排合成
from moviepy import VideoFileClip, CompositeVideoClip, ColorClip

left  = VideoFileClip("demo_a.mp4").resized(width=960).with_position((  0, "center"))
right = VideoFileClip("demo_b.mp4").resized(width=960).with_position((960, "center"))
bg    = ColorClip((1920, 1080), color=(0, 0, 0)).with_duration(max(left.duration, right.duration))
CompositeVideoClip([bg, left, right]).write_videofile("split.mp4", fps=30)
混合每个场景的 VO 与自动降低音量的音乐
from moviepy import AudioFileClip, CompositeAudioClip
from moviepy.audio.fx.MultiplyVolume import MultiplyVolume
from moviepy.audio.fx.AudioFadeIn import AudioFadeIn
from moviepy.audio.fx.AudioFadeOut import AudioFadeOut

music = AudioFileClip("music.mp3").with_effects([
    MultiplyVolume(0.22),  # duck under VO
    AudioFadeIn(0.5),
    AudioFadeOut(1.5),
])
vo = [
    AudioFileClip(f"scenes/0{i}.mp3").with_effects([MultiplyVolume(1.15)]).with_start(start)
    for i, start in [(1, 0.3), (2, 4.0), (3, 9.1)]
]
final_audio = CompositeAudioClip([music] + vo)

注意事项

  • moviepy 2.x 重命名了方法。 使用 subclipped(而不是 subclip),使用 with_duration / with_start / with_position(而不是 set_duration 等),使用 with_effects([...]) 代替 .fadein()/.fadeout()。网上的许多教程仍使用 1.x 语法,请谨慎参考。
  • TextClip(method='label') 会裁掉字母的上伸部和下伸部。 请始终使用上文介绍的 PIL 变通方法。
  • OffthreadVideo 仅适用于 Remotion。 moviepy 使用 VideoFileClip。不要混用两者。
  • 调整大小需要 Pillow ≥ 10.0 才能使用 LANCZOS 重采样。如果出现 ANTIALIAS 错误,请升级 Pillow。
  • ColorClip 接受 RGB 元组,而不是十六进制字符串。 使用 (20, 24, 38),不要使用 "#141826"。
  • VideoFileClip 默认会加载音频。 如果只需要画面,请调用 .without_audio()——将不需要的音频合成进去,会导致 CompositeAudioClip 中的静音 VO 丢失。
  • 始终为 CompositeVideoClip 设置 size=(W, H)。 否则,输出尺寸将取决于第一个片段,可能小于目标尺寸。

何时使用哪种工具

任务工具
为静态图像添加动画tools/ltx2.py --input
根据写实肖像生成会说话的人物视频tools/sadtalker.py
根据风格化角色生成会说话的人物视频tools/ltx2.py --input(参见 ltx2 技能)
为以上任一视频添加标签/字幕/下三分之一字幕条moviepy + PIL(此技能)
转换/压缩/调整现有文件的大小ffmpeg(参见 ffmpeg 技能)
制作长篇、由设计系统驱动的视频Remotion(参见 remotion 技能)

参考资料

  • 可运行示例——短篇广告风格视频:examples/quick-spot/build.py
  • 可运行示例——带文字叠加的数据可视化:examples/data-viz-chart/build.py
  • 以音频为锚点的时间线:CLAUDE.md → Video Timing → Audio-Anchored Timelines
  • 相关技能:ltx2、ffmpeg、remotion

评论

支持 Markdown