Manipulating video with moviepy the easy way

Today, we are going to try to understand how python library moviepy works. I had a requirement for video extraction, so moviepy seems to fit the bill perfectly.

Shamelessly copying from pypi, here is what it says,

MoviePy is a Python library for video editing: cutting, concatenations, title insertions, video compositing (a.k.a. non-linear editing), video processing, and creation of custom effects.

Installation

We will install moviepy in a virtual environment. For this project, we will use pip to create virtual environment. You can find more details for moviepy installation here.

$ python -m venv moviepytest
$ . ./moviepytest/bin/activate
(moviepytest)$ pip install moviepy

The commands above will create a virtual environment called moviepytest and install moviepy in it.

My requirement was fairly simple. I needed to read timing information from a database and extract clips based on the start and end time. Finally, I had to merge all these clips to create a mpeg file for output.

Moviepy makes creating this very simple. Let us look at the code for doing this workflow.

Video Extraction and Merge

Instead of a database, for this blog I just created a CSV file that has the start and end times listed. We will be extracting videos based on this file.

00:05, 00:15
00:20, 01:20
02:10, 02:45
03:10, 03:75

This file lists some start and end times. For example, the first line says start extracting from 5 second mark and continue extracting till 15 second mark. Similarly rest of the lines follow.

We use csv library to load this file.

def get_timings(self, flname):
  ins = []
  with open(flname, newline='') as f:
    aline = csv.reader(f, delimiter=',')
    for cols in aline:
      ins.append(cols)

  return ins

Next step is to start extraction of the clips. We will extract clips using subclip function. In this case we are also adding the extracted clips to an array for future processing. Also, just for fun, I am randomly changing some subclip color to grayscale. Moviepy has a lot of special effects (fx package). The effects range from grayscale, resizing, luminosity change etc.

subclips = []
# Load video
clip = VideoFileClip(vdo)
print('Video length: %d' % clip.duration)

# Extract clips first
for tmng in tmngs:
  print('Extracting: %s' % tmng)
  # Make some clips black and white
  if (random.randint(1, 10) > 7):
    subclips.append(clip.subclip(tmng[0], tmng[1]).fx(blackwhite))
    else:
      subclips.append(clip.subclip(tmng[0], tmng[1]))

Now that we have all the clips extracted, joining them and writing output mp4 file is just a matter of calling two functions.

merged = concatenate_videoclips(subclips)
merged.write_videofile(vdo_out, fps=30, threads=10, codec="libx264")

See generated output.

Video length: 340
Extracting: ['00:05', ' 00:15']
Extracting: ['00:20', ' 01:20']
Extracting: ['02:10', ' 02:45']
Extracting: ['03:10', ' 03:75']
Moviepy - Building video rsc/belfort_out.mp4.
MoviePy - Writing audio in belfort_outTEMP_MPY_wvf_snd.mp3
MoviePy - Done.
Moviepy - Writing video rsc/belfort_out.mp4

Conclusion

This is a fairly short blog as it only touched the top of the iceberg. Moviepy supports a lot more features than what is covered here. One of the good examples that moviepy supports is face tracking. We can blur faces by tracking on moviepy. There are additional fx functions that can be done on the video. A lot of these fx will need ImageMagick installed for image processing.

I will finish this blog for today, as I am travelling and do not have much time for researching additional functionalities. Hope you find this blog useful. As usual, code will be on my github public repository. Ciao for now!