Zulko / moviepy

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

write_videofile error #1625

Open rushkii opened 3 years ago

rushkii commented 3 years ago
class Editor:
    _start = 8.50

    def __init__(self, chara_name, elemental, star=5, picture=None) -> None:
        self.chara_name = chara_name
        self.elemental = elemental
        self.picture = picture
        self.star = star
        self._video = VideoFileClip("5starwish-single_1.mp4")
        self._compos = []

    def set_chara(self, picture=None):
        self._compos.append((
            ImageSequenceClip([picture or self.picture], fps=1)
            .set_position(('center','center'))
            .set_start(6.50)
            .set_duration((self._video.duration-6.50))
        ))
        return True

    def set_element(self, element:str=None):
        elemlist = ['pyro', 'cryo', 'geo', 'hydro', 'electro', 'anemo']
        if not element:
            element = self.elemental
        if element not in elemlist:
            element = random.choice(elemlist)
        self._compos.append((
            ImageSequenceClip([f'/app/assets/images/elemental/{element.lower()}.png'], fps=1)
            .resize(width=150)
            .set_position((80.0, 530.0))
            .fadein(0.2)
            .set_start(self._start-1)
            .set_duration((self._video.duration-self._start)+1)
        ))
        return True

    def set_star(self, count:int=None):
        if not count:
            count = self.star
        elif count >= 1 and count <= 5:
            count = count
        else:
            count = 5
        starsec = 9.0
        x,y = (190.0, 665.0)
        for _ in range(count):
            self._compos.append((
                ImageSequenceClip(['/app/assets/images/star.png'], fps=1)
                .resize(width=30)
                .set_position((x,y))
                .fadein(0.1)
                .set_start(starsec-1)
                .set_duration((self._video.duration-starsec)+1)
            ))
            starsec += 0.2
            x += 38.0
        return True

    def set_text(self, chara_name=None):
        self._compos.append((
            TextClip(chara_name or self.chara_name, font="Genshin-Impact", color='white', fontsize=50)
            .set_position((200, 600.0))
            .fadein(0.2)
            .set_start(self._start-1)
            .set_duration((self._video.duration-self._start)+1)
        ))

    def __create(self):
        self._compos.append(self._video)
        self.set_chara()
        self.set_element()
        self.set_star()
        self.set_text()
        return True

    @pool.run_in_thread
    def render_save(self, path, fps=30):
        created = self.__create()
        if created:
            result = CompositeVideoClip(self._compos)
            result.write_videofile(path, fps=fps)
            return path
        else:
            raise Exception('Failed to render, try again.')

wish = Editor("MyName", elemental="pyro", picture="PicturePath")
result = await wish.render_save("test_edited.mp4", fps=30)
print(result) #test_edited.mp4

-->

Expected Behavior

Successfully rendering and save it.

Actual Behavior

Moviepy - Building video test_wish.mp4.
MoviePy - Writing audio in test_wishTEMP_MPY_wvf_snd.mp3
MoviePy - Done.
Moviepy - Writing video test_wish.mp4

Traceback (most recent call last):
  File "main.py", line 73, in execute_py
    ret = await func(_, msg)
  File "", line 9, in func
  File "/app/core/pool.py", line 30, in wrapper
    return await loop.run_in_executor(_EXECUTOR, partial(func, *args, **kwargs))
  File "/app/.heroku/python/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/app/core/wish.py", line 85, in render_save
    result.write_videofile(path, fps=fps)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 54, in requires_duration
    return f(clip, *a, **k)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 135, in use_clip_fps_by_default
    return f(clip, *new_a, **new_kw)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 22, in convert_masks_to_RGB
    return f(clip, *a, **k)
  File "/app/moviepy/video/VideoClip.py", line 307, in write_videofile
    logger=logger)
  File "/app/moviepy/video/io/ffmpeg_writer.py", line 216, in ffmpeg_write_video
    ffmpeg_params=ffmpeg_params) as writer:
  File "/app/moviepy/video/io/ffmpeg_writer.py", line 88, in __init__
    '-r', '%.02f' % fps,
