mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
OP-4643 - added ExtractColorTranscode
Added method to convert from one colorspace to another to transcoding lib
This commit is contained in:
parent
2921579164
commit
8a67065fce
2 changed files with 177 additions and 0 deletions
|
|
@ -1045,3 +1045,56 @@ def convert_ffprobe_fps_to_float(value):
|
|||
if divisor == 0.0:
|
||||
return 0.0
|
||||
return dividend / divisor
|
||||
|
||||
|
||||
def convert_colorspace_for_input_paths(
|
||||
input_paths,
|
||||
output_dir,
|
||||
source_color_space,
|
||||
target_color_space,
|
||||
logger=None
|
||||
):
|
||||
"""Convert source files from one color space to another.
|
||||
|
||||
Filenames of input files are kept so make sure that output directory
|
||||
is not the same directory as input files have.
|
||||
- This way it can handle gaps and can keep input filenames without handling
|
||||
frame template
|
||||
|
||||
Args:
|
||||
input_paths (str): Paths that should be converted. It is expected that
|
||||
contains single file or image sequence of samy type.
|
||||
output_dir (str): Path to directory where output will be rendered.
|
||||
Must not be same as input's directory.
|
||||
source_color_space (str): ocio valid color space of source files
|
||||
target_color_space (str): ocio valid target color space
|
||||
logger (logging.Logger): Logger used for logging.
|
||||
|
||||
"""
|
||||
if logger is None:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
input_arg = "-i"
|
||||
oiio_cmd = [
|
||||
get_oiio_tools_path(),
|
||||
|
||||
# Don't add any additional attributes
|
||||
"--nosoftwareattrib",
|
||||
"--colorconvert", source_color_space, target_color_space
|
||||
]
|
||||
for input_path in input_paths:
|
||||
# Prepare subprocess arguments
|
||||
|
||||
oiio_cmd.extend([
|
||||
input_arg, input_path,
|
||||
])
|
||||
|
||||
# Add last argument - path to output
|
||||
base_filename = os.path.basename(input_path)
|
||||
output_path = os.path.join(output_dir, base_filename)
|
||||
oiio_cmd.extend([
|
||||
"-o", output_path
|
||||
])
|
||||
|
||||
logger.debug("Conversion command: {}".format(" ".join(oiio_cmd)))
|
||||
run_subprocess(oiio_cmd, logger=logger)
|
||||
|
|
|
|||
124
openpype/plugins/publish/extract_color_transcode.py
Normal file
124
openpype/plugins/publish/extract_color_transcode.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import pyblish.api
|
||||
|
||||
from openpype.pipeline import publish
|
||||
from openpype.lib import (
|
||||
|
||||
is_oiio_supported,
|
||||
)
|
||||
|
||||
from openpype.lib.transcoding import (
|
||||
convert_colorspace_for_input_paths,
|
||||
get_transcode_temp_directory,
|
||||
)
|
||||
|
||||
from openpype.lib.profiles_filtering import filter_profiles
|
||||
|
||||
|
||||
class ExtractColorTranscode(publish.Extractor):
|
||||
"""
|
||||
Extractor to convert colors from one colorspace to different.
|
||||
"""
|
||||
|
||||
label = "Transcode color spaces"
|
||||
order = pyblish.api.ExtractorOrder + 0.01
|
||||
|
||||
optional = True
|
||||
|
||||
# Configurable by Settings
|
||||
profiles = None
|
||||
options = None
|
||||
|
||||
def process(self, instance):
|
||||
if not self.profiles:
|
||||
self.log.warning("No profiles present for create burnin")
|
||||
return
|
||||
|
||||
if "representations" not in instance.data:
|
||||
self.log.warning("No representations, skipping.")
|
||||
return
|
||||
|
||||
if not is_oiio_supported():
|
||||
self.log.warning("OIIO not supported, no transcoding possible.")
|
||||
return
|
||||
|
||||
colorspace_data = instance.data.get("colorspaceData")
|
||||
if not colorspace_data:
|
||||
# TODO get_colorspace ??
|
||||
self.log.warning("Instance has not colorspace data, skipping")
|
||||
return
|
||||
source_color_space = colorspace_data["colorspace"]
|
||||
|
||||
host_name = instance.context.data["hostName"]
|
||||
family = instance.data["family"]
|
||||
task_data = instance.data["anatomyData"].get("task", {})
|
||||
task_name = task_data.get("name")
|
||||
task_type = task_data.get("type")
|
||||
subset = instance.data["subset"]
|
||||
|
||||
filtering_criteria = {
|
||||
"hosts": host_name,
|
||||
"families": family,
|
||||
"task_names": task_name,
|
||||
"task_types": task_type,
|
||||
"subset": subset
|
||||
}
|
||||
profile = filter_profiles(self.profiles, filtering_criteria,
|
||||
logger=self.log)
|
||||
|
||||
if not profile:
|
||||
self.log.info((
|
||||
"Skipped instance. None of profiles in presets are for"
|
||||
" Host: \"{}\" | Families: \"{}\" | Task \"{}\""
|
||||
" | Task type \"{}\" | Subset \"{}\" "
|
||||
).format(host_name, family, task_name, task_type, subset))
|
||||
return
|
||||
|
||||
self.log.debug("profile: {}".format(profile))
|
||||
|
||||
target_colorspace = profile["output_colorspace"]
|
||||
if not target_colorspace:
|
||||
raise RuntimeError("Target colorspace must be set")
|
||||
|
||||
repres = instance.data.get("representations") or []
|
||||
for idx, repre in enumerate(repres):
|
||||
self.log.debug("repre ({}): `{}`".format(idx + 1, repre["name"]))
|
||||
if not self.repre_is_valid(repre):
|
||||
continue
|
||||
|
||||
new_staging_dir = get_transcode_temp_directory()
|
||||
repre["stagingDir"] = new_staging_dir
|
||||
files_to_remove = repre["files"]
|
||||
if not isinstance(files_to_remove, list):
|
||||
files_to_remove = [files_to_remove]
|
||||
instance.context.data["cleanupFullPaths"].extend(files_to_remove)
|
||||
|
||||
convert_colorspace_for_input_paths(
|
||||
repre["files"],
|
||||
new_staging_dir,
|
||||
source_color_space,
|
||||
target_colorspace,
|
||||
self.log
|
||||
)
|
||||
|
||||
def repre_is_valid(self, repre):
|
||||
"""Validation if representation should be processed.
|
||||
|
||||
Args:
|
||||
repre (dict): Representation which should be checked.
|
||||
|
||||
Returns:
|
||||
bool: False if can't be processed else True.
|
||||
"""
|
||||
|
||||
if "review" not in (repre.get("tags") or []):
|
||||
self.log.info((
|
||||
"Representation \"{}\" don't have \"review\" tag. Skipped."
|
||||
).format(repre["name"]))
|
||||
return False
|
||||
|
||||
if not repre.get("files"):
|
||||
self.log.warning((
|
||||
"Representation \"{}\" have empty files. Skipped."
|
||||
).format(repre["name"]))
|
||||
return False
|
||||
return True
|
||||
Loading…
Add table
Add a link
Reference in a new issue