Zulko / moviepy

Video editing with Python
https://zulko.github.io/moviepy/
MIT License
12.07k stars 1.51k forks source link

Getting `AttributeError: 'NoneType' object has no attribute 'get_frame'` when trying to save a `CompositeVideoClip` #2196

Open Gammer0909 opened 3 weeks ago

Gammer0909 commented 3 weeks ago

I'm building a quick script to make some small 9:16 videos automatically from some pre-gathered clips. However, when I try to add multiple TextClips like this stackoverflow post. This should just create the video, however I'm getting this traceback at the write_videofile():

Traceback (most recent call last):
  File "/workspaces/AutoTube/src/main.py", line 19, in <module>
    main()
  File "/workspaces/AutoTube/src/main.py", line 12, in main
    create_video(True)
  File "/workspaces/AutoTube/src/autovideo/__init__.py", line 14, in create_video
    vid = _create_fact_video()
  File "/workspaces/AutoTube/src/autovideo/__init__.py", line 69, in _create_fact_video
    final.write_videofile('./Output/fact_video.mp4')
  File "<decorator-gen-55>", line 2, in write_videofile
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 54, in requires_duration
    return f(clip, *a, **k)
  File "<decorator-gen-54>", line 2, in write_videofile
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 135, in use_clip_fps_by_default
    return f(clip, *new_a, **new_kw)
  File "<decorator-gen-53>", line 2, in write_videofile
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 22, in convert_masks_to_RGB
    return f(clip, *a, **k)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/VideoClip.py", line 300, in write_videofile
    ffmpeg_write_video(self, filename, fps, codec,
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/io/ffmpeg_writer.py", line 220, in ffmpeg_write_video
    for t,frame in clip.iter_frames(logger=logger, with_times=True,
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 472, in iter_frames
    frame = self.get_frame(t)
  File "<decorator-gen-11>", line 2, in get_frame
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 89, in wrapper
    return f(*new_a, **new_kw)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 93, in get_frame
    return self.make_frame(t)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/compositing/CompositeVideoClip.py", line 111, in make_frame
    f = c.blit_on(f, t)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/VideoClip.py", line 527, in blit_on
    img = self.get_frame(ct)
  File "<decorator-gen-11>", line 2, in get_frame
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 89, in wrapper
    return f(*new_a, **new_kw)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 93, in get_frame
    return self.make_frame(t)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 136, in <lambda>
    newclip = self.set_make_frame(lambda t: fun(self.get_frame, t))
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/VideoClip.py", line 490, in <lambda>
    return self.fl(lambda gf, t: image_func(gf(t)), apply_to)
  File "<decorator-gen-11>", line 2, in get_frame
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 89, in wrapper
    return f(*new_a, **new_kw)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 93, in get_frame
    return self.make_frame(t)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 136, in <lambda>
    newclip = self.set_make_frame(lambda t: fun(self.get_frame, t))
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 187, in <lambda>
    return self.fl(lambda gf, t: gf(t_func(t)), apply_to,
  File "<decorator-gen-11>", line 2, in get_frame
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/decorators.py", line 89, in wrapper
    return f(*new_a, **new_kw)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/Clip.py", line 93, in get_frame
    return self.make_frame(t)
  File "/home/codespace/.python/current/lib/python3.10/site-packages/moviepy/video/io/VideoFileClip.py", line 113, in <lambda>
    self.make_frame = lambda t: self.reader.get_frame(t)
AttributeError: 'NoneType' object has no attribute 'get_frame'

As you can see from the traceback, somewhere I'm getting a None clip?

Here's the function (including my print debugs)

def _create_fact_video() -> str:
    # First, create the clip
    with _get_clip(f'./Assets/gameplay.mp4') as clip:
        print('Randomized Clip, editing...')
        fact = _get_random_fact()
        print(f'Got random fact!\nFact for the video is \"{fact}\"')
        # Create the tts file
        print('Creating audio...')
        tts_file = _get_tts(fact)
        print(f'Audio created successfully at {tts_file}')
        # Create a TextClip of the fact, for the duration of the tts file
        print('Creating text...')
        text = mp.TextClip(fact, fontsize=24, color='white', bg_color='black')
        # First, the intro
        intro_text = mp.TextClip('Interesting Fact of the Day', fontsize=24, color='white', bg_color='black')
        # Next, the ad
        ad_text = mp.TextClip('Ad', fontsize=24, color='white', bg_color='black')
        print('Text created successfully')
        print('Editing audio...')
        # Get the duration of the mp3 file, at ./Output/output.mp3
        audio = mp.AudioFileClip(tts_file)
        # Get the ending ad at ./Assets/ad.mp3
        ad = mp.AudioFileClip('./Assets/ad.mp3')
        # Get the Intro at Assets/factOpening.mp3
        intro = mp.AudioFileClip('./Assets/factOpening.mp3')

        # Set each textclip duration to the corresponding audio
        intro_text = intro_text.set_duration(intro.duration)
        text = text.set_duration(audio.duration)
        ad_text = ad_text.set_duration(ad.duration)
        print('Audio accessed, editing...')
        # Create the final audio
        final_audio = mp.concatenate_audioclips([intro, audio, ad])
        print('Audio edited successfully')
        print('Cutting final video together...')
        clip.set_audio(final_audio)
        final = mp.CompositeVideoClip([clip, intro_text, text, ad_text])
        final = final.set_audio(final_audio)
        final = final.set_duration(audio.duration + intro.duration + ad.duration)
        print('Video cut together successfully')
        print('Writing video...')
        # Save the video
        final.write_videofile('./Output/fact_video.mp4')
    print('Video written successfully at ./Output/fact_video.mp4')
    return './Output/fact_video.mp4'

(Side note: It shouldn't be in the _get_clip() function, however I'll provide that If I need to)

Is there anything I'm doing wrong?

thanks :)