diff --git a/moviepy/audio/io/ffmpeg_audiowriter.py b/moviepy/audio/io/ffmpeg_audiowriter.py index 409f4d1c6..a5c69288c 100644 --- a/moviepy/audio/io/ffmpeg_audiowriter.py +++ b/moviepy/audio/io/ffmpeg_audiowriter.py @@ -1,10 +1,10 @@ -import os import subprocess as sp import proglog from moviepy.config import FFMPEG_BINARY from moviepy.decorators import requires_duration +from moviepy.tools import cross_platform_popen_params class FFMPEG_AudioWriter: @@ -82,10 +82,9 @@ def __init__( cmd.extend(ffmpeg_params) cmd.extend([filename]) - popen_params = {"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE} - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + {"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE} + ) self.proc = sp.Popen(cmd, **popen_params) diff --git a/moviepy/audio/io/readers.py b/moviepy/audio/io/readers.py index 1c6fb3e97..4542e0979 100644 --- a/moviepy/audio/io/readers.py +++ b/moviepy/audio/io/readers.py @@ -1,4 +1,3 @@ -import os import subprocess as sp import warnings @@ -6,6 +5,7 @@ from moviepy.config import FFMPEG_BINARY from moviepy.video.io.ffmpeg_reader import ffmpeg_parse_infos +from moviepy.tools import cross_platform_popen_params class FFMPEG_AudioReader: @@ -111,15 +111,14 @@ def initialize(self, start_time=0): ] ) - popen_params = { - "bufsize": self.buffersize, - "stdout": sp.PIPE, - "stderr": sp.PIPE, - "stdin": sp.DEVNULL, - } - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + { + "bufsize": self.buffersize, + "stdout": sp.PIPE, + "stderr": sp.PIPE, + "stdin": sp.DEVNULL, + } + ) self.proc = sp.Popen(cmd, **popen_params) diff --git a/moviepy/config.py b/moviepy/config.py index 6da1fb375..186cd0920 100644 --- a/moviepy/config.py +++ b/moviepy/config.py @@ -2,6 +2,8 @@ from pathlib import Path import subprocess as sp +from moviepy.tools import cross_platform_popen_params + if os.name == "nt": import winreg as wr @@ -20,13 +22,9 @@ def try_cmd(cmd): try: - popen_params = {"stdout": sp.PIPE, "stderr": sp.PIPE, "stdin": sp.DEVNULL} - - # This was added so that no extra unwanted window opens on windows - # when the child process is created - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 - + popen_params = cross_platform_popen_params( + {"stdout": sp.PIPE, "stderr": sp.PIPE, "stdin": sp.DEVNULL} + ) proc = sp.Popen(cmd, **popen_params) proc.communicate() except Exception as err: diff --git a/moviepy/tools.py b/moviepy/tools.py index 36c7f12ca..15261f0fe 100644 --- a/moviepy/tools.py +++ b/moviepy/tools.py @@ -8,6 +8,19 @@ import proglog +def cross_platform_popen_params(popen_params): + """Wrap with this function a dictionary of ``subprocess.Popen`` kwargs and + will be ready to work without unexpected behaviours in any platform. + Currently, the implementation will add to them: + + - ``creationflags=0x08000000``: no extra unwanted window opens on Windows + when the child process is created. Only added on Windows. + """ + if os.name == "nt": + popen_params["creationflags"] = 0x08000000 + return popen_params + + def subprocess_call(cmd, logger="bar"): """Executes the given subprocess command. @@ -16,10 +29,9 @@ def subprocess_call(cmd, logger="bar"): logger = proglog.default_bar_logger(logger) logger(message="Moviepy - Running:\n>>> " + " ".join(cmd)) - popen_params = {"stdout": sp.DEVNULL, "stderr": sp.PIPE, "stdin": sp.DEVNULL} - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + {"stdout": sp.DEVNULL, "stderr": sp.PIPE, "stdin": sp.DEVNULL} + ) proc = sp.Popen(cmd, **popen_params) diff --git a/moviepy/video/VideoClip.py b/moviepy/video/VideoClip.py index b1ba574d4..46334b388 100644 --- a/moviepy/video/VideoClip.py +++ b/moviepy/video/VideoClip.py @@ -24,7 +24,12 @@ requires_duration, use_clip_fps_by_default, ) -from moviepy.tools import extensions_dict, find_extension, subprocess_call +from moviepy.tools import ( + cross_platform_popen_params, + extensions_dict, + find_extension, + subprocess_call, +) from moviepy.video.io.ffmpeg_writer import ffmpeg_write_video from moviepy.video.io.gif_writers import ( write_gif, @@ -1327,10 +1332,9 @@ def list(arg): """Returns a list of all valid entries for the ``font`` or ``color`` argument of ``TextClip``""" - popen_params = {"stdout": sp.PIPE, "stderr": sp.DEVNULL, "stdin": sp.DEVNULL} - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + {"stdout": sp.PIPE, "stderr": sp.DEVNULL, "stdin": sp.DEVNULL} + ) process = sp.Popen( [IMAGEMAGICK_BINARY, "-list", arg], encoding="utf-8", **popen_params diff --git a/moviepy/video/io/ffmpeg_reader.py b/moviepy/video/io/ffmpeg_reader.py index f66529df0..967d66433 100644 --- a/moviepy/video/io/ffmpeg_reader.py +++ b/moviepy/video/io/ffmpeg_reader.py @@ -3,7 +3,6 @@ using ffmpeg. It is quite ugly, as there are many pitfalls to avoid """ -import os import re import subprocess as sp import warnings @@ -11,7 +10,7 @@ import numpy as np from moviepy.config import FFMPEG_BINARY # ffmpeg, ffmpeg.exe, etc... -from moviepy.tools import convert_to_seconds +from moviepy.tools import convert_to_seconds, cross_platform_popen_params class FFMPEG_VideoReader: @@ -108,15 +107,14 @@ def initialize(self, start_time=0): "-", ] ) - popen_params = { - "bufsize": self.bufsize, - "stdout": sp.PIPE, - "stderr": sp.PIPE, - "stdin": sp.DEVNULL, - } - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + { + "bufsize": self.bufsize, + "stdout": sp.PIPE, + "stderr": sp.PIPE, + "stdin": sp.DEVNULL, + } + ) self.proc = sp.Popen(cmd, **popen_params) # self.pos represents the (0-indexed) index of the frame that is next in line @@ -301,15 +299,14 @@ def ffmpeg_parse_infos( if decode_file: cmd.extend(["-f", "null", "-"]) - popen_params = { - "bufsize": 10 ** 5, - "stdout": sp.PIPE, - "stderr": sp.PIPE, - "stdin": sp.DEVNULL, - } - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + { + "bufsize": 10 ** 5, + "stdout": sp.PIPE, + "stderr": sp.PIPE, + "stdin": sp.DEVNULL, + } + ) proc = sp.Popen(cmd, **popen_params) (output, error) = proc.communicate() diff --git a/moviepy/video/io/ffmpeg_writer.py b/moviepy/video/io/ffmpeg_writer.py index 6b1e46927..090b4d67a 100644 --- a/moviepy/video/io/ffmpeg_writer.py +++ b/moviepy/video/io/ffmpeg_writer.py @@ -3,13 +3,13 @@ out of VideoClips """ -import os import subprocess as sp import numpy as np from proglog import proglog from moviepy.config import FFMPEG_BINARY +from moviepy.tools import cross_platform_popen_params class FFMPEG_VideoWriter: @@ -128,12 +128,9 @@ def __init__( cmd.extend(["-pix_fmt", "yuv420p"]) cmd.extend([filename]) - popen_params = {"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE} - - # This was added so that no extra unwanted window opens on windows - # when the child process is created - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 # CREATE_NO_WINDOW + popen_params = cross_platform_popen_params( + {"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE} + ) self.proc = sp.Popen(cmd, **popen_params) @@ -297,10 +294,9 @@ def ffmpeg_write_image(filename, image, logfile=False, pixel_format=None): else: log_file = sp.PIPE - popen_params = {"stdout": sp.DEVNULL, "stderr": log_file, "stdin": sp.PIPE} - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + {"stdout": sp.DEVNULL, "stderr": log_file, "stdin": sp.PIPE} + ) proc = sp.Popen(cmd, **popen_params) out, err = proc.communicate(image.tostring()) diff --git a/moviepy/video/io/gif_writers.py b/moviepy/video/io/gif_writers.py index dc4896b1c..9c5300944 100644 --- a/moviepy/video/io/gif_writers.py +++ b/moviepy/video/io/gif_writers.py @@ -6,7 +6,7 @@ from moviepy.config import FFMPEG_BINARY, IMAGEMAGICK_BINARY from moviepy.decorators import requires_duration, use_clip_fps_by_default -from moviepy.tools import subprocess_call +from moviepy.tools import cross_platform_popen_params, subprocess_call try: import imageio @@ -238,10 +238,9 @@ def write_gif( "-", ] - popen_params = {"stdout": sp.DEVNULL, "stderr": sp.DEVNULL, "stdin": sp.DEVNULL} - - if os.name == "nt": - popen_params["creationflags"] = 0x08000000 + popen_params = cross_platform_popen_params( + {"stdout": sp.DEVNULL, "stderr": sp.DEVNULL, "stdin": sp.DEVNULL} + ) if program == "ffmpeg": popen_params["stdin"] = sp.PIPE