feat(global, resolve): otio publishing wip

This commit is contained in:
Jakub Jezek 2020-12-07 17:10:03 +01:00
parent cf89dbab48
commit f7f7b657bb
No known key found for this signature in database
GPG key ID: C4B96E101D2A47F3
6 changed files with 121 additions and 56 deletions

View file

@ -665,9 +665,11 @@ def get_otio_clip_instance_data(track_item_data):
track_item = track_item_data["clip"]["item"]
project = track_item_data["project"]
timeline = track_item_data["sequence"]
timeline_start = timeline.GetStartFrame()
frame_start = track_item.GetStart()
frame_duration = track_item.GetDuration()
frame_start = int(track_item.GetStart() - timeline_start)
frame_duration = int(track_item.GetDuration())
self.project_fps = project.GetSetting("timelineFrameRate")
otio_clip_range = otio_export.create_otio_time_range(

View file

@ -26,9 +26,17 @@ def create_otio_time_range(start_frame, frame_duration, fps):
def create_otio_reference(media_pool_item):
metadata = dict()
mp_clip_property = media_pool_item.GetClipProperty()
path = mp_clip_property["File Path"]
reformat_path = utils.get_reformated_path(path, padded=False)
padding = utils.get_padding_from_path(path)
if padding:
metadata.update({
"isSequence": True,
"padding": padding
})
# get clip property regarding to type
mp_clip_property = media_pool_item.GetClipProperty()
@ -42,7 +50,7 @@ def create_otio_reference(media_pool_item):
frame_duration = int(utils.timecode_to_frames(
audio_duration, float(fps)))
return otio.schema.ExternalReference(
otio_ex_ref_item = otio.schema.ExternalReference(
target_url=reformat_path,
available_range=create_otio_time_range(
frame_start,
@ -51,6 +59,11 @@ def create_otio_reference(media_pool_item):
)
)
# add metadata to otio item
add_otio_metadata(otio_ex_ref_item, media_pool_item, **metadata)
return otio_ex_ref_item
def create_otio_markers(track_item, fps):
track_item_markers = track_item.GetMarkers()
@ -85,7 +98,7 @@ def create_otio_clip(track_item):
else:
fps = self.project_fps
name = utils.get_reformated_path(track_item.GetName())
name = track_item.GetName()
media_reference = create_otio_reference(media_pool_item)
source_range = create_otio_time_range(
@ -160,6 +173,17 @@ def add_otio_gap(clip_start, otio_track, track_item, timeline):
)
def add_otio_metadata(otio_item, media_pool_item, **kwargs):
mp_metadata = media_pool_item.GetMetadata()
# add additional metadata from kwargs
if kwargs:
mp_metadata.update(kwargs)
# add metadata to otio item metadata
for key, value in mp_metadata.items():
otio_item.metadata.update({key: value})
def create_otio_timeline(timeline, fps):
# get current timeline
self.project_fps = fps

View file

@ -35,3 +35,24 @@ def get_reformated_path(path, padded=True):
else:
path = re.sub(num_pattern, f"%d", path)
return path
def get_padding_from_path(path):
"""
Return padding number from DaVinci Resolve sequence path style
Args:
path (str): path url or simple file name
Returns:
int: padding number
Example:
get_padding_from_path("plate.[0001-1008].exr") > 4
"""
padding_pattern = "(\\d+)(?=-)"
if "[" in path:
return len(re.findall(padding_pattern, path).pop())
return None

View file

@ -46,6 +46,11 @@ from .ffmpeg_utils import (
ffprobe_streams
)
from .editorial import (
is_overlapping,
convert_otio_range_to_frame_range
)
__all__ = [
"get_avalon_database",
"set_io_database",
@ -81,5 +86,8 @@ __all__ = [
"get_ffmpeg_tool_path",
"source_hash",
"_subprocess"
"_subprocess",
"is_overlapping",
"convert_otio_range_to_frame_range"
]

36
pype/lib/editorial.py Normal file
View file

@ -0,0 +1,36 @@
from opentimelineio.opentime import to_frames
def convert_otio_range_to_frame_range(otio_range):
start = to_frames(
otio_range.start_time, otio_range.start_time.rate)
end = start + to_frames(
otio_range.duration, otio_range.duration.rate) - 1
return start, end
def is_overlapping(test_range, main_range, strict=False):
test_start, test_end = convert_otio_range_to_frame_range(test_range)
main_start, main_end = convert_otio_range_to_frame_range(main_range)
covering_exp = bool(
(test_start <= main_start) and (test_end >= main_end)
)
inside_exp = bool(
(test_start >= main_start) and (test_end <= main_end)
)
overlaying_right_exp = bool(
(test_start < main_end) and (test_end >= main_end)
)
overlaying_left_exp = bool(
(test_end > main_start) and (test_start <= main_start)
)
if not strict:
return any((
covering_exp,
inside_exp,
overlaying_right_exp,
overlaying_left_exp
))
else:
return covering_exp

View file

@ -3,12 +3,14 @@ Requires:
otioTimeline -> context data attribute
review -> instance data attribute
masterLayer -> instance data attribute
otioClip -> instance data attribute
otioClipRange -> instance data attribute
"""
import opentimelineio as otio
from opentimelineio.opentime import to_frames
import pyblish.api
from pype.lib import (
is_overlapping,
convert_otio_range_to_frame_range
)
class CollectOcioReview(pyblish.api.InstancePlugin):
@ -23,64 +25,36 @@ class CollectOcioReview(pyblish.api.InstancePlugin):
# get basic variables
review_track_name = instance.data["review"]
master_layer = instance.data["masterLayer"]
otio_timeline_context = instance.context.data.get("otioTimeline")
otio_clip = instance.data["otioClip"]
otio_timeline_context = instance.context.data["otioTimeline"]
otio_clip_range = instance.data["otioClipRange"]
# skip if master layer is False
if not master_layer:
return
# get timeline time values
start_time = otio_timeline_context.global_start_time
timeline_fps = start_time.rate
playhead = start_time.value
frame_start = to_frames(
otio_clip_range.start_time, timeline_fps)
frame_duration = to_frames(
otio_clip_range.duration, timeline_fps)
self.log.debug(
("name: {} | "
"timeline_in: {} | timeline_out: {}").format(
otio_clip.name, frame_start,
(frame_start + frame_duration - 1)))
orwc_fps = timeline_fps
for otio_clip in otio_timeline_context.each_clip():
track_name = otio_clip.parent().name
parent_range = otio_clip.range_in_parent()
if track_name not in review_track_name:
continue
if isinstance(otio_clip, otio.schema.Clip):
orwc_source_range = otio_clip.source_range
orwc_fps = orwc_source_range.start_time.rate
orwc_start = to_frames(orwc_source_range.start_time, orwc_fps)
orwc_duration = to_frames(orwc_source_range.duration, orwc_fps)
source_in = orwc_start
source_out = (orwc_start + orwc_duration) - 1
timeline_in = playhead
timeline_out = (timeline_in + orwc_duration) - 1
self.log.debug(
("name: {} | source_in: {} | source_out: {} | "
"timeline_in: {} | timeline_out: {} "
"| orwc_fps: {}").format(
otio_clip.name, source_in, source_out,
timeline_in, timeline_out, orwc_fps))
if is_overlapping(parent_range, otio_clip_range, strict=False):
self.create_representation(
otio_clip, otio_clip_range, instance)
# move plyhead to next available frame
playhead = timeline_out + 1
elif isinstance(otio_clip, otio.schema.Gap):
gap_source_range = otio_clip.source_range
gap_fps = gap_source_range.start_time.rate
gap_start = to_frames(
gap_source_range.start_time, gap_fps)
gap_duration = to_frames(
gap_source_range.duration, gap_fps)
if gap_fps != orwc_fps:
gap_duration += 1
self.log.debug(
("name: Gap | gap_start: {} | gap_fps: {}"
"| gap_duration: {} | timeline_fps: {}").format(
gap_start, gap_fps, gap_duration, timeline_fps))
playhead += gap_duration
def create_representation(self, otio_clip, to_otio_range, instance):
to_timeline_start, to_timeline_end = convert_otio_range_to_frame_range(
to_otio_range)
timeline_start, timeline_end = convert_otio_range_to_frame_range(
otio_clip.range_in_parent())
source_start, source_end = convert_otio_range_to_frame_range(
otio_clip.source_range)
media_reference = otio_clip.media_reference
available_start, available_end = convert_otio_range_to_frame_range(
media_reference.available_range)
path = media_reference.target_url
self.log.debug(path)
self.log.debug((available_start, available_end))
self.log.debug((source_start, source_end))
self.log.debug((timeline_start, timeline_end))
self.log.debug((to_timeline_start, to_timeline_end))