import os import re import clique from .import_utils import discover_host_vendor_module try: from opentimelineio import opentime as _ot except ImportError: _ot = discover_host_vendor_module("opentimelineio.opentime") def otio_range_to_frame_range(otio_range): start = _ot.to_frames( otio_range.start_time, otio_range.start_time.rate) end = start + _ot.to_frames( otio_range.duration, otio_range.duration.rate) - 1 return start, end def otio_range_with_handles(otio_range, instance): handle_start = instance.data["handleStart"] handle_end = instance.data["handleEnd"] handles_duration = handle_start + handle_end fps = float(otio_range.start_time.rate) start = _ot.to_frames(otio_range.start_time, fps) duration = _ot.to_frames(otio_range.duration, fps) return _ot.TimeRange( start_time=_ot.RationalTime((start - handle_start), fps), duration=_ot.RationalTime((duration + handles_duration), fps) ) def is_overlapping_otio_ranges(test_otio_range, main_otio_range, strict=False): test_start, test_end = otio_range_to_frame_range(test_otio_range) main_start, main_end = otio_range_to_frame_range(main_otio_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 def convert_to_padded_path(path, padding): """ Return correct padding in sequence string Args: path (str): path url or simple file name padding (int): number of padding Returns: type: string with reformated path Example: convert_to_padded_path("plate.%d.exr") > plate.%04d.exr """ if "%d" in path: path = re.sub("%d", "%0{padding}d".format(padding=padding), path) return path def trim_media_range(media_range, source_range): """ Trim input media range with clip source range. Args: media_range (otio._ot._ot.TimeRange): available range of media source_range (otio._ot._ot.TimeRange): clip required range Returns: otio._ot._ot.TimeRange: trimmed media range """ rw_media_start = _ot.RationalTime( media_range.start_time.value + source_range.start_time.value, media_range.start_time.rate ) rw_media_duration = _ot.RationalTime( source_range.duration.value, media_range.duration.rate ) return _ot.TimeRange( rw_media_start, rw_media_duration) def range_from_frames(start, duration, fps): """ Returns otio time range. Args: start (int): frame start duration (int): frame duration fps (float): frame range Returns: otio._ot._ot.TimeRange: crated range """ return _ot.TimeRange( _ot.RationalTime(start, fps), _ot.RationalTime(duration, fps) ) def frames_to_secons(frames, framerate): """ Returning secons. Args: frames (int): frame framerate (flaot): frame rate Returns: float: second value """ rt = _ot.from_frames(frames, framerate) return _ot.to_seconds(rt) def make_sequence_collection(path, otio_range, metadata): """ Make collection from path otio range and otio metadata. Args: path (str): path to image sequence with `%d` otio_range (otio._ot._ot.TimeRange): range to be used metadata (dict): data where padding value can be found Returns: list: dir_path (str): path to sequence, collection object """ if "%" not in path: return None file_name = os.path.basename(path) dir_path = os.path.dirname(path) head = file_name.split("%")[0] tail = os.path.splitext(file_name)[-1] first, last = otio_range_to_frame_range(otio_range) collection = clique.Collection( head=head, tail=tail, padding=metadata["padding"]) collection.indexes.update([i for i in range(first, (last + 1))]) return dir_path, collection