Skip to content

Instantly share code, notes, and snippets.

@shimpe
Created November 26, 2022 16:49
Show Gist options
  • Save shimpe/c4140e8bae81f89505d217afbebeeb76 to your computer and use it in GitHub Desktop.
Save shimpe/c4140e8bae81f89505d217afbebeeb76 to your computer and use it in GitHub Desktop.
import moviepy.editor as mpy
from vectortween.Mapping import Mapping
basename = 'video.mp4'
inputfile = basename + ".mp4"
outputfile = basename + ".new.mp4"
video_file = mpy.VideoFileClip(inputfile)
duration = video_file.duration # duration
video_width, video_height = video_file.size
textclip = mpy.TextClip("www.YouTube.com",fontsize=30,color="red")
textclip_width, textclip_height = textclip.size
extra_margin = 10
desired_final_x = video_width - textclip_width - extra_margin
desired_final_y = 0
def position(t):
return Mapping.linlin(t, 0, duration, 0, desired_final_x), desired_final_y
add_text = textclip.set_position(position).set_duration(video_file.duration)
final = mpy.CompositeVideoClip([video_file,add_text])
final.write_videofile(outputfile)
@shimpe
Copy link
Author

shimpe commented Jan 11, 2023

Everything happens in the function position(t). The position function must return two numbers: an x value and a y value corresponding to a position on the screen. In the gist shown above, the x value is given by Mapping.linlin(t, 0, duration, 0, desired_final_x) and the y value is given by desired_final_y.

As you can see, the x-value is animated, since it depends on the time t. The arguments to Mapping are:

  1. t = the time
  2. 0 = the minimal value time can have (which is always 0)
  3. duration = the maximum value time can have (which is duration)
  4. the number you want to start from at time 0 (in the gist it's set to 0, meaning the x-position will be 0, meaning the left side)
  5. the number you want to reach at time "duration" (in the gist it's set to desired_final_x, i.e. the right side of the screen).

If you want to move from right to left, just swap arguments 4 and 5.
If you want to move top down or bottom up, you have to animate the y value in the same way as the x value is animated now.

So to write the code a bit more general:

import moviepy.editor as mpy
from vectortween.Mapping import Mapping

basename = 'video.mp4'
inputfile = basename + ".mp4"
outputfile = basename + ".new.mp4"
video_file = mpy.VideoFileClip(inputfile)
duration = video_file.duration # duration
video_width, video_height = video_file.size
textclip = mpy.TextClip("www.YouTube.com",fontsize=30,color="red")
textclip_width, textclip_height = textclip.size
extra_margin = 10
desired_start_x = 0
desired_final_x = video_width - textclip_width - extra_margin
desired_start_y = 0
desired_final_x = video_height - textclip_height - extra_margin

def position(t):
    return Mapping.linlin(t, 0, duration, desired_start_x, desired_final_x), Mapping.linlin(t, 0, duration, desired_start_y, desired_final_y)

add_text = textclip.set_position(position).set_duration(video_file.duration)

final = mpy.CompositeVideoClip([video_file,add_text])

final.write_videofile(outputfile)

in this code (untested, sorry) you need to edit only the values of desired_start_x, desired_final_x, desired_start_y and desired_final_y to make your text clip move from position (desired_start_x, desired_start_y) to position (desired_final_x, desired_final_y) with a constant speed.

For left to right: desired_start_x = 0, desired_final_x = video_width - textclip_width - extra_margin
For right to left: desired_start_x = video_width - textclip_width - extra_margin, desired_final_x = 0
For top to bottom: desired_start_y = 0, desired_final_y = video_height - textclip_height - extra_margin
For bottom to top: desired_start_y = video_height - textclip_height - extra_margin, desired_final_y = 0

(maybe I switched top to bottom and bottom to top - I didn't test it out)

To remain at a fixed x position, make desired_start_x = desired_final_x = the fixed x position
To remain at a fixed y position, make desired_start_y = desired_final_y = the fixed y position

Is this clear enough or am I speaking in riddles? :)

@ujjally
Copy link

ujjally commented Jan 12, 2023

WOW. It's Cool :)
I created a lot of presets by the instruction. And i have learned many new things.
By the way, you are a great teacher, God bless You.
Thank you so much🙏

@shimpe
Copy link
Author

shimpe commented Jan 12, 2023

I'm glad I could be of help. If you ever want to try making a more fancy text animation, you may want to take a look at my recently started hobby project: https://shimpe.github.io/camala/

@ujjally
Copy link

ujjally commented Jan 12, 2023

It's amazing, text animations are very attractive. I going to try it :)

@ujjally
Copy link

ujjally commented Jan 12, 2023

camala or pyvectortween, In which module can be set the random position (every custom second) of overlay text on video?

I tried FFmpeg by this instruction: https://ffmpeg.org/ffmpeg-filters.html#Examples-71

  • Show the text at a random position, switching to a new position every 30 seconds:
    drawtext="fontsize=30:fontfile=FreeSerif.ttf:text='hello world':x=if(eq(mod(t\,30)\,0)\,rand(0\,(w-text_w))\,x):y=if(eq(mod(t\,30)\,0)\,rand(0\,(h-text_h))\,y)"

My custom input, every 10 seconds: Working
ffmpeg -i video_input.mp4 -vf drawtext="fontfile='C\:/Users/BRIGHT/AppData/Local/Microsoft/WINDOWS/fonts/RacingSansOne-Regular.ttf':text='YouTube.com':fontsize=h/15:fontcolor=white:alpha=0.2:bordercolor=black:borderw=1:x=if(eq(mod(t\,10)\,0)\,rand(0\,(w-text_w))\,x):y=if(eq(mod(t\,10)\,0)\,rand(0\,(h-text_h))\,y)" -codec:a copy video_output.mp4

FFmpeg is too much complicated. Does have any option to create the same task by moviepy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment