From 70872c240fe4730b6e35877e73b02b9868a4a336 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:25:14 +0200 Subject: [PATCH 01/17] use list or arguments in extract trimming video where all arguments are known --- .../plugins/publish/extract_otio_trimming_video.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/plugins/publish/extract_otio_trimming_video.py b/openpype/plugins/publish/extract_otio_trimming_video.py index fdb7c4b096a..3e2d39c99cb 100644 --- a/openpype/plugins/publish/extract_otio_trimming_video.py +++ b/openpype/plugins/publish/extract_otio_trimming_video.py @@ -75,7 +75,7 @@ def _ffmpeg_trim_seqment(self, input_file_path, otio_range): output_path = self._get_ffmpeg_output(input_file_path) # start command list - command = ['"{}"'.format(ffmpeg_path)] + command = [ffmpeg_path] video_path = input_file_path frame_start = otio_range.start_time.value @@ -86,17 +86,17 @@ def _ffmpeg_trim_seqment(self, input_file_path, otio_range): # form command for rendering gap files command.extend([ - "-ss {}".format(sec_start), - "-t {}".format(sec_duration), - "-i \"{}\"".format(video_path), - "-c copy", + "-ss", str(sec_start), + "-t", str(sec_duration), + "-i", video_path, + "-c", "copy", output_path ]) # execute self.log.debug("Executing: {}".format(" ".join(command))) output = openpype.api.run_subprocess( - " ".join(command), logger=self.log + command, logger=self.log ) self.log.debug("Output: {}".format(output)) From 1f5f7ac25d67fb54084bd7e5d0b8ee34c50a0531 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:32:02 +0200 Subject: [PATCH 02/17] added function 'split_command_to_list' --- openpype/lib/__init__.py | 3 +++ openpype/lib/execute.py | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index e96f1cc99f1..5725e1c0e33 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -27,6 +27,7 @@ get_pype_execute_args, execute, run_subprocess, + split_command_to_list, CREATE_NO_WINDOW ) from .log import PypeLogger, timeit @@ -171,6 +172,8 @@ "get_pype_execute_args", "execute", "run_subprocess", + "split_command_to_list", + "CREATE_NO_WINDOW", "env_value_to_bool", "get_paths_from_environ", diff --git a/openpype/lib/execute.py b/openpype/lib/execute.py index 12fba23e825..d41db19a788 100644 --- a/openpype/lib/execute.py +++ b/openpype/lib/execute.py @@ -1,11 +1,10 @@ -import logging import os +import shlex import subprocess +import platform from .log import PypeLogger as Logger -log = logging.getLogger(__name__) - # MSDN process creation flag (Windows only) CREATE_NO_WINDOW = 0x08000000 @@ -100,7 +99,9 @@ def run_subprocess(*args, **kwargs): filtered_env = {str(k): str(v) for k, v in env.items()} # Use lib's logger if was not passed with kwargs. - logger = kwargs.pop("logger", log) + logger = kwargs.pop("logger", None) + if logger is None: + logger = Logger.get_logger("run_subprocess") # set overrides kwargs['stdout'] = kwargs.get('stdout', subprocess.PIPE) @@ -138,6 +139,14 @@ def run_subprocess(*args, **kwargs): return full_output +def split_command_to_list(string_command): + """Split string subprocess command to list.""" + posix = True + if platform.system().lower() == "windows": + posix = False + return shlex.split(string_command, posix=posix) + + def get_pype_execute_args(*args): """Arguments to run pype command. From 27d3a954ab0968273fc9da6689a7b097929438c7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:34:40 +0200 Subject: [PATCH 03/17] use split_command_to_list in extract jpeg --- openpype/plugins/publish/extract_jpeg_exr.py | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/openpype/plugins/publish/extract_jpeg_exr.py b/openpype/plugins/publish/extract_jpeg_exr.py index ae691285b5a..464c190762d 100644 --- a/openpype/plugins/publish/extract_jpeg_exr.py +++ b/openpype/plugins/publish/extract_jpeg_exr.py @@ -1,10 +1,16 @@ import os import pyblish.api -import openpype.api -import openpype.lib -from openpype.lib import should_decompress, \ - get_decompress_dir, decompress +from openpype.lib import ( + get_ffmpeg_tool_path, + + run_subprocess, + split_command_to_list, + + should_decompress, + get_decompress_dir, + decompress +) import shutil @@ -85,7 +91,7 @@ def process(self, instance): self.log.info("output {}".format(full_output_path)) - ffmpeg_path = openpype.lib.get_ffmpeg_tool_path("ffmpeg") + ffmpeg_path = get_ffmpeg_tool_path("ffmpeg") ffmpeg_args = self.ffmpeg_args or {} jpeg_items = [] @@ -106,13 +112,14 @@ def process(self, instance): # output file jpeg_items.append("\"{}\"".format(full_output_path)) - subprocess_jpeg = " ".join(jpeg_items) + subprocess_command = " ".join(jpeg_items) + subprocess_args = split_command_to_list(subprocess_command) # run subprocess - self.log.debug("{}".format(subprocess_jpeg)) + self.log.debug("{}".format(subprocess_command)) try: # temporary until oiiotool is supported cross platform - openpype.api.run_subprocess( - subprocess_jpeg, shell=True, logger=self.log + run_subprocess( + subprocess_args, shell=True, logger=self.log ) except RuntimeError as exp: if "Compression" in str(exp): From 1a588ede020d4ff60f08b270b7926849c4c12536 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:40:25 +0200 Subject: [PATCH 04/17] use list where all arguments are known and can be sent as list --- .../publish/extract_otio_audio_tracks.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/openpype/plugins/publish/extract_otio_audio_tracks.py b/openpype/plugins/publish/extract_otio_audio_tracks.py index 2dc822fb0ea..e340a176099 100644 --- a/openpype/plugins/publish/extract_otio_audio_tracks.py +++ b/openpype/plugins/publish/extract_otio_audio_tracks.py @@ -99,16 +99,16 @@ def add_audio_to_instances(self, audio_file, instances): # temp audio file audio_fpath = self.create_temp_file(name) - cmd = " ".join([ - '"{}"'.format(self.ffmpeg_path), - "-ss {}".format(start_sec), - "-t {}".format(duration_sec), - "-i \"{}\"".format(audio_file), + cmd = [ + self.ffmpeg_path, + "-ss", str(start_sec), + "-t", str(duration_sec), + "-i", audio_file, audio_fpath - ]) + ] # run subprocess - self.log.debug("Executing: {}".format(cmd)) + self.log.debug("Executing: {}".format(" ".join(cmd))) openpype.api.run_subprocess( cmd, logger=self.log ) @@ -220,17 +220,17 @@ def create_empty(self, inputs): max_duration_sec = max(end_secs) # create empty cmd - cmd = " ".join([ - '"{}"'.format(self.ffmpeg_path), - "-f lavfi", - "-i anullsrc=channel_layout=stereo:sample_rate=48000", - "-t {}".format(max_duration_sec), - "\"{}\"".format(empty_fpath) - ]) + cmd = [ + self.ffmpeg_path, + "-f", "lavfi", + "-i", "anullsrc=channel_layout=stereo:sample_rate=48000", + "-t", str(max_duration_sec), + empty_fpath + ] # generate empty with ffmpeg # run subprocess - self.log.debug("Executing: {}".format(cmd)) + self.log.debug("Executing: {}".format(" ".join(cmd))) openpype.api.run_subprocess( cmd, logger=self.log From 01bca81ea13c85de0ee1f0e75be45537b0c5a68b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:41:29 +0200 Subject: [PATCH 05/17] use split_command_to_list for audio inputs --- openpype/plugins/publish/extract_otio_audio_tracks.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_otio_audio_tracks.py b/openpype/plugins/publish/extract_otio_audio_tracks.py index e340a176099..3fc5a6740d0 100644 --- a/openpype/plugins/publish/extract_otio_audio_tracks.py +++ b/openpype/plugins/publish/extract_otio_audio_tracks.py @@ -2,7 +2,8 @@ import pyblish import openpype.api from openpype.lib import ( - get_ffmpeg_tool_path + get_ffmpeg_tool_path, + split_command_to_list ) import tempfile import opentimelineio as otio @@ -60,10 +61,13 @@ def process(self, context): cmd += self.create_cmd(audio_inputs) cmd += "\"{}\"".format(audio_temp_fpath) + # Split command to list for subprocess + cmd_list = split_command_to_list(cmd) + # run subprocess self.log.debug("Executing: {}".format(cmd)) openpype.api.run_subprocess( - cmd, logger=self.log + cmd_list, logger=self.log ) # remove empty From 6c0e71a7d7cc45c9afecc7111b8d9c0d7e3c4e94 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:45:13 +0200 Subject: [PATCH 06/17] use list of arguments where are all known --- .../plugins/publish/extract_otio_review.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/openpype/plugins/publish/extract_otio_review.py b/openpype/plugins/publish/extract_otio_review.py index 818903b54bd..ed2ba017d5c 100644 --- a/openpype/plugins/publish/extract_otio_review.py +++ b/openpype/plugins/publish/extract_otio_review.py @@ -312,7 +312,7 @@ def _render_seqment(self, sequence=None, out_frame_start += end_offset # start command list - command = ['"{}"'.format(ffmpeg_path)] + command = [ffmpeg_path] if sequence: input_dir, collection = sequence @@ -324,8 +324,8 @@ def _render_seqment(self, sequence=None, # form command for rendering gap files command.extend([ - "-start_number {}".format(in_frame_start), - "-i \"{}\"".format(input_path) + "-start_number", str(in_frame_start), + "-i", input_path ]) elif video: @@ -334,13 +334,15 @@ def _render_seqment(self, sequence=None, input_fps = otio_range.start_time.rate frame_duration = otio_range.duration.value sec_start = openpype.lib.frames_to_secons(frame_start, input_fps) - sec_duration = openpype.lib.frames_to_secons(frame_duration, input_fps) + sec_duration = openpype.lib.frames_to_secons( + frame_duration, input_fps + ) # form command for rendering gap files command.extend([ - "-ss {}".format(sec_start), - "-t {}".format(sec_duration), - "-i \"{}\"".format(video_path) + "-ss", str(sec_start), + "-t", str(sec_duration), + "-i", video_path ]) elif gap: @@ -349,22 +351,24 @@ def _render_seqment(self, sequence=None, # form command for rendering gap files command.extend([ - "-t {} -r {}".format(sec_duration, self.actual_fps), - "-f lavfi", - "-i color=c=black:s={}x{}".format(self.to_width, - self.to_height), - "-tune stillimage" + "-t", str(sec_duration), + "-r", str(self.actual_fps), + "-f", "lavfi", + "-i", "color=c=black:s={}x{}".format( + self.to_width, self.to_height + ), + "-tune", "stillimage" ]) # add output attributes command.extend([ - "-start_number {}".format(out_frame_start), - "\"{}\"".format(output_path) + "-start_number", str(out_frame_start), + output_path ]) # execute self.log.debug("Executing: {}".format(" ".join(command))) output = openpype.api.run_subprocess( - " ".join(command), logger=self.log + command, logger=self.log ) self.log.debug("Output: {}".format(output)) From bb69545050b949a15b746521f7afe6b10917b12d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:49:24 +0200 Subject: [PATCH 07/17] split arguments using split_command_to_list in extract review slate --- openpype/plugins/publish/extract_review_slate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 2b07d7db74c..ca917f3c3b9 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -197,11 +197,13 @@ def process(self, instance): " ".join(output_args) ] slate_subprcs_cmd = " ".join(slate_args) - + slate_subprocess_args = openpype.lib.split_command_to_list( + slate_subprcs_cmd + ) # run slate generation subprocess self.log.debug("Slate Executing: {}".format(slate_subprcs_cmd)) openpype.api.run_subprocess( - slate_subprcs_cmd, shell=True, logger=self.log + slate_subprocess_args, shell=True, logger=self.log ) # create ffmpeg concat text file path From 85728d5f96260ab944521c761c709bc417fa7e28 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:49:41 +0200 Subject: [PATCH 08/17] use list of arguments directly where are known --- .../plugins/publish/extract_review_slate.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index ca917f3c3b9..38c9b158447 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -223,23 +223,22 @@ def process(self, instance): ]) # concat slate and videos together - conc_input_args = ["-y", "-f concat", "-safe 0"] - conc_input_args.append("-i {}".format(conc_text_path)) - - conc_output_args = ["-c copy"] - conc_output_args.append(output_path) - concat_args = [ ffmpeg_path, - " ".join(conc_input_args), - " ".join(conc_output_args) + "-y", + "-f", "concat", + "-safe", "0", + "-i", conc_text_path, + "-c", "copy", + output_path ] - concat_subprcs_cmd = " ".join(concat_args) # ffmpeg concat subprocess - self.log.debug("Executing concat: {}".format(concat_subprcs_cmd)) + self.log.debug( + "Executing concat: {}".format(" ".join(concat_args)) + ) openpype.api.run_subprocess( - concat_subprcs_cmd, shell=True, logger=self.log + concat_args, shell=True, logger=self.log ) self.log.debug("__ repre[tags]: {}".format(repre["tags"])) From bd3d770acc2f206312bbe0927c31c898f3c354b5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 14:51:51 +0200 Subject: [PATCH 09/17] extract review use split_command_to_list --- openpype/plugins/publish/extract_review.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index 78cbea10be8..6d254d7366a 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -13,6 +13,9 @@ from openpype.lib import ( get_ffmpeg_tool_path, ffprobe_streams, + + split_command_to_list, + should_decompress, get_decompress_dir, decompress @@ -216,12 +219,15 @@ def main_process(self, instance): raise NotImplementedError subprcs_cmd = " ".join(ffmpeg_args) + subprocess_args = split_command_to_list(subprcs_cmd) # run subprocess - self.log.debug("Executing: {}".format(subprcs_cmd)) + self.log.debug( + "Executing: {}".format(" ".join(subprocess_args)) + ) openpype.api.run_subprocess( - subprcs_cmd, shell=True, logger=self.log + subprocess_args, shell=True, logger=self.log ) # delete files added to fill gaps From 08f43824093f6ef7b15e6f5debcd264a5378c452 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:01:21 +0200 Subject: [PATCH 10/17] use args as list where possible --- .../plugins/publish/extract_review.py | 6 +++-- .../publish/extract_trim_video_audio.py | 25 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index b52078fd5f2..1c53c3a2ef9 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -60,7 +60,8 @@ def process(self, instance): # Generate thumbnail. thumbnail_path = os.path.join(staging_dir, "thumbnail.jpg") args = [ - "{}".format(ffmpeg_path), "-y", + ffmpeg_path, + "-y", "-i", output_image_path, "-vf", "scale=300:-1", "-vframes", "1", @@ -78,7 +79,8 @@ def process(self, instance): # Generate mov. mov_path = os.path.join(staging_dir, "review.mov") args = [ - ffmpeg_path, "-y", + ffmpeg_path, + "-y", "-i", output_image_path, "-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2", "-vframes", "1", diff --git a/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py b/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py index 059ac9603c9..4d482825bcb 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py @@ -59,27 +59,30 @@ def process(self, instance): if "trimming" not in fml ] - args = [ - f"\"{ffmpeg_path}\"", + ffmpeg_args = [ + ffmpeg_path, "-ss", str(start / fps), - "-i", f"\"{video_file_path}\"", + "-i", video_file_path, "-t", str(dur / fps) ] if ext in [".mov", ".mp4"]: - args.extend([ + ffmpeg_args.extend([ "-crf", "18", - "-pix_fmt", "yuv420p"]) + "-pix_fmt", "yuv420p" + ]) elif ext in ".wav": - args.extend([ - "-vn -acodec pcm_s16le", - "-ar 48000 -ac 2" + ffmpeg_args.extend([ + "-vn", + "-acodec", "pcm_s16le", + "-ar", "48000", + "-ac", "2" ]) # add output path - args.append(f"\"{clip_trimed_path}\"") + ffmpeg_args.append(clip_trimed_path) - self.log.info(f"Processing: {args}") - ffmpeg_args = " ".join(args) + joined_args = " ".join(ffmpeg_args) + self.log.info(f"Processing: {joined_args}") openpype.api.run_subprocess( ffmpeg_args, shell=True, logger=self.log ) From 58cff296c03deb7fb125d47fe749da63ce8a5de0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:01:45 +0200 Subject: [PATCH 11/17] changed variable name from 'repr' to 'repre' ('repr' builtin function) --- .../plugins/publish/extract_trim_video_audio.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py b/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py index 4d482825bcb..1cbf186a6cc 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/extract_trim_video_audio.py @@ -87,7 +87,7 @@ def process(self, instance): ffmpeg_args, shell=True, logger=self.log ) - repr = { + repre = { "name": ext[1:], "ext": ext[1:], "files": os.path.basename(clip_trimed_path), @@ -100,10 +100,10 @@ def process(self, instance): } if ext in [".mov", ".mp4"]: - repr.update({ + repre.update({ "thumbnail": True, "tags": ["review", "ftrackreview", "delete"]}) - instance.data["representations"].append(repr) + instance.data["representations"].append(repre) self.log.debug(f"Instance data: {pformat(instance.data)}") From 443f79d1d2ae29215c674846ee9f78c6a22585f3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:02:08 +0200 Subject: [PATCH 12/17] log arguments that are going to be executed --- .../plugins/publish/extract_thumbnail.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/standalonepublisher/plugins/publish/extract_thumbnail.py b/openpype/hosts/standalonepublisher/plugins/publish/extract_thumbnail.py index 0792254716e..cdbfe942f0f 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/extract_thumbnail.py @@ -101,11 +101,14 @@ def process(self, instance): jpeg_items.append("\"{}\"".format(full_thumbnail_path)) subprocess_jpeg = " ".join(jpeg_items) + subprocess_args = openpype.lib.split_command_to_list( + subprocess_jpeg + ) # run subprocess - self.log.debug("Executing: {}".format(subprocess_jpeg)) + self.log.debug("Executing: {}".format(" ".join(subprocess_args))) openpype.api.run_subprocess( - subprocess_jpeg, shell=True, logger=self.log + subprocess_args, shell=True, logger=self.log ) # remove thumbnail key from origin repre From 9720dac97b7d82e9b7ce5bae897040a9bec6d298 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:04:08 +0200 Subject: [PATCH 13/17] removed unnecessary formatting --- openpype/hosts/harmony/plugins/publish/extract_render.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/harmony/plugins/publish/extract_render.py b/openpype/hosts/harmony/plugins/publish/extract_render.py index 8374a9427af..827b03443cb 100644 --- a/openpype/hosts/harmony/plugins/publish/extract_render.py +++ b/openpype/hosts/harmony/plugins/publish/extract_render.py @@ -91,7 +91,8 @@ def process(self, instance): thumbnail_path = os.path.join(path, "thumbnail.png") ffmpeg_path = openpype.lib.get_ffmpeg_tool_path("ffmpeg") args = [ - "{}".format(ffmpeg_path), "-y", + ffmpeg_path, + "-y", "-i", os.path.join(path, list(collections[0])[0]), "-vf", "scale=300:-1", "-vframes", "1", From 7f47367fbfc2c3b2656566d9e1c5902c56dc1305 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:12:35 +0200 Subject: [PATCH 14/17] added docstring for split_command_to_list and modified --- openpype/lib/execute.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/openpype/lib/execute.py b/openpype/lib/execute.py index d41db19a788..e93fc3efdd1 100644 --- a/openpype/lib/execute.py +++ b/openpype/lib/execute.py @@ -140,8 +140,25 @@ def run_subprocess(*args, **kwargs): def split_command_to_list(string_command): - """Split string subprocess command to list.""" - posix = True + """Split string subprocess command to list. + + Should be able to split complex subprocess command to separated arguments: + `"C:\\ffmpeg folder\\ffmpeg.exe" -i \"D:\\input.mp4\\" \"D:\\output.mp4\"` + + Should result into list: + `["C:\ffmpeg folder\ffmpeg.exe", "-i", "D:\input.mp4", "D:\output.mp4"]` + + This may be required on few versions of python where subprocess can handle + only list of arguments. + + To be able do that is using `shlex` python module. + + Args: + string_command(str): Full subprocess command. + + Returns: + list: Command separated into individual arguments. + """ if platform.system().lower() == "windows": posix = False return shlex.split(string_command, posix=posix) From 004b2c5a5e78632d686eb345cd42d35883621bdf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:13:36 +0200 Subject: [PATCH 15/17] use posix argument only on windows --- openpype/lib/execute.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/lib/execute.py b/openpype/lib/execute.py index e93fc3efdd1..2dbee4e674b 100644 --- a/openpype/lib/execute.py +++ b/openpype/lib/execute.py @@ -159,9 +159,11 @@ def split_command_to_list(string_command): Returns: list: Command separated into individual arguments. """ + kwargs = {} + # Use 'posix' argument only on windows if platform.system().lower() == "windows": - posix = False - return shlex.split(string_command, posix=posix) + kwargs["posix"] = False + return shlex.split(string_command, **kwargs) def get_pype_execute_args(*args): From 3d9970aa4fef902fff102267b76e77a3f0dc58d3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:57:25 +0200 Subject: [PATCH 16/17] added function 'path_to_subprocess_arg' which decide if path should be wrapped in quotes --- openpype/lib/__init__.py | 2 ++ openpype/lib/execute.py | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 5725e1c0e33..1acd07c0ba8 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -28,6 +28,7 @@ execute, run_subprocess, split_command_to_list, + path_to_subprocess_arg, CREATE_NO_WINDOW ) from .log import PypeLogger, timeit @@ -173,6 +174,7 @@ "execute", "run_subprocess", "split_command_to_list", + "path_to_subprocess_arg", "CREATE_NO_WINDOW", "env_value_to_bool", diff --git a/openpype/lib/execute.py b/openpype/lib/execute.py index 2dbee4e674b..3e5b6d3853f 100644 --- a/openpype/lib/execute.py +++ b/openpype/lib/execute.py @@ -139,6 +139,14 @@ def run_subprocess(*args, **kwargs): return full_output +def path_to_subprocess_arg(path): + """Prepare path for subprocess arguments. + + Returned path can be wrapped with quotes or kept as is. + """ + return subprocess.list2cmdline([path]) + + def split_command_to_list(string_command): """Split string subprocess command to list. @@ -159,6 +167,9 @@ def split_command_to_list(string_command): Returns: list: Command separated into individual arguments. """ + if not string_command: + return [] + kwargs = {} # Use 'posix' argument only on windows if platform.system().lower() == "windows": From 628e9df78467f2992a91e46daa7376fe800f1c01 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 16 Sep 2021 15:58:35 +0200 Subject: [PATCH 17/17] use 'path_to_subprocess_arg' in subprocess paths definitions --- openpype/plugins/publish/extract_jpeg_exr.py | 9 +++++--- .../publish/extract_otio_audio_tracks.py | 13 +++++++---- openpype/plugins/publish/extract_review.py | 13 +++++++---- .../plugins/publish/extract_review_slate.py | 22 ++++++++++++------- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/openpype/plugins/publish/extract_jpeg_exr.py b/openpype/plugins/publish/extract_jpeg_exr.py index 464c190762d..31e58025d59 100644 --- a/openpype/plugins/publish/extract_jpeg_exr.py +++ b/openpype/plugins/publish/extract_jpeg_exr.py @@ -6,6 +6,7 @@ run_subprocess, split_command_to_list, + path_to_subprocess_arg, should_decompress, get_decompress_dir, @@ -95,13 +96,15 @@ def process(self, instance): ffmpeg_args = self.ffmpeg_args or {} jpeg_items = [] - jpeg_items.append("\"{}\"".format(ffmpeg_path)) + jpeg_items.append(path_to_subprocess_arg(ffmpeg_path)) # override file if already exists jpeg_items.append("-y") # use same input args like with mov jpeg_items.extend(ffmpeg_args.get("input") or []) # input file - jpeg_items.append("-i \"{}\"".format(full_input_path)) + jpeg_items.append("-i {}".format( + path_to_subprocess_arg(full_input_path) + )) # output arguments from presets jpeg_items.extend(ffmpeg_args.get("output") or []) @@ -110,7 +113,7 @@ def process(self, instance): jpeg_items.append("-vframes 1") # output file - jpeg_items.append("\"{}\"".format(full_output_path)) + jpeg_items.append(path_to_subprocess_arg(full_output_path)) subprocess_command = " ".join(jpeg_items) subprocess_args = split_command_to_list(subprocess_command) diff --git a/openpype/plugins/publish/extract_otio_audio_tracks.py b/openpype/plugins/publish/extract_otio_audio_tracks.py index 3fc5a6740d0..2cdc072ffd8 100644 --- a/openpype/plugins/publish/extract_otio_audio_tracks.py +++ b/openpype/plugins/publish/extract_otio_audio_tracks.py @@ -3,7 +3,8 @@ import openpype.api from openpype.lib import ( get_ffmpeg_tool_path, - split_command_to_list + split_command_to_list, + path_to_subprocess_arg ) import tempfile import opentimelineio as otio @@ -57,9 +58,9 @@ def process(self, context): audio_inputs.insert(0, empty) # create cmd - cmd = '"{}"'.format(self.ffmpeg_path) + " " + cmd = path_to_subprocess_arg(self.ffmpeg_path) + " " cmd += self.create_cmd(audio_inputs) - cmd += "\"{}\"".format(audio_temp_fpath) + cmd += path_to_subprocess_arg(audio_temp_fpath) # Split command to list for subprocess cmd_list = split_command_to_list(cmd) @@ -265,10 +266,14 @@ def create_cmd(self, inputs): for index, input in enumerate(inputs): input_format = input.copy() input_format.update({"i": index}) + input_format["mediaPath"] = path_to_subprocess_arg( + input_format["mediaPath"] + ) + _inputs += ( "-ss {startSec} " "-t {durationSec} " - "-i \"{mediaPath}\" " + "-i {mediaPath} " ).format(**input_format) _filters += "[{i}]adelay={delayMilSec}:all=1[r{i}]; ".format( diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index 6d254d7366a..ecc49a8da6a 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -15,6 +15,7 @@ ffprobe_streams, split_command_to_list, + path_to_subprocess_arg, should_decompress, get_decompress_dir, @@ -486,7 +487,9 @@ def _ffmpeg_arguments(self, output_def, instance, new_repre, temp_data): # Add video/image input path ffmpeg_input_args.append( - "-i \"{}\"".format(temp_data["full_input_path"]) + "-i {}".format( + path_to_subprocess_arg(temp_data["full_input_path"]) + ) ) # Add audio arguments if there are any. Skipped when output are images. @@ -544,7 +547,7 @@ def _ffmpeg_arguments(self, output_def, instance, new_repre, temp_data): # NOTE This must be latest added item to output arguments. ffmpeg_output_args.append( - "\"{}\"".format(temp_data["full_output_path"]) + path_to_subprocess_arg(temp_data["full_output_path"]) ) return self.ffmpeg_full_args( @@ -613,7 +616,7 @@ def ffmpeg_full_args( audio_filters.append(arg) all_args = [] - all_args.append("\"{}\"".format(self.ffmpeg_path)) + all_args.append(path_to_subprocess_arg(self.ffmpeg_path)) all_args.extend(input_args) if video_filters: all_args.append("-filter:v") @@ -860,7 +863,9 @@ def audio_args(self, instance, temp_data, duration_seconds): audio_in_args.append("-to {:0.10f}".format(audio_duration)) # Add audio input path - audio_in_args.append("-i \"{}\"".format(audio["filename"])) + audio_in_args.append("-i {}".format( + path_to_subprocess_arg(audio["filename"]) + )) # NOTE: These were changed from input to output arguments. # NOTE: value in "-ac" was hardcoded to 2, changed to audio inputs len. diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 38c9b158447..4d26fd1ebc1 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -117,11 +117,13 @@ def process(self, instance): input_args.extend(repre["_profile"].get('input', [])) else: input_args.extend(repre["outputDef"].get('input', [])) - input_args.append("-loop 1 -i {}".format(slate_path)) + input_args.append("-loop 1 -i {}".format( + openpype.lib.path_to_subprocess_arg(slate_path) + )) input_args.extend([ "-r {}".format(fps), - "-t 0.04"] - ) + "-t 0.04" + ]) if use_legacy_code: codec_args = repre["_profile"].get('codec', []) @@ -188,20 +190,24 @@ def process(self, instance): output_args.append("-y") slate_v_path = slate_path.replace(".png", ext) - output_args.append(slate_v_path) + output_args.append( + openpype.lib.path_to_subprocess_arg(slate_v_path) + ) _remove_at_end.append(slate_v_path) slate_args = [ - "\"{}\"".format(ffmpeg_path), + openpype.lib.path_to_subprocess_arg(ffmpeg_path), " ".join(input_args), " ".join(output_args) ] - slate_subprcs_cmd = " ".join(slate_args) slate_subprocess_args = openpype.lib.split_command_to_list( - slate_subprcs_cmd + " ".join(slate_args) ) + # run slate generation subprocess - self.log.debug("Slate Executing: {}".format(slate_subprcs_cmd)) + self.log.debug( + "Slate Executing: {}".format(" ".join(slate_subprocess_args)) + ) openpype.api.run_subprocess( slate_subprocess_args, shell=True, logger=self.log )