Zulko / moviepy

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

Create an upgrade to finally get rid of a bug that make the library unusable (at least in NixOs) #1990

Open tobiasBora opened 1 year ago

tobiasBora commented 1 year ago

Expected Behavior

A code as simple as:

from moviepy.editor import *
clip = ColorClip((600, 400), color=(255, 100, 0), duration=2)
clip.write_videofile("test.webm", fps=24)

should work. As shown below, it fails with the version 1.0.3, but not with master, so it might be time to release a new version.

Actual Behavior

It will fail (at least on any recent NixOs, including unstable, that packs latest version of moviepy 1.0.3):

# Check version:
>> from importlib.metadata import version
>> version('moviepy')
1.0.3

>> from moviepy.editor import *
>> clip = ColorClip((600, 400), color=(255, 100, 0), duration=2)
>> clip.write_videofile("test.webm", fps=24)

Moviepy - Building video test.webm.
Moviepy - Writing video test.webm
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [9], in <cell line: 1>()
----> 1 clip.write_videofile("test.webm", fps=24)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/decorators.py:54, in requires_duration(f, clip, *a, **k)
     52     raise ValueError("Attribute 'duration' not set")
     53 else:
---> 54     return f(clip, *a, **k)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/decorators.py:135, in use_clip_fps_by_default(f, clip, *a, **k)
    130 new_a = [fun(arg) if (name=='fps') else arg
    131          for (arg, name) in zip(a, names)]
    132 new_kw = {k: fun(v) if k=='fps' else v
    133          for (k,v) in k.items()}
--> 135 return f(clip, *new_a, **new_kw)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/decorators.py:22, in convert_masks_to_RGB(f, clip, *a, **k)
     20 if clip.ismask:
     21     clip = clip.to_RGB()
---> 22 return f(clip, *a, **k)

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/video/VideoClip.py:300, in VideoClip.write_videofile(self, filename, fps, codec, bitrate, audio, audio_fps, preset, audio_nbytes, audio_codec, audio_bitrate, audio_bufsize, temp_audiofile, rewrite_audio, remove_temp, write_logfile, verbose, threads, ffmpeg_params, logger)
    292 if make_audio:
    293     self.audio.write_audiofile(audiofile, audio_fps,
    294                                audio_nbytes, audio_bufsize,
    295                                audio_codec, bitrate=audio_bitrate,
    296                                write_logfile=write_logfile,
    297                                verbose=verbose,
    298                                logger=logger)
--> 300 ffmpeg_write_video(self, filename, fps, codec,
    301                    bitrate=bitrate,
    302                    preset=preset,
    303                    write_logfile=write_logfile,
    304                    audiofile=audiofile,
    305                    verbose=verbose, threads=threads,
    306                    ffmpeg_params=ffmpeg_params,
    307                    logger=logger)
    309 if remove_temp and make_audio:
    310     if os.path.exists(audiofile):

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/video/io/ffmpeg_writer.py:213, in ffmpeg_write_video(clip, filename, fps, codec, bitrate, preset, withmask, write_logfile, audiofile, verbose, threads, ffmpeg_params, logger)
    211     logfile = None
    212 logger(message='Moviepy - Writing video %s\n' % filename)
--> 213 with FFMPEG_VideoWriter(filename, clip.size, fps, codec = codec,
    214                             preset=preset, bitrate=bitrate, logfile=logfile,
    215                             audiofile=audiofile, threads=threads,
    216                             ffmpeg_params=ffmpeg_params) as writer:
    218     nframes = int(clip.duration*fps)
    220     for t,frame in clip.iter_frames(logger=logger, with_times=True,
    221                                     fps=fps, dtype="uint8"):

File /nix/store/dpnnffs0s30cmkmlpdq35smpav2g8ir5-python3-3.10.9-env/lib/python3.10/site-packages/moviepy/video/io/ffmpeg_writer.py:88, in FFMPEG_VideoWriter.__init__(self, filename, size, fps, codec, audiofile, preset, bitrate, withmask, logfile, threads, ffmpeg_params)
     77 self.ext = self.filename.split(".")[-1]
     79 # order is important
     80 cmd = [
     81     get_setting("FFMPEG_BINARY"),
     82     '-y',
     83     '-loglevel', 'error' if logfile == sp.PIPE else 'info',
     84     '-f', 'rawvideo',
     85     '-vcodec', 'rawvideo',
     86     '-s', '%dx%d' % (size[0], size[1]),
     87     '-pix_fmt', 'rgba' if withmask else 'rgb24',
---> 88     '-r', '%.02f' % fps,
     89     '-an', '-i', '-'
     90 ]
     91 if audiofile is not None:
     92     cmd.extend([
     93         '-i', audiofile,
     94         '-acodec', 'copy'
     95     ])

