Merge pull request #5623 from ynput/enhancement/OP-6451_Nuke---ExctractReviewDataMov-plugin-with-multiple-format-support

Nuke: Multiple format supports for ExtractReviewDataMov
This commit is contained in:
Kayla Man 2023-09-29 23:06:40 +08:00 committed by GitHub
commit d83eb73e04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 387 additions and 13 deletions

View file

@ -3423,3 +3423,55 @@ def create_viewer_profile_string(viewer, display=None, path_like=False):
if path_like:
return "{}/{}".format(display, viewer)
return "{} ({})".format(viewer, display)
def get_head_filename_without_hashes(original_path, name):
"""Function to get the renamed head filename without frame hashes
To avoid the system being confused on finding the filename with
frame hashes if the head of the filename has the hashed symbol
Examples:
>>> get_head_filename_without_hashes("render.####.exr", "baking")
render.baking.####.exr
>>> get_head_filename_without_hashes("render.%04d.exr", "tag")
render.tag.%d.exr
>>> get_head_filename_without_hashes("exr.####.exr", "foo")
exr.foo.%04d.exr
Args:
original_path (str): the filename with frame hashes
name (str): the name of the tags
Returns:
str: the renamed filename with the tag
"""
filename = os.path.basename(original_path)
def insert_name(matchobj):
return "{}.{}".format(name, matchobj.group(0))
return re.sub(r"(%\d*d)|#+", insert_name, filename)
def get_filenames_without_hash(filename, frame_start, frame_end):
"""Get filenames without frame hash
i.e. "renderCompositingMain.baking.0001.exr"
Args:
filename (str): filename with frame hash
frame_start (str): start of the frame
frame_end (str): end of the frame
Returns:
list: filename per frame of the sequence
"""
filenames = []
for frame in range(int(frame_start), (int(frame_end) + 1)):
if "#" in filename:
# use regex to convert #### to {:0>4}
def replace(match):
return "{{:0>{}}}".format(len(match.group()))
filename_without_hashes = re.sub("#+", replace, filename)
new_filename = filename_without_hashes.format(frame)
filenames.append(new_filename)
return filenames

View file

@ -21,6 +21,9 @@ from openpype.pipeline import (
CreatedInstance,
get_current_task_name
)
from openpype.lib.transcoding import (
VIDEO_EXTENSIONS
)
from .lib import (
INSTANCE_DATA_KNOB,
Knobby,
@ -35,7 +38,9 @@ from .lib import (
get_node_data,
get_view_process_node,
get_viewer_config_from_string,
deprecated
deprecated,
get_head_filename_without_hashes,
get_filenames_without_hash
)
from .pipeline import (
list_instances,
@ -634,6 +639,10 @@ class ExporterReview(object):
"frameStart": self.first_frame,
"frameEnd": self.last_frame,
})
if ".{}".format(self.ext) not in VIDEO_EXTENSIONS:
filenames = get_filenames_without_hash(
self.file, self.first_frame, self.last_frame)
repre["files"] = filenames
if self.multiple_presets:
repre["outputName"] = self.name
@ -808,6 +817,18 @@ class ExporterReviewMov(ExporterReview):
self.log.info("File info was set...")
self.file = self.fhead + self.name + ".{}".format(self.ext)
if ".{}".format(self.ext) not in VIDEO_EXTENSIONS:
# filename would be with frame hashes if
# the file extension is not in video format
filename = get_head_filename_without_hashes(
self.path_in, self.name)
self.file = filename
# make sure the filename are in
# correct image output format
if ".{}".format(self.ext) not in self.file:
filename_no_ext, _ = os.path.splitext(filename)
self.file = "{}.{}".format(filename_no_ext, self.ext)
self.path = os.path.join(
self.staging_dir, self.file).replace("\\", "/")
@ -933,7 +954,6 @@ class ExporterReviewMov(ExporterReview):
self.log.debug("Path: {}".format(self.path))
write_node["file"].setValue(str(self.path))
write_node["file_type"].setValue(str(self.ext))
# Knobs `meta_codec` and `mov64_codec` are not available on centos.
# TODO shouldn't this come from settings on outputs?
try:

View file

