Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3259 from pypeclub/OP-3172_More-control-over-thum…
Browse files Browse the repository at this point in the history
…bnail-processing
  • Loading branch information
jakubjezek001 authored Jun 15, 2022
2 parents 310b338 + 18caa8c commit 1f4709a
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 99 deletions.
2 changes: 1 addition & 1 deletion openpype/lib/transcoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ def convert_input_paths_for_ffmpeg(
output_dir,
logger=None
):
"""Contert source file to format supported in ffmpeg.
"""Convert source file to format supported in ffmpeg.
Currently can convert only exrs. The input filepaths should be files
with same type. Information about input is loaded only from first found
Expand Down
193 changes: 99 additions & 94 deletions openpype/plugins/publish/extract_jpeg_exr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@
import pyblish.api
from openpype.lib import (
get_ffmpeg_tool_path,
get_oiio_tools_path,
is_oiio_supported,

run_subprocess,
path_to_subprocess_arg,

get_transcode_temp_directory,
convert_input_paths_for_ffmpeg,
should_convert_for_ffmpeg
execute,
)

import shutil


class ExtractJpegEXR(pyblish.api.InstancePlugin):
class ExtractThumbnail(pyblish.api.InstancePlugin):
"""Create jpg thumbnail from sequence using ffmpeg"""

label = "Extract Jpeg EXR"
label = "Extract Thumbnail"
order = pyblish.api.ExtractorOrder
families = [
"imagesequence", "render", "render2d",
Expand Down Expand Up @@ -49,7 +47,6 @@ def process(self, instance):
return

filtered_repres = self._get_filtered_repres(instance)

for repre in filtered_repres:
repre_files = repre["files"]
if not isinstance(repre_files, (list, tuple)):
Expand All @@ -62,100 +59,50 @@ def process(self, instance):

full_input_path = os.path.join(stagingdir, input_file)
self.log.info("input {}".format(full_input_path))

do_convert = should_convert_for_ffmpeg(full_input_path)
# If result is None the requirement of conversion can't be
# determined
if do_convert is None:
self.log.info((
"Can't determine if representation requires conversion."
" Skipped."
))
continue

# Do conversion if needed
# - change staging dir of source representation
# - must be set back after output definitions processing
convert_dir = None
if do_convert:
convert_dir = get_transcode_temp_directory()
filename = os.path.basename(full_input_path)
convert_input_paths_for_ffmpeg(
[full_input_path],
convert_dir,
self.log
)
full_input_path = os.path.join(convert_dir, filename)

filename = os.path.splitext(input_file)[0]
if not filename.endswith('.'):
filename += "."
jpeg_file = filename + "jpg"
full_output_path = os.path.join(stagingdir, jpeg_file)

self.log.info("output {}".format(full_output_path))

ffmpeg_path = get_ffmpeg_tool_path("ffmpeg")
ffmpeg_args = self.ffmpeg_args or {}

jpeg_items = []
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(
path_to_subprocess_arg(full_input_path)
))
# output arguments from presets
jpeg_items.extend(ffmpeg_args.get("output") or [])

# If its a movie file, we just want one frame.
if repre["ext"] == "mov":
jpeg_items.append("-vframes 1")

# output file
jpeg_items.append(path_to_subprocess_arg(full_output_path))

subprocess_command = " ".join(jpeg_items)

# run subprocess
self.log.debug("{}".format(subprocess_command))
try: # temporary until oiiotool is supported cross platform
run_subprocess(
subprocess_command, shell=True, logger=self.log
)
except RuntimeError as exp:
if "Compression" in str(exp):
self.log.debug(
"Unsupported compression on input files. Skipping!!!"
)
return
self.log.warning("Conversion crashed", exc_info=True)
raise
thumbnail_created = False
# Try to use FFMPEG if OIIO is not supported (for cases when
# oiiotool isn't available)
if not is_oiio_supported():
thumbnail_created = self.create_thumbnail_ffmpeg(full_input_path, full_output_path) # noqa
else:
# Check if the file can be read by OIIO
oiio_tool_path = get_oiio_tools_path()
args = [
oiio_tool_path, "--info", "-i", full_output_path
]
returncode = execute(args, silent=True)
# If the input can read by OIIO then use OIIO method for
# conversion otherwise use ffmpeg
if returncode == 0:
self.log.info("Input can be read by OIIO, converting with oiiotool now.") # noqa
thumbnail_created = self.create_thumbnail_oiio(full_input_path, full_output_path) # noqa
else:
self.log.info("Converting with FFMPEG because input can't be read by OIIO.") # noqa
thumbnail_created = self.create_thumbnail_ffmpeg(full_input_path, full_output_path) # noqa

