Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Milan Kolar 2021-09-17 20:06:27 +01:00
commit 6997633592
12 changed files with 195 additions and 101 deletions

View file

@ -91,7 +91,8 @@ class ExtractRender(pyblish.api.InstancePlugin):
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",

View file

@ -60,7 +60,8 @@ class ExtractReview(openpype.api.Extractor):
# 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 @@ class ExtractReview(openpype.api.Extractor):
# 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",

View file

@ -101,11 +101,14 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin):
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

View file

@ -59,32 +59,35 @@ class ExtractTrimVideoAudio(openpype.api.Extractor):
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
)
repr = {
repre = {
"name": ext[1:],
"ext": ext[1:],
"files": os.path.basename(clip_trimed_path),
@ -97,10 +100,10 @@ class ExtractTrimVideoAudio(openpype.api.Extractor):
}
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)}")

View file

@ -27,6 +27,8 @@ from .execute import (
get_pype_execute_args,
execute,
run_subprocess,
split_command_to_list,
path_to_subprocess_arg,
CREATE_NO_WINDOW
)
from .log import PypeLogger, timeit
@ -172,6 +174,9 @@ __all__ = [
"get_pype_execute_args",
"execute",
"run_subprocess",
"split_command_to_list",
"path_to_subprocess_arg",
"CREATE_NO_WINDOW",
"env_value_to_bool",
"get_paths_from_environ",

View file

@ -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,44 @@ 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.
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 not string_command:
return []
kwargs = {}
# Use 'posix' argument only on windows
if platform.system().lower() == "windows":
kwargs["posix"] = False
return shlex.split(string_command, **kwargs)
def get_pype_execute_args(*args):
"""Arguments to run pype command.

View file

@ -1,10 +1,17 @@
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,
path_to_subprocess_arg,
should_decompress,
get_decompress_dir,
decompress
)
import shutil
@ -85,17 +92,19 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
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 = []
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 [])
@ -104,15 +113,16 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
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_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):

View file

@ -2,7 +2,9 @@ import os
import pyblish
import openpype.api
from openpype.lib import (
get_ffmpeg_tool_path
get_ffmpeg_tool_path,
split_command_to_list,
path_to_subprocess_arg
)
import tempfile
import opentimelineio as otio
@ -56,14 +58,17 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
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)
# run subprocess
self.log.debug("Executing: {}".format(cmd))
openpype.api.run_subprocess(
cmd, logger=self.log
cmd_list, logger=self.log
)
# remove empty
@ -99,16 +104,16 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
# 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 +225,17 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
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
@ -261,10 +266,14 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
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(

View file

@ -312,7 +312,7 @@ class ExtractOTIOReview(openpype.api.Extractor):
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 @@ class ExtractOTIOReview(openpype.api.Extractor):
# 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 @@ class ExtractOTIOReview(openpype.api.Extractor):
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 @@ class ExtractOTIOReview(openpype.api.Extractor):
# 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))

View file

@ -75,7 +75,7 @@ class ExtractOTIOTrimmingVideo(openpype.api.Extractor):
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 @@ class ExtractOTIOTrimmingVideo(openpype.api.Extractor):
# 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))

View file

@ -13,6 +13,10 @@ import openpype.api
from openpype.lib import (
get_ffmpeg_tool_path,
ffprobe_streams,
split_command_to_list,
path_to_subprocess_arg,
should_decompress,
get_decompress_dir,
decompress
@ -216,12 +220,15 @@ class ExtractReview(pyblish.api.InstancePlugin):
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
@ -480,7 +487,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
# 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.
@ -538,7 +547,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
# 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(
@ -607,7 +616,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
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")
@ -854,7 +863,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
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.

View file

@ -117,11 +117,13 @@ class ExtractReviewSlate(openpype.api.Extractor):
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,26 @@ class ExtractReviewSlate(openpype.api.Extractor):
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(
" ".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_subprcs_cmd, shell=True, logger=self.log
slate_subprocess_args, shell=True, logger=self.log
)
# create ffmpeg concat text file path
@ -221,23 +229,22 @@ class ExtractReviewSlate(openpype.api.Extractor):
])
# 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"]))