Python受欢迎的原因之一就是其计算生态丰富,据不完全统计,Python 目前为止有约13万+的第三方库。
本系列将会陆续整理分享一些有趣、有用的第三方库。
-
通过百度网盘获取:
链接:https://pan.baidu.com/s/1FSGLd7aI_UQlCQuovVHc_Q?pwd=mnsj
提取码:mnsj
-
前往GitHub获取:
https://github.com/returu/Python_Ecosystem
-
MoviePy 的工作原理:
-
安装:
pip install moviepy
-
ffmpeg会在首次使用MoviePy时,由ImageIO自动下载安装。 -
ffplay不会自动下载,如需使用视频或音频的预览功能,需要确保安装了ffplay,并且Python 可以访问它。在 Windows 上,需要下载 FFmpeg 的预编译版本,并将其添加到系统环境变量中。
# FFmpeg 官网下载页面:
https://ffmpeg.org/download.html#build-windows
https://github.com/Zulko/moviepy
以下示例是 MoviePy 库官方文档基础教程:为电影《Big Buck Bunny》创建一个预告片。
该示例涵盖了 MoviePy 的基础,包括加载视频、剪辑场景、添加效果和过渡、叠加文本,甚至一些简单的滤镜应用。如希望深入了解 MoviePy,建议阅读官方文档中的《用户指南》以及查阅 API 参考。
-
第一步:导入 MoviePy 并加载视频
-
VideoClip:用于所有视觉元素,例如视频或图像。 -
AudioClip:用于所有音频元素,例如音频文件或视频中的音频轨道。
# 导入 moviepy,同时导入 numpy
from moviepy import *
import numpy as np
#################
# 视频加载 #
#################
video = VideoFileClip("./data/bbb.mp4")
-
第二步:提取片段
使用 subclipped 方法可以根据需要从主视频中提取特定场景。即,通过设置开始和结束时间(以秒为单位或以格式为 HH:MM:SS.µS 的文本形式)截取一个新的视频片段。
#####################
# 场景提取 #
#####################
# 提取想要使用的场景
# 相关片段
intro_clip = video.subclipped(1, 11) # 提取第 1 秒到第 11 秒的片段
bird_clip = video.subclipped(16, 20) # 提取第 16 秒到第 20 秒的片段
bunny_clip = video.subclipped(37, 55) # 提取第 37 秒到第 55 秒的片段
rodents_clip = video.subclipped(
"00:03:34.75", "00:03:56"
) # 也可以使用格式为 HH:MM:SS.uS 的字符串表示法
rambo_clip = video.subclipped("04:41.5", "04:44.70") # 提取第 4 分 41.5 秒到第 4 分 44.7 秒的片段
-
第三步:使用预览功能查看剪辑
可以使用 preview() 函数预览视频片段(AudioClip 还提供了一个互补的 audio_preview() 函数)。通过预览,可以看到到预览视频时不仅包含视频,还包含音频。这是因为加载视频时,不仅加载了图像,还加载了音频轨道,这些音频轨道被转换为 AudioClip 并添加到的视频剪辑中。
需要注意的是:预览功能需要安装 ffplay。另外,在预览时,可能会遇到视频变慢或视频/音频不同步的问题,一般都是因为计算机无法实时渲染预览而导致。在这种情况下,最好的办法是将 preview() 的 fps 参数设置为较低值,以减轻计算机的负担。
#####################
# 预览剪辑 #
#####################
# 注意:预览需要安装 ffplay 才能工作
# 可以将帧率设置为较低值,以便计算机能够实时渲染而不会变慢
intro_clip.preview(fps=20)
bird_clip.preview(fps=20)
# bunny_clip.preview(fps=20)
# rodents_clip.preview(fps=20)
# rambo_clip.preview(fps=20)
-
第四步:修改剪辑
预览剪辑后,可以使用众多以 with_ 开头的剪辑修改方法进行剪辑编辑。本次使用 with_section_cut_out 方法来移除剪辑中的特定部分。如需想查看完整的列表,请参阅官方API文档。
需要注意的是,MoviePy 中所有以 with_ 开头的函数都是“非原地修改”的,而不是“原地修改”,这意味着它不会修改原始数据,而是复制它并修改/返回副本。因此,需要存储方法的结果,并在必要时重新分配原始变量以更新剪辑。
##############################
# 剪辑修改:剪切部分 #
##############################
# 剪辑修改方法一般都是以 `with_*` 开头
# 使用 `with_section_cut_out`,移除剪辑中从 00:06:00 到 00:10:00 的部分
rodents_clip = rodents_clip.with_section_cut_out(start_time=4, end_time=10)
# 注意:所有以 `with_*` 开头的方法都会返回原始剪辑的一个修改后的副本,而不是直接修改原始剪辑。
# 查看结果
rodents_clip.preview(fps=10)
-
第五步:创建文本/标志剪辑
除了视频,MoviePy 提供了一些专门的 VideoClip 类型,用于处理图像和文本:ImageClip 和 TextClip。其中,ImageClip 非常简单,但 TextClip 是一个相当复杂的对象。
本次创建了多个文本剪辑对象和图像剪辑对象,文本剪辑对象用于显示不同的提示或描述性文本,图像剪辑对象用于展示特定的 logo 图片,并且对图片进行了大小调整。后续这些剪辑对象会被组合、添加到视频中,实现视频的字幕、标识等效果。
需要注意的是:来调整图像剪辑的大小的resized() 方法的工作方式与任何 with_* 方法类似,但由于调整大小是一个非常常见的任务,因此名称被简化为 resized()。cropped() 和 rotated() 也是如此。
############################
# 文本/标志剪辑创建 #
############################
# 定义字体文件路径,后续创建文本剪辑时会使用该字体
font = "./moviepy_10_minutes/resources/font/font.ttf"
# 创建一个文本剪辑对象 intro_text,用于显示介绍性文本
# font 参数指定使用的字体文件路径
# text 参数是要显示的具体文本内容,这里通过换行符 n 实现多行显示
# font_size 设置文本的字体大小为 50
# color 设置文本颜色为白色,使用十六进制颜色码 #fff 表示
# text_align 设置文本的对齐方式为居中对齐
intro_text = TextClip(
font=font,
text="The Blender Foundation andnPeach Project presents",
font_size=50,
color="#fff",
text_align="center",
)
# 创建一个文本剪辑对象 bird_text,显示关于鸟的描述性文本
bird_text = TextClip(font=font, text="An unlucky bird", font_size=50, color="#fff")
# 创建一个文本剪辑对象 bunny_text,显示关于兔子的描述性文本
bunny_text = TextClip(
font=font, text="A (slightly overweight) bunny", font_size=50, color="#fff"
)
# 创建一个文本剪辑对象 rodents_text,显示关于啮齿动物的描述性文本
rodents_text = TextClip(
font=font, text="And three rodent pests", font_size=50, color="#fff"
)
# 创建一个文本剪辑对象 revenge_text,显示关于复仇的提示性文本
revenge_text = TextClip(
font=font, text="Revenge is coming...", font_size=50, color="#fff"
)
# 创建一个文本剪辑对象 made_with_text,显示关于制作工具的提示性文本
made_with_text = TextClip(font=font, text="Made with", font_size=50, color="#fff")
# 加载《Big Buck Bunny》的 logo 图片,创建一个图像剪辑对象 logo_clip
# 并将其宽度调整为 400 像素,高度会根据图片原始宽高比自动调整
logo_clip = ImageClip("./moviepy_10_minutes/resources/logo_bbb.png").resized(width=400)
# 加载 MoviePy 的 logo 图片,创建一个图像剪辑对象 moviepy_clip
# 并将其宽度调整为 300 像素,高度会根据图片原始宽高比自动调整
moviepy_clip = ImageClip("./moviepy_10_minutes/resources/logo_moviepy.png").resized(width=300)
-
第六步:设置剪辑的时机
目前已经拥有了所有需要的剪辑,但如果将所有剪辑组合成一个单一剪辑,所有剪辑都会同时开始并叠加播放,这显然不是我们想要的效果。为了解决这个问题,需要指定每个剪辑在最终剪辑中的开始和结束时间。
在示例中,根据每个特定情况的便利性,使用 duration 或 end_time为每个剪辑对象设置在最终视频中的播放起始时间和持续时间,以此来确保各个剪辑能按照我们期望的顺序和时间安排依次播放,避免出现剪辑同时播放而相互叠加的情况。
默认情况下,所有剪辑的起始点为 0。如果剪辑没有 duration,但设置了 end_time,则会计算 duration。反之亦然。
################
# 剪辑时机设置 #
################
# 目前已经拥有了所有需要的剪辑,但如果将所有剪辑组合成一个单一剪辑(将在下一步中看到如何实现),所有剪辑都会同时开始并叠加播放,这显然不是我们想要的效果。
# 为了解决这个问题,我们需要指定每个剪辑在最终剪辑中的开始和结束时间。
# 因此,使用合适的 `with_*` 方法来指示每个剪辑的开始和结束时间。
# 设置引言文本剪辑的播放时间
# with_duration(6) 方法指定引言文本剪辑的持续时间为 6 秒
# with_start(3) 方法指定引言文本剪辑从最终剪辑的第 3 秒开始播放
intro_text = intro_text.with_duration(6).with_start(3)
# 设置标志剪辑的播放时间
# with_start(intro_text.start + 2) 方法让标志剪辑在引言文本剪辑开始 2 秒后开始播放
# with_end(intro_text.end) 方法让标志剪辑和引言文本剪辑同时结束播放
logo_clip = logo_clip.with_start(intro_text.start + 2).with_end(intro_text.end)
# 设置鸟的剪辑的播放时间
# with_start(intro_clip.end) 方法让鸟的剪辑在引言剪辑结束后立即开始播放
# 这里假设鸟的剪辑的持续时间已经在别处定义好了
bird_clip = bird_clip.with_start(intro_clip.end)
# 设置鸟的文本剪辑的播放时间
# with_start(bird_clip.start) 方法让鸟的文本剪辑和鸟的剪辑同时开始播放
# with_end(bird_clip.end) 方法让鸟的文本剪辑和鸟的剪辑同时结束播放
bird_text = bird_text.with_start(bird_clip.start).with_end(bird_clip.end)
# 设置兔子剪辑的播放时间
# with_start(bird_clip.end) 方法让兔子剪辑在鸟的剪辑结束后立即开始播放
bunny_clip = bunny_clip.with_start(bird_clip.end)
# 设置兔子的文本剪辑的播放时间
# with_start(bunny_clip.start + 2) 方法让兔子的文本剪辑在兔子剪辑开始 2 秒后开始播放
# with_duration(7) 方法指定兔子的文本剪辑的持续时间为 7 秒
bunny_text = bunny_text.with_start(bunny_clip.start + 2).with_duration(7)
# 设置啮齿动物剪辑的播放时间
# with_start(bunny_clip.end) 方法让啮齿动物剪辑在兔子剪辑结束后立即开始播放
rodents_clip = rodents_clip.with_start(bunny_clip.end)
# 设置啮齿动物的文本剪辑的播放时间
# with_start(rodents_clip.start) 方法让啮齿动物的文本剪辑和啮齿动物剪辑同时开始播放
# with_duration(4) 方法指定啮齿动物的文本剪辑的持续时间为 4 秒
rodents_text = rodents_text.with_start(rodents_clip.start).with_duration(4)
# 设置兰博(rambo)剪辑的播放时间
# with_start(rodents_clip.end - 1.5) 方法让兰博剪辑在啮齿动物剪辑结束前 1.5 秒开始播放
rambo_clip = rambo_clip.with_start(rodents_clip.end - 1.5)
# 设置复仇文本剪辑的播放时间
# with_start(rambo_clip.start + 1.5) 方法让复仇文本剪辑在兰博剪辑开始 1.5 秒后开始播放
# with_duration(4) 方法指定复仇文本剪辑的持续时间为 4 秒
revenge_text = revenge_text.with_start(rambo_clip.start + 1.5).with_duration(4)
# 设置 “Made with” 文本剪辑的播放时间
# with_start(rambo_clip.end) 方法让 “Made with” 文本剪辑在兰博剪辑结束后立即开始播放
# with_duration(3) 方法指定 “Made with” 文本剪辑的持续时间为 3 秒
made_with_text = made_with_text.with_start(rambo_clip.end).with_duration(3)
# 设置 MoviePy 标志剪辑的播放时间
# with_start(made_with_text.start) 方法让 MoviePy 标志剪辑和 “Made with” 文本剪辑同时开始播放
# with_duration(3) 方法指定 MoviePy 标志剪辑的持续时间为 3 秒
moviepy_clip = moviepy_clip.with_start(made_with_text.start).with_duration(3)
-
第七步:查看剪辑组合的效果
现在已经设置了所有剪辑的时机,让我们先看看最终剪辑的效果。在视频编辑中,将多个视频组合成一个单一视频的过程称为合成。
因此,MoviePy 提供了一种特殊的 VideoClip,专门用于将多个剪辑组合成一个,即 CompositeVideoClip。CompositeVideoClip 接受一个剪辑数组作为输入,并在渲染时将它们叠加播放,每个剪辑都会在其开始和结束时间点开始和停止。
需要注意的是,如果可能,CompositeVideoClip 会从最大/最后结束的剪辑中提取终点和大小。如果列表中的某个剪辑没有持续时间,则需要在渲染前手动设置 CompositeVideoClip 的持续时间。
########################
# 剪辑组合预览 #
########################
# 将所有剪辑组合成一个单一剪辑,并快速预览一下,看看一切是否同步
quick_compo = CompositeVideoClip(
[
intro_clip,
intro_text,
logo_clip,
bird_clip,
bird_text,
bunny_clip,
bunny_text,
rodents_clip,
rodents_text,
rambo_clip,
revenge_text,
made_with_text,
moviepy_clip,
]
)
quick_compo.preview(fps=10)
-
第八步:定位剪辑
通过查看这个初步预览,我们发现剪辑的时机设置得很好,但文本和标志的位置并不令人满意。这是因为到目前为止,我们只指定了剪辑的出现时间,而没有指定它们的显示位置。默认情况下,所有剪辑都从视频的左上角 (0, 0) 开始。
在示例中,我们的所有剪辑大小并不相同(文本和图像比视频小),而 CompositeVideoClip 会取最大剪辑的大小(在示例中是视频的大小),因此文本和图像都位于剪辑的左上角。为了解决这个问题,我们只需要使用 with_position 方法定义剪辑在合成中的位置。其中,位置参数是一个包含水平和垂直位置的元组,可以以像素、字符串(top、left、right、bottom、center)或百分比(通过提供浮点数并传递参数 relative=True)的形式给出。
######################
# 剪辑定位 #
######################
# 现在已经设置了不同剪辑的时机,需要确保它们处于正确的位置
# 将所有文本都设置为居中
bird_text = bird_text.with_position(("center", "center"))
bunny_text = bunny_text.with_position(("center", "center"))
rodents_text = rodents_text.with_position(("center", "center"))
revenge_text = revenge_text.with_position(("center", "center"))
# 对于标志和引言/结束部分,我们将使用像素位置而不是居中
top = intro_clip.h // 2
intro_text = intro_text.with_position(("center", 200))
logo_clip = logo_clip.with_position(("center", top))
made_with_text = made_with_text.with_position(("center", 300))
moviepy_clip = moviepy_clip.with_position(("center", 360))
# 再次查看,检查位置是否正确
quick_compo = CompositeVideoClip(
[
intro_clip,
intro_text,
logo_clip,
bird_clip,
bird_text,
bunny_clip,
bunny_text,
rodents_clip,
rodents_text,
rambo_clip,
revenge_text,
made_with_text,
moviepy_clip,
]
)
quick_compo.preview(fps=10)
quick_compo.preview(fps=10)
-
第九步:添加过渡和效果
现在,我们的剪辑已经设置好了时机和位置,但目前的结果看起来有些生硬,在剪辑之间添加平滑的过渡会更好。
在 MoviePy 中,这是通过使用效果来实现的。效果在增强视频剪辑的视觉和听觉吸引力方面发挥着关键作用。效果应用于剪辑,以创建过渡、变换或修改,从而制作出更美观的视频。无论是想在剪辑之间添加平滑过渡,改变视觉外观,还是操纵音频属性,MoviePy 都提供了许多现成的效果。
使用效果非常简单,只需在剪辑上调用 with_effects 方法,并传递一个效果对象数组以应用。在示例中,我们将在剪辑之间添加简单的淡入/淡出和交叉淡入/淡出过渡,并将 rambo_clip 放慢速度。
################################
# 剪辑过渡和效果添加 #
################################
# 现在我们的剪辑已经设置好了时间和位置,让我们添加一些过渡以使其更加自然
# 为此,我们使用 `with_effects` 方法和视频效果 `vfx`
# 我们在剪辑上调用 `with_effects` 并传递一个效果对象数组以应用
# 我们保持简单,不使用复杂的效果,只使用交叉淡入/淡出
# 为引言文本剪辑添加效果,淡入持续 1 秒,淡出持续 1 秒
intro_text = intro_text.with_effects([vfx.CrossFadeIn(1), vfx.CrossFadeOut(1)])
# 为标志剪辑添加效果,淡入持续 1 秒,淡出持续 1 秒
logo_clip = logo_clip.with_effects([vfx.CrossFadeIn(1), vfx.CrossFadeOut(1)])
# 为鸟的文本剪辑添加效果,淡入持续 0.5 秒,淡出持续 0.5 秒
bird_text = bird_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
# 为兔子的文本剪辑添加效果,淡入持续 0.5 秒,淡出持续 0.5 秒
bunny_text = bunny_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
# 为啮齿动物的文本剪辑添加效果,淡入持续 0.5 秒,淡出持续 0.5 秒
rodents_text = rodents_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
# 还为视频剪辑及其音频添加交叉淡入/淡出
# 注意视频效果在 `vfx` 下,音频效果在 `afx` 下
# 为引言视频剪辑添加视频和音频的淡入淡出效果,视频和音频的淡入淡出均持续 1 秒
intro_clip = intro_clip.with_effects(
[vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)]
)
# 为鸟的视频剪辑添加视频和音频的淡入淡出效果,视频和音频的淡入淡出均持续 1 秒
bird_clip = bird_clip.with_effects(
[vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)]
)
# 为兔子的视频剪辑添加视频和音频的淡入淡出效果,视频和音频的淡入淡出均持续 1 秒
bunny_clip = bunny_clip.with_effects(
[vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)]
)
# 为啮齿动物的视频剪辑添加视频和音频的效果,视频淡入持续 1 秒,交叉淡出持续 1.5 秒,音频淡入持续 1 秒,音频淡出持续 1.5 秒
# 这里只设置了淡入,`rambo_clip` 将完成交叉淡出的衔接
rodents_clip = rodents_clip.with_effects(
[vfx.FadeIn(1), vfx.CrossFadeOut(1.5), afx.AudioFadeIn(1), afx.AudioFadeOut(1.5)]
)
# 为兰博视频剪辑添加视频和音频的效果,视频交叉淡入持续 1.5 秒,淡出持续 1 秒,音频交叉淡入持续 1.5 秒,音频淡出持续 1 秒
rambo_clip = rambo_clip.with_effects(
[vfx.CrossFadeIn(1.5), vfx.FadeOut(1), afx.AudioFadeIn(1.5), afx.AudioFadeOut(1)]
)
# 再次为兰博视频剪辑添加相同的效果(可能是为了确保效果正确应用或有其他逻辑需求)
rambo_clip = rambo_clip.with_effects(
[vfx.CrossFadeIn(1.5), vfx.FadeOut(1), afx.AudioFadeIn(1.5), afx.AudioFadeOut(1)]
)
# 效果不仅用于过渡,还可以改变剪辑的时机或外观
# 为了展示这一点,让我们还将预告片中类似《第一滴血》的部分改为慢动作
# 注意:我们这样做是为了效果,但这是少数几种有直接快捷方式的效果之一,`with_speed_scaled`
# 其他快捷方式包括 `with_volume_scaled`、`resized`、`cropped` 和 `rotated`
# 将兰博视频剪辑的速度设置为原来的 0.5 倍,实现慢动作效果
rambo_clip = rambo_clip.with_effects([vfx.MultiplySpeed(0.5)])
# 由于我们使用 `MultiplySpeed` 效果修改了 `rambo_clip` 的时机,我们需要重新分配后续剪辑的时机
# 重新设置 “Made with” 文本剪辑的开始时间为兰博视频剪辑结束的时间,并设置其持续时间为 3 秒
made_with_text = made_with_text.with_start(rambo_clip.end).with_duration(3)
# 重新设置 MoviePy 标志剪辑的开始时间为 “Made with” 文本剪辑开始的时间,并设置其持续时间为 3 秒
moviepy_clip = moviepy_clip.with_start(made_with_text.start).with_duration(3)
# 最后检查结果,确保一切按预期工作
# 创建一个复合视频剪辑对象,包含了所有的视频和文本剪辑
quick_comp = CompositeVideoClip(
[
intro_clip,
intro_text,
logo_clip,
bird_clip,
bird_text,
bunny_clip,
bunny_text,
rodents_clip,
rodents_text,
rambo_clip,
revenge_text,
made_with_text,
moviepy_clip,
]
)
# 以每秒 10 帧的帧率预览复合视频剪辑,查看效果是否符合预期
quick_comp.preview(fps=10)
-
第十步:使用滤镜修改剪辑的外观
最后,为了使预告片更具史诗感,我们将为 rambo_clip 应用一个自定义滤镜,将其图像转换为棕褐色调。MoviePy 并没有自带棕褐色效果,创建完整的自定义效果超出了本教程的范围。本次将展示如何使用 image_transform() 方法为剪辑应用一个简单的滤镜。
要理解滤镜的工作原理,首先需要了解在 MoviePy 中,剪辑的每一帧实际上是一个形状为 HxWx3 的 numpy ndarray。这意味着可以通过应用简单的数学运算来修改帧的外观,对所有帧应用这些运算就可以为剪辑应用一个滤镜。“应用于所有帧”的部分由 image_transform 方法完成,该方法接受一个回调函数作为参数,在渲染时,它会为剪辑的每一帧触发回调函数,并传递当前帧。
###############
# 剪辑滤镜应用 #
###############
# 让我们最后修改一下 `rambo_clip`,将其转换为棕褐色调
# 首先,定义一个函数,将 numpy 图像转换为棕褐色调
# 它接受一个 numpy 数组作为输入,并返回修改后的图像作为输出
def sepia_filter(frame: np.ndarray):
# 棕褐色调转换矩阵
# 棕褐色调转换通过以下规则应用于图像的每个像素:
# res_R = (R * .393) + (G *.769) + (B * .189)
# res_G = (R * .349) + (G *.686) + (B * .168)
# res_B = (R * .272) + (G *.534) + (B * .131)
# 使用 numpy,我们可以通过矩阵乘法高效地实现这一点
sepia_matrix = np.array(
[[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]
)
# 将图像转换为 float32 格式以进行矩阵乘法
frame = frame.astype(np.float32)
# 应用棕褐色调转换
# `.T` 是必要的,因为 (n,m) * (m,k) 的矩阵乘法结果是 (n,k),而我们希望得到 (n,m),因此需要将矩阵 (m,k) 转置为 (k,m)
sepia_image = np.dot(frame, sepia_matrix.T)
# 由于最终结果可能大于 255,我们将结果限制在 [0, 255] 范围内
sepia_image = np.clip(sepia_image, 0, 255)
# 将图像转换回 uint8 格式,因为我们需要整数而不是浮点数
sepia_image = sepia_image.astype(np.uint8)
return sepia_image
# 现在,只需通过调用 `image_transform` 将滤镜应用于剪辑,它将在每一帧上应用我们的滤镜
rambo_clip = rambo_clip.image_transform(sepia_filter)
# 查看滤镜效果
rambo_clip.preview(fps=10)
-
第十一步:将最终剪辑渲染为文件
现在,我们的最终剪辑已经准备好,完成了所有剪辑和修改,现在可以将最终结果保存到文件中。在视频编辑中,这个操作称为渲染。
我们仍然保持简单,只进行视频渲染而不进行太多调整。在大多数情况下,MoviePy 和 FFmpeg 会自动找到最佳设置。更多详细信息,请查看 write_videofile()。
##################
# 剪辑渲染 #
##################
# 一切准备就绪,现在可以将剪辑渲染为文件
final_clip = CompositeVideoClip(
[
intro_clip,
intro_text,
logo_clip,
bird_clip,
bird_text,
bunny_clip,
bunny_text,
rodents_clip,
rodents_text,
rambo_clip,
revenge_text,
made_with_text,
moviepy_clip,
]
)
final_clip.write_videofile("./data/result.mp4")
更多内容可以前往官方文档查看:
https://zulko.github.io/moviepy/


本篇文章来源于微信公众号: 码农设计师