Skip to content

Commit

Permalink
example tweaks (#2258)
Browse files Browse the repository at this point in the history
* more api changes
  • Loading branch information
Zulko authored Nov 24, 2024
1 parent b22e702 commit 2e3c310
Show file tree
Hide file tree
Showing 54 changed files with 580 additions and 473 deletions.
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

[![MoviePy page on the Python Package Index](https://badge.fury.io/py/moviepy.svg)](https://pypi.org/project/moviepy/) [![Discuss MoviePy on Gitter](https://img.shields.io/gitter/room/movie-py/gitter?color=46BC99&logo=gitter)](Gitter_) [![Build status on gh-actions](https://img.shields.io/github/actions/workflow/status/Zulko/moviepy/test_suite.yml?logo=github)](https://github.com/Zulko/moviepy/actions/workflows/test_suite.yml) [![Code coverage from coveralls.io](https://img.shields.io/coveralls/github/Zulko/moviepy/master?logo=coveralls)](https://coveralls.io/github/Zulko/moviepy?branch=master)

> [!NOTE] MoviePy recently upgraded to v2.0, introducing major breaking changes. You can consult the last v1 docs [here](https://zulko.github.io/moviepy/v1.0.3/) but beware that v1 is no longer maintained. For more info on how to update your code from v1 to v2, see [this guide](https://zulko.github.io/moviepy/getting_started/updating_to_v2.html).
> [!NOTE]
> MoviePy recently upgraded to v2.0, introducing major breaking changes. You can consult the last v1 docs [here](https://zulko.github.io/moviepy/v1.0.3/) but beware that v1 is no longer maintained. For more info on how to update your code from v1 to v2, see [this guide](https://zulko.github.io/moviepy/getting_started/updating_to_v2.html).
MoviePy (online documentation [here](https://zulko.github.io/moviepy/)) is a
Python library for video editing: cuts, concatenations, title
Expand All @@ -20,26 +21,28 @@ In this example we open a video file, select the subclip between 10 and
result to a new file:

``` python
# Import everything needed to edit video clips
from moviepy import *
from moviepy import VideoFileClip, TextClip, CompositeVideoClip

# Load file example.mp4 and keep only the subclip from 00:00:10 to 00:00:20
clip = VideoFileClip("long_examples/example2.mp4").subclipped(10, 20)

# Reduce the audio volume to 80% of its original volume
clip = clip.with_volume_scaled(0.8)

# Generate a text clip. You can customize the font, color, etc.
txt_clip = TextClip(font="example.ttf", text="Big Buck Bunny", font_size=70, color='white')
clip = (
VideoFileClip("long_examples/example2.mp4")
.subclipped(10, 20)
.with_volume_scaled(0.8)
)

#The text clip should appear for 10s at the center of the screen
txt_clip = txt_clip.with_duration(10).with_position('center')
# Generate a text clip. You can customize the font, color, etc.
txt_clip = TextClip(
font="Arial.ttf",
text="Hello there!",
font_size=70,
color='white'
).with_duration(10).with_position('center')

# Overlay the text clip on the first video clip
video = CompositeVideoClip([clip, txt_clip])

# Write the result to a file (many options available!)
video.write_videofile("result.mp4")
final_video = CompositeVideoClip([clip, txt_clip])
final_video.write_videofile("result.mp4")
```

# Installation
Expand Down
22 changes: 13 additions & 9 deletions docs/_static/code/user_guide/compositing/CompositeAudioClip.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
from moviepy import *
"""Let's first concatenate (one after the other) then composite
(on top of each other) three audio clips."""

from moviepy import AudioFileClip, CompositeAudioClip, concatenate_audioclips

# We load all the clips we want to compose
aclip1 = AudioFileClip("example.wav")
aclip2 = AudioFileClip("example2.wav")
aclip3 = AudioFileClip("example3.wav")
clip1 = AudioFileClip("example.wav")
clip2 = AudioFileClip("example2.wav")
clip3 = AudioFileClip("example3.wav")

# All clip will play one after the other
concat = concatenate_audioclips([aclip1, aclip2, aclip3])
concat = concatenate_audioclips([clip1, clip2, clip3])

# We will play aclip1, then ontop of it aclip2 after 5s, and the aclip3 on top of both after 9s
# We will play clip1, then on top of it clip2 starting at t=5s,
# and clip3 on top of both starting t=9s
compo = CompositeAudioClip(
[
aclip1.with_volume_scaled(1.2),
aclip2.with_start(5), # start at t=5s
aclip3.with_start(9),
clip1.with_volume_scaled(1.2),
clip2.with_start(5), # start at t=5s
clip3.with_start(9),
]
)
10 changes: 7 additions & 3 deletions docs/_static/code/user_guide/compositing/CompositeVideoClip.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from moviepy import *
"""Let's stack three video clips on top of each other with
CompositeVideoClip."""

from moviepy import VideoFileClip, CompositeVideoClip

# We load all the clips we want to compose
clip1 = VideoFileClip("example.mp4")
clip2 = VideoFileClip("example2.mp4").subclipped(0, 1)
clip3 = VideoFileClip("example3.mp4")
clip3 = VideoFileClip("example.mp4")

# We concatenate them and write theme stacked on top of each other, with clip3 over clip2 over clip1
# We concatenate them and write theme stacked on top of each other,
# with clip3 over clip2 over clip1
final_clip = CompositeVideoClip([clip1, clip2, clip3])
final_clip.write_videofile("final_clip.mp4")
2 changes: 2 additions & 0 deletions docs/_static/code/user_guide/compositing/concatenate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Let's concatenate (play one after the other) three video clips."""

from moviepy import VideoFileClip, concatenate_videoclips

# We load all the clips we want to concatenate
Expand Down
23 changes: 10 additions & 13 deletions docs/_static/code/user_guide/compositing/crossfadein.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
from moviepy import *
"""In this example, we will concatenate two clips with a 1-second
crossfadein of the second clip."""

from moviepy import VideoFileClip, CompositeVideoClip, vfx

# We load all the clips we want to compose
clip1 = VideoFileClip("example.mp4")
clip2 = VideoFileClip("example2.mp4").subclipped(0, 1)

# Clip2 will be on top of clip1 for 1s
clip1 = clip1.with_end(2)
clip2 = clip2.with_start(1)

# We will add a crossfadein on clip2 for 1s
# As the other effects, transitions are added to Clip methods at runtime
clip2 = clip2.with_effects([vfx.CrossFadeIn(1)])

clip2 = VideoFileClip("example2.mp4")

# We write the result
final_clip = CompositeVideoClip([clip1, clip2])
clips = [
clip1.with_end(2),
clip2.with_start(1).with_effects([vfx.CrossFadeIn(1)]),
]
final_clip = CompositeVideoClip(clips)
final_clip.write_videofile("final_clip.mp4")
13 changes: 9 additions & 4 deletions docs/_static/code/user_guide/compositing/juxtaposing.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Let's juxtapose four video clips in a 2x2 grid."""

from moviepy import VideoFileClip, clips_array, vfx

# We will use the same clip and transform it in 3 ways
Expand All @@ -8,9 +10,12 @@

# The form of the final clip will depend of the shape of the array
# We want our clip to be our 4 videos, 2x2, so we make an array of 2x2
final_clip = clips_array([[clip1, clip2], [clip3, clip4]])
final_clip = final_clip.resized(
width=480
) # We resize the resulting clip to have the dimensions we want
array = [
[clip1, clip2],
[clip3, clip4],
]
final_clip = clips_array(array)
# let's resize the final clip so it has 480px of width
final_clip = final_clip.resized(width=480)

final_clip.write_videofile("final_clip.mp4")
12 changes: 8 additions & 4 deletions docs/_static/code/user_guide/compositing/with_position.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from moviepy import *
"""Let's position some text and images on a video."""

from moviepy import TextClip, VideoFileClip, CompositeVideoClip, ImageClip

# We load all the clips we want to compose
background = VideoFileClip("example2.mp4").subclipped(0, 2)
Expand Down Expand Up @@ -28,8 +30,9 @@
)
logo = ImageClip("./example2.png", duration=1).resized(height=50)

# We want our title to be at the center horizontaly and start at 25% of the video verticaly
# We can set as "center", "left", "right", "top" and "bottom", and % relative from the clip size
# We want our title to be at the center horizontaly and start at 25%
# of the video verticaly. We can set as "center", "left", "right",
# "top" and "bottom", and % relative from the clip size
title = title.with_position(("center", 0.25), relative=True)

# We want the author to be in the center, 30px under the title
Expand All @@ -42,7 +45,8 @@
copyright = copyright.with_position(("center", background.h - copyright.h - 30))

# Finally, we want the logo to be in the center, but to drop as time pass
# We can do so by setting position as a function that take time as argument, a lot like frame_function
# We can do so by setting position as a function that take time as argument,
# a lot like frame_function
top = (background.h - logo.h) / 2
logo = logo.with_position(lambda t: ("center", top + t * 30))

Expand Down
8 changes: 4 additions & 4 deletions docs/_static/code/user_guide/compositing/with_start.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from moviepy import *
from moviepy import VideoFileClip, CompositeVideoClip

# We load all the clips we want to compose
clip1 = VideoFileClip("example.mp4")
Expand All @@ -12,9 +12,9 @@
clip2 = clip2.with_start(1.5)

# We want to play clip3 at the end of clip2, and so for 3 seconds only
clip3 = clip3.with_start(clip2.end).with_duration(
1
) # Some times its more practical to modify the duration of a clip instead of his end
# Some times its more practical to modify the duration of a clip instead
# of his end
clip3 = clip3.with_start(clip2.end).with_duration(1)

# We write the result
final_clip = CompositeVideoClip([clip1, clip2, clip3])
Expand Down
6 changes: 5 additions & 1 deletion docs/_static/code/user_guide/effects/custom_effect.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""Let's write a custom effect that will add a basic progress bar
at the bottom of our clip."""

from moviepy import VideoClip
from moviepy.decorators import requires_duration

Expand All @@ -22,7 +25,8 @@ def filter(get_frame, t):
progression = t / clip.duration
bar_width = int(progression * clip.w)

# Showing a progress bar is just replacing bottom pixels on some part of our frame
# Showing a progress bar is just replacing bottom pixels
# on some part of our frame
frame = get_frame(t)
frame[-height:, 0:bar_width] = color

Expand Down
2 changes: 2 additions & 0 deletions docs/_static/code/user_guide/effects/image_transform.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Let's invert the green and blue channels of a video."""

from moviepy import VideoFileClip
import numpy

Expand Down
12 changes: 7 additions & 5 deletions docs/_static/code/user_guide/effects/modify_copy_example.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# Import everything needed to edit video clips
from moviepy import *
from moviepy import VideoFileClip

# Load example.mp4
clip = VideoFileClip("example.mp4")

# This does nothing, as multiply_volume will return a copy of clip which you will loose immediatly as you dont store it
# This does nothing, as multiply_volume will return a copy of clip
# which you will loose immediatly as you dont store it
# If you was to render clip now, the audio would still be at full volume
clip.with_volume_scaled(0.1)

# This create a copy of clip in clip_whisper with a volume of only 10% the original, but does not modify the original clip
# This create a copy of clip in clip_whisper with a volume of only 10% the original,
# but does not modify the original clip
# If you was to render clip right now, the audio would still be at full volume
# If you was to render clip_whisper, the audio would be a 10% of the original volume
clip_whisper = clip.with_volume_scaled(0.1)

# This replace the original clip with a copy of it where volume is only 10% of the original
# If you was to render clip now, the audio would be at 10%
# This replace the original clip with a copy of it where volume is only 10% of
# the original. If you was to render clip now, the audio would be at 10%
# The original clip is now lost
clip = clip.with_volume_scaled(0.1)
12 changes: 3 additions & 9 deletions docs/_static/code/user_guide/effects/time_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@

my_clip = VideoFileClip("example.mp4")


# You can define a function the classical way
def accel_x3(time: float) -> float:
return time * 3


modified_clip1 = my_clip.time_transform(accel_x3)

# Of you can also use lambda function
# Let's accelerate the video by a factor of 3
modified_clip1 = my_clip.time_transform(lambda t: t * 3)
# Let's play the video back and forth with a "sine" time-warping effect
modified_clip2 = my_clip.time_transform(lambda t: 1 + math.sin(t))
3 changes: 2 additions & 1 deletion docs/_static/code/user_guide/effects/transform.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Let's create a scolling video effect from scratch."""

from moviepy import VideoFileClip
import math

my_clip = VideoFileClip("example.mp4")

Expand Down
13 changes: 6 additions & 7 deletions docs/_static/code/user_guide/effects/using_effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
from moviepy import vfx, afx

myclip = VideoFileClip("example.mp4")
myclip = myclip.with_effects(
[vfx.Resize(width=460)]
) # resize clip to be 460px in width, keeping aspect ratio
# resize clip to be 460px in width, keeping aspect ratio
myclip = myclip.with_effects([vfx.Resize(width=460)])

# fx method return a copy of the clip, so we can easily chain them
myclip = myclip.with_effects(
[vfx.MultiplySpeed(2), afx.MultiplyVolume(0.5)]
) # double the speed and half the audio volume
# double the speed and half the audio volume
myclip = myclip.with_effects([vfx.MultiplySpeed(2), afx.MultiplyVolume(0.5)])

# because effects are added to Clip at runtime, you can also call them directly from your clip as methods
# because effects are added to Clip at runtime, you can also call
# them directly from your clip as methods
myclip = myclip.with_effects([vfx.MultiplyColor(0.5)]) # darken the clip
1 change: 0 additions & 1 deletion docs/_static/code/user_guide/effects/using_with_methods.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from moviepy import VideoFileClip
from moviepy import vfx, afx

myclip = VideoFileClip("example.mp4")
myclip = myclip.with_end(5) # stop the clip after 5 sec
Expand Down
25 changes: 13 additions & 12 deletions docs/_static/code/user_guide/loading/AudioArrayClip.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Let's create an audioclip from values in a numpy array."""

import numpy as np
from moviepy import *
from moviepy import AudioArrayClip

# We want to play those notes
notes = {"A": 440, "B": 494, "C": 523, "D": 587, "E": 659, "F": 698}
Expand All @@ -9,26 +11,25 @@
sample_rate = 44100 # Number of samples per second

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


def frame_function(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)
# At this point one could use this audioclip which generates the audio on the fly
# clip = AudioFileClip(frame_function)

# 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] = frame_function(times[i], frequency)
i += 1
# We generate all frames timepoints

audio_frame_values = [
2 * [frame_function(t, freq)]
for freq in notes.values()
for t in np.arange(0, note_duration, 1.0 / sample_rate)
]
# Create an AudioArrayClip from the audio samples
audio_clip = AudioArrayClip(audio_array, fps=sample_rate)
audio_clip = AudioArrayClip(np.array(audio_frame_values), fps=sample_rate)

# Write the audio clip to a WAV file
audio_clip.write_audiofile("result.wav", fps=44100)
12 changes: 7 additions & 5 deletions docs/_static/code/user_guide/loading/AudioClip.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from moviepy import *
from moviepy import AudioClip
import numpy as np

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

# AUDIO CLIPS
clip = AudioClip(frame_function_audio, duration=3)
def audio_frame(t):
"""Producing a sinewave of 440 Hz -> note A"""
return np.sin(440 * 2 * np.pi * t)


audio_clip = AudioClip(frame_function=audio_frame, duration=3)
1 change: 0 additions & 1 deletion docs/_static/code/user_guide/loading/AudioFileClip.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
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")
Expand Down
12 changes: 5 additions & 7 deletions docs/_static/code/user_guide/loading/ColorClip.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from moviepy import *
from moviepy import ColorClip

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

0 comments on commit 2e3c310

Please sign in to comment.