@ -8,15 +8,16 @@ from openpype.hosts.nuke.api import plugin
from openpype.hosts.nuke.api.lib import maintained_selection
class ExtractReviewDataMov(publish.Extractor):
"""Extracts movie and thumbnail with baked in luts
class ExtractReviewIntermediates(publish.Extractor):
"""Extracting intermediate videos or sequences with
thumbnail for transcoding.
must be run after extract_render_local.py
"""
order = pyblish.api.ExtractorOrder + 0.01
label = "Extract Review Data Mov"
label = "Extract Review Intermediates"
families = ["review"]
hosts = ["nuke"]
@ -25,6 +26,22 @@ class ExtractReviewDataMov(publish.Extractor):
viewer_lut_raw = None
outputs = {}
@classmethod
def apply_settings(cls, project_settings):
"""Apply the settings from the deprecated
ExtractReviewDataMov plugin for backwards compatibility
"""
nuke_publish = project_settings["nuke"]["publish"]
deprecated_setting = nuke_publish["ExtractReviewDataMov"]
current_setting = nuke_publish["ExtractReviewIntermediates"]
if deprecated_setting["enabled"]:
# Use deprecated settings if they are still enabled
cls.viewer_lut_raw = deprecated_setting["viewer_lut_raw"]
cls.outputs = deprecated_setting["outputs"]
elif current_setting["enabled"]:
cls.viewer_lut_raw = current_setting["viewer_lut_raw"]
cls.outputs = current_setting["outputs"]
def process(self, instance):
families = set(instance.data["families"])

View file

@ -748,7 +748,19 @@ def _convert_nuke_project_settings(ayon_settings, output):
)
new_review_data_outputs = {}
for item in ayon_publish["ExtractReviewDataMov"]["outputs"]:
outputs_settings = None
# Check deprecated ExtractReviewDataMov
# settings for backwards compatibility
deprecrated_review_settings = ayon_publish["ExtractReviewDataMov"]
current_review_settings = (
ayon_publish["ExtractReviewIntermediates"]
)
if deprecrated_review_settings["enabled"]:
outputs_settings = deprecrated_review_settings["outputs"]
elif current_review_settings["enabled"]:
outputs_settings = current_review_settings["outputs"]
for item in outputs_settings:
item_filter = item["filter"]
if "product_names" in item_filter:
item_filter["subsets"] = item_filter.pop("product_names")
@ -767,7 +779,11 @@ def _convert_nuke_project_settings(ayon_settings, output):
name = item.pop("name")
new_review_data_outputs[name] = item
ayon_publish["ExtractReviewDataMov"]["outputs"] = new_review_data_outputs
if deprecrated_review_settings["enabled"]:
deprecrated_review_settings["outputs"] = new_review_data_outputs
elif current_review_settings["enabled"]:
current_review_settings["outputs"] = new_review_data_outputs
collect_instance_data = ayon_publish["CollectInstanceData"]
if "sync_workfile_version_on_product_types" in collect_instance_data:

View file

@ -501,6 +501,60 @@
}
}
},
"ExtractReviewIntermediates": {
"enabled": true,
"viewer_lut_raw": false,
"outputs": {
"baking": {
"filter": {
"task_types": [],
"families": [],
"subsets": []
},
"read_raw": false,
"viewer_process_override": "",
"bake_viewer_process": true,
"bake_viewer_input_process": true,
"reformat_nodes_config": {
"enabled": false,
"reposition_nodes": [
{
"node_class": "Reformat",
"knobs": [
{
"type": "text",
"name": "type",
"value": "to format"
},
{
"type": "text",
"name": "format",
"value": "HD_1080"
},
{
"type": "text",
"name": "filter",
"value": "Lanczos6"
},
{
"type": "bool",
"name": "black_outside",
"value": true
},
{
"type": "bool",
"name": "pbb",
"value": false
}
]
}
]
},
"extension": "mov",
"add_custom_tags": []
}
}
},
"ExtractSlateFrame": {
"viewer_lut_raw": false,
"key_value_mapping": {

View file

@ -371,6 +371,151 @@
]
},
{
"type": "label",
"label": "^ Settings and for <span style=\"color:#FF0000\";><b>ExtractReviewDataMov</b></span> is deprecated and will be soon removed. <br> Please use <b>ExtractReviewIntermediates</b> instead."
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "ExtractReviewIntermediates",
"label": "ExtractReviewIntermediates",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "viewer_lut_raw",
"label": "Viewer LUT raw"
},
{
"key": "outputs",
"label": "Output Definitions",
"type": "dict-modifiable",
"highlight_content": true,
"object_type": {
"type": "dict",
"children": [
{
"type": "dict",
"collapsible": false,
"key": "filter",
"label": "Filtering",
"children": [
{
"key": "task_types",
"label": "Task types",
"type": "task-types-enum"
},
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"key": "subsets",
"label": "Subsets",
"type": "list",
"object_type": "text"
}
]
},
{
"type": "separator"
},
{
"type": "boolean",
"key": "read_raw",
"label": "Read colorspace RAW",
"default": false
},
{
"type": "text",
"key": "viewer_process_override",
"label": "Viewer Process colorspace profile override"
},
{
"type": "boolean",
"key": "bake_viewer_process",
"label": "Bake Viewer Process"
},
{
"type": "boolean",
"key": "bake_viewer_input_process",
"label": "Bake Viewer Input Process (LUTs)"
},
{
"type": "separator"
},
{
"key": "reformat_nodes_config",
"type": "dict",
"label": "Reformat Nodes",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "label",
"label": "Reposition knobs supported only.<br/>You can add multiple reformat nodes <br/>and set their knobs. Order of reformat <br/>nodes is important. First reformat node <br/>will be applied first and last reformat <br/>node will be applied last."
},
{
"key": "reposition_nodes",
"type": "list",
"label": "Reposition nodes",
"object_type": {
"type": "dict",
"children": [
{
"key": "node_class",
"label": "Node class",
"type": "text"
},
{
"type": "schema_template",
"name": "template_nuke_knob_inputs",
"template_data": [
{
"label": "Node knobs",
"key": "knobs"
}
]
}
]
}
}
]
},
{
"type": "separator"
},
{
"type": "text",
"key": "extension",
"label": "Write node file type"
},
{
"key": "add_custom_tags",
"label": "Add custom tags",
"type": "list",
"object_type": "text"
}
]
}
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -149,7 +149,7 @@ class ReformatNodesConfigModel(BaseSettingsModel):
)
class BakingStreamModel(BaseSettingsModel):
class IntermediateOutputModel(BaseSettingsModel):
name: str = Field(title="Output name")
filter: BakingStreamFilterModel = Field(
title="Filter", default_factory=BakingStreamFilterModel)
@ -166,9 +166,21 @@ class BakingStreamModel(BaseSettingsModel):
class ExtractReviewDataMovModel(BaseSettingsModel):
"""[deprecated] use Extract Review Data Baking
Streams instead.
"""
enabled: bool = Field(title="Enabled")
viewer_lut_raw: bool = Field(title="Viewer lut raw")
outputs: list[BakingStreamModel] = Field(
outputs: list[IntermediateOutputModel] = Field(
default_factory=list,
title="Baking streams"
)
class ExtractReviewIntermediatesModel(BaseSettingsModel):
enabled: bool = Field(title="Enabled")
viewer_lut_raw: bool = Field(title="Viewer lut raw")
outputs: list[IntermediateOutputModel] = Field(
default_factory=list,
title="Baking streams"
)
@ -270,6 +282,10 @@ class PublishPuginsModel(BaseSettingsModel):
title="Extract Review Data Mov",
default_factory=ExtractReviewDataMovModel
)
ExtractReviewIntermediates: ExtractReviewIntermediatesModel = Field(
title="Extract Review Intermediates",
default_factory=ExtractReviewIntermediatesModel
)
ExtractSlateFrame: ExtractSlateFrameModel = Field(
title="Extract Slate Frame",
default_factory=ExtractSlateFrameModel
@ -465,6 +481,61 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = {
}
]
},
"ExtractReviewIntermediates": {
"enabled": True,
"viewer_lut_raw": False,
"outputs": [
{
"name": "baking",
"filter": {
"task_types": [],
"product_types": [],
"product_names": []
},
"read_raw": False,
"viewer_process_override": "",
"bake_viewer_process": True,
"bake_viewer_input_process": True,
"reformat_nodes_config": {
"enabled": False,
"reposition_nodes": [
{
"node_class": "Reformat",
"knobs": [
{
"type": "text",
"name": "type",
"text": "to format"
},
{
"type": "text",
"name": "format",
"text": "HD_1080"
},
{
"type": "text",
"name": "filter",
"text": "Lanczos6"
},
{
"type": "bool",
"name": "black_outside",
"boolean": True
},
{
"type": "bool",
"name": "pbb",
"boolean": False
}
]
}
]
},
"extension": "mov",
"add_custom_tags": []
}
]
},
"ExtractSlateFrame": {
"viewer_lut_raw": False,
"key_value_mapping": {

View file

@ -1 +1 @@
__version__ = "0.1.2"
__version__ = "0.1.3"

View file

@ -189,7 +189,7 @@ A profile may generate multiple outputs from a single input. Each output must de
- Profile filtering defines which group of output definitions is used but output definitions may require more specific filters on their own.
- They may filter by subset name (regex can be used) or publish families. Publish families are more complex as are based on knowing code base.
- Filtering by custom tags -> this is used for targeting to output definitions from other extractors using settings (at this moment only Nuke bake extractor can target using custom tags).
- Nuke extractor settings path: `project_settings/nuke/publish/ExtractReviewDataMov/outputs/baking/add_custom_tags`
- Nuke extractor settings path: `project_settings/nuke/publish/ExtractReviewIntermediates/outputs/baking/add_custom_tags`
- Filtering by input length. Input may be video, sequence or single image. It is possible that `.mp4` should be created only when input is video or sequence and to create review `.png` when input is single frame. In some cases the output should be created even if it's single frame or multi frame input.

View file

@ -534,8 +534,7 @@ Plugin responsible for generating thumbnails with colorspace controlled by Nuke.
}
```
### `ExtractReviewDataMov`
### `ExtractReviewIntermediates`
`viewer_lut_raw` **true** will publish the baked mov file without any colorspace conversion. It will be baked with the workfile workspace. This can happen in case the Viewer input process uses baked screen space luts.
#### baking with controlled colorspace