Loading resources as clips#

The first step for making a video with MoviePy is to load the resources you wish to include in the final video.

In this section we present the different sorts of clips and how to load them. For information on modifying a clip, see Modifying clips and apply effects. For how to put clips together see Compositing multiple clips. And for how to see/save theme, see Previewing and saving video clips (we will usually save them in example, but we wont explain here).

There’s a lot of different resources you can use with MoviePy, and you will load those differents resources with different subtypes of Clip, and more preciselly of AudioClip for any audio element, or VideoClip for any visual element.

The following code summarizes the base clips that you can create with moviepy:

from moviepy import *
import numpy as np

# Define some constants for later use
black = (255, 255, 255)  # RGB for black
# Random noise image of 200x100
make_frame = lambda t: np.random.randint(low=0, high=255, size=(100, 200, 3))
# A note by producing a sinewave of 440 Hz
make_frame_audio = lambda t: np.sin(440 * 2 * np.pi * t)

# Now lets see how to load different type of resources !

# VIDEO CLIPS`
clip = VideoClip(
    make_frame, duration=5
)  # for custom animations, where make_frame is a function returning an image as numpy array for a given time
clip = VideoFileClip("example.mp4")  # for videos
clip = ImageSequenceClip(
    "example_img_dir", fps=24
)  # for a list or directory of images to be used as a video sequence
clip = ImageClip("example.png")  # For a picture
clip = TextClip(
    font="./example.ttf", text="Hello!", font_size=70, color="black"
)  # To create the image of a text
clip = ColorClip(
    size=(460, 380), color=black
)  # a clip of a single unified color, where color is a RGB tuple/array/list

# AUDIO CLIPS
clip = AudioFileClip(
    "example.wav"
)  # for audio files, but also videos where you only want the keep the audio track
clip = AudioClip(
    make_frame_audio, duration=3
)  # for custom audio, where make_frame is a function returning a float (or tuple for stereo) for a given time

The best to understand all these clips more thoroughly is to read the full documentation for each in the Api Reference.

Realasing resources by closing a clip#

When you create some types of clip instances - e.g. VideoFileClip or AudioFileClip - MoviePy creates a subprocess and locks the file. In order to release those resources when you are finished you should call the close() method.

This is more important for more complex applications and is particularly important when running on Windows. While Python’s garbage collector should eventually clean up the resources for you, closing them makes them available earlier.

However, if you close a clip too early, methods on the clip (and any clips derived from it) become unsafe.

So, the rules of thumb are:

  • Call close() on any clip that you construct once you have finished using it and have also finished using any clip that was derived from it.

  • Even if you close a CompositeVideoClip instance, you still need to close the clips it was created from.

  • Otherwise, if you have a clip that was created by deriving it from from another clip (e.g. by calling with_mask()), then generally you shouldn’t close it. Closing the original clip will also close the copy.

Clips act as context managers. This means you can use them with a with statement, and they will automatically be closed at the end of the block, even if there is an exception.

from moviepy import *

try:
    with AudioFileClip("example.wav") as clip:
        raise Exception("Let's simulate an exception")
except Exception as e:
    print("{}".format(e))
# clip.close() is implicitly called, so the lock on my_audiofile.mp3 file is immediately released.

Categories of video clips#

Video clips are the building blocks of longer videos. Technically, they are clips with a clip.get_frame(t) method which outputs a HxWx3 numpy array representing the frame of the clip at time t.

