0

Expected

  1. Create ImageClips of varying duration and append to:
    clips = [] (line 13-16)
  2. Make ImageClips into a concatenated clip:
    concatenated_videoclips(clips, method="chain") (line 19)
  3. Add Audio to concatenated clip (line 20-21)
  4. Loops through image-file list and remove them from memory (not in code example)
  5. Loop through list of clips = [<ImageClip>] and close each clip then delete from list (line 24-29)
  6. Return concatenated clip (line 32) and append to another list in global scope (not in code example)
  7. Repeat steps 1-6
  8. Concatenate all clips that were added to global list then set_audio(background_music_path.mp3) (not in code example)
  9. New Video written to new_video_path.mp4 (not in code example) Blockquote

Actual

  • 5% of the time goes through process outputting video correctly
  • 95% of the time will crash due to killed: 9 or leaked semaphore error
  • Tends to reach 120GB in activity monitor by end of process until Python venv terminated
  • Using Tracemalloc module it shows linearly increasing memory usage when:
    • Adding new ImageClips related to:
      1. imageio/plugins/pillow.py (imageio Pillow python wrapper)
      2. moviepy/video/VideoClip.py (from class ImageClip(VideoClip):)
    • concatenating clips list of ImageClips:
      1. numpy/lib/shape_base.py

Memory Usage by Tracemalloc

Immediately after first ImageClips Created:

#1
/venv/lib/python3.8/site-packages/moviepy/video/VideoClip.py:900: 293626.7 KiB
1.0 * img[:, :, 3] / 255, ismask=True)
#2
/venv/lib/python3.8/site-packages/imageio/plugins/pillow.py:792: 146813.8 KiB
frame = np.array(frame, dtype=dtype)

After first ImageClips are concatenated together:

#1
/venv/lib/python3.8/site-packages/moviepy/video/VideoClip.py:900: 293626.7 KiB
 1.0 * img[:, :, 3] / 255, ismask=True)
#2
/venv/lib/python3.8/site-packages/numpy/lib/shape_base.py:1256: 234900.2 KiB
 c = c.reshape(-1, n).repeat(nrep, 0)
#3
/venv/lib/python3.8/site-packages/imageio/plugins/pillow.py:792: 146813.8 KiB
frame = np.array(frame, dtype=dtype)

After several iterations of concatenating ImageClips:

#1
/venv/lib/python3.8/site-packages/moviepy/video/VideoClip.py:900: 32709961.1 KiB
 1.0 * img[:, :, 3] / 255, ismask=True)
#2
/venv/lib/python3.8/site-packages/imageio/plugins/pillow.py:792: 16355008.3 KiB
 c = c.reshape(-1, n).repeat(nrep, 0)
#3
/venv/lib/python3.8/site-packages/numpy/lib/shape_base.py:1256: 6107405.9 KiB
frame = np.array(frame, dtype=dtype)

CODE EXAMPLE

1  import random
2
3  # Moviepy library
4  from moviepy.editor import concatenate_videoclips
5  from moviepy.video.VideoClip import ImageClip
6  from moviepy.audio.io.AudioFileClip import AudioFileClip
7
8  def make_movie(img_files):
9     # List to hold all of the ImageClips
10    clips = []
11
12    # Loop through the image files and create ImageClip with random duration
13    for img in img_files:
14      duration = random.randomint(0,3)
15      with ImageClip(img, duration=duration) as img_clip:
16        clips.append(img_clip)
17
18    # Concatenate all of ImageClips in clips and save to all_clips (audio for example sake)
19    with concatenate_videoclips(clips, method="chain") as all_clips:
20      with AudioFileClip(audio_file_path.mp3) as audio_clip:
21        all_clips = all_clips.set_audio(audio_clip)
22
23    # Loop through list of clips and close individually 
24    for used_clip in clips:
25      used_clip.close()
26    
27    # Delete all clips in list
28    while len(clips) > 0:
29      del clips[0]
30    
31    # Return concatenated clip 'all_clips'
32    return all_clips
33
34

End Result

  • After returned, all_clips will be added to a list that will eventually be concatenated once more to create a final video clip
  • The problem is that the program no longer needs all of the ImageClips once used and it has proven difficult deallocating them from memory

System Setup

  • macOS
  • MoviePy 1.0.2

Thank you in advance for any suggestions!

1 Answers1

0

You could use Python's threading or multiprocessing library. Run each call to make_movie() inside a different process, and the memory should be freed when the function finishes. You could also write each individual all_clips to disk using all_clips.write_videofile() and read them all in again at the end when you want to create the final video.

Let me know if you have more problems.

Tom Burrows
  • 2,225
  • 2
  • 29
  • 46