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

Flame: sequence used for reference video #2869

Merged
6 changes: 4 additions & 2 deletions openpype/hosts/flame/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
)
from .render_utils import (
export_clip,
get_preset_path_by_xml_name
get_preset_path_by_xml_name,
modify_preset_file
)

__all__ = [
Expand Down Expand Up @@ -140,5 +141,6 @@

# render utils
"export_clip",
"get_preset_path_by_xml_name"
"get_preset_path_by_xml_name",
"modify_preset_file"
]
27 changes: 27 additions & 0 deletions openpype/hosts/flame/api/render_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from xml.etree import ElementTree as ET


def export_clip(export_path, clip, preset_path, **kwargs):
Expand Down Expand Up @@ -123,3 +124,29 @@ def _validate_results(results):

# if nothing found then return False
return False


def modify_preset_file(xml_path, staging_dir, data):
"""Modify xml preset with input data

Args:
xml_path (str ): path for input xml preset
staging_dir (str): staging dir path
data (dict): data where key is xmlTag and value as string

Returns:
str: _description_
"""
# create temp path
dirname, basename = os.path.split(xml_path)
temp_path = os.path.join(staging_dir, basename)

# change xml following data keys
with open(xml_path, "r") as datafile:
tree = ET.parse(datafile)
for key, value in data.items():
for element in tree.findall(".//{}".format(key)):
element.text = str(value)
tree.write(temp_path)