TypeError: must be real number, not NoneType

However, if I upgrade the source code of moviepy (while maintaining the version of all other packages and libraries), the error is gone.

In NixOs, this can be done, eg. by changing in the derivation:

  src = fetchPypi {
    inherit pname version;
    sha256 = "2884e35d1788077db3ff89e763c5ba7bfddbd7ae9108c9bc809e7ba58fa433f5";
  };

with:

  src = fetchFromGitHub {
    owner = "Zulko";
    repo = pname;
    rev = "b5bb086439cfd0960011a065f229eb7a7b4ebad5";
    sha256 = "sha256-Y+rehn+fLR0id5jAmfOkYHj8mLMJgnMwld7wp5BxmuQ=";
  };

I would happily submit this change online, but I seems cleaner to create first a new version upstream, so that NixOs only follows official versions… especially as no release has been made in the last 3 years!

Steps to Reproduce the Problem

On any system with a recent nix installed, enter into a shell with the appropriate dependencies locally loaded with:

$ nix develop --impure --expr 'let pkgs = (builtins.getFlake "github:NixOs/nixpkgs?rev=75a5ebf473cd60148ba9aec0d219f72e5cf52519").legacyPackages.x86_64-linux; in pkgs.mkShell { buildInputs = [ pkgs.ffmpeg (pkgs.python3.withPackages (ps: with ps; [ ipython moviepy ] )) ]; }'

(not extremely good looking, but at least it’s a one liner that pins precisely the good dependencies, that should be fairly reproducible due to the pure nature of nix, and that will not install or disturb in any way the host system, again due to the pure nature of nix) Then, run:

$ ipython
>> from moviepy.editor import *
>> clip = ColorClip((600, 400), color=(255, 100, 0), duration=2)
>> clip.write_videofile("test.webm", fps=24)

and experience the issue.

Now, to see the fix, exit the shell with Ctrl-D to unload the dependencies, then:

$ nix develop --impure --expr 'let pkgs = (builtins.getFlake "github:NixOs/nixpkgs?rev=75a5ebf473cd60148ba9aec0d219f72e5cf52519").legacyPackages.x86_64-linux; in pkgs.mkShell { buildInputs = [ pkgs.ffmpeg (pkgs.python3.withPackages (ps: with ps; [ ipython (moviepy.overrideAttrs (old: {src = pkgs.fetchFromGitHub { owner = "Zulko"; repo = "moviepy"; rev = "b5bb086439cfd0960011a065f229eb7a7b4ebad5"; sha256 = "sha256-Y+rehn+fLR0id5jAmfOkYHj8mLMJgnMwld7wp5BxmuQ="; };})) ] )) ]; }'

(even less good looking, but at least it is a one-liner that patches moviepy appropriately while not changing anything on the host system) and run again the same ipython commands: it should work.

Specifications

tobiasBora commented 1 year ago

Note that this issue has been reported repeatedly (might be caused when decorator is too recent… but hey in 2023 there is no reason to use a really old version of decorator if master can handle a more recent one), I don’t know why for some people upgrading solves the issue, for others it does not solve anything… at least on NixOs I can’t find any other alternative than upgrading moviepy to master instead of 1.0.3. Some related issues:

linyu0219 commented 11 months ago

https://github.com/Zulko/moviepy/issues/1625#issuecomment-973056577 fixed decorator problem

tobiasBora commented 11 months ago

@linyu0219 this is a hack as my understanding of this command is that it downgrades the version of decorator, which might create conflicts if other libraries require a recent version. Moreover, this does not work on Nix where the version of each package is pinned for maximum reproducibility (and of course Nix packs the latest version of decorator). Since master seems to be compatible with the latest version of decorator, why can't we create a new release?

Alfran007 commented 11 months 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

tobiasBora commented 11 months ago

Have you tried with master? The point of this issue is to create a new release as 1.0.3 is not working while master seems to solve this problem.

pablo-sampaio commented 8 months ago

See my comment and suggestion in Issue #1986 .

keikoro commented 4 months ago

This sounds like a duplicate of #1986, in which case I'd like to close this ticket in favour of the other one. As pointed out above, it contains comments which suggest to update to the latest master. Please check if upgrading fixes the issue.

keikoro commented 4 months ago

Ah, @tobiasBora you yourself said it fixed it for you, can we close this? I'm trying to point all duplicates to the other ticket. Thx.

tobiasBora commented 4 months ago

Well this issue is technically unrelated, I just ask for an official release.

keikoro commented 4 months ago

Well this issue is technically unrelated, I just ask for an official release.

Doesn't this then just translate to... adding noise? New tickets for known issues don't speed things up, they only add (administrative) overhead.