# Skip the rest of the process if the thumbnail wasn't created
if not thumbnail_created:
self.log.warning("Thumbanil has not been created.")
return

new_repre = {
"name": "thumbnail",
"ext": "jpg",
"files": jpeg_file,
"stagingDir": stagingdir,
"thumbnail": True,
"tags": ["thumbnail"]
}

# adding representation
self.log.debug("Adding: {}".format(new_repre))
instance.data["representations"].append(new_repre)

# Cleanup temp folder
if convert_dir is not None and os.path.exists(convert_dir):
shutil.rmtree(convert_dir)

# Create only one representation with name 'thumbnail'
# TODO maybe handle way how to decide from which representation
# will be thumbnail created
break
"name": "thumbnail",
"ext": "jpg",
"files": jpeg_file,
"stagingDir": stagingdir,
"thumbnail": True,
"tags": ["thumbnail"]
}

# adding representation
self.log.debug("Adding: {}".format(new_repre))
instance.data["representations"].append(new_repre)

def _get_filtered_repres(self, instance):
filtered_repres = []
Expand All @@ -175,3 +122,61 @@ def _get_filtered_repres(self, instance):

filtered_repres.append(repre)
return filtered_repres

def create_thumbnail_oiio(self, src_path, dst_path):
self.log.info("outputting {}".format(dst_path))
oiio_tool_path = get_oiio_tools_path()
oiio_cmd = [oiio_tool_path, "-a",
src_path, "-o",
dst_path
]
subprocess_exr = " ".join(oiio_cmd)
self.log.info(f"running: {subprocess_exr}")
try:
run_subprocess(oiio_cmd, logger=self.log)
return True
except Exception:
self.log.warning(
"Failed to create thubmnail using oiiotool",
exc_info=True
)
return False

def create_thumbnail_ffmpeg(self, src_path, dst_path):
self.log.info("outputting {}".format(dst_path))

ffmpeg_path = get_ffmpeg_tool_path("ffmpeg")
ffmpeg_args = self.ffmpeg_args or {}

jpeg_items = []
jpeg_items.append(path_to_subprocess_arg(ffmpeg_path))
# override file if already exists
jpeg_items.append("-y")
# flag for large file sizes
max_int = 2147483647
jpeg_items.append("-analyzeduration {}".format(max_int))
jpeg_items.append("-probesize {}".format(max_int))
# use same input args like with mov
jpeg_items.extend(ffmpeg_args.get("input") or [])
# input file
jpeg_items.append("-i {}".format(
path_to_subprocess_arg(src_path)
))
# output arguments from presets
jpeg_items.extend(ffmpeg_args.get("output") or [])
# we just want one frame from movie files
jpeg_items.append("-vframes 1")
# output file
jpeg_items.append(path_to_subprocess_arg(dst_path))
subprocess_command = " ".join(jpeg_items)
try:
run_subprocess(
subprocess_command, shell=True, logger=self.log
)
return True
except Exception:
self.log.warning(
"Failed to create thubmnail using ffmpeg",
exc_info=True
)
return False
2 changes: 1 addition & 1 deletion openpype/settings/defaults/project_settings/deadline.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,4 @@
}
}
}
}
}
2 changes: 1 addition & 1 deletion openpype/settings/defaults/project_settings/global.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"enabled": false,
"profiles": []
},
"ExtractJpegEXR": {
"ExtractThumbnail": {
"enabled": true,
"ffmpeg_args": {
"input": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "ExtractJpegEXR",
"label": "ExtractJpegEXR",
"key": "ExtractThumbnail",
"label": "ExtractThumbnail",
"is_group": true,
"children": [
{
Expand Down

0 comments on commit 1f4709a

Please sign in to comment.