0

I have a list of 4 moviepy ImageClips that I want to concatenate and then export. I notice that when I export the concatenated videoclip, it starts exporting at ~60 it/s but it quickly drops to ~6 after a couple seconds. I suspect that the drop is when it reaches the third clip, which is significantly longer than the others. The first are less than half a minute, while the third clip is upwards of 10 minutes. The first two clips are generated in the following way:

    background = Image.open("background.jpg")
    new_background = background.resize((screen_width, screen_height))
    new_background.save("temp/resized_background.png")

    # Maybe I could speed this up by only resizing the background once, but that is irrelevant to this issue
    image_clip = ImageClip(f"temp/resized_background.png")
    audio_clip = AudioFileClip(f'temp/{random_file_name}.mp3')
    video_clip = image_clip.set_audio(audio_clip)
    video_clip.duration = audio_clip.duration
    video_clip.fps = fps # fps=12

    # Memory cleanup
    del background
    del new_background
    del image_clip
    del audio_clip

    return video_clip

The third clip is created by the following code:

        clips = []
        for pic, audioFile in zip(self.images, self.audioFiles):
            try:
                audio_clip = AudioFileClip(f"temp/{audioFile}.mp3")
                image_clip = ImageClip(f"temp/{pic}.png").resize((screen_height, screen_width))
                # The images should already be this size, but also irrelevant here
            except:
                continue

            video_clip = image_clip.set_audio(audio_clip)
            video_clip.duration = audio_clip.duration
            video_clip.fps = self.fps

            clips.append(video_clip)

        # Memory management
        del image_clip
        del audio_clip
        del video_clip

        unsilenced_video = concatenate_videoclips(clips, method="compose")

        del clips

        self.duration = unsilenced_video.duration
        self.fullClip = unsilenced_video

        del unsilenced_video

        return self

I then made sure all of them are in a list in the correct order. Then I concatenate them

        concat_clip = concatenate_videoclips(allClipsInOrder, method="compose")

        # Put soft background music over the whole video
        background = AudioFileClip("background_music.mp3").volumex(0.1)
        full_background = afx.audio_loop(background, duration=concat_clip.duration)

        final_audio = CompositeAudioClip([concat_clip.audio, full_background])
        self.full_video = concat_clip.set_audio(final_audio)

And finally export them:

 self.full_video.write_videofile("sample_name.mp4", fps=self.fps, codec='h264_nvenc', verbose=False)

I have an NVIDIA RTX 3060 laptop GPU, hence the codec. However, when I try to export it, task manager shows that my RAM is being eaten(90+%) and my GPU is hardly being used(like 5%). I have also tried the libx264 codec, specifying different amounts of threads and without specifying threads, which give pretty much the same result. I also tried specifying the bitrate, without any luck. I am not sure if I need to install anything else that might allow me to use my GPU more effectively or that there is another setting I could use.

The weird thing is that when I export each of the clips separately(that means without background music added, I don't think that that matters since it starts at high it/s with it too), it does stay at a reasonable export speed. All the clips should however have the same size and fps, so I don't know what the issue is. I understand that lowering the size would speed it up and disabling logger would too, but that would still mean the high difference in export speed for the concatenated clip and the separate clips.

Is there a way to make the exporting faster? Or is it better to export the clips separately and then try to concatenate them afterwards? By deleting variables, I tried to clear up some of my RAM which also helped a bit, but still doesn't fix the issue

FFMPEG with moviepy This source also shows something about CompositeVideoClip, but I could not get that to work and not sure if that fixes the issue, as that is for concatenating I think, not exporting.

Thomas Smeman
  • 175
  • 11

1 Answers1

0

Okay, so I tested various things, and it indeed was the RAM holding me back, I think. I exported the clips separately and saw numbers like 250 it/s with the h264_nvenc codec. If you don't have a GPU(or your CPU is at least faster) I suggest you use that. Either way, make sure your RAM isn't being completely obliterated.

After exporting, I reïmported the video clips:

        allClipsInOrder = [VideoFileClip(vidPath) for vidPath in self.clipFilePaths]
        concat_clip = concatenate_videoclips(allClipsInOrder, method="compose")

        # Put soft background music over the whole video
        background = AudioFileClip("background_music.mp3").volumex(0.1)
        full_background = afx.audio_loop(background, duration=concat_clip.duration)

        final_audio = CompositeAudioClip([concat_clip.audio, full_background])
        self.full_video = concat_clip.set_audio(final_audio)

        del concat_clip
        del final_audio
        del background
        del full_background

In combination with reducing the quality a bit, some extra memory management and this, I managed to cut down the entire process from over an hour to just 7 minutes, so less than 50% of the video length in this case. I ended up exporting with the following settings for both the separate clips and the full video:

clip.write_videofile(f"temp/{random_file_name}.mp4", fps=self.fps, codec='h264_nvenc', verbose=False)
Thomas Smeman
  • 175
  • 11