mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 13:24:54 +01:00
feat(global, resolve): otio publishing wip
This commit is contained in:
parent
cf89dbab48
commit
f7f7b657bb
6 changed files with 121 additions and 56 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
36
pype/lib/editorial.py
Normal 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
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue