OpenTimelineIO (OTIO)

repository·main·Indexed 21 days ago

https://github.com/academysoftwarefoundation/opentimelineio

An interchange format and API for editorial cut information, providing a common data model for non-linear editing applications, game engines, and DCC tools. It includes native-feeling bridges for C++, Python, and Swift, and supports a plugin system for adapters, media linkers, hook scripts, and custom schema definitions.

Tokens
36K
Snippets
63
Records
210
Agent score
82%

What's inside OpenTimelineIO

  1. What is OpenTimelineIO (OTIO)?

    main

    OpenTimelineIO (OTIO) is an API and interchange format designed for editorial cut information. It functions as a modern Edit Decision List (EDL) that provides a standardized way to read, write, and manipulate editorial data.

    Key capabilities include support for:

    • Clips and timing
    • Tracks and transitions
    • Markers and metadata

    Note: OTIO does not support embedded video or audio; media is referenced externally. It utilizes a plugin system for translating between existing editorial formats and for linking to proprietary media storage schemas.

  2. Use the coordinate system for non-rectangular spatial data

    main

    The OTIO spatial coordinate system is not limited to rectangular Bounds. It can be used to express any spatial-based parameter in a resolution-independent way.

    Potential use cases include:

    • Effect parameters: Such as blur amounts.
    • Annotations: Defining specific annotation positions.
    • Masks: Defining wipe bar positions (e.g., angular masks).
  3. Use Nested Compositions (Tracks and Stacks)

    main

    OpenTimelineIO allows nesting Tracks and Stacks within other Tracks. This allows a complex composition to be treated as a single unit.

    • Nesting Behavior: A nested Track or Stack behaves like a single Clip within its parent composition.
    • Trimming Nested Content: If a source_range is specified on the nested composition, only that specific segment is included in the parent track.
    • Scope: Elements inside a nested composition (like clips or gaps) are not visible to the parent track's peers. For example, a Gap in a parent track cannot 'see' or reveal content inside a nested Stack unless that content is part of the nested composition's own rendered output.
  4. Structure of an OTIO JSON file

    main

    An OTIO file is a tree structure of nested OTIO objects stored as JSON dictionaries.

    Key Structural Rules:

    • No Instancing: OTIO does not support object references/instancing. If the same clip or media appears multiple times, it must be represented as identical copies of the Clip or MediaReference object.
    • Top-Level Object: While typically a Timeline, the top-level object can be any OTIO data type (e.g., Clip, Track, RationalTime). Code reading these files should guard against unexpected top-level types.
    • Schema Versioning: Every OTIO object contains an "OTIO_SCHEMA" key/value pair that identifies the data type and its specific version (e.g., "OTIO_SCHEMA": "Timeline.1"). This allows granular versioning of individual data types.
    • Formatting: Files are typically indented for human readability. To reduce file size, it is recommended to use gzip rather than minifying the JSON.
  5. Understand Clip time frames and ranges

    main

    When working with Clips, it is crucial to distinguish between the Clip time frame (the internal coordinate system of the media) and the parent time frame (the coordinate system of the Track or Stack containing the Clip).

    Clip Time Frame (Internal)

    These methods return ranges relative to the Clip's own media:

    • Clip.available_range(): The total duration and start timecode of the media referenced by the Clip. Returns None if unknown.
    • Clip.source_range: The specific segment of media selected for the Clip. Setting this trims the Clip. If None, the full available_range() is used.
    • Clip.trimmed_range(): Returns the source_range if set, otherwise returns available_range(). This represents how long the Clip is intended to be in its parent.
    • Clip.visible_range(): Similar to trimmed_range(), but includes the duration of any adjacent Transitions (e.g., an out-fade).
    • Clip.duration(): A convenience method for Clip.trimmed_range().duration(). It represents the "natural" duration seen in a timeline UI.

    Parent Time Frame (External)

    These methods return ranges relative to the Clip's position within its parent container:

    • Clip.range_in_parent(): The range within the parent Track or Stack where the Clip is visible. In a Track, clips are typically laid end-to-end.
    • Clip.trimmed_range_in_parent(): The range within the parent, but trimmed relative to the parent's own source_range. Returns None if the Clip is completely trimmed by the parent.
  6. OpenTimelineIO JSON File Format Specification

    main

    OpenTimelineIO files are serialized as JSON.

    Naming

    Files should use the .otio extension. Do not use .json as the file extension for OTIO files.

    Number Types

    • Integers: Represented as int64_t (signed 64-bit integer).
    • Floating Point: Represented as double (IEEE754 64-bit signed floating point).
    • Special Double Values: OTIO supports NaN (not a number), Inf/Infinity (positive infinity), and -Inf/-Infinity (negative infinity).
  7. What are OTIO Adapters?

    main

    OpenTimelineIO Adapters are plugins that enable OTIO to read from and write to other timeline formats. The opentimelineio.adapters module uses file extensions (e.g., .edl, .otio) to automatically select the appropriate adapter for conversion.

    Note that the .otio (JSON) format is the only lossless format; it preserves all objects, metadata, and features. Other formats are considered lossy and will only store features supported by both the format and the specific adapter implementation.

    import opentimelineio as otio
    # Reading from a format via an adapter
    mytimeline = otio.adapters.read_from_file("something.edl")
    # Writing to the lossless OTIO format
    otio.adapters.write_to_file(mytimeline, "something.otio")
  8. How otiotool processing phases work

    main

    While most command-line options can be provided in any order, otiotool processes them in a specific sequence of phases. Understanding this sequence is critical when combining operations.

    1. Input: Files provided via --input are read into memory.
    2. Filtering: Content is removed based on options like --video-only, --audio-only, --only-tracks-with-name, --only-tracks-with-index, --only-clips-with-name, --only-clips-with-name-regex, --remove-transitions, and --trim.
    3. Combine: If specified, --stack and then --concat are performed to merge multiple input timelines.
    4. Flatten: If --flatten is specified, multiple tracks are merged into one.
    5. Relink: --relink-by-name scans folders to match clip names to filenames. --copy-media-to-folder can be used to copy/download linked media.
    6. Remove/Redact: --remove-metadata-key removes specific metadata. --redact removes all metadata and renames all objects to generic names.
    7. Inspect: Information is gathered via --stats, --list-clips, --list-tracks, --list-media, --verify-media, --list-markers, --verify-ranges, and --inspect.
    8. Output: The resulting OTIO is written to the file specified by --output (format is inferred from extension).
  9. Use Bounds to define spatial areas

    main

    A Bounds object is a 2D box that defines a spatial area within the unit-less coordinate system. It is represented using a Box2d.1 schema containing min and max points (of type V2d.1).

    Because Bounds are serializable objects, they include a metadata member. This allows you to define various layouts such as:

    • First-quadrant-snapped rectangles: Defined by setting min to (0,0).
    • Origin-centered rectangles: Defined by setting min and max symmetrically around the origin.
    • Complex layouts: Multiple clips can share the same coordinate system to create side-by-side comparisons, Picture-in-Picture (PiP), or collage layouts.
    // Example: First-quadrant-snapped rectangle (16:9)
    "available_image_bounds": {
      "OTIO_SCHEMA": "Box2d.1",
      "min": {
        "OTIO_SCHEMA":"V2d.1",
        "x": 0.0,
        "y": 0.0
      },
      "max": {
        "OTIO_SCHEMA":"V2d.1",
        "x": 16.0,
        "y": 9.0
      }
    }
    
    // Example: Origin-centered rectangle (16:9)
    "available_image_bounds": {
      "OTIO_SCHEMA": "Box2d.1",
      "min": {
        "OTIO_SCHEMA":"V2d.1",
        "x": -8.0,
        "y": -4.5
      },
      "max": {
        "OTIO_SCHEMA":"V2d.1",
        "x": 8.0,
        "y": 4.5
      }
    }
  10. Use Schema-Version Sets (Families)

    main

    Instead of manual mappings, you can use "Families" to downgrade entire sets of schemas to a specific release label.

    Core Families: In C++, use otio::CORE_VERSION_MAP to access pre-defined maps for library releases (e.g., "0.15.0").

    Custom Families (Python): In Python, you can define custom families in a .plugin_manifest.json file located at the path specified by the OTIO_PLUGIN_MANIFEST_PATH environment variable. This allows studios to organize version sets for their own plugins (e.g., a family named "MYFAMILY" with labels like "June2022").

    Use otio.versioning.fetch_map(family, label) to retrieve these maps.

    # Fetch a built-in core family version
    downgrade_manifest = otio.versioning.fetch_map("OTIO_CORE", "0.15.0")
    otio.adapters.write_to_file(
        sc,
        "/path/to/file.otio", 
        target_schema_versions=downgrade_manifest
    )
    
    # Fetch a custom family from a plugin manifest
    downgrade_manifest = otio.versioning.fetch_map("MYFAMILY", "June2022")
    otio.adapters.write_to_file(
        sc,
        "/path/to/file.otio", 
        target_schema_versions=downgrade_manifest
    )
  11. How OpenTimelineIO schema versioning works

    main

    OpenTimelineIO uses a versioning system to ensure interoperability between different library releases. Every SerializableObject (the base class for all OTIO objects) contains a schema_name (e.g., Clip) and a schema_version (an integer, e.g., 3).

    Key behaviors:

    • In-memory objects: For a specific release of the OTIO library, all in-memory objects of a certain type will always use the same schema_version. You cannot instantiate a Clip with version 1 if the library's current version uses version 2.
    • Upgrading (Reading): When reading JSON from disk, OTIO automatically applies registered upgrade functions to transform older schema versions into the version supported by the current library before instantiating the in-memory object.
    • Downgrading (Writing): When serializing objects to disk, you can instruct OTIO to apply downgrade functions to convert the current in-memory schema versions back to older versions specified by the user.