Render an OTIO Timeline to a Video File
Description
Lowers a rotio (OpenTimelineIO) Timeline to a single ffmpeg invocation and
renders it. The video track’s clips are concatenated in order; an optional
separate audio track is mapped over them; a framing transform (scale + pad,
from metadata$cornball$framing) and an optional caption burn (from a
caption track referencing an .ass/.srt file) are applied.
Usage
render_timeline(timeline, output, media_dir = NULL, overwrite = TRUE,
dry_run = FALSE)
Arguments
timeline: A rotio Timeline, or a path to a.otiofile.output: Path for the output video file.media_dir: Base directory for resolving relative media urls. Defaults to the timeline file’s directory whentimelineis a path, otherwise NULL (urls used as-is).overwrite: If TRUE (default), overwrite the output file.dry_run: If TRUE, return the ffmpeg command string without executing. Note: concatenation of multiple video clips, still/sequence pre-renders, and layout composition still run, since they produce intermediates the final command depends on.
Details
The video track is lowered honoring per-clip source_range trims and
Transitions: a transition between two clips becomes a dissolve over
exactly its duration, fed by the incoming clip’s head handle (the media
before its source range – for chained generation, the conditioning-head
replay). Only transitions with out_offset == 0 are lowered (the
cornductor bundle shape: the outgoing clip has no tail handle). Gaps and
overlapping layers are not lowered yet.
Still-image clips (a media reference targeting a .png/.jpg/
…) are pre-rendered into video via still_clip at the
source_range’s rate, honoring cornball.* motion effects on the clip
(Ken Burns pan/zoom; the schema lives in
system.file("schema", "cornball-effects.md", package = "compost")).
A still-image clip must carry a source_range. ImageSequenceReference
clips are pre-rendered via frames_clip at the reference’s
rate; motion effects are not applied to sequences. Effects the renderer
cannot honor degrade to a static clip with a warning; effects outside the
cornball. namespace are ignored silently.
When the timeline carries metadata$cornball$layout (schema in
system.file("schema", "cornball-layout.md", package = "compost")),
tracks whose cornball$role matches a layout slot are each assembled
like the content track and composed onto the canvas via
compose_layout – muted, painted in slot order, with the
content track bound to the visual slot as the timing reference.
The framing transform is suppressed when composing (the layout defines
the canvas). A layout the renderer cannot honor – schema too new, a
slot’s track missing, or a roled track without a slot – degrades to the
plain single-stream render with one warning.
Caption tracks are identified by metadata$cornball$role == "caption" or
a name containing “caption”. When the primary video track has a single clip
that already carries its own audio (the talking-head case), no separate audio
track is needed.
Value
Invisibly returns the output path. If dry_run, returns the command string for the final render pass.
Examples
render_timeline("AAA/20260131/t41_n22_intro/timeline.otio",
"AAA/20260131/t41_n22_intro/video.mp4")