There are two main type of video clips:

  • animated clips (made with VideoFileClip, VideoClip and ImageSequenceClip), which will always have duration.

  • unanimated clips (made with ImageClip, VideoClip`TextClip and ColorClip), which show the same picture for an a-priori infinite duration.

There are also special video clips called masks, which belong to the categories above but output greyscale frames indicating which parts of another clip are visible or not.

A video clip can carry around an audio clip (AudioClip) in audio which is its soundtrack, and a mask clip in mask.

Animated clips#

Thoses are clips whose image will change in time, and who have a duration and a number of Frames Per Second.

VideoClip#

VideoClip is the base class for all the other video clips in MoviePy. If all you want is to edit video files, you will never need it. This class is practical when you want to make animations from frames that are generated by another library. All you need is to define a function make_frame(t) which returns a HxWx3 numpy array (of 8-bits integers) representing the frame at time t.

Here is an example where we will create a pulsating red circle with graphical library pillow.

from PIL import Image, ImageDraw
import numpy as np
from moviepy import *
import math

WIDTH, HEIGHT = (128, 128)
RED = (255, 0, 0)


def make_frame(t):
    frequency = 1  # One pulse per second
    coef = 0.5 * (1 + math.sin(2 * math.pi * frequency * t))  # radius varies over time
    radius = WIDTH * coef

    x1 = WIDTH / 2 - radius / 2
    y1 = HEIGHT / 2 - radius / 2
    x2 = WIDTH / 2 + radius / 2
    y2 = HEIGHT / 2 + radius / 2

    img = Image.new("RGB", (WIDTH, HEIGHT))
    draw = ImageDraw.Draw(img)
    draw.ellipse((x1, y1, x2, y2), fill=RED)

    return np.array(img)  # returns a 8-bit RGB array


clip = VideoClip(
    make_frame, duration=2
)  # we define a 2s duration for the clip to be able to render it later
clip.write_gif(
    "circle.gif", fps=15
)  # we must set a framerate because VideoClip have no framerate by default

Resulting in this.

A pulsating red circle on black background.

Note

Clips that are made with a make_frame do not have an explicit frame rate nor duration by default, so you must provide duration at clip creation and a frame rate (fps, frames per second) for write_gif() and write_videofile(), and more generally for any methods that requires iterating through the frames.

For more, see VideoClip.

VideoFileClip#

A VideoFileClip is a clip read from a video file (most formats are supported) or a GIF file. This is probably one of the most used object ! You load the video as follows:

from moviepy import *

myclip = VideoFileClip("example.mp4")

# video file clips already have fps and duration
print("Clip duration: {}".format(myclip.duration))
print("Clip fps: {}".format(myclip.fps))

myclip = myclip.with_subclip(0.5, 2)  # Cutting the clip between 0.5 and 2 secs.
print("Clip duration: {}".format(myclip.duration))  # Cuting will update duration
print("Clip fps: {}".format(myclip.fps))  # and keep fps

myclip.write_videofile(
    "result.mp4"
)  # the output video will be 1.5 sec long and use original fps

Note

These clips will have an fps (frame per second) and duration attributes, which will be transmitted if you do small modifications of the clip, and will be used by default in write_gif(), write_videofile(), etc.

For more, see VideoFileClip.

ImageSequenceClip#

This ImageSequenceClip is a clip made from a series of images :

from moviepy import *

# A clip with a list of images showed for 1 second each
myclip = ImageSequenceClip(
    [
        "example_img_dir/image_0001.jpg",
        "example_img_dir/image_0002.jpg",
        "example_img_dir/image_0003.jpg",
    ],
    durations=[1, 1, 1],
)
print(
    "Clip duration: {}".format(myclip.duration)
)  # 3 images, 1 seconds each, duration = 3
print("Clip fps: {}".format(myclip.fps))  # 3 seconds, 3 images, fps is 3/3 = 1

# This time we will load all images in the dir, and instead of showing theme for X seconds, we will define FPS
myclip2 = ImageSequenceClip("./example_img_dir", fps=30)
print(
    "Clip duration: {}".format(myclip2.duration)
)  # fps = 30, so duration = nb images in dir / 30
print("Clip fps: {}".format(myclip2.fps))  # fps = 30

myclip.write_gif("result.gif")  # the gif will be 3 sec and 1 fps
myclip2.write_gif(
    "result2.gif"
)  # the gif will be 30 fps, duration will vary based on number of images in dir

When creating an image sequence, sequence can be either a list of image names (that will be played in the provided order), a folder name (played in alphanumerical order), or a list of frames (Numpy arrays), obtained for instance from other clips.

Warning

All the images in list/folder/frames must be of the same size, or an exception will be raised

For more, see ImageSequenceClip.

DataVideoClip#

DataVideoClip is a video clip who take a list of datasets, a callback function, and make each frame by iterating over dataset and invoking the callback function with the current data as first argument.

You will probably never use this. But if you do, think of it like a VideoClip, where you make frames not based on time, but based on each entry of a data list.

from moviepy import *
import numpy as np

# Dataset will just be a list of colors as RGB
dataset = [
    (255, 0, 0),
    (0, 255, 0),
    (0, 0, 255),
    (0, 255, 255),
    (255, 0, 255),
    (255, 255, 0),
]


# The function make frame take data and create an image of 200x100 px fill with the color
def make_frame(data):
    frame = np.full((100, 200, 3), data, dtype=np.uint8)
    return frame


# We create the DataVideoClip, and we set FPS at 2, making a 3s clip (because len(dataset) = 6, so 6/2=3)
myclip = DataVideoClip(data=dataset, data_to_frame=make_frame, fps=2)

# Modifying fps here will change video FPS, not clip FPS
myclip.write_videofile("result.mp4", fps=30)

For more, see For more, see DataVideoClip.

UpdatedVideoClip#

Warning

This is really advanced usage, you will probably never need it, if you do, please go read the code.

UpdatedVideoClip is a video whose make_frame requires some objects to be updated before we can compute it.

This is particularly practical in science where some algorithm needs to make some steps before a new frame can be generated, or maybe when trying to make a video based on a live exterior context.

When you use this, you pass a world object to it. A world object is an object who respect thoses 3 rules :

  1. It has a clip_t property, indicating the current world time.

  2. It has an update() method, that will update the world state and is responsible for increasing clip_t when a new frame can be drown.

  3. It has a to_frame() method, that will render a frame based on world current state.

On get_frame() call, your UpdatedVideoClip will try to update the world until world.clip_t is superior or equal to frame time, then it will call world.to_frame().

from moviepy import *
import numpy as np
import random


# Imagine we want to make a video that become more and more red as we repeat same face on coinflip in a row
# because coinflip are done in real time, we need to wait until a winning row is done to be able
# to make the next frame.
# This is a world simulating that. Sorry, it's hard to come up with examples...
class CoinFlipWorld:
    def __init__(self, fps):
        """
        FPS is usefull because we must increment clip_t by 1/FPS to have UpdatedVideoClip run with a certain FPS

        """
        self.clip_t = 0
        self.win_strike = 0
        self.reset = False
        self.fps = fps

    def update(self):
        if self.reset:
            self.win_strike = 0
            self.reset = False

        print("strike : {}, clip_t : {}".format(self.win_strike, self.clip_t))
        print(self.win_strike)

        # 0 tails, 1 heads, this is our simulation of coinflip
        choice = random.randint(0, 1)
        face = random.randint(0, 1)

        # We win, we increment our serie and retry
        if choice == face:
            self.win_strike += 1
            return

        # Different face, we increment clip_t and set reset so we will reset on next update.
        # We dont reset immediately because we will need current state to make frame
        self.reset = True
        self.clip_t += 1 / self.fps

    def to_frame(self):
        red_intensity = 255 * (
            self.win_strike / 10
        )  # 100% red for 10 victories and more
        red_intensity = min(red_intensity, 255)

        # A 200x100 image with red more or less intense based on number of victories in a row
        return np.full((100, 200, 3), (red_intensity, 0, 0), dtype=np.uint8)


world = CoinFlipWorld(fps=5)

myclip = UpdatedVideoClip(world=world, duration=10)
# We will set FPS to same as world, if we was to use a different FPS, the lowest from world.fps and our write_videofile fps param
# will be the real visible fps
myclip.write_videofile("result.mp4", fps=5)

Unanimated clips#

Thoses are clips whose image will, at least before modifications, stay the same. By default they have no duration nor FPS. Meaning you will need to define thoses if you try to do operation needing such information (for example rendering).

ImageClip#

ImageClip is the base class for all unanimated clips, it’s a video clip that always displays the same image. Along with VideoFileClip it’s one of the most used kind of clip. You can create one as follows:

from moviepy import *
import numpy as np

# Random RGB noise image of 200x100
noise_image = np.random.randint(low=0, high=255, size=(100, 200, 3))

myclip1 = ImageClip("example.png")  # You can create it from a path
myclip2 = ImageClip(noise_image)  # from a (height x width x 3) RGB numpy array
myclip3 = VideoFileClip("./example.mp4").to_ImageClip(
    t="00:00:01"
)  # Or load videoclip and extract frame at a given time

For more, see ImageClip.

TextClip#

A TextClip is a clip that will turn a text string into an image clip.

TextClip accept many parameters, letting you configure the apparence of the text, such as font and font size, color, interlining, text alignement, etc.

The font you want to use must be an OpenType font, and you will set it by passing the path to the font file.

Here are a few example of using TextClip :

from moviepy import *

font = "./example.ttf"

# First we use as string and let system autocalculate clip dimensions to fit the text
# we set clip duration to 2 secs, if we do not, it got an infinite duration
txt_clip1 = TextClip(
    font=font,
    text="Hello World !",
    font_size=30,
    color="#FF0000",
    bg_color="#FFFFFF",
    duration=2,
)  # Red

# This time we load text from a file, we set a fixed size for clip and let the system find best font size,
# allowing for line breaking
txt_clip2 = TextClip(
    font=font,
    filename="./example.txt",
    size=(500, 200),
    bg_color="#FFFFFF",
    method="caption",
    color=(0, 0, 255, 127),
)  # Blue with 50% transparency

# we set duration, because by default image clip are infinite, and we cannot render infinite
txt_clip2 = txt_clip2.with_duration(2)

txt_clip1.write_videofile(
    "result1.mp4", fps=24
)  # ImageClip have no FPS either, so we must defined it
txt_clip2.write_videofile("result2.mp4", fps=24)

Note

The parameter method let you define if text should be written and overflow if too long (label) or be automatically breaked (caption).

For a more detailed explaination of all the parameters, see TextClip.

ColorClip#

A ColorClip is a clip that will return an image of only one color. It is sometimes usefull when doing compositing (see Compositing multiple clips).

from moviepy import *

myclip = ColorClip(
    size=(200, 100), color=(255, 0, 0), duration=1
)  # Color is passed as a RGB tuple
myclip.write_videofile(
    "result.mp4", fps=1
)  # We really dont need more than 1 fps do we ?

For more, see ColorClip.

Mask clips#

Masks are a special kind of VideoClip with the property is_mask set to True. They can be attached to any other kind of VideoClip through method with_mask().

When a clip as a mask attached to it, this mask will indicate which pixels will be visible when the clip is composed with other clips (see Compositing multiple clips). Masks are also used to define transparency when you export the clip as GIF file or as a PNG.

The fundamental difference between masks and standard clips is that standard clips output frames with 3 components (R-G-B) per pixel, comprised between 0 and 255, while a mask has just one composant per pixel, between 0 and 1 (1 indicating a fully visible pixel and 0 a transparent pixel). Seen otherwise, a mask is always in greyscale.

When you create or load a clip that you will use as a mask you need to declare it. You can then attach it to a clip with the same dimensions :

from moviepy import *
import numpy as np

# Random RGB noise image of 200x100
makeframe = lambda t: np.random.rand(100, 200)

# To define the VideoClip as a mask, just pass parameter is_mask as True
maskclip1 = VideoClip(makeframe, duration=4, is_mask=True)  # A random noise mask
maskclip2 = ImageClip("example_mask.jpg", is_mask=True)  # A fixed mask as jpeg
maskclip3 = VideoFileClip("example_mask.mp4", is_mask=True)  # A video as a mask

# Load our basic clip, resize to 200x100 and apply each mask
clip = VideoFileClip("example.mp4")
clip_masked1 = clip.with_mask(maskclip1)
clip_masked2 = clip.with_mask(maskclip2)
clip_masked3 = clip.with_mask(maskclip3)

Note

In the case of video and image files, if these are not already black and white they will be converted automatically.

Also, when you load an image with an alpha layer, like a PNG, MoviePy will use this layer as a mask, except if you pass transparent=False.

Any video clip can be turned into a mask with to_mask(), and a mask can be turned to a standard RGB video clip with to_RGB().

Masks are treated differently by many methods (because their frames are different) but at the core, they are VideoClip, so you can do with theme everything you can do with a video clip: modify, cut, apply effects, save, etc.

Using audio elements with audio clips#

In addition to VideoClip for visual, you can use audio elements, like an audio file, using the AudioClip class.

Both are quite similar, except AudioClip method get_frame() return a numpy array of size Nx1 for mono, and size Nx2 for stereo.

AudioClip#

AudioClip is the base class for all audio clips. If all you want is to edit audio files, you will never need it.

All you need is to define a function make_frame(t) which returns a Nx1 or Nx2 numpy array representing the sound at time t.

from moviepy import *
import numpy as np

# Producing a sinewave of 440 Hz -> note A
make_frame_audio = lambda t: np.sin(440 * 2 * np.pi * t)

# AUDIO CLIPS
clip = AudioClip(make_frame_audio, duration=3)

For more, see AudioClip.

AudioFileClip#

AudioFileClip is used to load an audio file, this is probably the only kind of audio clip you will use.

You simply pass him the file you want to load :

from moviepy import *
import numpy as np

# Works for audio files, but also videos file where you only want the keep the audio track
clip = AudioFileClip("example.wav")
clip.write_audiofile("./result.wav")

For more, see AudioFileClip.

AudioArrayClip#

AudioArrayClip is used to turn an array representing a sound into an audio clip. You will probably never use it, unless you need to use the result of some third library without using a temporary file.

You need to provide a numpy array representing the sound (of size Nx1 for mono, Nx2 for stereo), and the number of fps, indicating the speed at which the sound is supposed to be played.

import numpy as np
from moviepy import *

# We want to play those notes
notes = {"A": 440, "B": 494, "C": 523, "D": 587, "E": 659, "F": 698}

note_duration = 0.5
total_duration = len(notes) * note_duration
sample_rate = 44100  # Number of samples per second

note_size = int(note_duration * sample_rate)
total_size = note_size * len(notes)


def make_frame(t, note_frequency):
    return np.sin(note_frequency * 2 * np.pi * t)


# We generate all frames timepoints
times = np.linspace(0, total_duration, total_size)

# We make an array of size N*1, where N is the number of frames * total duration
audio_array = np.zeros((total_size, 2))
i = 0
for note, frequency in notes.items():
    for _ in range(note_size):
        audio_array[i][0] = make_frame(times[i], frequency)
        i += 1

# Create an AudioArrayClip from the audio samples
audio_clip = AudioArrayClip(audio_array, fps=sample_rate)

# Write the audio clip to a WAV file
audio_clip.write_audiofile("result.wav", fps=44100)

For more, see AudioArrayClip.