4

I am trying to make a video from a large number of images using MoviePy. The approach works fine for small numbers of images, but the process is killed for large numbers of images. At about 500 images added, the Python process is using all about half of the volatile memory available. There are many more images than that.

How should I address this? I want the processing to complete and I don't mind if the processing takes a bit longer, but it would be good if I could limit the memory and CPU usage in some way. With the current approach, the machine becomes almost unusable while processing.

The code is as follows:

import os
import time
from   moviepy.editor import *

def ls_files(
    path = "."
    ):
    return([fileName for fileName in os.listdir(path) if os.path.isfile(
        os.path.join(path, fileName)
    )])

def main():

    listOfFiles = ls_files()
    listOfTileImageFiles = [fileName for fileName in listOfFiles \
        if "_tile.png" in fileName
    ]
    numberOfTiledImages = len(listOfTileImageFiles)

    # Create a video clip for each image.
    print("create video")
    videoClips = []
    imageDurations = []
    for imageNumber in range(0, numberOfTiledImages):
        imageFileName = str(imageNumber) + "_tile.png"
        print("add image {fileName}".format(
            fileName = imageFileName
        ))
        imageClip = ImageClip(imageFileName)
        duration  = 0.1
        videoClip = imageClip.set_duration(duration)
        # Determine the image start time by calculating the sum of the durations
        # of all previous images.
        if imageNumber != 0:
            videoStartTime = sum(imageDurations[0:imageNumber])
        else:
            videoStartTime = 0
        videoClip = videoClip.set_start(videoStartTime)
        videoClips.append(videoClip)
        imageDurations.append(duration)
    fullDuration = sum(imageDurations)
    video = concatenate(videoClips)
    video.write_videofile(
        "video.mp4",
        fps         = 30,
        codec       = "mpeg4",
        audio_codec = "libvorbis"
    )

if __name__ == "__main__":
    main()
4
  • If MoviePy inherently requires holding all those clips in memory and then writing out the result only at the end, then I don't think you can do anything but use a different library. Commented May 2, 2015 at 8:26
  • I would hope that it would be smarter about that, leaving each clip as a duration and some other small info plus a reference to a file on disk rather than a whole slew of frames in memory, but… this is a library that's only a few months old and only on version 0.2, so it may not do everything perfectly yet even if the design is sound. Commented May 2, 2015 at 8:33
  • @abarnert It IS smarter. See my answer below. Commented May 2, 2015 at 8:44
  • @Zulko: Great! So it's just the docs that aren't perfect yet. Not a bad problem for 0.2. :) Commented May 2, 2015 at 8:49

1 Answer 1

6

If I understood correctly, you want to use the different images as the frames of your video.

In this case you should use ImageSequenceClip() (it's in the library, but not yet in the web docs, see here for the doc).

Basically, you just write

clip = ImageSequenceClip("some/directory/", fps=10)
clip.write_videofile("result.mp4")

And it will read the images in the directory in alpha-numerical order, while keeping only one frame at a time in the memory.

While I am at it, you can also provide a list of filenames or a list of numpy arrays to ImageSequenceClip.

Note that if you just want to transform images into a video, and not anything else fancy like adding titles or compositing with another video, then you can do it directly with ffmpeg. From memory the command should be:

ffmpeg -i *_tile.png -r 10 -o result.mp4
Sign up to request clarification or add additional context in comments.

1 Comment

Ah, excellent. Thank you for your help on that. This works well. The memory usage now is very small and the CPU usage is reasonable. Internally, it appears to be doing something similar to what you suggested with ffmpeg.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.