feat(hiero): update otio export import

This commit is contained in:
Jakub Jezek 2020-12-04 13:04:33 +01:00
parent 027f19f9f6
commit 7dfc6a56d8
No known key found for this signature in database
GPG key ID: C4B96E101D2A47F3
2 changed files with 83 additions and 49 deletions

View file

@ -49,6 +49,9 @@ class OTIOExportTask(hiero.core.TaskBase):
return str(type(self)) return str(type(self))
def get_rate(self, item): def get_rate(self, item):
if not hasattr(item, 'framerate'):
item = item.sequence()
num, den = item.framerate().toRational() num, den = item.framerate().toRational()
rate = float(num) / float(den) rate = float(num) / float(den)
@ -58,12 +61,12 @@ class OTIOExportTask(hiero.core.TaskBase):
return round(rate, 2) return round(rate, 2)
def get_clip_ranges(self, trackitem): def get_clip_ranges(self, trackitem):
# Is clip an audio file? Use sequence frame rate # Get rate from source or sequence
if not trackitem.source().mediaSource().hasVideo(): if trackitem.source().mediaSource().hasVideo():
rate_item = trackitem.sequence() rate_item = trackitem.source()
else: else:
rate_item = trackitem.source() rate_item = trackitem.sequence()
source_rate = self.get_rate(rate_item) source_rate = self.get_rate(rate_item)
@ -88,9 +91,10 @@ class OTIOExportTask(hiero.core.TaskBase):
duration=source_duration duration=source_duration
) )
available_range = None
hiero_clip = trackitem.source() hiero_clip = trackitem.source()
if not hiero_clip.mediaSource().isOffline():
available_range = None
if hiero_clip.mediaSource().isMediaPresent():
start_time = otio.opentime.RationalTime( start_time = otio.opentime.RationalTime(
hiero_clip.mediaSource().startTime(), hiero_clip.mediaSource().startTime(),
source_rate source_rate
@ -123,7 +127,7 @@ class OTIOExportTask(hiero.core.TaskBase):
def get_marker_color(self, tag): def get_marker_color(self, tag):
icon = tag.icon() icon = tag.icon()
pat = 'icons:Tag(?P<color>\w+)\.\w+' pat = r'icons:Tag(?P<color>\w+)\.\w+'
res = re.search(pat, icon) res = re.search(pat, icon)
if res: if res:
@ -155,13 +159,17 @@ class OTIOExportTask(hiero.core.TaskBase):
) )
) )
metadata = dict(
Hiero=tag.metadata().dict()
)
# Store the source item for future import assignment
metadata['Hiero']['source_type'] = hiero_item.__class__.__name__
marker = otio.schema.Marker( marker = otio.schema.Marker(
name=tag.name(), name=tag.name(),
color=self.get_marker_color(tag), color=self.get_marker_color(tag),
marked_range=marked_range, marked_range=marked_range,
metadata={ metadata=metadata
'Hiero': tag.metadata().dict()
}
) )
otio_item.markers.append(marker) otio_item.markers.append(marker)
@ -170,37 +178,44 @@ class OTIOExportTask(hiero.core.TaskBase):
hiero_clip = trackitem.source() hiero_clip = trackitem.source()
# Add Gap if needed # Add Gap if needed
prev_item = ( if itemindex == 0:
itemindex and trackitem.parent().items()[itemindex - 1] or prev_item = trackitem
trackitem
)
if prev_item == trackitem and trackitem.timelineIn() > 0: else:
prev_item = trackitem.parent().items()[itemindex - 1]
clip_diff = trackitem.timelineIn() - prev_item.timelineOut()
if itemindex == 0 and trackitem.timelineIn() > 0:
self.add_gap(trackitem, otio_track, 0) self.add_gap(trackitem, otio_track, 0)
elif ( elif itemindex and clip_diff != 1:
prev_item != trackitem and
prev_item.timelineOut() != trackitem.timelineIn()
):
self.add_gap(trackitem, otio_track, prev_item.timelineOut()) self.add_gap(trackitem, otio_track, prev_item.timelineOut())
# Create Clip # Create Clip
source_range, available_range = self.get_clip_ranges(trackitem) source_range, available_range = self.get_clip_ranges(trackitem)
otio_clip = otio.schema.Clip() otio_clip = otio.schema.Clip(
otio_clip.name = trackitem.name() name=trackitem.name(),
otio_clip.source_range = source_range source_range=source_range
)
# Add media reference # Add media reference
media_reference = otio.schema.MissingReference() media_reference = otio.schema.MissingReference()
if not hiero_clip.mediaSource().isOffline(): if hiero_clip.mediaSource().isMediaPresent():
source = hiero_clip.mediaSource() source = hiero_clip.mediaSource()
media_reference = otio.schema.ExternalReference() first_file = source.fileinfos()[0]
media_reference.available_range = available_range path = first_file.filename()
path, name = os.path.split(source.fileinfos()[0].filename()) if "%" in path:
media_reference.target_url = os.path.join(path, name) path = re.sub(r"%\d+d", "%d", path)
media_reference.name = name if "#" in path:
path = re.sub(r"#+", "%d", path)
media_reference = otio.schema.ExternalReference(
target_url=u'{}'.format(path),
available_range=available_range
)
otio_clip.media_reference = media_reference otio_clip.media_reference = media_reference
@ -218,6 +233,7 @@ class OTIOExportTask(hiero.core.TaskBase):
# Add tags as markers # Add tags as markers
if self._preset.properties()["includeTags"]: if self._preset.properties()["includeTags"]:
self.add_markers(trackitem, otio_clip)
self.add_markers(trackitem.source(), otio_clip) self.add_markers(trackitem.source(), otio_clip)
otio_track.append(otio_clip) otio_track.append(otio_clip)
@ -273,16 +289,16 @@ class OTIOExportTask(hiero.core.TaskBase):
name=alignment, # Consider placing Hiero name in metadata name=alignment, # Consider placing Hiero name in metadata
transition_type=otio.schema.TransitionTypes.SMPTE_Dissolve, transition_type=otio.schema.TransitionTypes.SMPTE_Dissolve,
in_offset=in_time, in_offset=in_time,
out_offset=out_time, out_offset=out_time
metadata={}
) )
if alignment == 'kFadeIn': if alignment == 'kFadeIn':
otio_track.insert(-2, otio_transition) otio_track.insert(-1, otio_transition)
else: else:
otio_track.append(otio_transition) otio_track.append(otio_transition)
def add_tracks(self): def add_tracks(self):
for track in self._sequence.items(): for track in self._sequence.items():
if isinstance(track, hiero.core.AudioTrack): if isinstance(track, hiero.core.AudioTrack):
@ -291,8 +307,7 @@ class OTIOExportTask(hiero.core.TaskBase):
else: else:
kind = otio.schema.TrackKind.Video kind = otio.schema.TrackKind.Video
otio_track = otio.schema.Track(kind=kind) otio_track = otio.schema.Track(name=track.name(), kind=kind)
otio_track.name = track.name()
for itemindex, trackitem in enumerate(track): for itemindex, trackitem in enumerate(track):
if isinstance(trackitem.source(), hiero.core.Clip): if isinstance(trackitem.source(), hiero.core.Clip):
@ -306,6 +321,12 @@ class OTIOExportTask(hiero.core.TaskBase):
def create_OTIO(self): def create_OTIO(self):
self.otio_timeline = otio.schema.Timeline() self.otio_timeline = otio.schema.Timeline()
# Set global start time based on sequence
self.otio_timeline.global_start_time = otio.opentime.RationalTime(
self._sequence.timecodeStart(),
self._sequence.framerate().toFloat()
)
self.otio_timeline.name = self._sequence.name() self.otio_timeline.name = self._sequence.name()
self.add_tracks() self.add_tracks()

