From 62b3f852f1d65286a650ac37fc0f8d479436d440 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 11 Feb 2020 14:01:56 +0100 Subject: [PATCH 1/6] use `get_path_to_ffmpeg` which checks if any of filled ffmpeg paths in FFMPEG_PATH exists --- pype/lib.py | 9 +++++++++ pype/plugins/global/publish/extract_jpeg.py | 3 ++- pype/plugins/global/publish/extract_review.py | 5 ++--- pype/plugins/global/publish/extract_review_slate.py | 3 ++- pype/plugins/global/publish/validate_ffmpeg_installed.py | 6 ++++-- .../standalonepublisher/publish/extract_review.py | 3 ++- .../standalonepublisher/publish/extract_thumbnail.py | 3 ++- pype/scripts/otio_burnin.py | 6 +++--- pype/standalonepublish/widgets/widget_drop_frame.py | 3 ++- 9 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index f26395d930..9cde3bd3af 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -13,6 +13,15 @@ import avalon log = logging.getLogger(__name__) +def get_path_to_ffmpeg(): + paths = os.environ.get("FFMPEG_PATH") or "" + path_items = paths.split(os.pathsep) + for item in path_items: + item = os.path.normpath(item) + if os.path.exists(item): + return item + return "" + # Special naming case for subprocess since its a built-in method. def _subprocess(*args, **kwargs): """Convenience method for getting output errors for subprocess.""" diff --git a/pype/plugins/global/publish/extract_jpeg.py b/pype/plugins/global/publish/extract_jpeg.py index 4978649ba2..6a0d7905b0 100644 --- a/pype/plugins/global/publish/extract_jpeg.py +++ b/pype/plugins/global/publish/extract_jpeg.py @@ -3,6 +3,7 @@ import os import pyblish.api import clique import pype.api +import pype.lib class ExtractJpegEXR(pyblish.api.InstancePlugin): @@ -67,7 +68,7 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin): jpeg_items = [] jpeg_items.append( - os.path.join(os.environ.get("FFMPEG_PATH"), "ffmpeg")) + os.path.join(pype.lib.get_path_to_ffmpeg(), "ffmpeg")) # override file if already exists jpeg_items.append("-y") # use same input args like with mov diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 2e79d86c38..5895a8c423 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -313,9 +313,8 @@ class ExtractReview(pyblish.api.InstancePlugin): mov_args = [ os.path.join( - os.environ.get( - "FFMPEG_PATH", - ""), "ffmpeg"), + pype.lib.get_path_to_ffmpeg(), "ffmpeg" + ), " ".join(input_args), " ".join(output_args) ] diff --git a/pype/plugins/global/publish/extract_review_slate.py b/pype/plugins/global/publish/extract_review_slate.py index 9a720b77a9..5d4990a027 100644 --- a/pype/plugins/global/publish/extract_review_slate.py +++ b/pype/plugins/global/publish/extract_review_slate.py @@ -1,5 +1,6 @@ import os import pype.api +import pype.lib import pyblish @@ -21,7 +22,7 @@ class ExtractReviewSlate(pype.api.Extractor): suffix = "_slate" slate_path = inst_data.get("slateFrame") - ffmpeg_path = os.path.join(os.environ.get("FFMPEG_PATH", ""), "ffmpeg") + ffmpeg_path = os.path.join(pype.lib.get_path_to_ffmpeg(), "ffmpeg") to_width = 1920 to_height = 1080 diff --git a/pype/plugins/global/publish/validate_ffmpeg_installed.py b/pype/plugins/global/publish/validate_ffmpeg_installed.py index df7c330e95..643e0f1821 100644 --- a/pype/plugins/global/publish/validate_ffmpeg_installed.py +++ b/pype/plugins/global/publish/validate_ffmpeg_installed.py @@ -1,6 +1,7 @@ import pyblish.api import os import subprocess +import pype.lib try: import os.errno as errno except ImportError: @@ -28,9 +29,10 @@ class ValidateFfmpegInstallef(pyblish.api.Validator): def process(self, instance): self.log.info("ffmpeg path: `{}`".format( - os.environ.get("FFMPEG_PATH", ""))) + pype.lib.get_path_to_ffmpeg() + )) if self.is_tool( os.path.join( - os.environ.get("FFMPEG_PATH", ""), "ffmpeg")) is False: + pype.lib.get_path_to_ffmpeg(), "ffmpeg")) is False: self.log.error("ffmpeg not found in PATH") raise RuntimeError('ffmpeg not installed.') diff --git a/pype/plugins/standalonepublisher/publish/extract_review.py b/pype/plugins/standalonepublisher/publish/extract_review.py index f06d9bcde0..29e1fcaac0 100644 --- a/pype/plugins/standalonepublisher/publish/extract_review.py +++ b/pype/plugins/standalonepublisher/publish/extract_review.py @@ -4,6 +4,7 @@ import tempfile import pyblish.api import clique import pype.api +import pype.lib class ExtractReviewSP(pyblish.api.InstancePlugin): @@ -148,7 +149,7 @@ class ExtractReviewSP(pyblish.api.InstancePlugin): # output filename output_args.append(full_output_path) - ffmpeg_path = os.getenv("FFMPEG_PATH", "") + ffmpeg_path = pype.lib.get_path_to_ffmpeg() if ffmpeg_path: ffmpeg_path += "/ffmpeg" else: diff --git a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py index 69a2e0fdad..b752419a35 100644 --- a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py +++ b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py @@ -3,6 +3,7 @@ import tempfile import subprocess import pyblish.api import pype.api +import pype.lib class ExtractThumbnailSP(pyblish.api.InstancePlugin): @@ -73,7 +74,7 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin): config_data.get("__default__", {}) ) - ffmpeg_path = os.getenv("FFMPEG_PATH", "") + ffmpeg_path = pype.lib.get_path_to_ffmpeg() if ffmpeg_path: ffmpeg_path += "/ffmpeg" else: diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index f128352974..1d589916e9 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -5,14 +5,14 @@ import json import opentimelineio_contrib.adapters.ffmpeg_burnins as ffmpeg_burnins from pypeapp.lib import config from pype import api as pype -from subprocess import Popen, PIPE +import pype.lib # FFmpeg in PATH is required log = pype.Logger().get_logger("BurninWrapper", "burninwrap") -ffmpeg_path = os.environ.get("FFMPEG_PATH") +ffmpeg_path = pype.lib.get_path_to_ffmpeg() if ffmpeg_path and os.path.exists(ffmpeg_path): # add separator "/" or "\" to be prepared for next part ffmpeg_path += os.path.sep @@ -267,7 +267,7 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins): command = self.command(output=output, args=args, overwrite=overwrite) - proc = Popen(command, shell=True) + proc = subprocess.Popen(command, shell=True) proc.communicate() if proc.returncode != 0: raise RuntimeError("Failed to render '%s': %s'" diff --git a/pype/standalonepublish/widgets/widget_drop_frame.py b/pype/standalonepublish/widgets/widget_drop_frame.py index 73b9f0e179..aa3335fb78 100644 --- a/pype/standalonepublish/widgets/widget_drop_frame.py +++ b/pype/standalonepublish/widgets/widget_drop_frame.py @@ -4,6 +4,7 @@ import json import clique import subprocess from pypeapp import config +import pype.lib from . import QtWidgets, QtCore from . import DropEmpty, ComponentsList, ComponentItem @@ -224,7 +225,7 @@ class DropDataFrame(QtWidgets.QFrame): self._process_data(data) def load_data_with_probe(self, filepath): - ffprobe_path = os.getenv("FFMPEG_PATH", "") + ffprobe_path = pype.lib.get_path_to_ffmpeg() if ffprobe_path: ffprobe_path += '/ffprobe' else: From 6a5d43a4790d9156c814a88457f92aa00e7cfb65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 15 Feb 2020 11:06:49 +0100 Subject: [PATCH 2/6] `get_path_to_ffmpeg` replaced with `get_paths_from_environ` and `get_ffmpeg_tool_path` --- pype/lib.py | 61 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index 9cde3bd3af..87b9facdb3 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -13,14 +13,61 @@ import avalon log = logging.getLogger(__name__) -def get_path_to_ffmpeg(): - paths = os.environ.get("FFMPEG_PATH") or "" +def get_paths_from_environ(env_key, return_first=False): + """Return existing paths from specific envirnment variable. + + :param env_key: Environment key where should look for paths. + :type env_key: str + :param return_first: Return first path on `True`, list of all on `False`. + :type return_first: boolean + + Difference when none of paths exists: + - when `return_first` is set to `False` then function returns empty list. + - when `return_first` is set to `True` then function returns `None`. + """ + + existing_paths = [] + paths = os.environ.get(env_key) or "" path_items = paths.split(os.pathsep) - for item in path_items: - item = os.path.normpath(item) - if os.path.exists(item): - return item - return "" + for path in path_items: + # Skip empty string + if not path: + continue + # Normalize path + path = os.path.normpath(path) + # Check if path exists + if os.path.exists(path): + # Return path if `return_first` is set to True + if return_first: + return path + # Store path + existing_paths.append(path) + + # Return None if none of paths exists + if return_first: + return None + # Return all existing paths from environment variable + return existing_paths + + +def get_ffmpeg_tool_path(tool="ffmpeg"): + """Find path to ffmpeg tool in FFMPEG_PATH paths. + + Function looks for tool in paths set in FFMPEG_PATH environment. If tool + exists then returns it's full path. + + Returns tool name itself when tool path was not found. (FFmpeg path may be + set in PATH environment variable) + """ + + dir_paths = get_paths_from_environ("FFMPEG_PATH") + for dir_path in dir_paths: + for file_name in os.listdir(dir_path): + base, ext = os.path.splitext(file_name) + if base.lower() == tool.lower(): + return os.path.join(dir_path, tool) + return tool + # Special naming case for subprocess since its a built-in method. def _subprocess(*args, **kwargs): From 6efb1b0a74572df70179ff0993fe68c86a372520 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 15 Feb 2020 11:08:39 +0100 Subject: [PATCH 3/6] use new functions in code --- pype/plugins/global/publish/extract_jpeg.py | 5 +++-- pype/plugins/global/publish/extract_review.py | 7 ++++--- pype/plugins/global/publish/extract_review_slate.py | 2 +- .../global/publish/validate_ffmpeg_installed.py | 9 +++------ .../standalonepublisher/publish/extract_review.py | 7 +------ .../publish/extract_thumbnail.py | 6 +----- pype/scripts/otio_burnin.py | 13 +++++-------- pype/standalonepublish/widgets/widget_drop_frame.py | 7 +------ 8 files changed, 19 insertions(+), 37 deletions(-) diff --git a/pype/plugins/global/publish/extract_jpeg.py b/pype/plugins/global/publish/extract_jpeg.py index 6a0d7905b0..803ce51000 100644 --- a/pype/plugins/global/publish/extract_jpeg.py +++ b/pype/plugins/global/publish/extract_jpeg.py @@ -66,9 +66,10 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin): proj_name = os.environ.get('AVALON_PROJECT', '__default__') profile = config_data.get(proj_name, config_data['__default__']) + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") + jpeg_items = [] - jpeg_items.append( - os.path.join(pype.lib.get_path_to_ffmpeg(), "ffmpeg")) + jpeg_items.append(ffmpeg_path) # override file if already exists jpeg_items.append("-y") # use same input args like with mov diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 5895a8c423..cdec90cb3d 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -311,10 +311,11 @@ class ExtractReview(pyblish.api.InstancePlugin): "creating dir: {}".format(stg_dir)) os.mkdir(stg_dir) + ffmpeg_path = ( + pype.lib.get_ffmpeg_tool_path("ffmpeg") + ) mov_args = [ - os.path.join( - pype.lib.get_path_to_ffmpeg(), "ffmpeg" - ), + ffmpeg_path, " ".join(input_args), " ".join(output_args) ] diff --git a/pype/plugins/global/publish/extract_review_slate.py b/pype/plugins/global/publish/extract_review_slate.py index 5d4990a027..699ed4a5eb 100644 --- a/pype/plugins/global/publish/extract_review_slate.py +++ b/pype/plugins/global/publish/extract_review_slate.py @@ -22,7 +22,7 @@ class ExtractReviewSlate(pype.api.Extractor): suffix = "_slate" slate_path = inst_data.get("slateFrame") - ffmpeg_path = os.path.join(pype.lib.get_path_to_ffmpeg(), "ffmpeg") + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") to_width = 1920 to_height = 1080 diff --git a/pype/plugins/global/publish/validate_ffmpeg_installed.py b/pype/plugins/global/publish/validate_ffmpeg_installed.py index 643e0f1821..40006789f7 100644 --- a/pype/plugins/global/publish/validate_ffmpeg_installed.py +++ b/pype/plugins/global/publish/validate_ffmpeg_installed.py @@ -28,11 +28,8 @@ class ValidateFfmpegInstallef(pyblish.api.Validator): return True def process(self, instance): - self.log.info("ffmpeg path: `{}`".format( - pype.lib.get_path_to_ffmpeg() - )) - if self.is_tool( - os.path.join( - pype.lib.get_path_to_ffmpeg(), "ffmpeg")) is False: + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") + self.log.info("ffmpeg path: `{}`".format(ffmpeg_path)) + if self.is_tool(ffmpeg_path) is False: self.log.error("ffmpeg not found in PATH") raise RuntimeError('ffmpeg not installed.') diff --git a/pype/plugins/standalonepublisher/publish/extract_review.py b/pype/plugins/standalonepublisher/publish/extract_review.py index 29e1fcaac0..66cdcdf4df 100644 --- a/pype/plugins/standalonepublisher/publish/extract_review.py +++ b/pype/plugins/standalonepublisher/publish/extract_review.py @@ -149,12 +149,7 @@ class ExtractReviewSP(pyblish.api.InstancePlugin): # output filename output_args.append(full_output_path) - ffmpeg_path = pype.lib.get_path_to_ffmpeg() - if ffmpeg_path: - ffmpeg_path += "/ffmpeg" - else: - ffmpeg_path = "ffmpeg" - + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") mov_args = [ ffmpeg_path, " ".join(input_args), diff --git a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py index b752419a35..daa3936359 100644 --- a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py +++ b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py @@ -74,11 +74,7 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin): config_data.get("__default__", {}) ) - ffmpeg_path = pype.lib.get_path_to_ffmpeg() - if ffmpeg_path: - ffmpeg_path += "/ffmpeg" - else: - ffmpeg_path = "ffmpeg" + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") jpeg_items = [] jpeg_items.append(ffmpeg_path) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 1d589916e9..1da254adb1 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -12,20 +12,17 @@ import pype.lib log = pype.Logger().get_logger("BurninWrapper", "burninwrap") -ffmpeg_path = pype.lib.get_path_to_ffmpeg() -if ffmpeg_path and os.path.exists(ffmpeg_path): - # add separator "/" or "\" to be prepared for next part - ffmpeg_path += os.path.sep -else: - ffmpeg_path = "" +ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") +ffprobe_path = pype.lib.get_ffmpeg_tool_path("ffprobe") + FFMPEG = ( '{} -loglevel panic -i %(input)s %(filters)s %(args)s%(output)s' -).format(os.path.normpath(ffmpeg_path + "ffmpeg")) +).format(ffmpeg_path) FFPROBE = ( '{} -v quiet -print_format json -show_format -show_streams %(source)s' -).format(os.path.normpath(ffmpeg_path + "ffprobe")) +).format(ffprobe_path) def _streams(source): diff --git a/pype/standalonepublish/widgets/widget_drop_frame.py b/pype/standalonepublish/widgets/widget_drop_frame.py index aa3335fb78..c85105a333 100644 --- a/pype/standalonepublish/widgets/widget_drop_frame.py +++ b/pype/standalonepublish/widgets/widget_drop_frame.py @@ -225,12 +225,7 @@ class DropDataFrame(QtWidgets.QFrame): self._process_data(data) def load_data_with_probe(self, filepath): - ffprobe_path = pype.lib.get_path_to_ffmpeg() - if ffprobe_path: - ffprobe_path += '/ffprobe' - else: - ffprobe_path = 'ffprobe' - + ffprobe_path = pype.lib.get_ffmpeg_tool_path("ffprobe") args = [ ffprobe_path, '-v', 'quiet', From c0af43dafecb0d1c0956b78cd3b0d8164c533dda Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 15 Feb 2020 11:09:24 +0100 Subject: [PATCH 4/6] fix typo in class name `ValidateFfmpegInstallef` --- pype/plugins/global/publish/validate_ffmpeg_installed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/validate_ffmpeg_installed.py b/pype/plugins/global/publish/validate_ffmpeg_installed.py index 40006789f7..f6738e6de1 100644 --- a/pype/plugins/global/publish/validate_ffmpeg_installed.py +++ b/pype/plugins/global/publish/validate_ffmpeg_installed.py @@ -8,7 +8,7 @@ except ImportError: import errno -class ValidateFfmpegInstallef(pyblish.api.Validator): +class ValidateFFmpegInstalled(pyblish.api.Validator): """Validate availability of ffmpeg tool in PATH""" order = pyblish.api.ValidatorOrder From a635e0108733e7d220961a67858fd5e2fb2fe929 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 18 Feb 2020 08:35:45 +0100 Subject: [PATCH 5/6] reimplemented after merge --- pype/plugins/global/publish/extract_jpeg.py | 6 ++++-- pype/plugins/global/publish/extract_review.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pype/plugins/global/publish/extract_jpeg.py b/pype/plugins/global/publish/extract_jpeg.py index abd20bb9ea..bedfe4f7f8 100644 --- a/pype/plugins/global/publish/extract_jpeg.py +++ b/pype/plugins/global/publish/extract_jpeg.py @@ -3,6 +3,7 @@ import os import pyblish.api import clique import pype.api +import pype.lib class ExtractJpegEXR(pyblish.api.InstancePlugin): @@ -69,9 +70,10 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin): proj_name = os.environ.get('AVALON_PROJECT', '__default__') profile = config_data.get(proj_name, config_data['__default__']) + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") + jpeg_items = [] - jpeg_items.append( - os.path.join(os.environ.get("FFMPEG_PATH"), "ffmpeg")) + jpeg_items.append(ffmpeg_path) # override file if already exists jpeg_items.append("-y") # use same input args like with mov diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 4d63e2c641..44c3b5dbc4 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -2,6 +2,7 @@ import os import pyblish.api import clique import pype.api +import pype.lib class ExtractReview(pyblish.api.InstancePlugin): @@ -40,6 +41,8 @@ class ExtractReview(pyblish.api.InstancePlugin): # get representation and loop them representations = inst_data["representations"] + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") + # filter out mov and img sequences representations_new = representations[:] for repre in representations: @@ -324,10 +327,7 @@ class ExtractReview(pyblish.api.InstancePlugin): os.mkdir(stg_dir) mov_args = [ - os.path.join( - os.environ.get( - "FFMPEG_PATH", - ""), "ffmpeg"), + ffmpeg_path, " ".join(input_args), " ".join(output_args) ] From b0a1b1a50376cde95a2bd3656f16c7b0c8b888b5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 22 Feb 2020 01:22:47 +0100 Subject: [PATCH 6/6] fix missing import after merge --- pype/scripts/otio_burnin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 945fcad3ec..7a724e22bf 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -6,7 +6,7 @@ import json import opentimelineio_contrib.adapters.ffmpeg_burnins as ffmpeg_burnins from pypeapp.lib import config from pypeapp import Logger - +import pype.lib log = Logger().get_logger("BurninWrapper", "burninwrap")