Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added StreamChannelIndexStreamAddress
Signed-off-by: Eric Reinecke <ereinecke@netflix.com>
  • Loading branch information
reinecke committed Apr 7, 2026
commit 16d2b783a3f910d7aeeaed064cc70f11e225f969
2 changes: 2 additions & 0 deletions src/opentimelineio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(OPENTIMELINEIO_HEADER_FILES
stackAlgorithm.h
indexStreamAddress.h
streamAddress.h
streamChannelIndexStreamAddress.h
streamInfo.h
stringStreamAddress.h
streamSelector.h
Expand Down Expand Up @@ -74,6 +75,7 @@ add_library(opentimelineio ${OTIO_SHARED_OR_STATIC_LIB}
stackAlgorithm.cpp
indexStreamAddress.cpp
streamAddress.cpp
streamChannelIndexStreamAddress.cpp
streamInfo.cpp
stringStreamAddress.cpp
streamSelector.cpp
Expand Down
1 change: 1 addition & 0 deletions src/opentimelineio/CORE_VERSION_MAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ const label_to_schema_version_map CORE_VERSION_MAP{
{ "HookScript", 1 },
{ "ImageSequenceReference", 1 },
{ "IndexStreamAddress", 1 },
{ "StreamChannelIndexStreamAddress", 1 },
{ "Item", 1 },
{ "LinearTimeWarp", 1 },
{ "Marker", 2 },
Expand Down
35 changes: 35 additions & 0 deletions src/opentimelineio/streamChannelIndexStreamAddress.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the OpenTimelineIO project

#include "opentimelineio/streamChannelIndexStreamAddress.h"

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {

StreamChannelIndexStreamAddress::StreamChannelIndexStreamAddress(
int64_t stream_index,
int64_t channel_index)
: Parent()
, _stream_index(stream_index)
, _channel_index(channel_index)
{}

StreamChannelIndexStreamAddress::~StreamChannelIndexStreamAddress()
{}

bool
StreamChannelIndexStreamAddress::read_from(Reader& reader)
{
return reader.read("stream_index", &_stream_index)
&& reader.read("channel_index", &_channel_index)
&& Parent::read_from(reader);
}

void
StreamChannelIndexStreamAddress::write_to(Writer& writer) const
{
Parent::write_to(writer);
writer.write("stream_index", _stream_index);
writer.write("channel_index", _channel_index);
}

}} // namespace opentimelineio::OPENTIMELINEIO_VERSION_NS
67 changes: 67 additions & 0 deletions src/opentimelineio/streamChannelIndexStreamAddress.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the OpenTimelineIO project

#pragma once

#include "opentimelineio/streamAddress.h"
#include "opentimelineio/version.h"

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {

/// @brief Addresses a stream by track index and channel index within that track.
///
/// Use this for container formats that organise media into discrete tracks,
/// each of which may contain one or more channels — for example MP4/MOV and
/// MXF. The `stream_index` identifies the track and the `channel_index`
/// identifies the channel within that track.
class OTIO_API_TYPE StreamChannelIndexStreamAddress : public StreamAddress
{
public:
/// @brief This struct provides the StreamChannelIndexStreamAddress schema.
struct Schema
{
static char constexpr name[] = "StreamChannelIndexStreamAddress";
static int constexpr version = 1;
};

using Parent = StreamAddress;

/// @brief Create a new StreamChannelIndexStreamAddress.
///
/// @param stream_index Integer index of the media track within its
/// container (e.g. the ffmpeg/libav stream index).
/// @param channel_index Integer index of the channel within that track.
OTIO_API explicit StreamChannelIndexStreamAddress(
int64_t stream_index = 0,
int64_t channel_index = 0);

/// @brief Return the stream (track) index.
OTIO_API int64_t stream_index() const noexcept { return _stream_index; }

/// @brief Set the stream (track) index.
OTIO_API void set_stream_index(int64_t stream_index) noexcept
{
_stream_index = stream_index;
}

/// @brief Return the channel index within the stream.
OTIO_API int64_t channel_index() const noexcept { return _channel_index; }

/// @brief Set the channel index within the stream.
OTIO_API void set_channel_index(int64_t channel_index) noexcept
{
_channel_index = channel_index;
}

protected:
virtual ~StreamChannelIndexStreamAddress();

bool read_from(Reader&) override;
void write_to(Writer&) const override;

private:
int64_t _stream_index;
int64_t _channel_index;
};

}} // namespace opentimelineio::OPENTIMELINEIO_VERSION_NS
2 changes: 2 additions & 0 deletions src/opentimelineio/typeRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "opentimelineio/stack.h"
#include "opentimelineio/indexStreamAddress.h"
#include "opentimelineio/streamAddress.h"
#include "opentimelineio/streamChannelIndexStreamAddress.h"
#include "opentimelineio/streamInfo.h"
#include "opentimelineio/stringStreamAddress.h"
#include "opentimelineio/streamSelector.h"
Expand Down Expand Up @@ -90,6 +91,7 @@ TypeRegistry::TypeRegistry()
register_type<Stack>();
register_type<StreamAddress>();
register_type<IndexStreamAddress>();
register_type<StreamChannelIndexStreamAddress>();
register_type<StringStreamAddress>();
register_type<StreamInfo>();
register_type<StreamSelector>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "opentimelineio/stack.h"
#include "opentimelineio/indexStreamAddress.h"
#include "opentimelineio/streamAddress.h"
#include "opentimelineio/streamChannelIndexStreamAddress.h"
#include "opentimelineio/streamInfo.h"
#include "opentimelineio/stringStreamAddress.h"
#include "opentimelineio/streamSelector.h"
Expand Down Expand Up @@ -723,6 +724,25 @@ static void define_stream_address_and_info(py::module m) {
.def_property("index", &IndexStreamAddress::index, &IndexStreamAddress::set_index,
"Integer index identifying the stream within its container.");

py::class_<StreamChannelIndexStreamAddress, StreamAddress,
managing_ptr<StreamChannelIndexStreamAddress>>(
m, "StreamChannelIndexStreamAddress", py::dynamic_attr(),
"Addresses a stream by track index and channel index within that track. "
"Use this for container formats that organise media into discrete tracks "
"each of which may contain one or more channels, such as MP4/MOV and MXF.")
.def(py::init([](int64_t stream_index, int64_t channel_index) {
return new StreamChannelIndexStreamAddress(stream_index, channel_index); }),
"stream_index"_a = 0LL,
"channel_index"_a = 0LL)
.def_property("stream_index",
&StreamChannelIndexStreamAddress::stream_index,
&StreamChannelIndexStreamAddress::set_stream_index,
"Integer index of the media track within its container.")
.def_property("channel_index",
&StreamChannelIndexStreamAddress::channel_index,
&StreamChannelIndexStreamAddress::set_channel_index,
"Integer index of the channel within the stream.");

py::class_<StringStreamAddress, StreamAddress,
managing_ptr<StringStreamAddress>>(m, "StringStreamAddress", py::dynamic_attr(),
"Addresses a stream by string identifier (e.g. channel label).")
Expand Down
3 changes: 3 additions & 0 deletions src/py-opentimelineio/opentimelineio/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
GeneratorReference,
ImageSequenceReference,
IndexStreamAddress,
StreamChannelIndexStreamAddress,
Marker,
MissingReference,
SerializableCollection,
Expand Down Expand Up @@ -51,6 +52,7 @@
generator_reference,
image_sequence_reference,
index_stream_address,
stream_channel_index_stream_address,
marker,
serializable_collection,
stream_address,
Expand Down Expand Up @@ -81,6 +83,7 @@ def timeline_from_clips(clips):
'GeneratorReference',
'ImageSequenceReference',
'IndexStreamAddress',
'StreamChannelIndexStreamAddress',
'Marker',
'MissingReference',
'SerializableCollection',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the OpenTimelineIO project

from .. core._core_utils import add_method
from .. import _otio


@add_method(_otio.StreamChannelIndexStreamAddress)
def __str__(self):
return "StreamChannelIndexStreamAddress({}, {})".format(
self.stream_index, self.channel_index
)


@add_method(_otio.StreamChannelIndexStreamAddress)
def __repr__(self):
return (
"otio.schema.StreamChannelIndexStreamAddress("
"stream_index={}, channel_index={})".format(
repr(self.stream_index), repr(self.channel_index)
)
)
50 changes: 50 additions & 0 deletions tests/test_stream_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,56 @@ def test_round_trip_serialization(self):
self.assertEqual(restored.index, 5)


class TestStreamChannelIndexStreamAddress(unittest.TestCase):
def test_create_default(self):
addr = otio.schema.StreamChannelIndexStreamAddress()
self.assertEqual(addr.stream_index, 0)
self.assertEqual(addr.channel_index, 0)
self.assertEqual(addr.schema_name(), "StreamChannelIndexStreamAddress")
self.assertEqual(addr.schema_version(), 1)

def test_create_with_indices(self):
addr = otio.schema.StreamChannelIndexStreamAddress(
stream_index=1, channel_index=2
)
self.assertEqual(addr.stream_index, 1)
self.assertEqual(addr.channel_index, 2)

def test_set_indices(self):
addr = otio.schema.StreamChannelIndexStreamAddress()
addr.stream_index = 3
addr.channel_index = 5
self.assertEqual(addr.stream_index, 3)
self.assertEqual(addr.channel_index, 5)

def test_round_trip_serialization(self):
addr = otio.schema.StreamChannelIndexStreamAddress(
stream_index=1, channel_index=2
)
json_str = addr.to_json_string()
restored = otio.adapters.read_from_string(json_str, "otio_json")
self.assertIsInstance(restored, otio.schema.StreamChannelIndexStreamAddress)
self.assertEqual(restored.stream_index, 1)
self.assertEqual(restored.channel_index, 2)

def test_use_in_stream_info(self):
addr = otio.schema.StreamChannelIndexStreamAddress(
stream_index=1, channel_index=2
)
info = StreamInfo(
name="right surround",
address=addr,
kind=otio.schema.TrackKind.Audio,
)
json_str = info.to_json_string()
restored = otio.adapters.read_from_string(json_str, "otio_json")
self.assertIsInstance(
restored.address, otio.schema.StreamChannelIndexStreamAddress
)
self.assertEqual(restored.address.stream_index, 1)
self.assertEqual(restored.address.channel_index, 2)


class TestStringStreamAddress(unittest.TestCase):
def test_create_default(self):
addr = otio.schema.StringStreamAddress()
Expand Down