moviepy icon indicating copy to clipboard operation
moviepy copied to clipboard

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

Open Gammer0909 opened this issue 8 months ago • 0 comments

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 :)

Gammer0909 avatar Jun 08 '24 18:06 Gammer0909