O
All pages

Editing a timeline

The ten edit operations, what each one does to its neighbours, and which of them change a track's length.

Appending clips to a track builds a cut. Changing one is a different problem, because every change has a question attached: what happens to everything after it?

There are ten operations, and they are the ones a non-linear editor has. They are functions rather than methods, because each is about two objects and belongs to neither — which is how upstream arranges them too.

import opentimelineio as otio


def second(name):
    """One second of picture, named."""
    return otio.schema.Clip(
        name=name,
        source_range=otio.opentime.TimeRange(
            otio.opentime.RationalTime(0, 24), otio.opentime.RationalTime(24, 24)
        ),
    )


def show(track):
    names = " ".join(child.name for child in track)
    print(names, "-", track.duration().value, "frames")


track = otio.schema.Track(name="V1", kind="Video")
for name in ["A", "B", "C"]:
    track.append(second(name))
show(track)

# Insert makes room: everything from the insertion point onwards moves later,
# and the track gets longer.
otio.algorithms.insert(
    second("D"), track, otio.opentime.RationalTime(24, 24), remove_transitions=False
)
show(track)

# Overwrite does not: it lays an item over a span and whatever was in that
# span gives way. The track is the same length afterwards.
otio.algorithms.overwrite(
    second("E"),
    track,
    otio.opentime.TimeRange(
        otio.opentime.RationalTime(48, 24), otio.opentime.RationalTime(24, 24)
    ),
    remove_transitions=False,
)
show(track)

The ten

OperationWhat it does
insertPuts an item at an instant, pushing what follows later.
overwriteLays an item over a span, replacing what was there.
trimMoves an item's in and out points without moving its neighbours.
rippleMoves an item's in and out points, sliding everything after it.
rollMoves the cut between an item and its neighbour.
slipMoves the media inside an item without moving the item.
slideMoves an item along its track, taking the time from its neighbours.
sliceCuts whatever sits at an instant into two.
fillDrops an item into a gap, fitted as the reference point says.
removeTakes whatever sits at an instant out.

The question each one answers

The useful way to hold these is by what they do to the track's length and to the neighbours.

Length changes. insert makes the track longer by the length of what went in. remove without a fill makes it shorter, because what follows moves up; remove with a fill leaves a gap and the length alone. ripple changes it by however much the in or out point moved.

Length does not change. overwrite replaces rather than displaces. trim, roll, slip and slide all move boundaries around within the track without altering how much track there is. slice puts a cut in and changes nothing else — two items where there was one, occupying the same span.

Neighbours move. insert, ripple and remove without a fill. Those are the three that shift material you did not name.

Neighbours do not move. overwrite, trim, slip, slice and fill. roll and slide are the interesting pair: both change a neighbour, but only by moving the boundary they share, so nothing further along the track notices.

The sample above is insert and overwrite side by side, because that is the distinction people reach for first and the one that decides whether a cut gets longer.

Filling what an edit opens

Several of these can open a hole — overwrite past the end of a track, remove with a fill, insert at a point past the end.

Each takes a fill template: the item to put in that hole. Pass nothing and it is an ordinary Gap, which is transparent, so on a multi-track timeline whatever is underneath shows through. When you want something else — solid black, a slate, colour bars — pass a clip with a GeneratorReference as the template and that is what fills it instead.

Slip and slide

These two are named after the editing desk and the names are worth learning the way round.

slip keeps the item where it is on the track and moves the media inside it: same four seconds of the cut, a different four seconds of the shot. The track does not change at all, and neither does any neighbour.

slide keeps the media and moves the item along the track: the same four seconds of the shot, arriving earlier or later. The time has to come from somewhere, so the neighbours on either side absorb it — the one before grows or shrinks, and the one after does the opposite.

Where they are, and where they are not

All ten are in the core, in the C ABI, in every SDK generated from it, and in Python as opentimelineio.algorithms.overwrite, insert and the rest, with a ReferencePoint enum for fill's four-point edits.

Upstream's own Python package does not bind them; only its C++ has them. The Python functions here follow that C++ editAlgorithm.h in their names, parameters and defaults, and raise what its error handler raises. An object an edit takes out of a track stays usable while Python holds it, with no parent, as any removed child does.

What the copied piece holds

slice, insert and overwrite copy the piece of an item a split leaves over, and fill with ReferencePoint.Sequence copies the clip it drops in. The copy is made as upstream makes it, by the equivalent of writing the item out and reading it back, so it shares nothing with the original: an object the item holds in two places — one object under two metadata keys, one effect listed twice, one media reference under two keys — becomes two separate objects in the copy. The item left in place keeps what it held.

An item that holds itself

Metadata can hold whole objects, including the item it belongs to: clip.metadata["self"] = clip. slice, insert and overwrite copy the piece of an item a split leaves over, and fill copies the clip it drops in; here that copy keeps the cycle, so the leftover piece holds itself just as the original does, and the edit goes through like any other.

That is a deliberate difference from upstream. Upstream copies by writing the item out and reading it back, which cannot carry a cycle, so the same edits fail there with a cycle error — and slice, insert and overwrite fail only after changing the track, leaving the clip cut short and the rest of it lost. The cycle still cannot be saved: writing it as .otio is refused, here as upstream.