Skip to content

Commit 311b507

Browse files
committed
understood the basics of moviepy
1 parent c14027b commit 311b507

13 files changed

Lines changed: 602 additions & 0 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from moviepy import *
2+
3+
bbbclip = VideoFileClip("./example_vids/bbb.mp4").subclipped(0, -96)
4+
5+
txt_clp = TextClip(font="./fonts/font.ttf",
6+
text="Getting Hang of this",
7+
font_size=70,
8+
color='black')
9+
10+
txt_clp = txt_clp.with_position(("center", "top")).with_duration(15)
11+
12+
video_cutout = CompositeVideoClip([bbbclip, txt_clp])
13+
14+
video_cutout.write_videofile("./results/bbb_cutout.mp4")
84.2 KB
Loading
33 KB
Loading

movie_py_explored/fonts/font.ttf

156 KB
Binary file not shown.

movie_py_explored/result.mp4

7.37 MB
Binary file not shown.

movie_py_explored/trailer.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Lets import moviepy, lets also import numpy we will use it a some point
2+
from moviepy import *
3+
import numpy as np
4+
5+
6+
#################
7+
# VIDEO LOADING #
8+
#################
9+
# We load our video
10+
video = VideoFileClip("./example_vids/bbb.mp4")
11+
12+
13+
#####################
14+
# SCENES EXTRACTION #
15+
#####################
16+
# We extract the scenes we want to use
17+
18+
# First the characters
19+
intro_clip = video.subclipped(1, 11)
20+
bird_clip = video.subclipped(16, 20)
21+
bunny_clip = video.subclipped(37, 55)
22+
rodents_clip = video.subclipped('00:03:34.75', '00:03:56')
23+
# we can also use string notation with format HH:MM:SS.uS
24+
rambo_clip = video.subclipped('04:41.5', '04:44.70')
25+
26+
27+
#####################
28+
# SCENES PREVIEWING #
29+
#####################
30+
# Now, lets have a first look at our clips
31+
# Warning: you need ffplay installed for preview to work
32+
# We set a low fps so our machine can render in real time without slowing down
33+
""" intro_clip.preview(fps=20)
34+
bird_clip.preview(fps=20)
35+
bunny_clip.preview(fps=20)
36+
rodents_clip.preview(fps=20)
37+
rambo_clip.preview(fps=20) """
38+
39+
40+
##############################
41+
# CLIPS MODIFICATION CUTTING #
42+
##############################
43+
# Well, looking at the rodent scene it is
44+
# a bit long isn't?
45+
# Let's see how we modify the clip
46+
# with one of the many clip manipulation
47+
# method starting by with_*
48+
# in that case by removing of
49+
# the clip the part between
50+
# 00:06:00 to 00:10:00 of the clip, using
51+
# with_cutout
52+
rodents_clip = rodents_clip.with_section_cut_out(start_time=4, end_time=10)
53+
54+
# Note: You may have noticed that we have reassign rodents_clip, this is because all with_* methods return a modified *copy* of the
55+
# original clip instead of modifying it directly. In MoviePy any function starting by with_* is out-place instead of in-place
56+
# meaning it does not modify the original data, but instead copy it and modify/return the copy
57+
58+
# Lets check the result
59+
rodents_clip.preview(fps=10)
60+
61+
############################
62+
# TEXT/LOGO CLIPS CREATION #
63+
############################
64+
# Lets create the texts to put between our clips
65+
font = "./fonts/font.ttf"
66+
intro_text = TextClip(font=font, text="The Blender Foundation and\nPeach Project presents", font_size=50, color='#fff', text_align="center")
67+
bird_text = TextClip(font=font, text="An unlucky bird", font_size=50, color='#fff')
68+
bunny_text = TextClip(font=font, text="A (slightly overweight) bunny", font_size=50, color='#fff')
69+
rodents_text = TextClip(font=font, text="And three rodent pests", font_size=50, color='#fff')
70+
revenge_text = TextClip(font=font, text="Revenge is coming...", font_size=50, color='#fff')
71+
made_with_text = TextClip(font=font, text="Made with", font_size=50, color='#fff')
72+
73+
# We will also need the big buck bunny logo, so lets load it and resize it
74+
logo_clip = ImageClip('./example_vids/logo_bbb.png').resized(width=400)
75+
moviepy_clip = ImageClip('./example_vids/logo_moviepy.png').resized(width=300)
76+
77+
78+
################
79+
# CLIPS TIMING #
80+
################
81+
# We have all the clips we need, but if we was to turn all thoses clips into a single one with composition (we will see that during next step)
82+
# all our clips would start at the same time and play on top of each other, which is obviously not what we want.
83+
# To fix that, we need to say when a clip should start and stop in the final clip.
84+
# So, lets start by telling when each clip must start and end with appropriate with_* methods
85+
intro_text = intro_text.with_duration(6).with_start(3) # Intro for 6 seconds, start after 3 seconds
86+
logo_clip = logo_clip.with_start(intro_text.start + 2).with_end(intro_text.end) # Logo start 2 second after intro text and stop with it
87+
bird_clip = bird_clip.with_start(intro_clip.end) # Make bird clip start after intro, duration already known
88+
bird_text = bird_text.with_start(bird_clip.start).with_end(bird_clip.end) # Make text synchro with clip
89+
bunny_clip = bunny_clip.with_start(bird_clip.end) # Make bunny clip follow bird clip
90+
bunny_text = bunny_text.with_start(bunny_clip.start + 2).with_duration(7)
91+
rodents_clip = rodents_clip.with_start(bunny_clip.end)
92+
rodents_text = rodents_text.with_start(rodents_clip.start).with_duration(4)
93+
rambo_clip = rambo_clip.with_start(rodents_clip.end - 1.5)
94+
revenge_text = revenge_text.with_start(rambo_clip.start + 1.5).with_duration(4)
95+
made_with_text = made_with_text.with_start(rambo_clip.end).with_duration(3)
96+
moviepy_clip = moviepy_clip.with_start(made_with_text.start).with_duration(3)
97+
98+
99+
########################
100+
# CLIPS TIMING PREVIEW #
101+
########################
102+
# Lets make a first compositing of thoses clips into one single clip and do a quick preview to see if everything is synchro
103+
104+
quick_compo = CompositeVideoClip([intro_clip, intro_text, logo_clip, bird_clip, bird_text, bunny_clip, bunny_text, rodents_clip,
105+
rodents_text, rambo_clip, revenge_text, made_with_text, moviepy_clip])
106+
quick_compo.preview(fps=10)
107+
108+
109+
######################
110+
# CLIPS POSITIONNING #
111+
######################
112+
# Now that we have set the timing of our different clips, we need to make sure they are in the right position
113+
# We will keep things simple, and almost always set center center for every texts
114+
bird_text = bird_text.with_position(('center', 'center'))
115+
bunny_text = bunny_text.with_position(('center', 'center'))
116+
rodents_text = rodents_text.with_position(('center', 'center'))
117+
revenge_text = revenge_text.with_position(('center', 'center'))
118+
119+
# For the logos and intro/end, we will use pixel position instead of center
120+
top = intro_clip.h // 2
121+
intro_text = intro_text.with_position(('center', 200))
122+
logo_clip = logo_clip.with_position(("center", top))
123+
made_with_text = made_with_text.with_position(('center', 300))
124+
moviepy_clip = moviepy_clip.with_position(('center', 360))
125+
126+
# Lets take another look to check positions
127+
quick_compo = CompositeVideoClip([intro_clip, intro_text, logo_clip, bird_clip, bird_text, bunny_clip, bunny_text, rodents_clip,
128+
rodents_text, rambo_clip, revenge_text, made_with_text, moviepy_clip])
129+
# quick_compo.preview(fps=10)
130+
131+
132+
################################
133+
# CLIPS TRANSITION AND EFFECTS #
134+
################################
135+
# Now that our clip are timed and positionned, lets add some transition to make it more natural
136+
# To do so we use the with_effects method and the video effects in vfx
137+
# We call with_effects on our clip and pass him an array of effect objects to apply
138+
# We'll keep it simple, nothing fancy just cross fading
139+
intro_text = intro_text.with_effects([vfx.CrossFadeIn(1), vfx.CrossFadeOut(1)])
140+
logo_clip = logo_clip.with_effects([vfx.CrossFadeIn(1), vfx.CrossFadeOut(1)])
141+
bird_text = bird_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
142+
bunny_text = bunny_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
143+
rodents_text = rodents_text.with_effects([vfx.CrossFadeIn(0.5), vfx.CrossFadeOut(0.5)])
144+
145+
# Also add cross fading on video clips and video clips audio
146+
# See how video effects are under vfx and audio ones under afx
147+
intro_clip = intro_clip.with_effects([vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)])
148+
bird_clip = bird_clip.with_effects([vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)])
149+
bunny_clip = bunny_clip.with_effects([vfx.FadeIn(1), vfx.FadeOut(1), afx.AudioFadeIn(1), afx.AudioFadeOut(1)])
150+
rodents_clip = rodents_clip.with_effects([vfx.FadeIn(1), vfx.CrossFadeOut(1.5), afx.AudioFadeIn(1), afx.AudioFadeOut(1.5)]) # Just fade in, rambo clip will do the cross fade
151+
rambo_clip = rambo_clip.with_effects([vfx.CrossFadeIn(1.5), vfx.FadeOut(1), afx.AudioFadeIn(1.5), afx.AudioFadeOut(1)])
152+
rambo_clip = rambo_clip.with_effects([vfx.CrossFadeIn(1.5), vfx.FadeOut(1), afx.AudioFadeIn(1.5), afx.AudioFadeOut(1)])
153+
154+
# Effects are not only for transition, they can also change a clip timing or apparence
155+
# To show that, lets also modify the Rambo-like part of our clip to be in slow motion
156+
# PS : We do it for effect, but this is one of the few effects that have a direct shortcut, with_multiply_speed
157+
# the others are with_multiply_volume, resized, croped and rotated
158+
rambo_clip = rambo_clip.with_effects([vfx.MultiplySpeed(0.5)])
159+
160+
# Because we modified timing of rambo_clip with our MultiplySpeed effect, we must re-assign the following clips timing
161+
made_with_text = made_with_text.with_start(rambo_clip.end).with_duration(3)
162+
moviepy_clip = moviepy_clip.with_start(made_with_text.start).with_duration(3)
163+
164+
# Let's have a last look at the result to make sure everything is working as expected
165+
quick_comp = CompositeVideoClip([intro_clip, intro_text, logo_clip, bird_clip, bird_text, bunny_clip, bunny_text,
166+
rodents_clip, rodents_text, rambo_clip, revenge_text, made_with_text, moviepy_clip])
167+
quick_comp.preview(fps=10)
168+
169+
170+
###############
171+
# CLIP FILTER #
172+
###############
173+
# Lets finish by modifying our rambo clip to make it sepia
174+
175+
# We will start by defining a function that turn a numpy image into sepia
176+
# It takes the image as numpy array in entry and return the modified image as output
177+
def sepia_fitler(frame: np.ndarray):
178+
# Sepia filter transformation matrix
179+
# Sepia transform works by applying to each pixel of the image the following rules
180+
# res_R = (R * .393) + (G *.769) + (B * .189)
181+
# res_G = (R * .349) + (G *.686) + (B * .168)
182+
# res_B = (R * .272) + (G *.534) + (B * .131)
183+
#
184+
# With numpy we can do that very efficiently by multiplying the image matrix by a transformation matrix
185+
sepia_matrix = np.array([[0.393, 0.769, 0.189],
186+
[0.349, 0.686, 0.168],
187+
[0.272, 0.534, 0.131]])
188+
189+
# Convert the image to float32 format for matrix multiplication
190+
frame = frame.astype(np.float32)
191+
192+
# Apply the sepia transformation
193+
# .T is needed because multiplying matrix of shape (n,m) * (m,k) result in a matrix of shape (n,k)
194+
# what we want is (n,m), so we must transpose matrix (m,k) to (k,m)
195+
sepia_image = np.dot(frame, sepia_matrix.T)
196+
197+
# Because final result can be > 255, we limit the result to range [0, 255]
198+
sepia_image = np.clip(sepia_image, 0, 255)
199+
200+
# Convert the image back to uint8 format, because we need integer not float
201+
sepia_image = sepia_image.astype(np.uint8)
202+
203+
return sepia_image
204+
205+
# Now, we simply apply the filter to our clip by calling image_transform, which will call our filter on every frame
206+
rambo_clip = rambo_clip.image_transform(sepia_fitler)
207+
208+
# Let's see how our filter look
209+
rambo_clip.preview(fps=10)
210+
211+
212+
##################
213+
# CLIP RENDERING #
214+
##################
215+
# Everything is good and ready, we can finally render our clip into a file
216+
final_clip = CompositeVideoClip([intro_clip, intro_text, logo_clip, bird_clip, bird_text, bunny_clip, bunny_text,
217+
rodents_clip, rodents_text, rambo_clip, revenge_text, made_with_text, moviepy_clip])
218+
final_clip.write_videofile("./result.mp4")
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FONTLOG for the Libre Baskerville fonts
2+
3+
This file provides detailed information on the Libre Baskerville Font Software.
4+
5+
This information should be distributed along with the Libre Baskerville fonts and any derivative works.
6+
7+
Basic Font Information:
8+
Libre Baskerville is a webfont family optimized for body text. Based on 1941 ATF Baskerville Specimens, it has a taller x height, wider counters and minor contrast that allow it to work on small sizes in any screen.
9+
10+
Libre Baskerville characters set covers 103 Latin languages:
11+
Afar, Afrikaans, Albanian, Azerbaijani, Basque, Belarusian, Bislama, Bosnian, Breton, Catalan, Chamorro, Chichewa, Comorian, Czech, Danish, Dutch, English, Esperanto, Estonian, Faroese, Fijian, Filipino/Tagalog, Finnish, Flemish, French, Gaelic (Irish / Manx / Scottish), Gagauz, German, Gikuyu, Gilbertese/Kiribati, Greenlandic, Guarani, Haitian_Creole, Hawaiian, Hungarian, Icelandic, Igo/Igbo, Indonesian, Irish, Italian, Javanese, Kashubian, Kinyarwanda, Kirundi, Latin, Latvian, Lithuanian, Luba/Ciluba/Kasai, Luxembourgish, Malagasy, Malay, Maltese, Maori, Marquesan, Marshallese, Moldovan/Moldovian/Romanian, Montenegrin, Nauruan, Ndebele, Norwegian, Oromo, Palauan/Belauan, Polish, Portuguese, Quechua, Romanian, Romansh, Sami, Samoan, Sango, Serbian, Sesotho, Setswana/Sitswana/Tswana, Seychellois_Creole, SiSwati/Swati/Swazi, Silesian, Slovak, Slovenian, Somali, Sorbian, Sotho, Spanish, Swahili, Swedish, Tahitian, Tetum, Tok_Pisin, Tongan, Tsonga, Tswana, Tuareg/Berber, Turkish, Turkmen, Tuvaluan, Uzbek/Usbek, Wallisian, Walloon, Welsh, Xhosa, Yoruba, Zulu.
12+
13+
Join the project at:
14+
http://www.impallari.com/projects/overview/libre-baskerville
15+
16+
Documentation can be found at www.impallari.com
17+
18+
To contribute to the project contact Pablo Impallari at impallari@gmail.com
19+
20+
ChangeLog
21+
22+
29 Nov 2012 (Pablo Impallari, Rodrigo Fuenzalida) Libre Baskerville v1.0
23+
- Regular, Italic and Bold styles
24+
- All ikerned
25+
- Initial v1.0 release
26+
27+
24 Sep 2012 (Pablo Impallari, Rodrigo Fuenzalida) Libre Baskerville v0.16
28+
- Initial public Beta release
29+
- First draft for caps and lowercase.
30+
31+
Acknowledgements
32+
33+
If you make modifications be sure to add your name (N),
34+
email (E), web-address (if you have one) (W) and
35+
description (D). This list is in alphabetical order.
36+
37+
N: Pablo Impallari
38+
E: impallari@gmail.com
39+
W: http://www.impallari.com
40+
D: Designer
41+
42+
N: Rodrigo Fuenzalida
43+
E: hello@rfuenzalida.com
44+
W: http://www.rfuenzalida.com
45+
D: Designer
46+
47+
48+
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
Copyright (c) 2012, Pablo Impallari (www.impallari.com|impallari@gmail.com),
2+
Copyright (c) 2012, Rodrigo Fuenzalida (www.rfuenzalida.com|hello�rfuenzalida.com), with Reserved Font Name Libre Baskerville.
3+
4+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
5+
This license is copied below, and is also available with a FAQ at:
6+
http://scripts.sil.org/OFL
7+
8+
9+
-----------------------------------------------------------
10+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11+
-----------------------------------------------------------
12+
13+
PREAMBLE
14+
The goals of the Open Font License (OFL) are to stimulate worldwide
15+
development of collaborative font projects, to support the font creation
16+
efforts of academic and linguistic communities, and to provide a free and
17+
open framework in which fonts may be shared and improved in partnership
18+
with others.
19+
20+
The OFL allows the licensed fonts to be used, studied, modified and
21+
redistributed freely as long as they are not sold by themselves. The
22+
fonts, including any derivative works, can be bundled, embedded,
23+
redistributed and/or sold with any software provided that any reserved
24+
names are not used by derivative works. The fonts and derivatives,
25+
however, cannot be released under any other type of license. The
26+
requirement for fonts to remain under this license does not apply
27+
to any document created using the fonts or their derivatives.
28+
29+
DEFINITIONS
30+
"Font Software" refers to the set of files released by the Copyright
31+
Holder(s) under this license and clearly marked as such. This may
32+
include source files, build scripts and documentation.
33+
34+
"Reserved Font Name" refers to any names specified as such after the
35+
copyright statement(s).
36+
37+
"Original Version" refers to the collection of Font Software components as
38+
distributed by the Copyright Holder(s).
39+
40+
"Modified Version" refers to any derivative made by adding to, deleting,
41+
or substituting -- in part or in whole -- any of the components of the
42+
Original Version, by changing formats or by porting the Font Software to a
43+
new environment.
44+
45+
"Author" refers to any designer, engineer, programmer, technical
46+
writer or other person who contributed to the Font Software.
47+
48+
PERMISSION & CONDITIONS
49+
Permission is hereby granted, free of charge, to any person obtaining
50+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
51+
redistribute, and sell modified and unmodified copies of the Font
52+
Software, subject to the following conditions:
53+
54+
1) Neither the Font Software nor any of its individual components,
55+
in Original or Modified Versions, may be sold by itself.
56+
57+
2) Original or Modified Versions of the Font Software may be bundled,
58+
redistributed and/or sold with any software, provided that each copy
59+
contains the above copyright notice and this license. These can be
60+
included either as stand-alone text files, human-readable headers or
61+
in the appropriate machine-readable metadata fields within text or
62+
binary files as long as those fields can be easily viewed by the user.
63+
64+
3) No Modified Version of the Font Software may use the Reserved Font
65+
Name(s) unless explicit written permission is granted by the corresponding
66+
Copyright Holder. This restriction only applies to the primary font name as
67+
presented to the users.
68+
69+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70+
Software shall not be used to promote, endorse or advertise any
71+
Modified Version, except to acknowledge the contribution(s) of the
72+
Copyright Holder(s) and the Author(s) or with their explicit written
73+
permission.
74+
75+
5) The Font Software, modified or unmodified, in part or in whole,
76+
must be distributed entirely under this license, and must not be
77+
distributed under any other license. The requirement for fonts to
78+
remain under this license does not apply to any document created
79+
using the Font Software.
80+
81+
TERMINATION
82+
This license becomes null and void if any of the above conditions are
83+
not met.
84+
85+
DISCLAIMER
86+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94+
OTHER DEALINGS IN THE FONT SOFTWARE.

0 commit comments

Comments
 (0)