Skip to content

Add core C++ support for otioz and otiod #1869

@darbyjohnston

Description

@darbyjohnston
Contributor

After some discussion in Slack:
https://academysoftwarefdn.slack.com/archives/CMQ9J4BQC/p1729878665473649

I wanted to create a proposal for adding core C++ support for otioz and otiod. I think adding them to the C++ API would have a couple of benefits:

  • Broader adoption by users of the C++ API and other language bindings.
  • Provide a common interface to ensure bundles are created according to the specification.

I propose adding minizip-ng as a new dependency to support otioz. It has a permissive license (zlib), and is also used by OpenColorIO for their .ocioz files. The use of minizip-ng would be internal and not part of the OTIO public API.

Outline of the required work:

Add an enum for the media reference policy

(https://opentimelineio.readthedocs.io/en/stable/tutorials/otio-filebundles.html#mediareferencepolicy)

enum class MediaReferencePolicy
{
    ErrorIfNotFile,
    MissingIfNotFile,
    AllMissing
 };

Add constants for the file bundle versions

static std::string const otiozVersion = "1.0.0";
static std::string const otiodVersion = "1.0.0";

Add I/O functions to SerializableObject

bool to_otioz_file(
    std::string const&        file_name,
    MediaReferencePolicy      media_reference_policy   = MediaReferencePolicy::ErrorIfNotFile,
    ErrorStatus*              error_status             = nullptr,
    const schema_version_map* target_family_label_spec = nullptr,
    int                       indent                   = 4) const;
  • Create a new ZIP file.
  • Resolve external references based on the media reference policy and add them to the ZIP file.
  • Create the version file and add it to the ZIP file.
  • Clone the SerializableObject and modify it based upon the media reference policy, and to change the external reference paths.
  • Call to_json_string() to create content.otio and add it to the ZIP file.
static SerializableObject* from_otioz_file(
    std::string const& file_name,
    std::string const& temp_dir,
    ErrorStatus*       error_status = nullptr);
  • Unzip the file to the temporary directory.
  • Call from_json_file() on the content.otio file in the temporary directory.

Should we also add a version of this function that reads the otioz directly without unzipping it (i.e., memory-mapping)?

bool to_otiod_bundle(
    std::string const&        dir_name,
    MediaReferencePolicy      media_reference_policy   = MediaReferencePolicy::ErrorIfNotFile,
    ErrorStatus*              error_status             = nullptr,
    const schema_version_map* target_family_label_spec = nullptr,
    int                       indent                   = 4) const;
  • Create the given directory.
  • Resolve external references based on the media reference policy and copy them to the directory.
  • Create the version file in the directory.
  • Clone the SerializableObject and modify it based upon the media reference policy, and to change the external reference paths.
  • Call to_json_string() to create the content.otio file in the directory.
static SerializableObject* from_otiod_bundle(
    std::string const& file_name,
    ErrorStatus*       error_status = nullptr);
  • Call from_json_file() on the content.otio file in the otiod directory.

Python bindings

Add Python bindings for the new C++ functionality and update the otioz/otiod Python adapters to use the new code.

Activity

ssteinbach

ssteinbach commented on Apr 3, 2025

@ssteinbach
Collaborator

Glad you're diving into this!

  • I suspect you might want to have the adapter as a shim to trigger a call to the otioz/d functions, similar to how there is a python shim around the otio_json adapter: https://github.com/AcademySoftwareFoundation/OpenTimelineIO/blob/main/src/py-opentimelineio/opentimelineio/adapters/otio_json.py
    This exposes options to the commandline interface (and, for example, to otiopluginfo) and streamlines the entry-level python API. For basic use cases you can use otio.adapters.read_from_file() and the adapter interface handles all the type dispatching without special casing the internal formats.
  • Whether you feel like an otiod read function is necessary is a good one for discussion. I'm not sure if folks use otiod separate from otioz development. The adapter notes that it also converts the relative media references in the otiod content.otio into absolute paths:
    # convert the media_reference paths to absolute paths

    ... but that could be left in the adapter and not moved into the core. The adapter would probably remain pretty unchanged in this scenario.
  • It might be worth poking the community to see if otiod should be separately exposed at all. Originally it was super easy to build while building otioz and helped me debug/stage otioz stuff but I'm not sure if anyone else finds it useful. If folks wanted to cut it or not expose it as its own thing that would make sense to me too.

Excited to see the otioz prototype move into the core!

darbyjohnston

darbyjohnston commented on Apr 3, 2025

@darbyjohnston
ContributorAuthor

That makes sense about the adapters, I'll update the notes.

If we do keep otiod I think having the read function would be a good idea. It keeps the API symmetrical and let's us update the format in the future.

I also find otiod helpful for debugging, but I'm sure there are other use cases for it. Like if you had an .otio with media located in various different places, and wanted to copy it to a single high speed drive for playback.

peter-targett

peter-targett commented on Apr 10, 2025

@peter-targett
Contributor

Kicking myself I should have proposed this earlier, it actually wasn't too difficult to write C++/Python-API code to call-down into the adapters to write otiod and otioz files, a C++ API would however simplify the call-setup-code!

ssteinbach

ssteinbach commented on Apr 11, 2025

@ssteinbach
Collaborator

I also find otiod helpful for debugging, but I'm sure there are other use cases for it. Like if you had an .otio with media located in various different places, and wanted to copy it to a single high speed drive for playback.

This is argument enough to keep it around in my opinion. If you want to float it at a TSC meeting and get a temperature check, I'm fine with that too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @ssteinbach@darbyjohnston@peter-targett

      Issue actions

        Add core C++ support for otioz and otiod · Issue #1869 · AcademySoftwareFoundation/OpenTimelineIO