return temp_path
9 changes: 8 additions & 1 deletion openpype/hosts/flame/api/scripts/wiretap_com.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,13 +420,20 @@ def _set_project_colorspace(self, project_name, color_policy):
RuntimeError: Not able to set colorspace policy
"""
color_policy = color_policy or "Legacy"

# check if the colour policy in custom dir
if not os.path.exists(color_policy):
color_policy = "/syncolor/policies/Autodesk/{}".format(
color_policy)

# create arguments
project_colorspace_cmd = [
os.path.join(
self.wiretap_tools_dir,
"wiretap_duplicate_node"
),
"-s",
"/syncolor/policies/Autodesk/{}".format(color_policy),
color_policy,
"-n",
"/projects/{}/syncolor".format(project_name)
]
Expand Down
24 changes: 23 additions & 1 deletion openpype/hosts/flame/hooks/pre_flame_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def execute(self):
"FrameWidth": int(width),
"FrameHeight": int(height),
"AspectRatio": float((width / height) * _db_p_data["pixelAspect"]),
"FrameRate": "{} fps".format(fps),
"FrameRate": self._get_flame_fps(fps),
"FrameDepth": str(imageio_flame["project"]["frameDepth"]),
"FieldDominance": str(imageio_flame["project"]["fieldDominance"])
}
Expand Down Expand Up @@ -101,6 +101,28 @@ def execute(self):

self.launch_context.launch_args.extend(app_arguments)

def _get_flame_fps(self, fps_num):
fps_table = {
float(23.976): "23.976 fps",
int(25): "25 fps",
int(24): "24 fps",
float(29.97): "29.97 fps DF",
int(30): "30 fps",
int(50): "50 fps",
float(59.94): "59.94 fps DF",
int(60): "60 fps"
}

match_key = min(fps_table.keys(), key=lambda x: abs(x - fps_num))

try:
return fps_table[match_key]
except KeyError as msg:
raise KeyError((
"Missing FPS key in conversion table. "
"Following keys are available: {}".format(fps_table.keys())
)) from msg

def _add_pythonpath(self):
pythonpath = self.launch_context.env.get("PYTHONPATH")

Expand Down
125 changes: 105 additions & 20 deletions openpype/hosts/flame/plugins/publish/extract_subset_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class ExtractSubsetResources(openpype.api.Extractor):
"ext": "jpg",
"xml_preset_file": "Jpeg (8-bit).xml",
"xml_preset_dir": "",
"export_type": "File Sequence",
"colorspace_out": "Output - sRGB",
"representation_add_range": False,
"representation_tags": ["thumbnail"]
Expand All @@ -30,6 +31,7 @@ class ExtractSubsetResources(openpype.api.Extractor):
"ext": "mov",
"xml_preset_file": "Apple iPad (1920x1080).xml",
"xml_preset_dir": "",
"export_type": "Movie",
"colorspace_out": "Output - Rec.709",
"representation_add_range": True,
"representation_tags": [
Expand All @@ -54,21 +56,35 @@ def process(self, instance):
):
instance.data["representations"] = []

# flame objects
segment = instance.data["item"]
sequence_clip = instance.context.data["flameSequence"]
clip_data = instance.data["flameSourceClip"]
clip = clip_data["PyClip"]

# segment's parent track name
s_track_name = segment.parent.name.get_value()

# get configured workfile frame start/end (handles excluded)
frame_start = instance.data["frameStart"]
handle_start = instance.data["handleStart"]
frame_start_handle = frame_start - handle_start
# get media source first frame
source_first_frame = instance.data["sourceFirstFrame"]
source_start_handles = instance.data["sourceStartH"]
source_end_handles = instance.data["sourceEndH"]
source_duration_handles = (
source_end_handles - source_start_handles) + 1

clip_data = instance.data["flameSourceClip"]
clip = clip_data["PyClip"]
# get timeline in/out of segment
clip_in = instance.data["clipIn"]
clip_out = instance.data["clipOut"]

# get handles value - take only the max from both
handle_start = instance.data["handleStart"]
handle_end = instance.data["handleStart"]
handles = max(handle_start, handle_end)

in_mark = (source_start_handles - source_first_frame) + 1
out_mark = in_mark + source_duration_handles
# get media source range with handles
source_end_handles = instance.data["sourceEndH"]
source_start_handles = instance.data["sourceStartH"]
source_end_handles = instance.data["sourceEndH"]

# create staging dir path
staging_dir = self.staging_dir(instance)

# add default preset type for thumbnail and reviewable video
Expand All @@ -77,15 +93,52 @@ def process(self, instance):
export_presets = deepcopy(self.default_presets)
export_presets.update(self.export_presets_mapping)

# with maintained duplication loop all presets
with opfapi.maintained_object_duplication(clip) as duplclip:
# loop all preset names and
for unique_name, preset_config in export_presets.items():
# loop all preset names and
for unique_name, preset_config in export_presets.items():
modify_xml_data = {}

# get all presets attributes
preset_file = preset_config["xml_preset_file"]
preset_dir = preset_config["xml_preset_dir"]
export_type = preset_config["export_type"]
repre_tags = preset_config["representation_tags"]
color_out = preset_config["colorspace_out"]

# get frame range with handles for representation range
frame_start_handle = frame_start - handle_start
source_duration_handles = (
source_end_handles - source_start_handles) + 1

# define in/out marks
in_mark = (source_start_handles - source_first_frame) + 1
out_mark = in_mark + source_duration_handles

# by default export source clips
exporting_clip = clip

if export_type == "Sequence Publish":
# change export clip to sequence
exporting_clip = sequence_clip

# change in/out marks to timeline in/out
in_mark = clip_in
out_mark = clip_out

# add xml tags modifications
modify_xml_data.update({
"exportHandles": True,
"nbHandles": handles,
"startFrame": frame_start
})

# with maintained duplication loop all presets
with opfapi.maintained_object_duplication(
exporting_clip) as duplclip:
kwargs = {}
preset_file = preset_config["xml_preset_file"]
preset_dir = preset_config["xml_preset_dir"]
repre_tags = preset_config["representation_tags"]
color_out = preset_config["colorspace_out"]

if export_type == "Sequence Publish":
# only keep visible layer where instance segment is child
self.hide_other_tracks(duplclip, s_track_name)

# validate xml preset file is filled
if preset_file == "":
Expand All @@ -108,10 +161,13 @@ def process(self, instance):
)

# create preset path
preset_path = str(os.path.join(
preset_orig_xml_path = str(os.path.join(
preset_dir, preset_file
))

preset_path = opfapi.modify_preset_file(
preset_orig_xml_path, staging_dir, modify_xml_data)

# define kwargs based on preset type
if "thumbnail" in unique_name:
kwargs["thumb_frame_number"] = in_mark + (
Expand All @@ -122,6 +178,7 @@ def process(self, instance):
"out_mark": out_mark
})

# get and make export dir paths
export_dir_path = str(os.path.join(
staging_dir, unique_name
))
Expand All @@ -132,6 +189,7 @@ def process(self, instance):
export_dir_path, duplclip, preset_path, **kwargs)

extension = preset_config["ext"]

# create representation data
representation_data = {
"name": unique_name,
Expand Down Expand Up @@ -159,7 +217,18 @@ def process(self, instance):
# add files to represetation but add
# imagesequence as list
if (
"movie_file" in preset_path
# first check if path in files is not mov extension
next(
# iter all paths in files
# return only .mov positive test
iter([
f for f in files
if ".mov" in os.path.splitext(f)[-1]
]),
# if nothing return default
None
)
jakubjezek001 marked this conversation as resolved.
Show resolved Hide resolved
# then try if thumbnail is not in unique name
or unique_name == "thumbnail"
):
representation_data["files"] = files.pop()
Expand Down Expand Up @@ -246,3 +315,19 @@ def _unfolds_nested_folders(self, stage_dir, files_list, ext):
)

return new_stage_dir, new_files_list

def hide_other_tracks(self, sequence_clip, track_name):
"""Helper method used only if sequence clip is used

Args:
sequence_clip (flame.Clip): sequence clip
track_name (str): track name
"""
# create otio tracks and clips
for ver in sequence_clip.versions:
for track in ver.tracks:
if len(track.segments) == 0 and track.hidden:
continue

if track.name.get_value() != track_name:
track.hidden = True
1 change: 1 addition & 0 deletions openpype/settings/defaults/project_settings/flame.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"ext": "exr",
"xml_preset_file": "OpenEXR (16-bit fp DWAA).xml",
"xml_preset_dir": "",
"export_type": "File Sequence",
"colorspace_out": "ACES - ACEScg",
"representation_add_range": true,
"representation_tags": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@
"label": "XML preset folder (optional)",
"type": "text"
},
{
"key": "export_type",
"label": "Eport clip type",
"type": "enum",
"default": "File Sequence",
"enum_items": [
{
"Movie": "Movie"
},
{
"File Sequence": "File Sequence"
},
{
"Sequence Publish": "Sequence Publish"
}
]

},
{
"key": "colorspace_out",
"label": "Output color (imageio)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@
{
"type": "text",
"key": "colourPolicy",
"label": "Colour Policy"
"label": "Colour Policy (name or path)"
},
{
"type": "text",
Expand Down