From d3e064de849c4eda341da38554057a051a17b8c0 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Tue, 17 Feb 2026 22:13:42 -0800 Subject: [PATCH 1/7] Updated to OpenTimelineIO 0.18.1 Signed-off-by: Joshua Minor --- OpenTimelineIO | 2 +- Package.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenTimelineIO b/OpenTimelineIO index 4440afa..4423671 160000 --- a/OpenTimelineIO +++ b/OpenTimelineIO @@ -1 +1 @@ -Subproject commit 4440afaa27b16f81cdf81215ce4d0b08e1424148 +Subproject commit 44236713c1db295a6ffc66189ae98dbdfd0cb9c4 diff --git a/Package.swift b/Package.swift index 8261612..ef62d79 100644 --- a/Package.swift +++ b/Package.swift @@ -33,7 +33,7 @@ let package = Package( .target(name: "OpenTime_CXX", dependencies: ["otio_header_root"], path: "OpenTimelineIO/src/opentime", - exclude: ["CMakeLists.txt", "OpenTimeConfig.cmake.in"], + exclude: ["CMakeLists.txt", "OpenTimeConfig.cmake.in", "version.h.in"], sources: ["."], publicHeadersPath: ".", cxxSettings: [ .headerSearchPath(".")]), @@ -41,7 +41,7 @@ let package = Package( .target(name: "OpenTimelineIO_CXX", dependencies: ["OpenTime_CXX"], path: "OpenTimelineIO/src/opentimelineio", - exclude: ["CMakeLists.txt", "CORE_VERSION_MAP.last.cpp", "OpenTimelineIOConfig.cmake.in"], + exclude: ["CMakeLists.txt", "CORE_VERSION_MAP.last.cpp", "OpenTimelineIOConfig.cmake.in", "version.h.in"], sources: ["."], publicHeadersPath: ".", cxxSettings: [ From e77a08be06de9e7a61ffd393413c954bf955c979 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Tue, 17 Feb 2026 22:13:53 -0800 Subject: [PATCH 2/7] Fixed bogus NTSC rates in tests. Signed-off-by: Joshua Minor --- .../testRationalTime.swift | 154 +++++++++--------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/Tests/OpenTimelineIOTests/testRationalTime.swift b/Tests/OpenTimelineIOTests/testRationalTime.swift index 8f18b11..b610b09 100644 --- a/Tests/OpenTimelineIOTests/testRationalTime.swift +++ b/Tests/OpenTimelineIOTests/testRationalTime.swift @@ -13,25 +13,25 @@ class testRationalTime: XCTestCase { let tVal = 30.2 let t = RationalTime(value: tVal) XCTAssertEqual(t.value, tVal) - + let t2 = RationalTime() XCTAssertEqual(t2.value, 0) XCTAssertEqual(t2.rate, 1) } - + func testEquality() { let t1 = RationalTime(value: 30.2) XCTAssertEqual(t1, t1) let t2 = RationalTime(value: 30.2) XCTAssertEqual(t1, t2) } - + func testInequality() { let t1 = RationalTime(value: 30.2) XCTAssertEqual(t1, t1) let t2 = RationalTime(value: 33.2) XCTAssertNotEqual(t1, t2) - + let t3 = RationalTime(value: 30.2) XCTAssertFalse(t1 != t3) } @@ -43,14 +43,14 @@ class testRationalTime: XCTestCase { XCTAssert(t1 <= t2) XCTAssertFalse(t1 > t2) XCTAssertFalse(t1 >= t2) - + // Ensure the equality case of the comparisons works correctly let t3 = RationalTime(value: 30.4, rate: 2) XCTAssert(t1 <= t3) XCTAssert(t1 >= t3) XCTAssert(t3 <= t1) XCTAssert(t3 >= t1) - + // test implicit base conversion t2 = RationalTime(value: 15.6, rate: 48) XCTAssert(t1 > t2) @@ -58,72 +58,72 @@ class testRationalTime: XCTestCase { XCTAssertFalse(t1 < t2) XCTAssertFalse(t1 <= t2) } - + func testBaseConversion() { // from a number var t = RationalTime(value: 10, rate: 24) XCTAssertEqual(t.rate, 24) - + t = t.rescaled(to: 48) XCTAssertEqual(t.rate, 48) - + // from another RationalTime t = RationalTime(value: 10, rate: 24) let t2 = RationalTime(value: 20, rate: 48) t = t.rescaled(to: t2) XCTAssertEqual(t.rate, t2.rate) } - + func testTimecodeConvert() { XCTAssertThrowsError(try RationalTime.from(timecode: "abc", rate: 24)) - + let timecode = "00:06:56:17" let t = try! RationalTime.from(timecode: timecode, rate: 24) XCTAssertEqual(timecode, try! t.toTimecode()) } - + func testTimecode24() { var timecode = "00:00:01:00" var t = RationalTime(value: 24, rate: 24) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) - + timecode = "00:01:00:00" t = RationalTime(value: 24 * 60, rate: 24) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) - + timecode = "01:00:00:00" t = RationalTime(value: 24 * 60 * 60, rate: 24) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) - + timecode = "24:00:00:00" t = RationalTime(value: 24 * 60 * 60 * 24, rate: 24) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) - + timecode = "23:59:59:23" t = RationalTime(value: 24 * 60 * 60 * 24 - 1, rate: 24) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) } - + func testPlusEquals() { var sum1 = RationalTime() var sum2 = RationalTime() - + for i in 0...10 { let incr = RationalTime(value: Double(i+1), rate: 24) sum1 += incr sum2 = sum2 + incr } - + XCTAssertEqual(sum1, sum2) } - + func testTimeTimecodeZero() { let t = RationalTime() let timecode = "00:00:00:00" XCTAssertEqual(timecode, try! t.toTimecode(rate: 24)) XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 24)) } - + func testLongRunningTimecode24() { let finalFrameNumber = 24 * 60 * 60 * 24 - 1 let finalTime = RationalTime.from(frame: finalFrameNumber, rate: 24) @@ -137,7 +137,7 @@ class testRationalTime: XCTestCase { cumulativeTime += stepTime } XCTAssertEqual(cumulativeTime, finalTime) - + var fnum = 1113 while fnum < finalFrameNumber { defer { fnum += 1113 } @@ -148,35 +148,36 @@ class testRationalTime: XCTestCase { XCTAssertEqual(tc, try! rt2.toTimecode()) } } - + func testTimecode23976FPS() { // This should behave exactly like 24 fps + let ntsc_rate = 24000.0 / 1001.0 var timecode = "00:00:01:00" - var t = RationalTime(value: 24, rate: 23.976) - XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 23.976)) - + var t = RationalTime(value: 24, rate: ntsc_rate) + XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: ntsc_rate)) + timecode = "00:01:00:00" - t = RationalTime(value: 24 * 60, rate: 23.976) - XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 23.976)) + t = RationalTime(value: 24 * 60, rate: ntsc_rate) + XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: ntsc_rate)) timecode = "01:00:00:00" - t = RationalTime(value: 24 * 60 * 60, rate: 23.976) - XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 23.976)) - + t = RationalTime(value: 24 * 60 * 60, rate: ntsc_rate) + XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: ntsc_rate)) + timecode = "24:00:00:00" - t = RationalTime(value: 24 * 60 * 60 * 24, rate: 23.976) - XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 23.976)) - + t = RationalTime(value: 24 * 60 * 60 * 24, rate: ntsc_rate) + XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: ntsc_rate)) + timecode = "23:59:59:23" - t = RationalTime(value: 24 * 60 * 60 * 24 - 1, rate: 23.976) - XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: 23.976)) + t = RationalTime(value: 24 * 60 * 60 * 24 - 1, rate: ntsc_rate) + XCTAssertEqual(t, try! RationalTime.from(timecode: timecode, rate: ntsc_rate)) } - + func testConvertingNegativeValuesToTimecode() { let t = RationalTime(value: -1, rate: 25) try XCTAssertThrowsError(t.toTimecode(rate: 25)) } - + func testFaultyFormattedTimecode2997() { // Test if "faulty" passed ":" in tc gets converted to ";" let refColonValues = [ @@ -187,88 +188,89 @@ class testRationalTime: XCTestCase { (17983, "00:10:00:01", "00:10:00;01"), (17984, "00:10:00:02", "00:10:00;02") ] - + + let ntsc_rate = 30000.0 / 1001.0 for (value, colon_tc, tc) in refColonValues { - let t = RationalTime(value: Double(value), rate: 29.97) - XCTAssertEqual(tc, try t.toTimecode(rate: 29.97)) - let to_tc = try! t.toTimecode(rate: 29.97) + let t = RationalTime(value: Double(value), rate: ntsc_rate) + XCTAssertEqual(tc, try t.toTimecode(rate: ntsc_rate)) + let to_tc = try! t.toTimecode(rate: ntsc_rate) XCTAssertNotEqual(colon_tc, to_tc) - let t1 = try! RationalTime.from(timecode: tc, rate: 29.97) + let t1 = try! RationalTime.from(timecode: tc, rate: ntsc_rate) XCTAssertEqual(t, t1) } } - + func testFaultyFormattedTimecode24() { try XCTAssertThrowsError(RationalTime.from(timecode: "01:00:13;23", rate: 24)) } func testInvalidToTimecode() { let t = RationalTime(value: 100, rate: 29.98) - + try XCTAssertThrowsError(t.toTimecode(rate: 29.98)) try XCTAssertThrowsError(t.toTimecode()) } - + func testTimeString24() { var time_string = "00:00:00.041667" var t = RationalTime(value: 1.0, rate: 24) var timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "00:00:01" t = RationalTime(value: 24, rate: 24) timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "00:01:00" t = RationalTime(value: 24 * 60, rate: 24) timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "01:00:00" t = RationalTime(value: 24 * 60 * 60, rate: 24) timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "24:00:00" t = RationalTime(value: 24 * 60 * 60 * 24, rate: 24) timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - - + + time_string = "23:59:59.958333" t = RationalTime(value: 24 * 60 * 60 * 24 - 1, rate: 24) timeObj = try! RationalTime.from(timestring: time_string, rate: 24) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) } - + func testTimeString25() { var time_string = "00:00:01" var t = RationalTime(value: 25, rate: 25) var timeObj = try! RationalTime.from(timestring: time_string, rate: 25) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "00:01:00" t = RationalTime(value: 25*60, rate: 25) timeObj = try! RationalTime.from(timestring: time_string, rate: 25) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "01:00:00" t = RationalTime(value: 25*60*60, rate: 25) timeObj = try! RationalTime.from(timestring: time_string, rate: 25) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "24:00:00" t = RationalTime(value: 25*60*60*24, rate: 25) timeObj = try! RationalTime.from(timestring: time_string, rate: 25) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) - + time_string = "23:59:59.92" t = RationalTime(value: 25*60*60*24 - 2, rate: 25) timeObj = try! RationalTime.from(timestring: time_string, rate: 25) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) } - + func testTimeStringZero() { let t = RationalTime() let time_string = "00:00:00.0" @@ -276,19 +278,19 @@ class testRationalTime: XCTestCase { XCTAssertEqual(time_string, t.toTimestring()) XCTAssert(t.almostEqual(timeObj, delta: 0.001)) } - + func testLongRunningTimeString24() { let final_frame_number = 24 * 60 * 60 * 24 - 1 let final_time = RationalTime.from(frame: Double(final_frame_number), rate: 24) XCTAssertEqual(final_time.toTimestring(), "23:59:59.958333") - + let step_time = RationalTime(value: 1, rate: 24) var cumTime = RationalTime(value: 0, rate: 24) for _ in 0.. Date: Tue, 17 Feb 2026 22:34:15 -0800 Subject: [PATCH 3/7] Fix a warning about integer overflow due to a typo. Signed-off-by: Joshua Minor --- Sources/objc/CxxAny.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sources/objc/CxxAny.mm b/Sources/objc/CxxAny.mm index 4bc20d8..de7a6a1 100644 --- a/Sources/objc/CxxAny.mm +++ b/Sources/objc/CxxAny.mm @@ -18,7 +18,7 @@ case CxxAny::BOOL_: return std::any(cxxAny.value.b); case CxxAny::INT: - if (cxxAny.value.i < -INT_MIN || cxxAny.value.i > INT_MAX) { + if (cxxAny.value.i < INT_MIN || cxxAny.value.i > INT_MAX) { return std::any(cxxAny.value.i); } else { @@ -50,12 +50,11 @@ namespace { struct _ToCxxAny { std::map> function_map; - + _ToCxxAny() { auto& m = function_map; m[std::type_index(typeid(void))] = [](std::any const& a, CxxAny* cxxAny) { cxxAny->type_code = CxxAny::NONE; - }; m[std::type_index(typeid(bool))] = [](std::any const& a, CxxAny* cxxAny) { cxxAny->type_code = CxxAny::BOOL_; @@ -108,7 +107,7 @@ void otio_any_to_cxx_any(std::any const& a, CxxAny* cxxAny) { static auto toCxxAny = _ToCxxAny(); auto e = toCxxAny.function_map.find(std::type_index(a.type())); - + if (e != toCxxAny.function_map.end()) { e->second(a, cxxAny); } From f3d0bb2cc945922a2b7cdb3ed097e71c08a5cf99 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Tue, 17 Feb 2026 22:35:04 -0800 Subject: [PATCH 4/7] Mark isValidTimecodeRate deprecated in favor of isSmpteTimecodeRate Signed-off-by: Joshua Minor --- Sources/objc/include/opentime.h | 3 +- Sources/objc/opentime.mm | 5 +++ Sources/swift/RationalTime.swift | 34 +++++++++++-------- .../testRationalTime.swift | 9 +++++ 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Sources/objc/include/opentime.h b/Sources/objc/include/opentime.h index 75ad733..d398bae 100644 --- a/Sources/objc/include/opentime.h +++ b/Sources/objc/include/opentime.h @@ -60,7 +60,7 @@ extern "C" { #endif - + double rational_time_value_rescaled_to(CxxRationalTime const*, double new_rate); double rational_time_value_rescaled_to_copy(CxxRationalTime, double new_rate); CxxRationalTime rational_time_rescaled_to(CxxRationalTime const* rt, double new_rate); @@ -68,6 +68,7 @@ bool rational_time_almost_equal(CxxRationalTime, CxxRationalTime, double); CxxRationalTime rational_time_duration_from_start_end_time(CxxRationalTime, CxxRationalTime); bool rational_time_is_valid_timecode_rate(double); +bool rational_time_is_smpte_timecode_rate(double); CxxRationalTime rational_time_from_timecode(NSString* timecode, double rate, CxxErrorStruct* err); CxxRationalTime rational_time_from_timestring(NSString* timestring, double rate, CxxErrorStruct* err); diff --git a/Sources/objc/opentime.mm b/Sources/objc/opentime.mm index cf76fca..8036dff 100644 --- a/Sources/objc/opentime.mm +++ b/Sources/objc/opentime.mm @@ -41,10 +41,15 @@ CxxRationalTime rational_time_duration_from_start_end_time(CxxRationalTime s, Cx otioRationalTime(e))); } +// deprecated bool rational_time_is_valid_timecode_rate(double rate) { return otio::RationalTime::is_valid_timecode_rate(rate); } +bool rational_time_is_smpte_timecode_rate(double rate) { + return otio::RationalTime::is_smpte_timecode_rate(rate); +} + static inline void deal_with_error(opentime::ErrorStatus const& error_status, CxxErrorStruct* err) { if (error_status.outcome != error_status.OK) { err->statusCode = error_status.outcome; diff --git a/Sources/swift/RationalTime.swift b/Sources/swift/RationalTime.swift index 19e410d..999b783 100644 --- a/Sources/swift/RationalTime.swift +++ b/Sources/swift/RationalTime.swift @@ -10,19 +10,19 @@ import OpenTimelineIO_objc public struct RationalTime: CustomStringConvertible, Equatable { public var value: Double { return cxxRationalTime.value } public var rate: Double { return cxxRationalTime.rate } - + public var description: String { return "RationalTime(\(value), \(rate))" } - + public init(value: Double = 0, rate: Double = 1) { cxxRationalTime = CxxRationalTime(value: value, rate: rate) } - + public func isInvalidTime() -> Bool { return rate <= 0 } - + public func rescaled(to newRate: Double) -> RationalTime { return withUnsafePointer(to: self.cxxRationalTime) { RationalTime(rational_time_rescaled_to($0, newRate)); @@ -55,11 +55,16 @@ public struct RationalTime: CustomStringConvertible, Equatable { return RationalTime(rational_time_duration_from_start_end_time(startTime.cxxRationalTime, endTime.cxxRationalTime)) } - + + @available(*, deprecated, renamed: "isSmpteTimecodeRate") static public func isValidTimecodeRate(_ inRate: Double) -> Bool { return rational_time_is_valid_timecode_rate(inRate) } - + + static public func isSmpteTimecodeRate(_ inRate: Double) -> Bool { + return rational_time_is_smpte_timecode_rate(inRate) + } + static public func from(frame: Double, rate inRate: Double) -> RationalTime { return RationalTime(value: floor(frame), rate: inRate) } @@ -71,27 +76,27 @@ public struct RationalTime: CustomStringConvertible, Equatable { static public func from(seconds: Double) -> RationalTime { return RationalTime(value: seconds, rate: 1) } - + static public func from(timecode: String, rate inRate: Double) throws -> RationalTime { return try OpentimeError.returnOrThrow { RationalTime(rational_time_from_timecode(timecode, inRate, &$0)) } } - + static public func from(timestring: String, rate inRate: Double) throws -> RationalTime { return try OpentimeError.returnOrThrow { RationalTime(rational_time_from_timestring(timestring, inRate, &$0)) } } - + public func toFrames() -> Int { return Int(value) } - + public func toFrames(rate inRate: Double) -> Int { return Int(valueRescaled(to: inRate)) } - + public func toSeconds() -> Double { return valueRescaled(to: 1) } - + public func toTimecode(rate inRate: Double) throws -> String { return try OpentimeError.returnOrThrow { rational_time_to_timecode(cxxRationalTime, inRate, &$0) } } @@ -115,7 +120,7 @@ public struct RationalTime: CustomStringConvertible, Equatable { static public prefix func - (lhs: RationalTime) -> RationalTime { return RationalTime(value: -lhs.value, rate: -lhs.rate) } - + static public func + (lhs: RationalTime, rhs: RationalTime) -> RationalTime { return RationalTime(rational_time_add(lhs.cxxRationalTime, rhs.cxxRationalTime)) } @@ -151,7 +156,6 @@ public struct RationalTime: CustomStringConvertible, Equatable { internal init(_ cxxRationalTime: CxxRationalTime) { self.cxxRationalTime = cxxRationalTime } - + internal let cxxRationalTime: CxxRationalTime } - diff --git a/Tests/OpenTimelineIOTests/testRationalTime.swift b/Tests/OpenTimelineIOTests/testRationalTime.swift index b610b09..72455f5 100644 --- a/Tests/OpenTimelineIOTests/testRationalTime.swift +++ b/Tests/OpenTimelineIOTests/testRationalTime.swift @@ -211,6 +211,15 @@ class testRationalTime: XCTestCase { try XCTAssertThrowsError(t.toTimecode()) } + func testSmpteRates() { + XCTAssertFalse(RationalTime.isSmpteTimecodeRate(29.98)) + XCTAssertFalse(RationalTime.isSmpteTimecodeRate(23.98)) + XCTAssertTrue(RationalTime.isSmpteTimecodeRate(30000.0 / 1001.0)) + XCTAssertTrue(RationalTime.isSmpteTimecodeRate(24000.0 / 1001.0)) + XCTAssertTrue(RationalTime.isSmpteTimecodeRate(30)) + XCTAssertTrue(RationalTime.isSmpteTimecodeRate(24)) + } + func testTimeString24() { var time_string = "00:00:00.041667" var t = RationalTime(value: 1.0, rate: 24) From 6052b07909ca9c5f10c9f8e283d2307816e7fca5 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Tue, 17 Feb 2026 22:54:33 -0800 Subject: [PATCH 5/7] Switch runner to macos-26 Signed-off-by: Joshua Minor --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53dc5f7..0e86994 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ concurrency: jobs: build: - runs-on: macos-latest + runs-on: macos-26 steps: - uses: actions/checkout@v6 From a0f2cced08717dc1abc48046f8e9ec4b33c9e4f3 Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Tue, 17 Feb 2026 23:45:52 -0800 Subject: [PATCH 6/7] Added pre-made version.h files and header search paths to find them. Signed-off-by: Joshua Minor --- Package.swift | 8 +++++--- Sources/cpp/opentime/version.h | 16 +++++++++++++++ Sources/cpp/opentimelineio/version.h | 29 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 Sources/cpp/opentime/version.h create mode 100644 Sources/cpp/opentimelineio/version.h diff --git a/Package.swift b/Package.swift index ef62d79..3510869 100644 --- a/Package.swift +++ b/Package.swift @@ -36,7 +36,9 @@ let package = Package( exclude: ["CMakeLists.txt", "OpenTimeConfig.cmake.in", "version.h.in"], sources: ["."], publicHeadersPath: ".", - cxxSettings: [ .headerSearchPath(".")]), + cxxSettings: [ + .headerSearchPath("."), + .headerSearchPath("../../../Sources/cpp")]), .target(name: "OpenTimelineIO_CXX", dependencies: ["OpenTime_CXX"], @@ -47,7 +49,7 @@ let package = Package( cxxSettings: [ .headerSearchPath("."), .headerSearchPath("../deps/any/"), - .headerSearchPath("../deps/Imath/src/Imath"), + .headerSearchPath("../deps/Imath/src"), .headerSearchPath("../../../Sources/cpp"), .headerSearchPath("../deps/rapidjson/include")]), @@ -58,7 +60,7 @@ let package = Package( sources: ["objc"], publicHeadersPath: "objc/include", cxxSettings: [ - .headerSearchPath("../OpenTimelineIO/src/deps/Imath/src/Imath"), + .headerSearchPath("../OpenTimelineIO/src/deps/Imath/src"), .headerSearchPath("../Sources/cpp"), .headerSearchPath("objc/include")]), diff --git a/Sources/cpp/opentime/version.h b/Sources/cpp/opentime/version.h new file mode 100644 index 0000000..a5d1224 --- /dev/null +++ b/Sources/cpp/opentime/version.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the OpenTimelineIO project + +#pragma once + +#define OPENTIME_VERSION_MAJOR 0 +#define OPENTIME_VERSION_MINOR 18 +#define OPENTIME_VERSION_PATCH 1 +#define OPENTIME_VERSION v0_18_1 + +namespace opentime { +namespace OPENTIME_VERSION { +} + +using namespace OPENTIME_VERSION; +} // namespace opentime diff --git a/Sources/cpp/opentimelineio/version.h b/Sources/cpp/opentimelineio/version.h new file mode 100644 index 0000000..054d96b --- /dev/null +++ b/Sources/cpp/opentimelineio/version.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the OpenTimelineIO project + +#pragma once + +#define OPENTIMELINEIO_VERSION_MAJOR 0 +#define OPENTIMELINEIO_VERSION_MINOR 18 +#define OPENTIMELINEIO_VERSION_PATCH 1 +#define OPENTIMELINEIO_VERSION v0_18_1 + +#include "opentime/rationalTime.h" +#include "opentime/timeRange.h" +#include "opentime/timeTransform.h" +#include "opentime/version.h" + +namespace opentimelineio { namespace OPENTIMELINEIO_VERSION { +using opentime::RationalTime; +using opentime::TimeRange; +using opentime::TimeTransform; +}} // namespace opentimelineio::OPENTIMELINEIO_VERSION + +/// @brief Convenience macro for the full namespace of OpenTimelineIO API. +/// +/// This can be used in place of the full namespace, e.g.: +/// +/// OTIO_NS::Track* track = new OTIO_NS::Track; +/// +/// +#define OTIO_NS opentimelineio::OPENTIMELINEIO_VERSION From 53e38c82add57a9ddd29519d869eb09fb7b6c5ff Mon Sep 17 00:00:00 2001 From: Joshua Minor Date: Sat, 28 Feb 2026 23:17:23 -0800 Subject: [PATCH 7/7] Trying out OTIO PR#1993 https://github.com/AcademySoftwareFoundation/OpenTimelineIO/pull/1993 Signed-off-by: Joshua Minor --- Examples/Sources/cxx_example/main.cpp | 5 +-- OpenTimelineIO | 2 +- Package.swift | 4 +- Sources/cpp/opentime/version.h | 16 ------- Sources/cpp/opentimelineio/version.h | 29 ------------- .../include/CxxAnyDictionaryMutationStamp.h | 2 +- .../objc/include/CxxAnyVectorMutationStamp.h | 2 +- Sources/objc/include/CxxRetainer.h | 2 +- Sources/objc/include/CxxVectorProperty.h | 26 ++++++------ Sources/objc/include/opentime.h | 2 +- Sources/objc/opentime.mm | 2 +- Sources/objc/opentimelineio.mm | 42 +++++++++---------- 12 files changed, 43 insertions(+), 91 deletions(-) delete mode 100644 Sources/cpp/opentime/version.h delete mode 100644 Sources/cpp/opentimelineio/version.h diff --git a/Examples/Sources/cxx_example/main.cpp b/Examples/Sources/cxx_example/main.cpp index 3e02ce3..294a362 100644 --- a/Examples/Sources/cxx_example/main.cpp +++ b/Examples/Sources/cxx_example/main.cpp @@ -8,7 +8,7 @@ #include "opentime/timeRange.h" #include "opentimelineio/optional.h" -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; otio::SerializableObject* create_stuff() { auto x = new otio::SerializableObjectWithMetadata; @@ -20,7 +20,7 @@ otio::SerializableObject* create_stuff() { x->metadata()["stuff4"] = 3.14159; x->metadata()["stuff5"] = opentime::RationalTime(); x->metadata()["stuff6"] = opentime::TimeRange(); - + otio::AnyVector junk; junk.push_back(13); junk.push_back("hello"); @@ -34,4 +34,3 @@ int main() { std::string s = so->to_json_string(&status); printf("%s\n", s.c_str()); } - diff --git a/OpenTimelineIO b/OpenTimelineIO index 4423671..d3d5713 160000 --- a/OpenTimelineIO +++ b/OpenTimelineIO @@ -1 +1 @@ -Subproject commit 44236713c1db295a6ffc66189ae98dbdfd0cb9c4 +Subproject commit d3d5713511eaa4fbdfb428ce804898618e338286 diff --git a/Package.swift b/Package.swift index 3510869..3f538f3 100644 --- a/Package.swift +++ b/Package.swift @@ -36,9 +36,7 @@ let package = Package( exclude: ["CMakeLists.txt", "OpenTimeConfig.cmake.in", "version.h.in"], sources: ["."], publicHeadersPath: ".", - cxxSettings: [ - .headerSearchPath("."), - .headerSearchPath("../../../Sources/cpp")]), + cxxSettings: [.headerSearchPath(".")]), .target(name: "OpenTimelineIO_CXX", dependencies: ["OpenTime_CXX"], diff --git a/Sources/cpp/opentime/version.h b/Sources/cpp/opentime/version.h deleted file mode 100644 index a5d1224..0000000 --- a/Sources/cpp/opentime/version.h +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Contributors to the OpenTimelineIO project - -#pragma once - -#define OPENTIME_VERSION_MAJOR 0 -#define OPENTIME_VERSION_MINOR 18 -#define OPENTIME_VERSION_PATCH 1 -#define OPENTIME_VERSION v0_18_1 - -namespace opentime { -namespace OPENTIME_VERSION { -} - -using namespace OPENTIME_VERSION; -} // namespace opentime diff --git a/Sources/cpp/opentimelineio/version.h b/Sources/cpp/opentimelineio/version.h deleted file mode 100644 index 054d96b..0000000 --- a/Sources/cpp/opentimelineio/version.h +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Contributors to the OpenTimelineIO project - -#pragma once - -#define OPENTIMELINEIO_VERSION_MAJOR 0 -#define OPENTIMELINEIO_VERSION_MINOR 18 -#define OPENTIMELINEIO_VERSION_PATCH 1 -#define OPENTIMELINEIO_VERSION v0_18_1 - -#include "opentime/rationalTime.h" -#include "opentime/timeRange.h" -#include "opentime/timeTransform.h" -#include "opentime/version.h" - -namespace opentimelineio { namespace OPENTIMELINEIO_VERSION { -using opentime::RationalTime; -using opentime::TimeRange; -using opentime::TimeTransform; -}} // namespace opentimelineio::OPENTIMELINEIO_VERSION - -/// @brief Convenience macro for the full namespace of OpenTimelineIO API. -/// -/// This can be used in place of the full namespace, e.g.: -/// -/// OTIO_NS::Track* track = new OTIO_NS::Track; -/// -/// -#define OTIO_NS opentimelineio::OPENTIMELINEIO_VERSION diff --git a/Sources/objc/include/CxxAnyDictionaryMutationStamp.h b/Sources/objc/include/CxxAnyDictionaryMutationStamp.h index 29ffd8a..d82e94b 100644 --- a/Sources/objc/include/CxxAnyDictionaryMutationStamp.h +++ b/Sources/objc/include/CxxAnyDictionaryMutationStamp.h @@ -12,7 +12,7 @@ #if defined(__cplusplus) #import -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; #endif NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/objc/include/CxxAnyVectorMutationStamp.h b/Sources/objc/include/CxxAnyVectorMutationStamp.h index f4e1ef0..58fb1e0 100644 --- a/Sources/objc/include/CxxAnyVectorMutationStamp.h +++ b/Sources/objc/include/CxxAnyVectorMutationStamp.h @@ -12,7 +12,7 @@ #if defined(__cplusplus) #import -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; #endif NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/objc/include/CxxRetainer.h b/Sources/objc/include/CxxRetainer.h index ec2fdb0..3576e9b 100644 --- a/Sources/objc/include/CxxRetainer.h +++ b/Sources/objc/include/CxxRetainer.h @@ -9,7 +9,7 @@ #if defined(__cplusplus) #import -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; #endif NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/objc/include/CxxVectorProperty.h b/Sources/objc/include/CxxVectorProperty.h index e5b39ea..89fc4d4 100644 --- a/Sources/objc/include/CxxVectorProperty.h +++ b/Sources/objc/include/CxxVectorProperty.h @@ -10,7 +10,7 @@ #if defined(__cplusplus) #import -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; class CxxSOVectorBase { public: @@ -18,11 +18,11 @@ class CxxSOVectorBase { CxxSOVectorBase& operator=(CxxSOVectorBase const&) = delete; CxxSOVectorBase(CxxSOVectorBase const&) = delete; virtual ~CxxSOVectorBase(); - + virtual otio::SerializableObject* _Nullable fetch(int index) = 0; virtual int size() = 0; virtual void clear() = 0; - + virtual void store(int index, otio::SerializableObject* _Nonnull) = 0; virtual void moveIndex(int fromIndex, int toIndex) = 0; virtual void removeAtEnd() = 0; @@ -38,7 +38,7 @@ class CxxSOVector : public CxxSOVectorBase { : _v{* new std::vector>}, _owner{true} { } - + CxxSOVector(std::vector>& v) : _v{v}, _owner{false} { } @@ -46,17 +46,17 @@ class CxxSOVector : public CxxSOVectorBase { virtual otio::SerializableObject* _Nullable fetch(int index) { return index < _v.size() ? _v[index] : nullptr; } - + virtual int size() { return int(_v.size()); } - + virtual ~CxxSOVector() { if (_owner) { delete &_v; } } - + virtual void clear() { _v.clear(); } @@ -69,19 +69,19 @@ class CxxSOVector : public CxxSOVectorBase { _v.emplace_back(otio::SerializableObject::Retainer((T*)so)); } } - + virtual void moveIndex(int fromIndex, int toIndex) { std::swap(_v[fromIndex], _v[toIndex]); } - + virtual void append(otio::SerializableObject* _Nonnull so) { _v.emplace_back(otio::SerializableObject::Retainer((T*)so)); } - + virtual void removeAtEnd() { _v.pop_back(); } - + virtual void shrinkOrGrow(int n, bool grow) { if (grow) { for (int i = 0; i < n; i++) { @@ -93,13 +93,13 @@ class CxxSOVector : public CxxSOVectorBase { _v.clear(); return; } - + for (int i = 0; i < n; i++) { _v.pop_back(); } } } - + virtual void setContents(CxxSOVectorBase* _Nonnull src, bool destroyingSrc) { CxxSOVector* typedSrc = (CxxSOVector*) src; if (destroyingSrc) { diff --git a/Sources/objc/include/opentime.h b/Sources/objc/include/opentime.h index d398bae..d1f333c 100644 --- a/Sources/objc/include/opentime.h +++ b/Sources/objc/include/opentime.h @@ -28,7 +28,7 @@ typedef struct CxxNonsense { #import #import -namespace ot = opentime::OPENTIME_VERSION; +namespace ot = opentime::OPENTIME_VERSION_NS; inline ot::RationalTime const& otioRationalTime(CxxRationalTime const& rt) { return *((ot::RationalTime const*)(&rt)); diff --git a/Sources/objc/opentime.mm b/Sources/objc/opentime.mm index 8036dff..9ced13f 100644 --- a/Sources/objc/opentime.mm +++ b/Sources/objc/opentime.mm @@ -10,7 +10,7 @@ #import #import "opentime.h" -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; static inline otio::RationalTime const* otioRationalTime(CxxRationalTime const* rt) { return (otio::RationalTime const*)(rt); diff --git a/Sources/objc/opentimelineio.mm b/Sources/objc/opentimelineio.mm index b750d0c..4252b0d 100644 --- a/Sources/objc/opentimelineio.mm +++ b/Sources/objc/opentimelineio.mm @@ -39,7 +39,7 @@ #import "errorStruct.h" #import "CxxVectorProperty.h" -namespace otio = opentimelineio::OPENTIMELINEIO_VERSION; +namespace otio = opentimelineio::OPENTIMELINEIO_VERSION_NS; template inline T* _Nonnull SO_cast(CxxRetainer const* r) { @@ -97,11 +97,11 @@ otio::AnyDictionary d, d2; d["abc"] = 123; d["xyz"] = 456; - + d2["r1"] = otio::RationalTime(1,2); d2["r2"] = otio::RationalTime(100,200); d2["plugh"] = 37; - + d["nested"] = d2; c->metadata() = d; return c;*/ @@ -193,7 +193,7 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch _AutoErrorHandler aeh(cxxErr); otio::schema_version_map map = _to_cxx_schema_version_map(target_family_label_spec); self.retainer.value->to_json_file(filename.UTF8String, &aeh.error_status, &map, indent); - + } NSString* serializable_object_to_json_string(CxxRetainer* self, schema_version_map *target_family_label_spec, int indent, CxxErrorStruct* cxxErr) { @@ -216,7 +216,7 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch _AutoErrorHandler aeh(cxxErr); return self.retainer.value->clone(&aeh.error_status); } - + bool serializable_object_is_equivalent_to(CxxRetainer* lhs, CxxRetainer* rhs) { return lhs.retainer.value->is_equivalent_to(*rhs.retainer.value); } @@ -382,7 +382,7 @@ bool item_trimmed_range_in_parent(CxxRetainer* self, CxxTimeRange* tr, CxxErrorS _AutoErrorHandler aeh(cxxErr); auto item = SO_cast(self); auto result = item->trimmed_range_in_parent(&aeh.error_status); - + if (result) { *tr = cxxTimeRange(*result); return true; @@ -479,7 +479,7 @@ void clip_set_media_reference(CxxRetainer* self, CxxRetainer* media_reference) { CxxVectorProperty* create_composition_children_vector_property(CxxRetainer* self) { auto composition = SO_cast(self); auto p = [CxxVectorProperty new]; - + // Yes, I know: but we're not going to mutate this and neither is anybody else. // We're only going to look at it. auto& children = const_cast>&>(composition->children()); @@ -521,13 +521,13 @@ void composition_append_child(CxxRetainer* self, CxxRetainer* child_retainer, Cx auto dict = [NSMutableDictionary new]; _AutoErrorHandler aeh(cxxErr); auto result = SO_cast(self)->range_of_all_children(&aeh.error_status); - + for (auto item: result) { auto tr = cxxTimeRange(item.second); [dict setObject: [NSValue valueWithBytes:&tr objCType:@encode(CxxTimeRange)] forKey: [NSValue valueWithPointer:item.first]]; } - + return dict; } @@ -548,7 +548,7 @@ void composition_handles_of_child(CxxRetainer* self, CxxRetainer* composable, bool* hasLeft, bool* hasRight, CxxErrorStruct* cxxErr) { _AutoErrorHandler aeh(cxxErr); auto result = SO_cast(self)->handles_of_child(SO_cast(composable), &aeh.error_status); - + if (result.first) { *hasLeft = true; *rt1 = cxxRationalTime(*(result.first)); @@ -556,7 +556,7 @@ void composition_handles_of_child(CxxRetainer* self, CxxRetainer* composable, else { *hasLeft = false; } - + if (result.second) { *hasRight = true; *rt2 = cxxRationalTime(*(result.second)); @@ -645,27 +645,27 @@ void media_reference_clear_available_range(CxxRetainer* self) { // If true, value of passed in rect is set. If false, there was no media reference bounds bool media_reference_available_image_bounds(CxxRetainer* self, CGRect* rect) { std::optional iBox2D = SO_cast(self)->available_image_bounds(); - + if (iBox2D) { rect->origin.x = iBox2D->min.x; rect->origin.y = iBox2D->min.y; rect->size.width = iBox2D->max.x - iBox2D->min.x; rect->size.height = iBox2D->max.y - iBox2D->min.y; - + return true; } - + return false; } void media_reference_set_available_image_bounds(CxxRetainer* self, CGRect image_bounds) { std::optional iBox2D = std::optional(); - + iBox2D->min.x = image_bounds.origin.x; iBox2D->min.y = image_bounds.origin.y; iBox2D->max.x = image_bounds.size.width + image_bounds.origin.x; iBox2D->max.y = image_bounds.size.height + image_bounds.origin.y; - + SO_cast(self)->set_available_image_bounds(iBox2D); } @@ -718,7 +718,7 @@ CxxTimeRange timeline_range_of_child(CxxRetainer* self, CxxRetainer* child, CxxE } return array; } - + NSArray* timeline_video_tracks(CxxRetainer* self) { auto array = [NSMutableArray new]; for (auto t: SO_cast(self)->video_tracks()) { @@ -757,7 +757,7 @@ void effect_set_name(CxxRetainer* self, NSString* name) { NSString* external_reference_get_target_url(CxxRetainer* self) { return make_nsstring(SO_cast(self)->target_url()); } - + void external_reference_set_target_url(CxxRetainer* self, NSString* target_url) { SO_cast(self)->set_target_url([target_url UTF8String]); } @@ -770,7 +770,7 @@ void external_reference_set_target_url(CxxRetainer* self, NSString* target_url) void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) { SO_cast(self)->set_generator_kind([kind UTF8String]); } - + void* generator_reference_parameters(CxxRetainer* self) { return &SO_cast(self)->parameters(); } @@ -779,7 +779,7 @@ void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) { double linear_time_warp_get_time_scalar(CxxRetainer* self) { return SO_cast(self)->time_scalar(); } - + void linear_time_warp_set_time_scalar(CxxRetainer* self, double time_scalar) { SO_cast(self)->set_time_scalar(time_scalar); } @@ -794,7 +794,7 @@ void linear_time_warp_set_time_scalar(CxxRetainer* self, double time_scalar) { void* algorithms_flatten_stack(CxxRetainer* in_stack, CxxErrorStruct* cxxErr) { _AutoErrorHandler aeh(cxxErr); - return otio::flatten_stack(SO_cast(in_stack), &aeh.error_status); + return otio::flatten_stack(SO_cast(in_stack), &aeh.error_status); } void* algorithms_flatten_track_array(NSArray* tracks, CxxErrorStruct* cxxErr) {