TypeError: must be real number, not NoneType

Specifications

karamo-aws commented 3 years ago

@rushkii it seems like you're writing an empty video?

In the constructor: self._compos = []

And in render: result = CompositeVideoClip(self._compos)

rushkii commented 3 years ago

@rushkii it seems like you're writing an empty video?

In the constructor: self._compos = []

And in render: result = CompositeVideoClip(self._compos)

Uh-- Sorry, I was given incomplete code before, I've edit it you can see it again. The problem is in FPS, the error says:

Traceback (most recent call last):
  File "main.py", line 73, in execute_py
    ret = await func(_, msg)
  File "", line 9, in func
  File "/app/core/pool.py", line 30, in wrapper
    return await loop.run_in_executor(_EXECUTOR, partial(func, *args, **kwargs))
  File "/app/.heroku/python/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/app/core/wish.py", line 85, in render_save
    result.write_videofile(path, fps=fps)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 54, in requires_duration
    return f(clip, *a, **k)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 135, in use_clip_fps_by_default
    return f(clip, *new_a, **new_kw)
  File "/app/.heroku/python/lib/python3.7/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/app/moviepy/decorators.py", line 22, in convert_masks_to_RGB
    return f(clip, *a, **k)
  File "/app/moviepy/video/VideoClip.py", line 307, in write_videofile
    logger=logger)
  File "/app/moviepy/video/io/ffmpeg_writer.py", line 216, in ffmpeg_write_video
    ffmpeg_params=ffmpeg_params) as writer:
  File "/app/moviepy/video/io/ffmpeg_writer.py", line 88, in __init__
    '-r', '%.02f' % fps,
TypeError: must be real number, not NoneType
karamo-aws commented 3 years ago

It is hard to see without the full code, but it seems your problem is here: File "/app/core/wish.py", line 85, in render_save result.write_videofile(path, fps=fps)

In that line, your fps variable is not set to a number. You can print it before, to verify, and then you need to trace to figure out why it is not set.

To test, you can replace fps=fps with fps=30, and check the rest of your code works ...

rushkii commented 3 years ago

It is hard to see without the full code, but it seems your problem is here: File "/app/core/wish.py", line 85, in render_save result.write_videofile(path, fps=fps)

In that line, your fps variable is not set to a number. You can print it before, to verify, and then you need to trace to figure out why it is not set.

To test, you can replace fps=fps with fps=30, and check the rest of your code works ...

This is my full code https://pastebin.com/Bp81V3uv, I run a Telegram bot in Heroku, but it return an error like that, I've already tested in my local computer (Windows 10) it really works actually. I don't know what's the problem.

ViniciusDantz commented 3 years ago

Hi, I think the problem might be in the decorator moviepy.decorators.use_clip_fps_by_default. I put it as the last decorator of the VideoClip.write_videofile method and now it looks like it worked. I believe the problem was due to the func_code.co_varnames[1:] inside the decorator, this will return the main method arguments. Therefore, the main method of use_clip_fps_by_default has to be write_videofile and not convert_masks_to_RGB or anything else. So the VideoClip.write_videofile method signature should look like this:

@requires_duration
@convert_masks_to_RGB
@use_clip_fps_by_default
def write_videofile(self, filename, fps=None, codec=None,
    ...
smidm commented 2 years ago

This happens when moviepy and decorator modules are not compatible (e.g. after the decorator module was upgraded to the last version).

This should solve the issue:

pip uninstall moviepy decorator
pip install moviepy
Alfran007 commented 1 year ago

This does not resolve the mentioned issue, after uninstalling decorator and installing moviepy, I get Successfully installed decorator-4.4.2 moviepy-1.0.3. However same error occurs when performing the before mentioned. Python : 3.10

keikoro commented 8 months ago

Is the decorator issue separate from what #1986 is about? Or does upgrading to the latest changes in the repo, as suggested over there, fix this issue as well? If so, I'd like to close it as duplicate of the other one.