Skip to content

editorial

convert_to_padded_path(path, padding)

Return correct padding in sequence string

Parameters:

Name Type Description Default
path str

path url or simple file name

required
padding int

number of padding

required

Returns:

Name Type Description
type

string with reformatted path

Example

convert_to_padded_path("plate.%d.exr") > plate.%04d.exr

Source code in client/ayon_core/pipeline/editorial.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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 reformatted 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

frames_to_seconds(frames, framerate)

Returning seconds.

Parameters:

Name Type Description Default
frames int

frame

required
framerate float

frame rate

required

Returns:

Name Type Description
float

second value

Source code in client/ayon_core/pipeline/editorial.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def frames_to_seconds(frames, framerate):
    """
    Returning seconds.

    Args:
        frames (int): frame
        framerate (float): frame rate

    Returns:
        float: second value
    """

    rt = _ot.from_frames(frames, framerate)
    return _ot.to_seconds(rt)

is_clip_from_media_sequence(otio_clip)

Parameters:

Name Type Description Default
otio_clip Clip

The OTIO clip to check.

required

Returns:

Type Description

bool. Is the provided clip from an input media sequence ?

Source code in client/ayon_core/pipeline/editorial.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
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

make_sequence_collection(path, otio_range, metadata)

Make collection from path otio range and otio metadata.

Parameters:

Name Type Description Default
path str

path to image sequence with %d

required
otio_range TimeRange

range to be used

required
metadata dict

data where padding value can be found

required

Returns:

Name Type Description
list

dir_path (str): path to sequence, collection object

Source code in client/ayon_core/pipeline/editorial.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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)])
    return dir_path, collection

range_from_frames(start, duration, fps)

Returns otio time range.

Parameters:

Name Type Description Default
start int

frame start

required
duration int

frame duration

required
fps float

frame range

required

Returns:

Type Description

otio._ot._ot.TimeRange: created range

Source code in client/ayon_core/pipeline/editorial.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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: created range

    """
    return _ot.TimeRange(
        _ot.RationalTime(start, fps),
        _ot.RationalTime(duration, fps)
    )

remap_range_on_file_sequence(otio_clip, otio_range)

Parameters:

Name Type Description Default
otio_clip Clip

The OTIO clip to check.

required
otio_range TimeRange

The trim range to apply.

required

Returns:

Name Type Description
tuple (int, int)

The remapped range as discrete frame number.

Source code in client/ayon_core/pipeline/editorial.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
def remap_range_on_file_sequence(otio_clip, otio_range):
    """
    Args:
        otio_clip (otio.schema.Clip): The OTIO clip to check.
        otio_range (otio.schema.TimeRange): The trim range to apply.

    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}.")

    media_ref = otio_clip.media_reference
    available_range = otio_clip.available_range()
    available_range_rate = available_range.start_time.rate

    # Backward-compatibility for Hiero OTIO exporter.
    # NTSC compatibility might introduce floating rates, when these are
    # not exactly the same (23.976 vs 23.976024627685547)
    # this will cause precision issue in computation.
    # Currently round to 2 decimals for comparison,
    # but this should always rescale after that.
    rounded_av_rate = round(available_range_rate, 2)
    rounded_range_rate = round(otio_range.start_time.rate, 2)

    if rounded_av_rate != rounded_range_rate:
        raise ValueError("Inconsistent range between clip and provided clip")

    source_range = otio_clip.source_range
    media_in = available_range.start_time
    available_range_start_frame = (
        available_range.start_time.to_frames()
    )

    # 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.
    conformed_src_in = source_range.start_time.rescaled_to(
        available_range_rate
    )
    if (
        is_clip_from_media_sequence(otio_clip)
        and available_range_start_frame == media_ref.start_frame
        and conformed_src_in.to_frames() < media_ref.start_frame
    ):
        media_in = otio.opentime.RationalTime(
            0, rate=available_range_rate
        )

    src_offset_in = otio_range.start_time - media_in
    frame_in = otio.opentime.RationalTime.from_frames(
        media_ref.start_frame + src_offset_in.to_frames(),
        rate=available_range_rate,
    ).to_frames()

    # e.g.:
    # duration = 10 frames at 24fps
    # if frame_in = 1001 then
    # frame_out = 1010
    offset_duration = max(0, otio_range.duration.to_frames() - 1)

    frame_out = otio.opentime.RationalTime.from_frames(
        frame_in + offset_duration,
        rate=available_range_rate,
    ).to_frames()

    return frame_in, frame_out

trim_media_range(media_range, source_range)

Trim input media range with clip source range.

Parameters:

Name Type Description Default
media_range TimeRange

available range of media

required
source_range TimeRange

clip required range

required

Returns:

Type Description

otio._ot._ot.TimeRange: trimmed media range

Source code in client/ayon_core/pipeline/editorial.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
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(
        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)