This repository has been archived by the owner on Sep 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1172 from tokejepsen/2.x/feature/hiero_frame_publish
- Loading branch information
Showing
6 changed files
with
187 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import json | ||
|
||
import hiero | ||
|
||
from pyblish import api | ||
|
||
|
||
class CollectFrames(api.ContextPlugin): | ||
"""Collect frames from tags. | ||
Tag is expected to have metadata: | ||
{ | ||
"family": "frame" | ||
"subset": "main" | ||
} | ||
""" | ||
|
||
order = api.CollectorOrder | ||
label = "Collect Frames" | ||
hosts = ["hiero"] | ||
|
||
def process(self, context): | ||
sequence = hiero.ui.activeSequence() | ||
|
||
publish_frames = range( | ||
int(sequence.timecodeStart()), | ||
int(sequence.duration() + sequence.timecodeStart()) | ||
) | ||
selection = hiero.selection | ||
if selection: | ||
publish_frames = [] | ||
for track_item in selection: | ||
publish_frames.extend( | ||
range(track_item.timelineIn(), track_item.timelineOut()) | ||
) | ||
|
||
publish_frames = list(set(publish_frames)) | ||
|
||
subset_data = {} | ||
for tag in sequence.tags(): | ||
metadata = tag.metadata().dict() | ||
if "tag.family" not in metadata: | ||
continue | ||
if metadata["tag.family"] != "frame": | ||
continue | ||
|
||
frame = int(metadata["tag.start"]) | ||
|
||
if frame not in publish_frames: | ||
continue | ||
|
||
subset = metadata["tag.subset"] | ||
try: | ||
subset_data[subset]["frames"].append(frame) | ||
except KeyError: | ||
subset_data[subset] = { | ||
"frames": [frame], "format": metadata["tag.format"] | ||
} | ||
|
||
for subset_name, subset_data in subset_data.items(): | ||
name = "frame" + subset_name.title() | ||
data = { | ||
"name": name, | ||
"label": "{} {}".format(name, subset_data["frames"]), | ||
"family": "image", | ||
"families": ["frame"], | ||
"asset": context.data["assetEntity"]["name"], | ||
"subset": subset_name, | ||
"format": subset_data["format"], | ||
"frames": subset_data["frames"] | ||
} | ||
context.create_instance(**data) | ||
self.log.info( | ||
"Created instance: {}".format( | ||
json.dumps(data, sort_keys=True, indent=4) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import os | ||
|
||
import hiero | ||
|
||
from pyblish import api | ||
|
||
import pype | ||
|
||
|
||
class ExtractFrames(pype.api.Extractor): | ||
"""Extracts frames""" | ||
|
||
order = api.ExtractorOrder | ||
label = "Extract Frames" | ||
hosts = ["hiero"] | ||
families = ["frame"] | ||
movie_extensions = ["mov"] | ||
|
||
def process(self, instance): | ||
staging_dir = self.staging_dir(instance) | ||
output_template = os.path.join(staging_dir, instance.data["name"]) | ||
sequence = hiero.ui.activeSequence() | ||
files = [] | ||
for frame in instance.data["frames"]: | ||
track_item = sequence.trackItemAt(frame) | ||
media_source = track_item.source().mediaSource() | ||
input_path = media_source.fileinfos()[0].filename() | ||
input_frame = ( | ||
track_item.mapTimelineToSource(frame) + | ||
track_item.source().mediaSource().startTime() | ||
) | ||
format = instance.data["format"] | ||
output_path = output_template | ||
output_path += ".{:04d}.{}".format(int(frame), format) | ||
|
||
args = ["oiiotool"] | ||
|
||
ext = os.path.splitext(input_path)[1][1:] | ||
if ext in self.movie_extensions: | ||
args.extend(["--subimage", str(int(input_frame))]) | ||
else: | ||
args.extend(["--frames", str(int(input_frame))]) | ||
|
||
if ext == "exr": | ||
args.extend(["--powc", "0.45,0.45,0.45,1.0"]) | ||
|
||
args.extend([input_path, "-o", output_path]) | ||
output = pype.api.subprocess(args) | ||
|
||
failed_output = "oiiotool produced no output." | ||
if failed_output in output: | ||
raise ValueError( | ||
"oiiotool processing failed. Args: {}".format(args) | ||
) | ||
|
||
files.append(output_path) | ||
|
||
# Feedback to user because "oiiotool" can make the publishing | ||
# appear unresponsive. | ||
self.log.info( | ||
"Processed {} of {} frames".format( | ||
instance.data["frames"].index(frame) + 1, | ||
len(instance.data["frames"]) | ||
) | ||
) | ||
|
||
if len(files) == 1: | ||
instance.data["representations"] = [ | ||
{ | ||
"name": format, | ||
"ext": format, | ||
"files": os.path.basename(files[0]), | ||
"stagingDir": staging_dir | ||
} | ||
] | ||
else: | ||
instance.data["representations"] = [ | ||
{ | ||
"name": format, | ||
"ext": format, | ||
"files": [os.path.basename(x) for x in files], | ||
"stagingDir": staging_dir | ||
} | ||
] |