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 #3685 from pypeclub/feature/OP-2356_ftrack-enhance…
Browse files Browse the repository at this point in the history
…-component-metadata

Ftrack: Addiotional component metadata
  • Loading branch information
iLLiCiTiT authored Aug 18, 2022
2 parents e0a31da + da3268c commit ba9b82d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 47 deletions.
126 changes: 81 additions & 45 deletions openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import copy
import pyblish.api

from openpype.lib.openpype_version import get_openpype_version
from openpype.lib.transcoding import (
get_ffprobe_streams,
convert_ffprobe_fps_to_float,
Expand All @@ -20,6 +21,17 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin):
label = "Integrate Ftrack Component"
families = ["ftrack"]

metadata_keys_to_label = {
"openpype_version": "OpenPype version",
"frame_start": "Frame start",
"frame_end": "Frame end",
"duration": "Duration",
"width": "Resolution width",
"height": "Resolution height",
"fps": "FPS",
"codec": "Codec"
}

family_mapping = {
"camera": "cam",
"look": "look",
Expand All @@ -43,6 +55,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin):
}
keep_first_subset_name_for_review = True
asset_versions_status_profiles = {}
additional_metadata_keys = []

def process(self, instance):
self.log.debug("instance {}".format(instance))
Expand Down Expand Up @@ -105,7 +118,8 @@ def process(self, instance):
"component_data": None,
"component_path": None,
"component_location": None,
"component_location_name": None
"component_location_name": None,
"additional_data": {}
}

# Filter types of representations
Expand Down Expand Up @@ -152,6 +166,7 @@ def process(self, instance):
"name": "thumbnail"
}
thumbnail_item["thumbnail"] = True

# Create copy of item before setting location
src_components_to_add.append(copy.deepcopy(thumbnail_item))
# Create copy of first thumbnail
Expand Down Expand Up @@ -248,19 +263,15 @@ def process(self, instance):
first_thumbnail_component[
"asset_data"]["name"] = extended_asset_name

component_meta = self._prepare_component_metadata(
instance, repre, repre_path, True
)

# Change location
review_item["component_path"] = repre_path
# Change component data
review_item["component_data"] = {
# Default component name is "main".
"name": "ftrackreview-mp4",
"metadata": {
"ftr_meta": json.dumps(component_meta)
}
"metadata": self._prepare_component_metadata(
instance, repre, repre_path, True
)
}

if is_first_review_repre:
Expand Down Expand Up @@ -302,13 +313,9 @@ def process(self, instance):
component_data = copy_src_item["component_data"]
component_name = component_data["name"]
component_data["name"] = component_name + "_src"
component_meta = self._prepare_component_metadata(
component_data["metadata"] = self._prepare_component_metadata(
instance, repre, copy_src_item["component_path"], False
)
if component_meta:
component_data["metadata"] = {
"ftr_meta": json.dumps(component_meta)
}
component_list.append(copy_src_item)

# Add others representations as component
Expand All @@ -326,16 +333,12 @@ def process(self, instance):
):
other_item["asset_data"]["name"] = extended_asset_name

component_meta = self._prepare_component_metadata(
instance, repre, published_path, False
)
component_data = {
"name": repre["name"]
"name": repre["name"],
"metadata": self._prepare_component_metadata(
instance, repre, published_path, False
)
}
if component_meta:
component_data["metadata"] = {
"ftr_meta": json.dumps(component_meta)
}
other_item["component_data"] = component_data
other_item["component_location_name"] = unmanaged_location_name
other_item["component_path"] = published_path
Expand All @@ -354,6 +357,9 @@ def json_obj_parser(obj):
))
instance.data["ftrackComponentsList"] = component_list

def _collect_additional_metadata(self, streams):
pass

def _get_repre_path(self, instance, repre, only_published):
"""Get representation path that can be used for integration.
Expand Down Expand Up @@ -423,6 +429,11 @@ def _get_asset_version_status_name(self, instance):
def _prepare_component_metadata(
self, instance, repre, component_path, is_review
):
metadata = {}
if "openpype_version" in self.additional_metadata_keys:
label = self.metadata_keys_to_label["openpype_version"]
metadata[label] = get_openpype_version()

extension = os.path.splitext(component_path)[-1]
streams = []
try:
Expand All @@ -442,22 +453,32 @@ def _prepare_component_metadata(
# - exr is special case which can have issues with reading through
# ffmpegh but we want to set fps for it
if not video_streams and extension not in [".exr"]:
return {}
return metadata

stream_width = None
stream_height = None
stream_fps = None
frame_out = None
codec_label = None
for video_stream in video_streams:
codec_label = video_stream.get("codec_long_name")
if not codec_label:
codec_label = video_stream.get("codec")

if codec_label:
pix_fmt = video_stream.get("pix_fmt")
if pix_fmt:
codec_label += " ({})".format(pix_fmt)

tmp_width = video_stream.get("width")
tmp_height = video_stream.get("height")
if tmp_width and tmp_height:
stream_width = tmp_width
stream_height = tmp_height

input_framerate = video_stream.get("r_frame_rate")
duration = video_stream.get("duration")
if input_framerate is None or duration is None:
stream_duration = video_stream.get("duration")
if input_framerate is None or stream_duration is None:
continue
try:
stream_fps = convert_ffprobe_fps_to_float(
Expand All @@ -473,53 +494,68 @@ def _prepare_component_metadata(
stream_height = tmp_height

self.log.debug("FPS from stream is {} and duration is {}".format(
input_framerate, duration
input_framerate, stream_duration
))
frame_out = float(duration) * stream_fps
frame_out = float(stream_duration) * stream_fps
break

# Prepare FPS
instance_fps = instance.data.get("fps")
if instance_fps is None:
instance_fps = instance.context.data["fps"]

if not is_review:
output = {}
fps = stream_fps or instance_fps
if fps:
output["frameRate"] = fps
repre_fps = repre.get("fps")
if repre_fps is not None:
repre_fps = float(repre_fps)

if stream_width and stream_height:
output["width"] = int(stream_width)
output["height"] = int(stream_height)
return output
fps = stream_fps or repre_fps or instance_fps

# Prepare frame ranges
frame_start = repre.get("frameStartFtrack")
frame_end = repre.get("frameEndFtrack")
if frame_start is None or frame_end is None:
frame_start = instance.data["frameStart"]
frame_end = instance.data["frameEnd"]
duration = (frame_end - frame_start) + 1

for key, value in [
("fps", fps),
("frame_start", frame_start),
("frame_end", frame_end),
("duration", duration),
("width", stream_width),
("height", stream_height),
("fps", fps),
("codec", codec_label)
]:
if not value or key not in self.additional_metadata_keys:
continue
label = self.metadata_keys_to_label[key]
metadata[label] = value

fps = None
repre_fps = repre.get("fps")
if repre_fps is not None:
repre_fps = float(repre_fps)
if not is_review:
ftr_meta = {}
if fps:
ftr_meta["frameRate"] = fps

fps = stream_fps or repre_fps or instance_fps
if stream_width and stream_height:
ftr_meta["width"] = int(stream_width)
ftr_meta["height"] = int(stream_height)
metadata["ftr_meta"] = json.dumps(ftr_meta)
return metadata

# Frame end of uploaded video file should be duration in frames
# - frame start is always 0
# - frame end is duration in frames
if not frame_out:
frame_out = frame_end - frame_start + 1
frame_out = duration

# Ftrack documentation says that it is required to have
# 'width' and 'height' in review component. But with those values
# review video does not play.
component_meta = {
metadata["ftr_meta"] = json.dumps({
"frameIn": 0,
"frameOut": frame_out,
"frameRate": float(fps)
}

return component_meta
})
return metadata
3 changes: 2 additions & 1 deletion openpype/settings/defaults/project_settings/ftrack.json
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,8 @@
"usd": "usd"
},
"keep_first_subset_name_for_review": true,
"asset_versions_status_profiles": []
"asset_versions_status_profiles": [],
"additional_metadata_keys": []
},
"IntegrateFtrackFarmStatus": {
"farm_status_profiles": []
Expand Down
2 changes: 1 addition & 1 deletion openpype/settings/defaults/project_settings/shotgrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@
"step": "step"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,22 @@
}
]
}
},
{
"key": "additional_metadata_keys",
"label": "Additional metadata keys on components",
"type": "enum",
"multiselection": true,
"enum_items": [
{"openpype_version": "OpenPype version"},
{"frame_start": "Frame start"},
{"frame_end": "Frame end"},
{"duration": "Duration"},
{"width": "Resolution width"},
{"height": "Resolution height"},
{"fps": "FPS"},
{"code": "Codec"}
]
}
]
},
Expand Down

0 comments on commit ba9b82d

Please sign in to comment.