which will call function from the the parent class: VideoClip.write_videofile:
@requires_duration
@use_clip_fps_by_default
@convert_masks_to_RGB
def write_videofile(self, filename, fps=None, codec=None,
bitrate=None, audio=True, audio_fps=44100,
preset="medium",
audio_nbytes=4, audio_codec=None,
audio_bitrate=None, audio_bufsize=2000,
temp_audiofile=None,
rewrite_audio=True, remove_temp=True,
write_logfile=False, verbose=True,
threads=None, ffmpeg_params=None,
logger='bar'):
"""Write the clip to a videofile.
Expected Behavior
Because of the decorator: @use_clip_fps_by_default, even though fps is not passed as an argument to this function, it should be given the value from the attribute clip.fps which is 25 in my case, and it should generate a video with that FPS.
Actual Behavior
However, I got the Type Error saying that fps is in fact Nonetype when passing to ffmepg. Part of the traceback:
File ~/anaconda3/envs/myenv/lib/python3.11/site-packages/moviepy/video/io/ffmpeg_writer.py:86, in FFMPEG_VideoWriter.__init__(self, filename, size, fps, codec, audiofile, preset, bitrate, withmask, logfile, threads, ffmpeg_params)
75 self.ext = self.filename.split(".")[-1]
77 # order is important
78 cmd = [
79 get_setting("FFMPEG_BINARY"),
80 '-y',
81 '-loglevel', 'error' if logfile == sp.PIPE else 'info',
82 '-f', 'rawvideo',
83 '-vcodec', 'rawvideo',
84 '-s', '%dx%d' % (size[0], size[1]),
85 '-pix_fmt', 'rgba' if withmask else 'rgb24',
---> 86 '-r', '%.02f' % fps,
87 '-i', '-', '-an',
88 ]
89 if audiofile is not None:
90 cmd.extend([
91 '-i', audiofile,
92 '-acodec', 'copy'
93 ])
TypeError: must be real number, not NoneType
Upon checking the execution of the decorator use_clip_fps_by_default, I found that in this case fps doesn't show up in neither the names = func_code.co_varnames[1:] or the kwargs, so neither of the lines:
new_a = [fun(arg) if (name=='fps') else arg
for (arg, name) in zip(a, names)]
new_kw = {k: fun(v) if k=='fps' else v
for (k,v) in k.items()}
will call function fun and handle the None type FPS. So I had to hardcode and add the following to the end of the function to make it work:
if 'fps' not in names and ('fps' not in k or k['fps'] is None):
if hasattr(clip, 'fps') and clip.fps is not None:
new_kw['fps'] = clip.fps
else:
raise AttributeError("No 'fps' (frames per second) attribute specified"
" for function %s and the clip has no 'fps' attribute. Either"
" provide e.g. fps=24 in the arguments of the function, or define"
" the clip's fps with `clip.fps=24`" % f.__name__)
I was trying to run in my ipython notebook:
which will call function from the the parent class:
VideoClip.write_videofile
:Expected Behavior
Because of the decorator:
@use_clip_fps_by_default
, even thoughfps
is not passed as an argument to this function, it should be given the value from the attributeclip.fps
which is 25 in my case, and it should generate a video with that FPS.Actual Behavior
However, I got the Type Error saying that fps is in fact Nonetype when passing to ffmepg. Part of the traceback:
Upon checking the execution of the decorator
use_clip_fps_by_default
, I found that in this case fps doesn't show up in neither thenames = func_code.co_varnames[1:]
or thekwargs
, so neither of the lines:will call function
fun
and handle the None type FPS. So I had to hardcode and add the following to the end of the function to make it work:Steps to Reproduce the Problem
Specifications