mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge pull request #1268 from ynput/bugfix/ocio-v2-aces1.3-display-resolving-error
Handles OCIO shared view token
This commit is contained in:
commit
3f549a0ecf
4 changed files with 223 additions and 40 deletions
|
|
@ -6,6 +6,8 @@ import collections
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
|
import warnings
|
||||||
|
import functools
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import xml.etree.ElementTree
|
import xml.etree.ElementTree
|
||||||
|
|
@ -67,6 +69,47 @@ VIDEO_EXTENSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def deprecated(new_destination):
|
||||||
|
"""Mark functions as deprecated.
|
||||||
|
|
||||||
|
It will result in a warning being emitted when the function is used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
func = None
|
||||||
|
if callable(new_destination):
|
||||||
|
func = new_destination
|
||||||
|
new_destination = None
|
||||||
|
|
||||||
|
def _decorator(decorated_func):
|
||||||
|
if new_destination is None:
|
||||||
|
warning_message = (
|
||||||
|
" Please check content of deprecated function to figure out"
|
||||||
|
" possible replacement."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
warning_message = " Please replace your usage with '{}'.".format(
|
||||||
|
new_destination
|
||||||
|
)
|
||||||
|
|
||||||
|
@functools.wraps(decorated_func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
warnings.simplefilter("always", DeprecationWarning)
|
||||||
|
warnings.warn(
|
||||||
|
(
|
||||||
|
"Call to deprecated function '{}'"
|
||||||
|
"\nFunction was moved or removed.{}"
|
||||||
|
).format(decorated_func.__name__, warning_message),
|
||||||
|
category=DeprecationWarning,
|
||||||
|
stacklevel=4
|
||||||
|
)
|
||||||
|
return decorated_func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
if func is None:
|
||||||
|
return _decorator
|
||||||
|
return _decorator(func)
|
||||||
|
|
||||||
|
|
||||||
def get_transcode_temp_directory():
|
def get_transcode_temp_directory():
|
||||||
"""Creates temporary folder for transcoding.
|
"""Creates temporary folder for transcoding.
|
||||||
|
|
||||||
|
|
@ -966,6 +1009,8 @@ def convert_ffprobe_fps_to_float(value):
|
||||||
return dividend / divisor
|
return dividend / divisor
|
||||||
|
|
||||||
|
|
||||||
|
# --- Deprecated functions ---
|
||||||
|
@deprecated("oiio_color_convert")
|
||||||
def convert_colorspace(
|
def convert_colorspace(
|
||||||
input_path,
|
input_path,
|
||||||
output_path,
|
output_path,
|
||||||
|
|
@ -977,7 +1022,62 @@ def convert_colorspace(
|
||||||
additional_command_args=None,
|
additional_command_args=None,
|
||||||
logger=None,
|
logger=None,
|
||||||
):
|
):
|
||||||
"""Convert source file from one color space to another.
|
"""DEPRECATED function use `oiio_color_convert` instead
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_path (str): Path to input file that should be converted.
|
||||||
|
output_path (str): Path to output file where result will be stored.
|
||||||
|
config_path (str): Path to OCIO config file.
|
||||||
|
source_colorspace (str): OCIO valid color space of source files.
|
||||||
|
target_colorspace (str, optional): OCIO valid target color space.
|
||||||
|
If filled, 'view' and 'display' must be empty.
|
||||||
|
view (str, optional): Name for target viewer space (OCIO valid).
|
||||||
|
Both 'view' and 'display' must be filled
|
||||||
|
(if not 'target_colorspace').
|
||||||
|
display (str, optional): Name for target display-referred
|
||||||
|
reference space. Both 'view' and 'display' must be filled
|
||||||
|
(if not 'target_colorspace').
|
||||||
|
additional_command_args (list, optional): Additional arguments
|
||||||
|
for oiiotool (like binary depth for .dpx).
|
||||||
|
logger (logging.Logger, optional): Logger used for logging.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None: Function returns None.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If parameters are misconfigured.
|
||||||
|
"""
|
||||||
|
return oiio_color_convert(
|
||||||
|
input_path,
|
||||||
|
output_path,
|
||||||
|
config_path,
|
||||||
|
source_colorspace,
|
||||||
|
target_colorspace=target_colorspace,
|
||||||
|
target_display=display,
|
||||||
|
target_view=view,
|
||||||
|
additional_command_args=additional_command_args,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def oiio_color_convert(
|
||||||
|
input_path,
|
||||||
|
output_path,
|
||||||
|
config_path,
|
||||||
|
source_colorspace,
|
||||||
|
source_display=None,
|
||||||
|
source_view=None,
|
||||||
|
target_colorspace=None,
|
||||||
|
target_display=None,
|
||||||
|
target_view=None,
|
||||||
|
additional_command_args=None,
|
||||||
|
logger=None,
|
||||||
|
):
|
||||||
|
"""Transcode source file to other with colormanagement.
|
||||||
|
|
||||||
|
Oiiotool also support additional arguments for transcoding.
|
||||||
|
For more information, see the official documentation:
|
||||||
|
https://openimageio.readthedocs.io/en/latest/oiiotool.html
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_path (str): Path that should be converted. It is expected that
|
input_path (str): Path that should be converted. It is expected that
|
||||||
|
|
@ -989,17 +1089,26 @@ def convert_colorspace(
|
||||||
sequence in 'file.FRAMESTART-FRAMEEND#.ext', `output.1-3#.tif`)
|
sequence in 'file.FRAMESTART-FRAMEEND#.ext', `output.1-3#.tif`)
|
||||||
config_path (str): path to OCIO config file
|
config_path (str): path to OCIO config file
|
||||||
source_colorspace (str): ocio valid color space of source files
|
source_colorspace (str): ocio valid color space of source files
|
||||||
|
source_display (str, optional): name for source display-referred
|
||||||
|
reference space (ocio valid). If provided, source_view must also be
|
||||||
|
provided, and source_colorspace will be ignored
|
||||||
|
source_view (str, optional): name for source viewer space (ocio valid)
|
||||||
|
If provided, source_display must also be provided, and
|
||||||
|
source_colorspace will be ignored
|
||||||
target_colorspace (str): ocio valid target color space
|
target_colorspace (str): ocio valid target color space
|
||||||
if filled, 'view' and 'display' must be empty
|
if filled, 'view' and 'display' must be empty
|
||||||
view (str): name for viewer space (ocio valid)
|
target_display (str): name for target display-referred reference space
|
||||||
both 'view' and 'display' must be filled (if 'target_colorspace')
|
(ocio valid) both 'view' and 'display' must be filled (if
|
||||||
display (str): name for display-referred reference space (ocio valid)
|
'target_colorspace')
|
||||||
|
target_view (str): name for target viewer space (ocio valid)
|
||||||
both 'view' and 'display' must be filled (if 'target_colorspace')
|
both 'view' and 'display' must be filled (if 'target_colorspace')
|
||||||
additional_command_args (list): arguments for oiiotool (like binary
|
additional_command_args (list): arguments for oiiotool (like binary
|
||||||
depth for .dpx)
|
depth for .dpx)
|
||||||
logger (logging.Logger): Logger used for logging.
|
logger (logging.Logger): Logger used for logging.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: if misconfigured
|
ValueError: if misconfigured
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if logger is None:
|
if logger is None:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -1024,23 +1133,82 @@ def convert_colorspace(
|
||||||
"--ch", channels_arg
|
"--ch", channels_arg
|
||||||
])
|
])
|
||||||
|
|
||||||
if all([target_colorspace, view, display]):
|
# Validate input parameters
|
||||||
raise ValueError("Colorspace and both screen and display"
|
if target_colorspace and target_view and target_display:
|
||||||
" cannot be set together."
|
raise ValueError(
|
||||||
"Choose colorspace or screen and display")
|
"Colorspace and both view and display cannot be set together."
|
||||||
if not target_colorspace and not all([view, display]):
|
"Choose colorspace or screen and display"
|
||||||
raise ValueError("Both screen and display must be set.")
|
)
|
||||||
|
|
||||||
|
if not target_colorspace and not target_view and not target_display:
|
||||||
|
raise ValueError(
|
||||||
|
"Both view and display must be set if target_colorspace is not "
|
||||||
|
"provided."
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(source_view and not source_display)
|
||||||
|
or (source_display and not source_view)
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
"Both source_view and source_display must be provided if using "
|
||||||
|
"display/view inputs."
|
||||||
|
)
|
||||||
|
|
||||||
|
if source_view and source_display and source_colorspace:
|
||||||
|
logger.warning(
|
||||||
|
"Both source display/view and source_colorspace provided. "
|
||||||
|
"Using source display/view pair and ignoring source_colorspace."
|
||||||
|
)
|
||||||
|
|
||||||
if additional_command_args:
|
if additional_command_args:
|
||||||
oiio_cmd.extend(additional_command_args)
|
oiio_cmd.extend(additional_command_args)
|
||||||
|
|
||||||
if target_colorspace:
|
# Handle the different conversion cases
|
||||||
oiio_cmd.extend(["--colorconvert:subimages=0",
|
# Source view and display are known
|
||||||
source_colorspace,
|
if source_view and source_display:
|
||||||
target_colorspace])
|
if target_colorspace:
|
||||||
if view and display:
|
# This is a two-step conversion process since there's no direct
|
||||||
oiio_cmd.extend(["--iscolorspace", source_colorspace])
|
# display/view to colorspace command
|
||||||
oiio_cmd.extend(["--ociodisplay:subimages=0", display, view])
|
# This could be a config parameter or determined from OCIO config
|
||||||
|
# Use temporarty role space 'scene_linear'
|
||||||
|
color_convert_args = ("scene_linear", target_colorspace)
|
||||||
|
elif source_display != target_display or source_view != target_view:
|
||||||
|
# Complete display/view pair conversion
|
||||||
|
# - go through a reference space
|
||||||
|
color_convert_args = (target_display, target_view)
|
||||||
|
else:
|
||||||
|
color_convert_args = None
|
||||||
|
logger.debug(
|
||||||
|
"Source and target display/view pairs are identical."
|
||||||
|
" No color conversion needed."
|
||||||
|
)
|
||||||
|
|
||||||
|
if color_convert_args:
|
||||||
|
oiio_cmd.extend([
|
||||||
|
"--ociodisplay:inverse=1:subimages=0",
|
||||||
|
source_display,
|
||||||
|
source_view,
|
||||||
|
"--colorconvert:subimages=0",
|
||||||
|
*color_convert_args
|
||||||
|
])
|
||||||
|
|
||||||
|
elif target_colorspace:
|
||||||
|
# Standard color space to color space conversion
|
||||||
|
oiio_cmd.extend([
|
||||||
|
"--colorconvert:subimages=0",
|
||||||
|
source_colorspace,
|
||||||
|
target_colorspace,
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
# Standard conversion from colorspace to display/view
|
||||||
|
oiio_cmd.extend([
|
||||||
|
"--iscolorspace",
|
||||||
|
source_colorspace,
|
||||||
|
"--ociodisplay:subimages=0",
|
||||||
|
target_display,
|
||||||
|
target_view,
|
||||||
|
])
|
||||||
|
|
||||||
oiio_cmd.extend(["-o", output_path])
|
oiio_cmd.extend(["-o", output_path])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1404,7 +1404,7 @@ def _get_display_view_colorspace_name(config_path, display, view):
|
||||||
"""
|
"""
|
||||||
config = _get_ocio_config(config_path)
|
config = _get_ocio_config(config_path)
|
||||||
colorspace = config.getDisplayViewColorSpaceName(display, view)
|
colorspace = config.getDisplayViewColorSpaceName(display, view)
|
||||||
# Special token. See https://opencolorio.readthedocs.io/en/latest/guides/authoring/authoring.html#shared-views # noqa
|
# Special token. See https://opencolorio.readthedocs.io/en/latest/guides/authoring/authoring.html#shared-views # noqa
|
||||||
if colorspace == "<USE_DISPLAY_NAME>":
|
if colorspace == "<USE_DISPLAY_NAME>":
|
||||||
colorspace = display
|
colorspace = display
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from ayon_core.lib import (
|
||||||
is_oiio_supported,
|
is_oiio_supported,
|
||||||
)
|
)
|
||||||
from ayon_core.lib.transcoding import (
|
from ayon_core.lib.transcoding import (
|
||||||
convert_colorspace,
|
oiio_color_convert,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ayon_core.lib.profiles_filtering import filter_profiles
|
from ayon_core.lib.profiles_filtering import filter_profiles
|
||||||
|
|
@ -87,6 +87,14 @@ class ExtractOIIOTranscode(publish.Extractor):
|
||||||
new_representations = []
|
new_representations = []
|
||||||
repres = instance.data["representations"]
|
repres = instance.data["representations"]
|
||||||
for idx, repre in enumerate(list(repres)):
|
for idx, repre in enumerate(list(repres)):
|
||||||
|
# target space, display and view might be defined upstream
|
||||||
|
# TODO: address https://github.com/ynput/ayon-core/pull/1268#discussion_r2156555474
|
||||||
|
# Implement upstream logic to handle target_colorspace,
|
||||||
|
# target_display, target_view in other DCCs
|
||||||
|
target_colorspace = False
|
||||||
|
target_display = instance.data.get("colorspaceDisplay")
|
||||||
|
target_view = instance.data.get("colorspaceView")
|
||||||
|
|
||||||
self.log.debug("repre ({}): `{}`".format(idx + 1, repre["name"]))
|
self.log.debug("repre ({}): `{}`".format(idx + 1, repre["name"]))
|
||||||
if not self._repre_is_valid(repre):
|
if not self._repre_is_valid(repre):
|
||||||
continue
|
continue
|
||||||
|
|
@ -96,6 +104,8 @@ class ExtractOIIOTranscode(publish.Extractor):
|
||||||
|
|
||||||
colorspace_data = repre["colorspaceData"]
|
colorspace_data = repre["colorspaceData"]
|
||||||
source_colorspace = colorspace_data["colorspace"]
|
source_colorspace = colorspace_data["colorspace"]
|
||||||
|
source_display = colorspace_data.get("display")
|
||||||
|
source_view = colorspace_data.get("view")
|
||||||
config_path = colorspace_data.get("config", {}).get("path")
|
config_path = colorspace_data.get("config", {}).get("path")
|
||||||
if not config_path or not os.path.exists(config_path):
|
if not config_path or not os.path.exists(config_path):
|
||||||
self.log.warning("Config file doesn't exist, skipping")
|
self.log.warning("Config file doesn't exist, skipping")
|
||||||
|
|
@ -126,7 +136,6 @@ class ExtractOIIOTranscode(publish.Extractor):
|
||||||
|
|
||||||
transcoding_type = output_def["transcoding_type"]
|
transcoding_type = output_def["transcoding_type"]
|
||||||
|
|
||||||
target_colorspace = view = display = None
|
|
||||||
# NOTE: we use colorspace_data as the fallback values for
|
# NOTE: we use colorspace_data as the fallback values for
|
||||||
# the target colorspace.
|
# the target colorspace.
|
||||||
if transcoding_type == "colorspace":
|
if transcoding_type == "colorspace":
|
||||||
|
|
@ -138,18 +147,20 @@ class ExtractOIIOTranscode(publish.Extractor):
|
||||||
colorspace_data.get("colorspace"))
|
colorspace_data.get("colorspace"))
|
||||||
elif transcoding_type == "display_view":
|
elif transcoding_type == "display_view":
|
||||||
display_view = output_def["display_view"]
|
display_view = output_def["display_view"]
|
||||||
view = display_view["view"] or colorspace_data.get("view")
|
target_view = (
|
||||||
display = (
|
display_view["view"]
|
||||||
|
or colorspace_data.get("view"))
|
||||||
|
target_display = (
|
||||||
display_view["display"]
|
display_view["display"]
|
||||||
or colorspace_data.get("display")
|
or colorspace_data.get("display")
|
||||||
)
|
)
|
||||||
|
|
||||||
# both could be already collected by DCC,
|
# both could be already collected by DCC,
|
||||||
# but could be overwritten when transcoding
|
# but could be overwritten when transcoding
|
||||||
if view:
|
if target_view:
|
||||||
new_repre["colorspaceData"]["view"] = view
|
new_repre["colorspaceData"]["view"] = target_view
|
||||||
if display:
|
if target_display:
|
||||||
new_repre["colorspaceData"]["display"] = display
|
new_repre["colorspaceData"]["display"] = target_display
|
||||||
if target_colorspace:
|
if target_colorspace:
|
||||||
new_repre["colorspaceData"]["colorspace"] = \
|
new_repre["colorspaceData"]["colorspace"] = \
|
||||||
target_colorspace
|
target_colorspace
|
||||||
|
|
@ -168,16 +179,18 @@ class ExtractOIIOTranscode(publish.Extractor):
|
||||||
new_staging_dir,
|
new_staging_dir,
|
||||||
output_extension)
|
output_extension)
|
||||||
|
|
||||||
convert_colorspace(
|
oiio_color_convert(
|
||||||
input_path,
|
input_path=input_path,
|
||||||
output_path,
|
output_path=output_path,
|
||||||
config_path,
|
config_path=config_path,
|
||||||
source_colorspace,
|
source_colorspace=source_colorspace,
|
||||||
target_colorspace,
|
target_colorspace=target_colorspace,
|
||||||
view,
|
target_display=target_display,
|
||||||
display,
|
target_view=target_view,
|
||||||
additional_command_args,
|
source_display=source_display,
|
||||||
self.log
|
source_view=source_view,
|
||||||
|
additional_command_args=additional_command_args,
|
||||||
|
logger=self.log
|
||||||
)
|
)
|
||||||
|
|
||||||
# cleanup temporary transcoded files
|
# cleanup temporary transcoded files
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from ayon_core.lib import (
|
||||||
path_to_subprocess_arg,
|
path_to_subprocess_arg,
|
||||||
run_subprocess,
|
run_subprocess,
|
||||||
)
|
)
|
||||||
from ayon_core.lib.transcoding import convert_colorspace
|
from ayon_core.lib.transcoding import oiio_color_convert
|
||||||
|
|
||||||
from ayon_core.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS
|
from ayon_core.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS
|
||||||
|
|
||||||
|
|
@ -433,13 +433,15 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
||||||
oiio_default_view = display_and_view["view"]
|
oiio_default_view = display_and_view["view"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
convert_colorspace(
|
oiio_color_convert(
|
||||||
src_path,
|
src_path,
|
||||||
dst_path,
|
dst_path,
|
||||||
colorspace_data["config"]["path"],
|
colorspace_data["config"]["path"],
|
||||||
colorspace_data["colorspace"],
|
colorspace_data["colorspace"],
|
||||||
display=repre_display or oiio_default_display,
|
source_display=colorspace_data.get("display"),
|
||||||
view=repre_view or oiio_default_view,
|
source_view=colorspace_data.get("view"),
|
||||||
|
target_display=repre_display or oiio_default_display,
|
||||||
|
target_view=repre_view or oiio_default_view,
|
||||||
target_colorspace=oiio_default_colorspace,
|
target_colorspace=oiio_default_colorspace,
|
||||||
additional_command_args=resolution_arg,
|
additional_command_args=resolution_arg,
|
||||||
logger=self.log,
|
logger=self.log,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue