Skip to content

Commit

Permalink
Merge pull request #916 from ynput/bugfix/#895_fix_extract_otio_review
Browse files Browse the repository at this point in the history
Fix extract_otio_review extraction logic for corner-case media
  • Loading branch information
iLLiCiTiT authored Oct 2, 2024
2 parents 8182914 + abd0e7d commit 1072fc9
Show file tree
Hide file tree
Showing 8 changed files with 2,279 additions and 105 deletions.
97 changes: 83 additions & 14 deletions client/ayon_core/pipeline/editorial.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def trim_media_range(media_range, source_range):
"""
rw_media_start = _ot.RationalTime(
media_range.start_time.value + source_range.start_time.value,
source_range.start_time.value,
media_range.start_time.rate
)
rw_media_duration = _ot.RationalTime(
Expand Down Expand Up @@ -173,6 +173,80 @@ def _sequence_resize(source, length):
yield (1 - ratio) * source[int(low)] + ratio * source[int(high)]


def is_clip_from_media_sequence(otio_clip):
"""
Args:
otio_clip (otio.schema.Clip): The OTIO clip to check.
Returns:
bool. Is the provided clip from an input media sequence ?
"""
media_ref = otio_clip.media_reference
metadata = media_ref.metadata

# OpenTimelineIO 0.13 and newer
is_input_sequence = (
hasattr(otio.schema, "ImageSequenceReference") and
isinstance(media_ref, otio.schema.ImageSequenceReference)
)

# OpenTimelineIO 0.12 and older
is_input_sequence_legacy = bool(metadata.get("padding"))

return is_input_sequence or is_input_sequence_legacy


def remap_range_on_file_sequence(otio_clip, in_out_range):
"""
Args:
otio_clip (otio.schema.Clip): The OTIO clip to check.
in_out_range (tuple[float, float]): The in-out range to remap.
Returns:
tuple(int, int): The remapped range as discrete frame number.
Raises:
ValueError. When the otio_clip or provided range is invalid.
"""
if not is_clip_from_media_sequence(otio_clip):
raise ValueError(f"Cannot map on non-file sequence clip {otio_clip}.")

try:
media_in_trimmed, media_out_trimmed = in_out_range

except ValueError as error:
raise ValueError("Invalid in_out_range provided.") from error

media_ref = otio_clip.media_reference
available_range = otio_clip.available_range()
source_range = otio_clip.source_range
available_range_rate = available_range.start_time.rate
media_in = available_range.start_time.value

# Temporary.
# Some AYON custom OTIO exporter were implemented with relative
# source range for image sequence. Following code maintain
# backward-compatibility by adjusting media_in
# while we are updating those.
if (
is_clip_from_media_sequence(otio_clip)
and otio_clip.available_range().start_time.to_frames() == media_ref.start_frame
and source_range.start_time.to_frames() < media_ref.start_frame
):
media_in = 0

frame_in = otio.opentime.RationalTime.from_frames(
media_in_trimmed - media_in + media_ref.start_frame,
rate=available_range_rate,
).to_frames()
frame_out = otio.opentime.RationalTime.from_frames(
media_out_trimmed - media_in + media_ref.start_frame,
rate=available_range_rate,
).to_frames()

return frame_in, frame_out


def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
source_range = otio_clip.source_range
available_range = otio_clip.available_range()
Expand All @@ -182,10 +256,7 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
# mediaIn/mediaOut have to correspond
# to frame numbers from source sequence.
media_ref = otio_clip.media_reference
is_input_sequence = (
hasattr(otio.schema, "ImageSequenceReference")
and isinstance(media_ref, otio.schema.ImageSequenceReference)
)
is_input_sequence = is_clip_from_media_sequence(otio_clip)

# Temporary.
# Some AYON custom OTIO exporter were implemented with relative
Expand Down Expand Up @@ -296,17 +367,15 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
media_in = available_range.start_time.value
media_out = available_range.end_time_inclusive().value

# If media source is an image sequence, returned
# mediaIn/mediaOut have to correspond
# to frame numbers from source sequence.
if is_input_sequence:
# preserve discrete frame numbers
media_in_trimmed = otio.opentime.RationalTime.from_frames(
media_in_trimmed - media_in + media_ref.start_frame,
rate=available_range_rate,
).to_frames()
media_out_trimmed = otio.opentime.RationalTime.from_frames(
media_out_trimmed - media_in + media_ref.start_frame,
rate=available_range_rate,
).to_frames()

media_in_trimmed, media_out_trimmed = remap_range_on_file_sequence(
otio_clip,
(media_in_trimmed, media_out_trimmed)
)
media_in = media_ref.start_frame
media_out = media_in + available_range.duration.to_frames() - 1

Expand Down
Loading

0 comments on commit 1072fc9

Please sign in to comment.