View file

@ -356,19 +356,38 @@ def create_trackitem(playhead, track, otio_clip, clip, tagsbin):
return trackitem return trackitem
def build_sequence(otio_timeline, project=None, track_kind=None): def build_sequence(
otio_timeline, project=None, sequence=None, track_kind=None):
if project is None: if project is None:
# TODO: Find a proper way for active project if sequence:
project = hiero.core.projects(hiero.core.Project.kUserProjects)[-1] project = sequence.project()
# Create a Sequence else:
sequence = hiero.core.Sequence(otio_timeline.name or 'OTIOSequence') # Per version 12.1v2 there is no way of getting active project
project = hiero.core.projects(hiero.core.Project.kUserProjects)[-1]
# Create a Bin to hold clips
projectbin = project.clipsBin() projectbin = project.clipsBin()
projectbin.addItem(hiero.core.BinItem(sequence))
sequencebin = hiero.core.Bin(sequence.name()) if not sequence:
projectbin.addItem(sequencebin) # Create a Sequence
sequence = hiero.core.Sequence(otio_timeline.name or 'OTIOSequence')
# Set sequence settings from otio timeline if available
if hasattr(otio_timeline, 'global_start_time'):
if otio_timeline.global_start_time:
start_time = otio_timeline.global_start_time
sequence.setFramerate(start_time.rate)
sequence.setTimecodeStart(start_time.value)
# Create a Bin to hold clips
projectbin.addItem(hiero.core.BinItem(sequence))
sequencebin = hiero.core.Bin(sequence.name())
projectbin.addItem(sequencebin)
else:
sequencebin = projectbin
# Get tagsBin # Get tagsBin
tagsbin = hiero.core.project("Tag Presets").tagsBin() tagsbin = hiero.core.project("Tag Presets").tagsBin()
@ -376,17 +395,11 @@ def build_sequence(otio_timeline, project=None, track_kind=None):
# Add timeline markers # Add timeline markers
add_markers(otio_timeline, sequence, tagsbin) add_markers(otio_timeline, sequence, tagsbin)
# add sequence attributes form otio timeline
if otio_timeline.global_start_time:
sequence.setFramerate(otio_timeline.global_start_time.rate)
sequence.setTimecodeStart(otio_timeline.global_start_time.value)
if isinstance(otio_timeline, otio.schema.Timeline): if isinstance(otio_timeline, otio.schema.Timeline):
tracks = otio_timeline.tracks tracks = otio_timeline.tracks
else: else:
# otio.schema.Stack tracks = [otio_timeline]
tracks = otio_timeline
for tracknum, otio_track in enumerate(tracks): for tracknum, otio_track in enumerate(tracks):
playhead = 0 playhead = 0