From 7fb5dcc2ec6b0f678bbe9e42b7e14f9f81f3fe1b Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Sun, 1 Oct 2023 17:53:31 -0700 Subject: [PATCH 01/10] Exclude deps --- etc/Linux/lcov.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/Linux/lcov.sh b/etc/Linux/lcov.sh index 470a9030e..ab0809201 100644 --- a/etc/Linux/lcov.sh +++ b/etc/Linux/lcov.sh @@ -1,8 +1,8 @@ #!/bin/sh -lcov -c -b . -d . -o coverage.info --exclude deps +lcov -c -b . -d . -o coverage.info lcov -r coverage.info '*/usr/*' -o coverage_filtered.info lcov -r coverage_filtered.info '*/install/*' -o coverage_filtered.info lcov -r coverage_filtered.info '*/tests/*' -o coverage_filtered.info +lcov -r coverage_filtered.info '*/deps/*' -o coverage_filtered.info lcov --list coverage_filtered.info - From 2d7a6e1bc90aade79ec524b476739e375f9bb6d3 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 10:24:43 -0700 Subject: [PATCH 02/10] Add tests --- lib/tlCore/Matrix.h | 29 ++++- lib/tlCore/MatrixInline.h | 118 +++++++++++++------- lib/tlCore/Vector.h | 9 ++ lib/tlCore/VectorInline.h | 48 ++++++-- lib/tlTimeline/ImageOptions.h | 6 +- lib/tlTimeline/PlayerOptions.h | 24 ++-- tests/tlCoreTest/MatrixTest.cpp | 24 ++++ tests/tlTimelineTest/CMakeLists.txt | 8 ++ tests/tlTimelineTest/CompareOptionsTest.cpp | 85 ++++++++++++++ tests/tlTimelineTest/CompareOptionsTest.h | 24 ++++ tests/tlTimelineTest/DisplayOptionsTest.cpp | 90 +++++++++++++++ tests/tlTimelineTest/DisplayOptionsTest.h | 24 ++++ tests/tlTimelineTest/ImageOptionsTest.cpp | 48 ++++++++ tests/tlTimelineTest/ImageOptionsTest.h | 24 ++++ tests/tlTimelineTest/PlayerOptionsTest.cpp | 47 ++++++++ tests/tlTimelineTest/PlayerOptionsTest.h | 24 ++++ tests/tltest/main.cpp | 8 ++ 17 files changed, 574 insertions(+), 66 deletions(-) create mode 100644 tests/tlTimelineTest/CompareOptionsTest.cpp create mode 100644 tests/tlTimelineTest/CompareOptionsTest.h create mode 100644 tests/tlTimelineTest/DisplayOptionsTest.cpp create mode 100644 tests/tlTimelineTest/DisplayOptionsTest.h create mode 100644 tests/tlTimelineTest/ImageOptionsTest.cpp create mode 100644 tests/tlTimelineTest/ImageOptionsTest.h create mode 100644 tests/tlTimelineTest/PlayerOptionsTest.cpp create mode 100644 tests/tlTimelineTest/PlayerOptionsTest.h diff --git a/lib/tlCore/Matrix.h b/lib/tlCore/Matrix.h index 868af76ab..ab0af8c33 100644 --- a/lib/tlCore/Matrix.h +++ b/lib/tlCore/Matrix.h @@ -25,8 +25,6 @@ namespace tl constexpr bool operator == (const Matrix3x3&) const; constexpr bool operator != (const Matrix3x3&) const; - - inline Matrix3x3 operator * (const Matrix3x3&) const; }; //! 4x4 matrix. @@ -45,8 +43,6 @@ namespace tl constexpr bool operator == (const Matrix4x4&) const; constexpr bool operator != (const Matrix4x4&) const; - - Matrix4x4 operator * (const Matrix4x4&) const; }; //! 3x3 floating point matrix. @@ -55,6 +51,9 @@ namespace tl //! 4x4 floating point matrix. typedef Matrix4x4 Matrix4x4f; + //! \name Matrices + ///@{ + //! Create a translation matrix. template constexpr Matrix4x4 translate(const Vector3&); @@ -83,6 +82,28 @@ namespace tl template constexpr Matrix4x4 perspective(T fov, T aspect, T nearClip, T farClip); + ///@} + + //! \name Operators + ///@{ + + template + Matrix3x3 operator * (const Matrix3x3&, const Matrix3x3&); + + template + Vector2 operator * (const Matrix3x3&, const Vector2&); + + template + Matrix4x4 operator * (const Matrix4x4&, const Matrix4x4&); + + template + Vector3 operator * (const Matrix4x4&, const Vector3&); + + template + Vector4 operator * (const Matrix4x4&, const Vector4&); + + ///@} + //! \name Serialize ///@{ diff --git a/lib/tlCore/MatrixInline.h b/lib/tlCore/MatrixInline.h index 95740a216..626f3766a 100644 --- a/lib/tlCore/MatrixInline.h +++ b/lib/tlCore/MatrixInline.h @@ -70,25 +70,6 @@ namespace tl return !(*this == other); } - template - inline Matrix3x3 Matrix3x3::operator * (const Matrix3x3& value) const - { - Matrix3x3 out; - for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - float tmp = 0.F; - for (int k = 0; k < 3; ++k) - { - tmp += value.e[i * 3 + k] * e[k * 3 + j]; - } - out.e[i * 3 + j] = tmp; - } - } - return out; - } - template constexpr bool Matrix4x4::operator == (const Matrix4x4& other) const { @@ -117,25 +98,6 @@ namespace tl return !(*this == other); } - template - inline Matrix4x4 Matrix4x4::operator * (const Matrix4x4& value) const - { - Matrix4x4 out; - for (int i = 0; i < 4; ++i) - { - for (int j = 0; j < 4; ++j) - { - float tmp = 0.F; - for (int k = 0; k < 4; ++k) - { - tmp += value.e[i * 4 + k] * e[k * 4 + j]; - } - out.e[i * 4 + j] = tmp; - } - } - return out; - } - template constexpr Matrix4x4 translate(const Vector3& value) { @@ -221,5 +183,85 @@ namespace tl T(0), T(0), b, T(-1), T(0), T(0), c, T(0)); } + + template + inline Matrix3x3 operator * (const Matrix3x3& a, const Matrix3x3& b) + { + Matrix3x3 out; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + float tmp = 0.F; + for (int k = 0; k < 3; ++k) + { + tmp += b.e[i * 3 + k] * a.e[k * 3 + j]; + } + out.e[i * 3 + j] = tmp; + } + } + return out; + } + + template + inline Vector2 operator * (const Matrix3x3& a, const Vector2& v) + { + Vector2 out; + for (int i = 0; i < 2; ++i) + { + for (int j = 0; j < 2; ++j) + { + out[i] += a.e[i * 3 + j] * v[j]; + } + } + return out; + } + + template + inline Matrix4x4 operator * (const Matrix4x4& a, const Matrix4x4& b) + { + Matrix4x4 out; + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + float tmp = 0.F; + for (int k = 0; k < 4; ++k) + { + tmp += b.e[i * 4 + k] * a.e[k * 4 + j]; + } + out.e[i * 4 + j] = tmp; + } + } + return out; + } + + template + inline Vector3 operator * (const Matrix4x4& a, const Vector3& v) + { + Vector3 out; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + out[i] += a.e[i * 4 + j] * v[j]; + } + } + return out; + } + + template + inline Vector4 operator * (const Matrix4x4& a, const Vector4& v) + { + Vector4 out; + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + out[i] += a.e[i * 4 + j] * v[j]; + } + } + return out; + } }; } diff --git a/lib/tlCore/Vector.h b/lib/tlCore/Vector.h index ba1399942..96e0adb07 100644 --- a/lib/tlCore/Vector.h +++ b/lib/tlCore/Vector.h @@ -28,6 +28,9 @@ namespace tl void zero(); + constexpr T operator [] (int) const; + T& operator [] (int); + ///@} constexpr bool operator == (const Vector2&) const; @@ -51,6 +54,9 @@ namespace tl void zero(); + constexpr T operator [] (int) const; + T& operator [] (int); + ///@} constexpr bool operator == (const Vector3&) const; @@ -75,6 +81,9 @@ namespace tl void zero(); + constexpr T operator [] (int) const; + T& operator [] (int); + ///@} constexpr bool operator == (const Vector4&) const; diff --git a/lib/tlCore/VectorInline.h b/lib/tlCore/VectorInline.h index 9ed4c1a9f..bf6e60a2c 100644 --- a/lib/tlCore/VectorInline.h +++ b/lib/tlCore/VectorInline.h @@ -59,25 +59,55 @@ namespace tl template inline void Vector2::zero() { - x = T(0); - y = T(0); + x = y = T(0); } template inline void Vector3::zero() { - x = T(0); - y = T(0); - z = T(0); + x = y = z = T(0); } template inline void Vector4::zero() { - x = T(0); - y = T(0); - z = T(0); - w = T(0); + x = y = z = w = T(0); + } + + template + constexpr T Vector2::operator [] (int index) const + { + return 0 == index ? x : y; + } + + template + T& Vector2::operator [] (int index) + { + return 0 == index ? x : y; + } + + template + constexpr T Vector3::operator [] (int index) const + { + return 0 == index ? x : (1 == index ? y : z); + } + + template + T& Vector3::operator [] (int index) + { + return 0 == index ? x : (1 == index ? y : z); + } + + template + constexpr T Vector4::operator [] (int index) const + { + return 0 == index ? x : (1 == index ? y : (2 == index ? z : w)); + } + + template + T& Vector4::operator [] (int index) + { + return 0 == index ? x : (1 == index ? y : (2 == index ? z : w)); } template diff --git a/lib/tlTimeline/ImageOptions.h b/lib/tlTimeline/ImageOptions.h index 227e6ebc0..b6a1324f4 100644 --- a/lib/tlTimeline/ImageOptions.h +++ b/lib/tlTimeline/ImageOptions.h @@ -60,7 +60,7 @@ namespace tl //! Image filters. struct ImageFilters { - ImageFilter minify = ImageFilter::Linear; + ImageFilter minify = ImageFilter::Linear; ImageFilter magnify = ImageFilter::Linear; bool operator == (const ImageFilters&) const; @@ -70,8 +70,8 @@ namespace tl //! Image options. struct ImageOptions { - InputVideoLevels videoLevels = InputVideoLevels::FromFile; - AlphaBlend alphaBlend = AlphaBlend::Straight; + InputVideoLevels videoLevels = InputVideoLevels::FromFile; + AlphaBlend alphaBlend = AlphaBlend::Straight; ImageFilters imageFilters; bool operator == (const ImageOptions&) const; diff --git a/lib/tlTimeline/PlayerOptions.h b/lib/tlTimeline/PlayerOptions.h index e8dec22b6..70d63549c 100644 --- a/lib/tlTimeline/PlayerOptions.h +++ b/lib/tlTimeline/PlayerOptions.h @@ -22,6 +22,18 @@ namespace tl TLRENDER_ENUM(TimerMode); TLRENDER_ENUM_SERIALIZE(TimerMode); + //! External time mode. + enum class ExternalTimeMode + { + Relative, + Absolute, + + Count, + First = Relative + }; + TLRENDER_ENUM(ExternalTimeMode); + TLRENDER_ENUM_SERIALIZE(ExternalTimeMode); + //! Timeline player cache options. struct PlayerCacheOptions { @@ -35,18 +47,6 @@ namespace tl bool operator != (const PlayerCacheOptions&) const; }; - //! External time mode. - enum class ExternalTimeMode - { - Relative, - Absolute, - - Count, - First = Relative - }; - TLRENDER_ENUM(ExternalTimeMode); - TLRENDER_ENUM_SERIALIZE(ExternalTimeMode); - //! Get an external time from a source time. otime::RationalTime getExternalTime( const otime::RationalTime& sourceTime, diff --git a/tests/tlCoreTest/MatrixTest.cpp b/tests/tlCoreTest/MatrixTest.cpp index aa5ab4690..5a5390c37 100644 --- a/tests/tlCoreTest/MatrixTest.cpp +++ b/tests/tlCoreTest/MatrixTest.cpp @@ -38,16 +38,40 @@ namespace tl a.e[1] = 1.F; TLRENDER_ASSERT(a != b); } + { + TLRENDER_ASSERT(translate(Vector3f(1.F, 2.F, 3.F)) != Matrix4x4f()); + TLRENDER_ASSERT(rotateX(90.F) != Matrix4x4f()); + TLRENDER_ASSERT(rotateY(90.F) != Matrix4x4f()); + TLRENDER_ASSERT(rotateZ(90.F) != Matrix4x4f()); + TLRENDER_ASSERT(scale(Vector3f(1.F, 2.F, 3.F)) != Matrix4x4f()); + TLRENDER_ASSERT(ortho(-1.F, -1.F, 1.F, 1.F, -1.F, 1.F) != Matrix4x4f()); + TLRENDER_ASSERT(perspective(90.F, 1.F, .1F, 10000.F) != Matrix4x4f()); + } { Matrix3x3f a; Matrix3x3f b; TLRENDER_ASSERT(a * b == Matrix3x3f()); } + { + Matrix3x3f a; + Vector2f b(1.F, 2.F); + TLRENDER_ASSERT(a * b == b); + } { Matrix4x4f a; Matrix4x4f b; TLRENDER_ASSERT(a * b == Matrix4x4f()); } + { + Matrix4x4f a; + Vector3f b(1.F, 2.F, 3.F); + TLRENDER_ASSERT(a * b == b); + } + { + Matrix4x4f a; + Vector4f b(1.F, 2.F, 3.F, 4.F); + TLRENDER_ASSERT(a * b == b); + } { const Matrix3x3f m; nlohmann::json json; diff --git a/tests/tlTimelineTest/CMakeLists.txt b/tests/tlTimelineTest/CMakeLists.txt index a62b23b82..01eb954ef 100644 --- a/tests/tlTimelineTest/CMakeLists.txt +++ b/tests/tlTimelineTest/CMakeLists.txt @@ -1,17 +1,25 @@ set(HEADERS ColorConfigOptionsTest.h + CompareOptionsTest.h + DisplayOptionsTest.h EditTest.h IRenderTest.h + ImageOptionsTest.h LUTOptionsTest.h + PlayerOptionsTest.h PlayerTest.h TimelineTest.h UtilTest.h) set(SOURCE ColorConfigOptionsTest.cpp + CompareOptionsTest.cpp + DisplayOptionsTest.cpp EditTest.cpp IRenderTest.cpp + ImageOptionsTest.cpp LUTOptionsTest.cpp + PlayerOptionsTest.cpp PlayerTest.cpp TimelineTest.cpp UtilTest.cpp) diff --git a/tests/tlTimelineTest/CompareOptionsTest.cpp b/tests/tlTimelineTest/CompareOptionsTest.cpp new file mode 100644 index 000000000..fdbde0fab --- /dev/null +++ b/tests/tlTimelineTest/CompareOptionsTest.cpp @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#include + +#include + +#include +#include + +using namespace tl::timeline; + +namespace tl +{ + namespace timeline_tests + { + CompareOptionsTest::CompareOptionsTest(const std::shared_ptr& context) : + ITest("timeline_tests::CompareOptionsTest", context) + {} + + std::shared_ptr CompareOptionsTest::create(const std::shared_ptr& context) + { + return std::shared_ptr(new CompareOptionsTest(context)); + } + + void CompareOptionsTest::run() + { + { + _enum("CompareMode", getCompareModeEnums); + } + { + CompareOptions options; + options.mode = CompareMode::B; + TLRENDER_ASSERT(options == options); + TLRENDER_ASSERT(options != CompareOptions()); + } + { + const std::vector sizes = + { + image::Size(1920, 1080), + image::Size(1920 / 2, 1080 / 2) + }; + + for (auto mode : + { + CompareMode::A, + CompareMode::B, + CompareMode::Wipe, + CompareMode::Overlay, + CompareMode::Difference + }) + { + auto boxes = getBoxes(mode, sizes); + TLRENDER_ASSERT(2 == boxes.size()); + TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[0]); + TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[1]); + auto renderSize = getRenderSize(mode, sizes); + TLRENDER_ASSERT(math::Size2i(1920, 1080) == renderSize); + } + + auto boxes = getBoxes(CompareMode::Horizontal, sizes); + TLRENDER_ASSERT(2 == boxes.size()); + TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[0]); + TLRENDER_ASSERT(math::Box2i(1920, 0, 1920, 1080) == boxes[1]); + auto renderSize = getRenderSize(CompareMode::Horizontal, sizes); + TLRENDER_ASSERT(math::Size2i(1920 * 2, 1080) == renderSize); + + boxes = getBoxes(CompareMode::Vertical, sizes); + TLRENDER_ASSERT(2 == boxes.size()); + TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[0]); + TLRENDER_ASSERT(math::Box2i(0, 1080, 1920, 1080) == boxes[1]); + renderSize = getRenderSize(CompareMode::Vertical, sizes); + TLRENDER_ASSERT(math::Size2i(1920, 1080 * 2) == renderSize); + + boxes = getBoxes(CompareMode::Tile, sizes); + TLRENDER_ASSERT(2 == boxes.size()); + TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[0]); + TLRENDER_ASSERT(math::Box2i(0, 1080, 1920, 1080) == boxes[1]); + renderSize = getRenderSize(CompareMode::Tile, sizes); + TLRENDER_ASSERT(math::Size2i(1920, 1080 * 2) == renderSize); + } + } + } +} diff --git a/tests/tlTimelineTest/CompareOptionsTest.h b/tests/tlTimelineTest/CompareOptionsTest.h new file mode 100644 index 000000000..9378cff37 --- /dev/null +++ b/tests/tlTimelineTest/CompareOptionsTest.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +namespace tl +{ + namespace timeline_tests + { + class CompareOptionsTest : public tests::ITest + { + protected: + CompareOptionsTest(const std::shared_ptr&); + + public: + static std::shared_ptr create(const std::shared_ptr&); + + void run() override; + }; + } +} diff --git a/tests/tlTimelineTest/DisplayOptionsTest.cpp b/tests/tlTimelineTest/DisplayOptionsTest.cpp new file mode 100644 index 000000000..7b2fcf21a --- /dev/null +++ b/tests/tlTimelineTest/DisplayOptionsTest.cpp @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#include + +#include + +#include +#include + +using namespace tl::timeline; + +namespace tl +{ + namespace timeline_tests + { + DisplayOptionsTest::DisplayOptionsTest(const std::shared_ptr& context) : + ITest("timeline_tests::DisplayOptionsTest", context) + {} + + std::shared_ptr DisplayOptionsTest::create(const std::shared_ptr& context) + { + return std::shared_ptr(new DisplayOptionsTest(context)); + } + + void DisplayOptionsTest::run() + { + { + _enum("Channels", getChannelsEnums); + } + { + Color color; + color.enabled = true; + TLRENDER_ASSERT(color == color); + TLRENDER_ASSERT(color != Color()); + } + { + const auto mat = brightness(math::Vector3f(2.F, 1.F, 1.F)); + const auto vec = mat * math::Vector3f(1.F, 1.F, 1.F); + } + { + const auto mat = contrast(math::Vector3f(2.F, 1.F, 1.F)); + const auto vec = mat * math::Vector3f(1.F, 1.F, 1.F); + } + { + const auto mat = saturation(math::Vector3f(2.F, 1.F, 1.F)); + const auto vec = mat * math::Vector3f(1.F, 1.F, 1.F); + } + { + const auto mat = tint(2.F); + const auto vec = mat * math::Vector3f(1.F, 1.F, 1.F); + } + { + Color color; + color.brightness = math::Vector3f(2.F, 1.F, 1.F); + color.contrast = math::Vector3f(2.F, 1.F, 1.F); + color.saturation = math::Vector3f(2.F, 1.F, 1.F); + color.tint = 2.F; + color.invert = true; + const auto mat = timeline::color(color); + const auto vec = mat * math::Vector3f(1.F, 1.F, 1.F); + } + { + Levels levels; + levels.enabled = true; + TLRENDER_ASSERT(levels == levels); + TLRENDER_ASSERT(levels != Levels()); + } + { + EXRDisplay exrDisplay; + exrDisplay.enabled = true; + TLRENDER_ASSERT(exrDisplay == exrDisplay); + TLRENDER_ASSERT(exrDisplay != EXRDisplay()); + } + { + SoftClip softClip; + softClip.enabled = true; + TLRENDER_ASSERT(softClip == softClip); + TLRENDER_ASSERT(softClip != SoftClip()); + } + { + DisplayOptions displayOptions; + displayOptions.channels = Channels::Red; + TLRENDER_ASSERT(displayOptions == displayOptions); + TLRENDER_ASSERT(displayOptions != DisplayOptions()); + } + } + } +} diff --git a/tests/tlTimelineTest/DisplayOptionsTest.h b/tests/tlTimelineTest/DisplayOptionsTest.h new file mode 100644 index 000000000..e42e5eae6 --- /dev/null +++ b/tests/tlTimelineTest/DisplayOptionsTest.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +namespace tl +{ + namespace timeline_tests + { + class DisplayOptionsTest : public tests::ITest + { + protected: + DisplayOptionsTest(const std::shared_ptr&); + + public: + static std::shared_ptr create(const std::shared_ptr&); + + void run() override; + }; + } +} diff --git a/tests/tlTimelineTest/ImageOptionsTest.cpp b/tests/tlTimelineTest/ImageOptionsTest.cpp new file mode 100644 index 000000000..e10c2c370 --- /dev/null +++ b/tests/tlTimelineTest/ImageOptionsTest.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#include + +#include + +#include +#include + +using namespace tl::timeline; + +namespace tl +{ + namespace timeline_tests + { + ImageOptionsTest::ImageOptionsTest(const std::shared_ptr& context) : + ITest("timeline_tests::ImageOptionsTest", context) + {} + + std::shared_ptr ImageOptionsTest::create(const std::shared_ptr& context) + { + return std::shared_ptr(new ImageOptionsTest(context)); + } + + void ImageOptionsTest::run() + { + { + _enum("InputVideoLevels", getInputVideoLevelsEnums); + _enum("AlphaBlend", getAlphaBlendEnums); + _enum("ImageFilter", getImageFilterEnums); + } + { + ImageFilters v; + v.minify = ImageFilter::Nearest; + TLRENDER_ASSERT(v == v); + TLRENDER_ASSERT(v != ImageFilters()); + } + { + ImageOptions v; + v.videoLevels = InputVideoLevels::FullRange; + TLRENDER_ASSERT(v == v); + TLRENDER_ASSERT(v != ImageOptions()); + } + } + } +} diff --git a/tests/tlTimelineTest/ImageOptionsTest.h b/tests/tlTimelineTest/ImageOptionsTest.h new file mode 100644 index 000000000..019cc48d4 --- /dev/null +++ b/tests/tlTimelineTest/ImageOptionsTest.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +namespace tl +{ + namespace timeline_tests + { + class ImageOptionsTest : public tests::ITest + { + protected: + ImageOptionsTest(const std::shared_ptr&); + + public: + static std::shared_ptr create(const std::shared_ptr&); + + void run() override; + }; + } +} diff --git a/tests/tlTimelineTest/PlayerOptionsTest.cpp b/tests/tlTimelineTest/PlayerOptionsTest.cpp new file mode 100644 index 000000000..bce7f9f36 --- /dev/null +++ b/tests/tlTimelineTest/PlayerOptionsTest.cpp @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#include + +#include + +#include +#include + +using namespace tl::timeline; + +namespace tl +{ + namespace timeline_tests + { + PlayerOptionsTest::PlayerOptionsTest(const std::shared_ptr& context) : + ITest("timeline_tests::PlayerOptionsTest", context) + {} + + std::shared_ptr PlayerOptionsTest::create(const std::shared_ptr& context) + { + return std::shared_ptr(new PlayerOptionsTest(context)); + } + + void PlayerOptionsTest::run() + { + { + _enum("TimerMode", getTimerModeEnums); + _enum("ExternalTimeMode", getExternalTimeModeEnums); + } + { + PlayerCacheOptions v; + v.readAhead = otime::RationalTime(10.0, 1.0); + TLRENDER_ASSERT(v == v); + TLRENDER_ASSERT(v != PlayerCacheOptions()); + } + { + PlayerOptions v; + v.timerMode = TimerMode::Audio; + TLRENDER_ASSERT(v == v); + TLRENDER_ASSERT(v != PlayerOptions()); + } + } + } +} diff --git a/tests/tlTimelineTest/PlayerOptionsTest.h b/tests/tlTimelineTest/PlayerOptionsTest.h new file mode 100644 index 000000000..c7ee7b405 --- /dev/null +++ b/tests/tlTimelineTest/PlayerOptionsTest.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +namespace tl +{ + namespace timeline_tests + { + class PlayerOptionsTest : public tests::ITest + { + protected: + PlayerOptionsTest(const std::shared_ptr&); + + public: + static std::shared_ptr create(const std::shared_ptr&); + + void run() override; + }; + } +} diff --git a/tests/tltest/main.cpp b/tests/tltest/main.cpp index 0e9a11363..f80ab0bff 100644 --- a/tests/tltest/main.cpp +++ b/tests/tltest/main.cpp @@ -18,9 +18,13 @@ #include #include +#include +#include #include #include +#include #include +#include #include #include #include @@ -167,8 +171,12 @@ void timelineTests( const std::shared_ptr& context) { tests.push_back(timeline_tests::ColorConfigOptionsTest::create(context)); + tests.push_back(timeline_tests::CompareOptionsTest::create(context)); + tests.push_back(timeline_tests::DisplayOptionsTest::create(context)); tests.push_back(timeline_tests::IRenderTest::create(context)); + tests.push_back(timeline_tests::ImageOptionsTest::create(context)); tests.push_back(timeline_tests::LUTOptionsTest::create(context)); + tests.push_back(timeline_tests::PlayerOptionsTest::create(context)); tests.push_back(timeline_tests::PlayerTest::create(context)); tests.push_back(timeline_tests::TimelineTest::create(context)); tests.push_back(timeline_tests::UtilTest::create(context)); From e808ef1d605878c686091fafed72a9d75dcb7707 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 11:31:47 -0700 Subject: [PATCH 03/10] Add tests --- lib/tlPlayQtApp/App.cpp | 3 +- lib/tlPlayQtApp/CMakeLists.txt | 2 - lib/tlPlayQtApp/MemoryTimeline.cpp | 91 ---------------------- lib/tlPlayQtApp/MemoryTimeline.h | 22 ------ lib/tlTimeline/PlayerOptions.h | 14 ++-- lib/tlTimeline/Util.cpp | 71 +++++++++++++++++ lib/tlTimeline/Util.h | 6 ++ tests/tlTimelineTest/PlayerOptionsTest.cpp | 24 ++++++ tests/tlTimelineTest/TimelineTest.cpp | 21 ++++- tests/tlTimelineTest/TimelineTest.h | 6 ++ 10 files changed, 134 insertions(+), 126 deletions(-) delete mode 100644 lib/tlPlayQtApp/MemoryTimeline.cpp delete mode 100644 lib/tlPlayQtApp/MemoryTimeline.h diff --git a/lib/tlPlayQtApp/App.cpp b/lib/tlPlayQtApp/App.cpp index b97d1e703..00f50704e 100644 --- a/lib/tlPlayQtApp/App.cpp +++ b/lib/tlPlayQtApp/App.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -786,7 +785,7 @@ namespace tl timeline::create(items[i]->path, items[i]->audioPath, _context, options); if (0) { - createMemoryTimeline( + timeline::toMemoryReferences( otioTimeline, items[i]->path.getDirectory(), options.pathOptions); diff --git a/lib/tlPlayQtApp/CMakeLists.txt b/lib/tlPlayQtApp/CMakeLists.txt index 2a7832f0b..f85f9ceab 100644 --- a/lib/tlPlayQtApp/CMakeLists.txt +++ b/lib/tlPlayQtApp/CMakeLists.txt @@ -15,7 +15,6 @@ set(HEADERS InfoTool.h InfoModel.h MainWindow.h - MemoryTimeline.h MessagesTool.h OpenSeparateAudioDialog.h PlaybackActions.h @@ -47,7 +46,6 @@ set(SOURCE InfoTool.cpp InfoModel.cpp MainWindow.cpp - MemoryTimeline.cpp MessagesTool.cpp OpenSeparateAudioDialog.cpp PlaybackActions.cpp diff --git a/lib/tlPlayQtApp/MemoryTimeline.cpp b/lib/tlPlayQtApp/MemoryTimeline.cpp deleted file mode 100644 index 2a2d59673..000000000 --- a/lib/tlPlayQtApp/MemoryTimeline.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2021-2023 Darby Johnston -// All rights reserved. - -#include - -#include -#include - -#include - -#include -#include -#include - -namespace tl -{ - namespace play_qt - { - void createMemoryTimeline( - otio::Timeline* otioTimeline, - const std::string& directory, - const file::PathOptions& pathOptions) - { - // Recursively iterate over all clips in the timeline. - for (auto clip : otioTimeline->children_if()) - { - if (auto externalReference = - dynamic_cast(clip->media_reference())) - { - // Get the external reference path. - const auto path = timeline::getPath(externalReference->target_url(), directory, pathOptions); - - // Read the external reference media into memory. - auto fileIO = file::FileIO::create(path.get(), file::Mode::Read); - const size_t size = fileIO->getSize(); - auto memory = std::make_shared(); - memory->resize(size); - fileIO->read(memory->data(), size); - - // Replace the external reference with a memory reference. - auto memoryReference = new timeline::SharedMemoryReference( - externalReference->target_url(), - memory, - clip->available_range(), - externalReference->metadata()); - clip->set_media_reference(memoryReference); - } - else if (auto imageSequenceRefence = - dynamic_cast(clip->media_reference())) - { - // Get the image sequence reference path. - int padding = imageSequenceRefence->frame_zero_padding(); - std::string number; - std::stringstream ss; - ss << imageSequenceRefence->target_url_base() << - imageSequenceRefence->name_prefix() << - std::setfill('0') << std::setw(padding) << imageSequenceRefence->start_frame() << - imageSequenceRefence->name_suffix(); - const auto path = timeline::getPath(ss.str(), directory, pathOptions); - - // Read the image sequence reference media into memory. - std::vector > memoryList; - const auto range = clip->trimmed_range(); - for ( - int64_t frame = imageSequenceRefence->start_frame(); - frame < imageSequenceRefence->start_frame() + range.duration().value(); - ++frame) - { - const auto& fileName = path.get(frame); - auto fileIO = file::FileIO::create(fileName, file::Mode::Read); - const size_t size = fileIO->getSize(); - auto memory = std::make_shared(); - memory->resize(size); - fileIO->read(memory->data(), size); - memoryList.push_back(memory); - } - - // Replace the image sequence reference with a memory - // sequence reference. - auto memorySequenceReference = new timeline::SharedMemorySequenceReference( - path.get(), - memoryList, - clip->available_range(), - imageSequenceRefence->metadata()); - clip->set_media_reference(memorySequenceReference); - } - } - } - } -} diff --git a/lib/tlPlayQtApp/MemoryTimeline.h b/lib/tlPlayQtApp/MemoryTimeline.h deleted file mode 100644 index 9f53850f5..000000000 --- a/lib/tlPlayQtApp/MemoryTimeline.h +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2021-2023 Darby Johnston -// All rights reserved. - -#pragma once - -#include - -#include - -namespace tl -{ - namespace play_qt - { - //! For each clip in the timeline, load the associated media into - //! memory and replace the media references with memory references. - void createMemoryTimeline( - otio::Timeline*, - const std::string& directory, - const file::PathOptions&); - } -} diff --git a/lib/tlTimeline/PlayerOptions.h b/lib/tlTimeline/PlayerOptions.h index 70d63549c..267d2c009 100644 --- a/lib/tlTimeline/PlayerOptions.h +++ b/lib/tlTimeline/PlayerOptions.h @@ -47,13 +47,6 @@ namespace tl bool operator != (const PlayerCacheOptions&) const; }; - //! Get an external time from a source time. - otime::RationalTime getExternalTime( - const otime::RationalTime& sourceTime, - const otime::TimeRange& sourceTimeRange, - const otime::TimeRange& externalTimeRange, - ExternalTimeMode); - //! Timeline player options. struct PlayerOptions { @@ -81,6 +74,13 @@ namespace tl bool operator == (const PlayerOptions&) const; bool operator != (const PlayerOptions&) const; }; + + //! Get an external time from a source time. + otime::RationalTime getExternalTime( + const otime::RationalTime& sourceTime, + const otime::TimeRange& sourceTimeRange, + const otime::TimeRange& externalTimeRange, + ExternalTimeMode); } } diff --git a/lib/tlTimeline/Util.cpp b/lib/tlTimeline/Util.cpp index f2e9cc935..7940d7744 100644 --- a/lib/tlTimeline/Util.cpp +++ b/lib/tlTimeline/Util.cpp @@ -364,6 +364,77 @@ namespace tl return out; } + void toMemoryReferences( + otio::Timeline* otioTimeline, + const std::string& directory, + const file::PathOptions& pathOptions) + { + // Recursively iterate over all clips in the timeline. + for (auto clip : otioTimeline->children_if()) + { + if (auto externalReference = + dynamic_cast(clip->media_reference())) + { + // Get the external reference path. + const auto path = timeline::getPath(externalReference->target_url(), directory, pathOptions); + + // Read the external reference media into memory. + auto fileIO = file::FileIO::create(path.get(), file::Mode::Read); + const size_t size = fileIO->getSize(); + auto memory = std::make_shared(); + memory->resize(size); + fileIO->read(memory->data(), size); + + // Replace the external reference with a memory reference. + auto memoryReference = new timeline::SharedMemoryReference( + externalReference->target_url(), + memory, + clip->available_range(), + externalReference->metadata()); + clip->set_media_reference(memoryReference); + } + else if (auto imageSequenceRefence = + dynamic_cast(clip->media_reference())) + { + // Get the image sequence reference path. + int padding = imageSequenceRefence->frame_zero_padding(); + std::string number; + std::stringstream ss; + ss << imageSequenceRefence->target_url_base() << + imageSequenceRefence->name_prefix() << + std::setfill('0') << std::setw(padding) << imageSequenceRefence->start_frame() << + imageSequenceRefence->name_suffix(); + const auto path = timeline::getPath(ss.str(), directory, pathOptions); + + // Read the image sequence reference media into memory. + std::vector > memoryList; + const auto range = clip->trimmed_range(); + for ( + int64_t frame = imageSequenceRefence->start_frame(); + frame < imageSequenceRefence->start_frame() + range.duration().value(); + ++frame) + { + const auto& fileName = path.get(frame); + auto fileIO = file::FileIO::create(fileName, file::Mode::Read); + const size_t size = fileIO->getSize(); + auto memory = std::make_shared(); + memory->resize(size); + fileIO->read(memory->data(), size); + memoryList.push_back(memory); + } + + // Replace the image sequence reference with a memory + // sequence reference. + auto memorySequenceReference = new timeline::SharedMemorySequenceReference( + path.get(), + memoryList, + clip->available_range(), + imageSequenceRefence->metadata()); + clip->set_media_reference(memorySequenceReference); + } + } + } + otime::RationalTime toVideoMediaTime( const otime::RationalTime& time, const otio::Clip* clip, diff --git a/lib/tlTimeline/Util.h b/lib/tlTimeline/Util.h index 155093d52..0f36307c1 100644 --- a/lib/tlTimeline/Util.h +++ b/lib/tlTimeline/Util.h @@ -71,6 +71,12 @@ namespace tl std::vector getMemoryRead( const otio::MediaReference*); + //! Convert media references to memory references for testing. + void toMemoryReferences( + otio::Timeline*, + const std::string& directory, + const file::PathOptions& = file::PathOptions()); + //! Transform track time to video media time. otime::RationalTime toVideoMediaTime( const otime::RationalTime&, diff --git a/tests/tlTimelineTest/PlayerOptionsTest.cpp b/tests/tlTimelineTest/PlayerOptionsTest.cpp index bce7f9f36..3f199dafd 100644 --- a/tests/tlTimelineTest/PlayerOptionsTest.cpp +++ b/tests/tlTimelineTest/PlayerOptionsTest.cpp @@ -42,6 +42,30 @@ namespace tl TLRENDER_ASSERT(v == v); TLRENDER_ASSERT(v != PlayerOptions()); } + { + const auto time = getExternalTime( + otime::RationalTime(0.0, 24.0), + otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)), + otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)), + ExternalTimeMode::Absolute); + TLRENDER_ASSERT(time == otime::RationalTime(0.0, 24.0)); + } + { + const auto time = getExternalTime( + otime::RationalTime(0.0, 24.0), + otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)), + otime::TimeRange( + otime::RationalTime(24.0, 24.0), + otime::RationalTime(24.0, 24.0)), + ExternalTimeMode::Relative); + TLRENDER_ASSERT(time == otime::RationalTime(24.0, 24.0)); + } } } } diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index f23cf3546..3fd1d24ec 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -187,8 +187,25 @@ namespace tl write->writeVideo(otime::RationalTime(i, 24.0), image); } - // Create a timeline from the OTIO timeline. - auto timeline = Timeline::create(fileName, _context); + // Test timelines. + { + auto timeline = Timeline::create(fileName, _context); + _timeline(fileName, imageInfo, timeline); + } + { + const file::Path path(fileName); + auto otioTimeline = timeline::create(path, _context); + toMemoryReferences(otioTimeline, path.getDirectory()); + auto timeline = timeline::Timeline::create(otioTimeline, _context); + _timeline(fileName, imageInfo, timeline); + } + } + + void TimelineTest::_timeline( + const std::string& fileName, + const image::Info& imageInfo, + const std::shared_ptr& timeline) + { TLRENDER_ASSERT(timeline->getTimeline()); TLRENDER_ASSERT(fileName == timeline->getPath().get()); TLRENDER_ASSERT(Options() == timeline->getOptions()); diff --git a/tests/tlTimelineTest/TimelineTest.h b/tests/tlTimelineTest/TimelineTest.h index bcf9ab139..3ce789694 100644 --- a/tests/tlTimelineTest/TimelineTest.h +++ b/tests/tlTimelineTest/TimelineTest.h @@ -6,6 +6,8 @@ #include +#include + namespace tl { namespace timeline_tests @@ -27,6 +29,10 @@ namespace tl void _videoData(); void _create(); void _timeline(); + void _timeline( + const std::string& fileName, + const image::Info&, + const std::shared_ptr&); void _imageSequence(); }; } From 5954626ad82d2846184c707df610c5cc71ca56b5 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 12:37:14 -0700 Subject: [PATCH 04/10] Add tests --- tests/tlTimelineTest/TimelineTest.cpp | 115 +++++++++++++++----------- tests/tlTimelineTest/TimelineTest.h | 5 +- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index 3fd1d24ec..7b117f0a3 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -14,6 +14,7 @@ #include #include +#include #include using namespace tl::timeline; @@ -138,83 +139,101 @@ namespace tl auto otioClip = new otio::Clip; otioClip->set_media_reference(new otio::ImageSequenceReference( "file://", "Timeline Test.", ".ppm", 0, 1, 1, 0)); - const otime::TimeRange clipTimeRange( + otioClip->set_source_range(otime::TimeRange( otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0)); - otioClip->set_source_range(clipTimeRange); - otio::ErrorStatus errorStatus; + otime::RationalTime(24.0, 24.0))); auto otioTrack = new otio::Track(); - otioTrack->append_child(otioClip, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } + otioTrack->append_child(otioClip); + otioClip = new otio::Clip; otioClip->set_media_reference(new otio::ImageSequenceReference( "", "Timeline Test.", ".ppm", 0, 1, 1, 0)); - otioClip->set_source_range(clipTimeRange); - otioTrack->append_child(otioClip, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } + otioClip->set_source_range(otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0))); + otioTrack->append_child(otioClip); + +#if defined(TLRENDER_FFMPEG) + otioClip = new otio::Clip; + otioClip->set_media_reference(new otio::ExternalReference( + "Timeline Test.mov")); + otioClip->set_source_range(otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0))); + otioTrack->append_child(otioClip); +#endif // TLRENDER_FFMPEG + + otime::TimeRange timeRange = otioTrack->available_range(); auto otioStack = new otio::Stack; - otioStack->append_child(otioTrack, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } + otioStack->append_child(otioTrack); otio::SerializableObject::Retainer otioTimeline( new otio::Timeline); otioTimeline->set_tracks(otioStack); const std::string fileName("Timeline Test.otio"); - otioTimeline->to_json_file(fileName, &errorStatus); - if (otio::is_error(errorStatus)) + otioTimeline->to_json_file(fileName); + + // Write the media files. { - throw std::runtime_error("Cannot write file: " + fileName); + image::Info imageInfo(16, 16, image::PixelType::RGB_U8); + imageInfo.layout.endian = memory::Endian::MSB; + const auto image = image::Image::create(imageInfo); + io::Info ioInfo; + ioInfo.video.push_back(imageInfo); + ioInfo.videoTime = otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)); + auto write = _context->getSystem()->write(file::Path("Timeline Test.0.ppm"), ioInfo); + for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) + { + write->writeVideo(otime::RationalTime(i, 24.0), image); + } } - - // Write the image sequence files. - image::Info imageInfo(16, 16, image::PixelType::RGB_U8); - imageInfo.layout.endian = memory::Endian::MSB; - const auto image = image::Image::create(imageInfo); - io::Info ioInfo; - ioInfo.video.push_back(imageInfo); - ioInfo.videoTime = clipTimeRange; - auto write = _context->getSystem()->write(file::Path("Timeline Test.0.ppm"), ioInfo); - for (size_t i = 0; i < static_cast(clipTimeRange.duration().value()); ++i) +#if defined(TLRENDER_FFMPEG) { - write->writeVideo(otime::RationalTime(i, 24.0), image); + image::Info imageInfo(16, 16, image::PixelType::RGB_U8); + const auto image = image::Image::create(imageInfo); + io::Info ioInfo; + ioInfo.video.push_back(imageInfo); + ioInfo.videoTime = otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)); + auto write = _context->getSystem()->write(file::Path("Timeline Test.mov"), ioInfo); + for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) + { + write->writeVideo(otime::RationalTime(i, 24.0), image); + } } +#endif // TLRENDER_FFMPEG // Test timelines. { auto timeline = Timeline::create(fileName, _context); - _timeline(fileName, imageInfo, timeline); + TLRENDER_ASSERT(timeline->getTimeline()); + TLRENDER_ASSERT(fileName == timeline->getPath().get()); + TLRENDER_ASSERT(Options() == timeline->getOptions()); + TLRENDER_ASSERT(time::compareExact(timeRange, timeline->getTimeRange())); + TLRENDER_ASSERT(!timeline->getIOInfo().video.empty()); + _timeline(timeline); } { const file::Path path(fileName); auto otioTimeline = timeline::create(path, _context); + TLRENDER_ASSERT(otioTimeline); toMemoryReferences(otioTimeline, path.getDirectory()); auto timeline = timeline::Timeline::create(otioTimeline, _context); - _timeline(fileName, imageInfo, timeline); + TLRENDER_ASSERT(timeline->getTimeline()); + TLRENDER_ASSERT(fileName == timeline->getPath().get()); + TLRENDER_ASSERT(Options() == timeline->getOptions()); + TLRENDER_ASSERT(time::compareExact(timeRange, timeline->getTimeRange())); + TLRENDER_ASSERT(!timeline->getIOInfo().video.empty()); + _timeline(timeline); } } - void TimelineTest::_timeline( - const std::string& fileName, - const image::Info& imageInfo, - const std::shared_ptr& timeline) + void TimelineTest::_timeline(const std::shared_ptr& timeline) { - TLRENDER_ASSERT(timeline->getTimeline()); - TLRENDER_ASSERT(fileName == timeline->getPath().get()); - TLRENDER_ASSERT(Options() == timeline->getOptions()); - const otime::TimeRange timeRange(otime::RationalTime(0.0, 24.0), otime::RationalTime(48.0, 24.0)); - TLRENDER_ASSERT(time::compareExact(timeRange, timeline->getTimeRange())); - TLRENDER_ASSERT(imageInfo.size == timeline->getIOInfo().video[0].size); - TLRENDER_ASSERT(imageInfo.pixelType == timeline->getIOInfo().video[0].pixelType); - // Get video from the timeline. + const otime::TimeRange& timeRange = timeline->getTimeRange(); std::vector videoData; std::vector > futures; for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) diff --git a/tests/tlTimelineTest/TimelineTest.h b/tests/tlTimelineTest/TimelineTest.h index 3ce789694..ef39a0d7c 100644 --- a/tests/tlTimelineTest/TimelineTest.h +++ b/tests/tlTimelineTest/TimelineTest.h @@ -29,10 +29,7 @@ namespace tl void _videoData(); void _create(); void _timeline(); - void _timeline( - const std::string& fileName, - const image::Info&, - const std::shared_ptr&); + void _timeline(const std::shared_ptr&); void _imageSequence(); }; } From 6cbbbc78fded79190e589bc7ca891a16eb8bb37f Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 14:31:20 -0700 Subject: [PATCH 05/10] Add tests --- lib/tlTimeline/CompareOptions.cpp | 2 +- tests/tlTimelineTest/CMakeLists.txt | 2 + tests/tlTimelineTest/CompareOptionsTest.cpp | 10 +- tests/tlTimelineTest/MemoryReferenceTest.cpp | 86 +++++++++ tests/tlTimelineTest/MemoryReferenceTest.h | 24 +++ tests/tlTimelineTest/PlayerTest.cpp | 183 ++++++++++++------- tests/tlTimelineTest/PlayerTest.h | 3 + tests/tlTimelineTest/TimelineTest.cpp | 2 +- tests/tltest/main.cpp | 12 +- 9 files changed, 248 insertions(+), 76 deletions(-) create mode 100644 tests/tlTimelineTest/MemoryReferenceTest.cpp create mode 100644 tests/tlTimelineTest/MemoryReferenceTest.h diff --git a/lib/tlTimeline/CompareOptions.cpp b/lib/tlTimeline/CompareOptions.cpp index 3a8ba013c..0facd52ad 100644 --- a/lib/tlTimeline/CompareOptions.cpp +++ b/lib/tlTimeline/CompareOptions.cpp @@ -131,7 +131,7 @@ namespace tl } break; default: - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < std::min(count, static_cast(2)); ++i) { out.push_back(math::Box2i( 0, diff --git a/tests/tlTimelineTest/CMakeLists.txt b/tests/tlTimelineTest/CMakeLists.txt index 01eb954ef..8f410402b 100644 --- a/tests/tlTimelineTest/CMakeLists.txt +++ b/tests/tlTimelineTest/CMakeLists.txt @@ -6,6 +6,7 @@ set(HEADERS IRenderTest.h ImageOptionsTest.h LUTOptionsTest.h + MemoryReferenceTest.h PlayerOptionsTest.h PlayerTest.h TimelineTest.h @@ -19,6 +20,7 @@ set(SOURCE IRenderTest.cpp ImageOptionsTest.cpp LUTOptionsTest.cpp + MemoryReferenceTest.cpp PlayerOptionsTest.cpp PlayerTest.cpp TimelineTest.cpp diff --git a/tests/tlTimelineTest/CompareOptionsTest.cpp b/tests/tlTimelineTest/CompareOptionsTest.cpp index fdbde0fab..d976d84d9 100644 --- a/tests/tlTimelineTest/CompareOptionsTest.cpp +++ b/tests/tlTimelineTest/CompareOptionsTest.cpp @@ -39,6 +39,8 @@ namespace tl const std::vector sizes = { image::Size(1920, 1080), + image::Size(1920 / 2, 1080 / 2), + image::Size(1920 / 2, 1080 / 2), image::Size(1920 / 2, 1080 / 2) }; @@ -74,11 +76,13 @@ namespace tl TLRENDER_ASSERT(math::Size2i(1920, 1080 * 2) == renderSize); boxes = getBoxes(CompareMode::Tile, sizes); - TLRENDER_ASSERT(2 == boxes.size()); + TLRENDER_ASSERT(4 == boxes.size()); TLRENDER_ASSERT(math::Box2i(0, 0, 1920, 1080) == boxes[0]); - TLRENDER_ASSERT(math::Box2i(0, 1080, 1920, 1080) == boxes[1]); + TLRENDER_ASSERT(math::Box2i(1920, 0, 1920, 1080) == boxes[1]); + TLRENDER_ASSERT(math::Box2i(0, 1080, 1920, 1080) == boxes[2]); + TLRENDER_ASSERT(math::Box2i(1920, 1080, 1920, 1080) == boxes[3]); renderSize = getRenderSize(CompareMode::Tile, sizes); - TLRENDER_ASSERT(math::Size2i(1920, 1080 * 2) == renderSize); + TLRENDER_ASSERT(math::Size2i(1920 * 2, 1080 * 2) == renderSize); } } } diff --git a/tests/tlTimelineTest/MemoryReferenceTest.cpp b/tests/tlTimelineTest/MemoryReferenceTest.cpp new file mode 100644 index 000000000..e8956390c --- /dev/null +++ b/tests/tlTimelineTest/MemoryReferenceTest.cpp @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#include + +#include + +#include +#include + +using namespace tl::timeline; + +namespace tl +{ + namespace timeline_tests + { + MemoryReferenceTest::MemoryReferenceTest(const std::shared_ptr& context) : + ITest("timeline_tests::MemoryReferenceTest", context) + {} + + std::shared_ptr MemoryReferenceTest::create(const std::shared_ptr& context) + { + return std::shared_ptr(new MemoryReferenceTest(context)); + } + + void MemoryReferenceTest::run() + { + { + otio::SerializableObject::Retainer v(new RawMemoryReference); + v->set_target_url("url"); + TLRENDER_ASSERT("url" == v->target_url()); + std::vector memory(100, 0); + v->set_memory(memory.data(), memory.size()); + TLRENDER_ASSERT(v->memory() == memory.data()); + TLRENDER_ASSERT(v->memory_size() == memory.size()); + } + { + otio::SerializableObject::Retainer v(new SharedMemoryReference); + v->set_target_url("url"); + TLRENDER_ASSERT("url" == v->target_url()); + std::shared_ptr > memory(new std::vector(100, 0)); + v->set_memory(memory); + TLRENDER_ASSERT(v->memory() == memory); + } + { + otio::SerializableObject::Retainer v(new RawMemorySequenceReference); + v->set_target_url("url"); + TLRENDER_ASSERT("url" == v->target_url()); + std::vector > > dataList; + std::vector memory; + std::vector sizes; + for (size_t i = 0; i < 10; ++i) + { + std::shared_ptr > data(new std::vector(100, 0)); + dataList.push_back(data); + memory.push_back(data->data()); + sizes.push_back(100); + } + v->set_memory(memory, sizes); + TLRENDER_ASSERT(v->memory() == memory); + TLRENDER_ASSERT(v->memory_sizes() == sizes); + } + { + otio::SerializableObject::Retainer v(new SharedMemorySequenceReference); + v->set_target_url("url"); + TLRENDER_ASSERT("url" == v->target_url()); + std::vector > > memory; + std::vector sizes; + for (size_t i = 0; i < 10; ++i) + { + std::shared_ptr > data(new std::vector(100, 0)); + memory.push_back(data); + } + v->set_memory(memory); + TLRENDER_ASSERT(v->memory() == memory); + } + { + otio::SerializableObject::Retainer v(new ZipMemoryReference); + } + { + otio::SerializableObject::Retainer v(new ZipMemorySequenceReference); + } + } + } +} diff --git a/tests/tlTimelineTest/MemoryReferenceTest.h b/tests/tlTimelineTest/MemoryReferenceTest.h new file mode 100644 index 000000000..f574c203d --- /dev/null +++ b/tests/tlTimelineTest/MemoryReferenceTest.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2023 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +namespace tl +{ + namespace timeline_tests + { + class MemoryReferenceTest : public tests::ITest + { + protected: + MemoryReferenceTest(const std::shared_ptr&); + + public: + static std::shared_ptr create(const std::shared_ptr&); + + void run() override; + }; + } +} diff --git a/tests/tlTimelineTest/PlayerTest.cpp b/tests/tlTimelineTest/PlayerTest.cpp index 65a1075ac..8940cca14 100644 --- a/tests/tlTimelineTest/PlayerTest.cpp +++ b/tests/tlTimelineTest/PlayerTest.cpp @@ -12,8 +12,9 @@ #include #include -#include +#include #include +#include #include @@ -86,65 +87,109 @@ namespace tl // Write an OTIO timeline. auto otioTrack = new otio::Track(); auto otioClip = new otio::Clip; - otioClip->set_media_reference(new otio::ImageSequenceReference("", "PlayerTest.", ".ppm", 0, 1, 1, 0)); - const otime::TimeRange clipTimeRange(otime::RationalTime(0.0, 24.0), otime::RationalTime(24.0, 24.0)); - otioClip->set_source_range(clipTimeRange); - otio::ErrorStatus errorStatus = otio::ErrorStatus::OK; - otioTrack->append_child(otioClip, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } + otioClip->set_media_reference(new otio::ImageSequenceReference( + "", "PlayerTest.", ".ppm", 0, 1, 1, 0)); + otioClip->set_source_range(otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0))); + otioTrack->append_child(otioClip); + otioClip = new otio::Clip; - otioClip->set_media_reference(new otio::ImageSequenceReference("", "PlayerTest.", ".ppm", 0, 1, 1, 0)); - otioClip->set_source_range(clipTimeRange); - otioTrack->append_child(otioClip, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } + otioClip->set_media_reference(new otio::ImageSequenceReference( + "", "PlayerTest.", ".ppm", 0, 1, 1, 0)); + otioClip->set_source_range(otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0))); + otioTrack->append_child(otioClip); + +#if defined(TLRENDER_FFMPEG) + otioClip = new otio::Clip; + otioClip->set_media_reference(new otio::ExternalReference( + "PlayerTest.mov")); + otioClip->set_source_range(otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0))); + otioTrack->append_child(otioClip); +#endif // TLRENDER_FFMPEG + auto otioStack = new otio::Stack; - otioStack->append_child(otioTrack, &errorStatus); - if (otio::is_error(errorStatus)) - { - throw std::runtime_error("Cannot append child"); - } - auto otioTimeline = new otio::Timeline; + otioStack->append_child(otioTrack); + otio::SerializableObject::Retainer otioTimeline( + new otio::Timeline); otioTimeline->set_tracks(otioStack); otioTimeline->set_global_start_time(otime::RationalTime(10.0, 24.0)); const std::string fileName("PlayerTest.otio"); - otioTimeline->to_json_file(fileName, &errorStatus); - if (otio::is_error(errorStatus)) + otioTimeline->to_json_file(fileName); + + // Write the media files. + otime::TimeRange timeRange( + otime::RationalTime(10.0, 24.0), + otioTrack->available_range().duration()); { - throw std::runtime_error("Cannot write file: " + fileName); + image::Info imageInfo(16, 16, image::PixelType::RGB_U8); + imageInfo.layout.endian = memory::Endian::MSB; + const auto image = image::Image::create(imageInfo); + io::Info ioInfo; + ioInfo.video.push_back(imageInfo); + ioInfo.videoTime = otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)); + auto write = _context->getSystem()->write(file::Path("PlayerTest.0.ppm"), ioInfo); + for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) + { + write->writeVideo(otime::RationalTime(i, 24.0), image); + } } - - // Write the image sequence files. - image::Info imageInfo(16, 16, image::PixelType::RGB_U8); - imageInfo.layout.endian = memory::Endian::MSB; - const auto image = image::Image::create(imageInfo); - io::Info ioInfo; - ioInfo.video.push_back(imageInfo); - ioInfo.videoTime = clipTimeRange; - auto write = _context->getSystem()->write(file::Path("PlayerTest.0.ppm"), ioInfo); - for (size_t i = 0; i < static_cast(clipTimeRange.duration().value()); ++i) +#if defined(TLRENDER_FFMPEG) { - write->writeVideo(otime::RationalTime(i, 24.0), image); + image::Info imageInfo(16, 16, image::PixelType::RGB_U8); + const auto image = image::Image::create(imageInfo); + io::Info ioInfo; + ioInfo.video.push_back(imageInfo); + ioInfo.videoTime = otime::TimeRange( + otime::RationalTime(0.0, 24.0), + otime::RationalTime(24.0, 24.0)); + auto write = _context->getSystem()->write(file::Path("PlayerTest.mov"), ioInfo); + for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) + { + write->writeVideo(otime::RationalTime(i, 24.0), image); + } } +#endif // TLRENDER_FFMPEG - // Create a timeline player from the OTIO timeline. - auto timeline = Timeline::create(fileName, _context); - auto player = Player::create(timeline, _context); - TLRENDER_ASSERT(player->getTimeline()); - TLRENDER_ASSERT(fileName == player->getPath().get()); - TLRENDER_ASSERT(Options() == player->getOptions()); - const otime::TimeRange timeRange(otime::RationalTime(10.0, 24.0), otime::RationalTime(48.0, 24.0)); - TLRENDER_ASSERT(time::compareExact(timeRange, player->getTimeRange())); - TLRENDER_ASSERT(imageInfo.size == player->getIOInfo().video[0].size); - TLRENDER_ASSERT(imageInfo.pixelType == player->getIOInfo().video[0].pixelType); - TLRENDER_ASSERT(timeRange.duration().rate() == player->getDefaultSpeed()); + // Test timeline players. + { + auto timeline = Timeline::create(fileName, _context); + auto player = Player::create(timeline, _context); + TLRENDER_ASSERT(player->getTimeline()); + TLRENDER_ASSERT(fileName == player->getPath().get()); + TLRENDER_ASSERT(Options() == player->getOptions()); + TLRENDER_ASSERT(time::compareExact(timeRange, player->getTimeRange())); + TLRENDER_ASSERT(!player->getIOInfo().video.empty()); + TLRENDER_ASSERT(timeRange.duration().rate() == player->getDefaultSpeed()); + _player(player); + } + { + const file::Path path(fileName); + auto otioTimeline = timeline::create(path, _context); + TLRENDER_ASSERT(otioTimeline); + toMemoryReferences(otioTimeline, path.getDirectory()); + auto timeline = Timeline::create(otioTimeline, _context); + auto player = Player::create(timeline, _context); + TLRENDER_ASSERT(player->getTimeline()); + TLRENDER_ASSERT(fileName == player->getPath().get()); + TLRENDER_ASSERT(Options() == player->getOptions()); + TLRENDER_ASSERT(time::compareExact(timeRange, player->getTimeRange())); + TLRENDER_ASSERT(!player->getIOInfo().video.empty()); + TLRENDER_ASSERT(timeRange.duration().rate() == player->getDefaultSpeed()); + _player(player); + } + } + void PlayerTest::_player(const std::shared_ptr& player) + { // Test frames. + const otime::TimeRange& timeRange = player->getTimeRange(); struct FrameOptions { uint16_t layer = 0; @@ -254,26 +299,26 @@ namespace tl { currentTime = value; }); - player->seek(otime::RationalTime(10.0, 24.0)); - TLRENDER_ASSERT(otime::RationalTime(10.0, 24.0) == currentTime); - player->seek(otime::RationalTime(11.0, 24.0)); - TLRENDER_ASSERT(otime::RationalTime(11.0, 24.0) == currentTime); + player->seek(timeRange.start_time()); + TLRENDER_ASSERT(timeRange.start_time() == currentTime); + player->seek(timeRange.start_time() + otime::RationalTime(1.0, 24.0)); + TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(1.0, 24.0) == currentTime); player->end(); - TLRENDER_ASSERT(otime::RationalTime(57.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); player->start(); - TLRENDER_ASSERT(otime::RationalTime(10.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.start_time() == currentTime); player->frameNext(); - TLRENDER_ASSERT(otime::RationalTime(11.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(1.0, 24.0) == currentTime); player->timeAction(TimeAction::FrameNextX10); - TLRENDER_ASSERT(otime::RationalTime(21.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(11.0, 24.0) == currentTime); player->timeAction(TimeAction::FrameNextX100); - TLRENDER_ASSERT(otime::RationalTime(10.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.start_time() == currentTime); player->framePrev(); - TLRENDER_ASSERT(otime::RationalTime(57.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); player->timeAction(TimeAction::FramePrevX10); - TLRENDER_ASSERT(otime::RationalTime(47.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.end_time_inclusive() - otime::RationalTime(10.0, 24.0) == currentTime); player->timeAction(TimeAction::FramePrevX100); - TLRENDER_ASSERT(otime::RationalTime(57.0, 24.0) == currentTime); + TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); // Test the in/out points. otime::TimeRange inOutRange = time::invalidTimeRange; @@ -283,16 +328,22 @@ namespace tl { inOutRange = value; }); - player->setInOutRange(otime::TimeRange(otime::RationalTime(10.0, 24.0), otime::RationalTime(33.0, 24.0))); - TLRENDER_ASSERT(otime::TimeRange(otime::RationalTime(10.0, 24.0), otime::RationalTime(33.0, 24.0)) == inOutRange); - player->seek(otime::RationalTime(12.0, 24.0)); + player->setInOutRange(otime::TimeRange( + timeRange.start_time(), + otime::RationalTime(33.0, 24.0))); + TLRENDER_ASSERT(otime::TimeRange( + timeRange.start_time(), + otime::RationalTime(33.0, 24.0)) == inOutRange); + player->seek(timeRange.start_time() + otime::RationalTime(2.0, 24.0)); player->setInPoint(); - player->seek(otime::RationalTime(32.0, 24.0)); + player->seek(timeRange.start_time() + otime::RationalTime(22.0, 24.0)); player->setOutPoint(); - TLRENDER_ASSERT(otime::TimeRange(otime::RationalTime(12.0, 24.0), otime::RationalTime(21.0, 24.0)) == inOutRange); + TLRENDER_ASSERT(otime::TimeRange( + timeRange.start_time() + otime::RationalTime(2.0, 24.0), + otime::RationalTime(21.0, 24.0)) == inOutRange); player->resetInPoint(); player->resetOutPoint(); - TLRENDER_ASSERT(otime::TimeRange(otime::RationalTime(10.0, 24.0), timeRange.duration()) == inOutRange); + TLRENDER_ASSERT(otime::TimeRange(timeRange.start_time(), timeRange.duration()) == inOutRange); } } } diff --git a/tests/tlTimelineTest/PlayerTest.h b/tests/tlTimelineTest/PlayerTest.h index 5b182918a..bdc0b382d 100644 --- a/tests/tlTimelineTest/PlayerTest.h +++ b/tests/tlTimelineTest/PlayerTest.h @@ -6,6 +6,8 @@ #include +#include + namespace tl { namespace timeline_tests @@ -24,6 +26,7 @@ namespace tl void _enums(); void _loop(); void _player(); + void _player(const std::shared_ptr&); }; } } diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index 7b117f0a3..b494f7042 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -13,9 +13,9 @@ #include #include -#include #include #include +#include using namespace tl::timeline; diff --git a/tests/tltest/main.cpp b/tests/tltest/main.cpp index f80ab0bff..073e33031 100644 --- a/tests/tltest/main.cpp +++ b/tests/tltest/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,7 @@ void timelineTests( tests.push_back(timeline_tests::IRenderTest::create(context)); tests.push_back(timeline_tests::ImageOptionsTest::create(context)); tests.push_back(timeline_tests::LUTOptionsTest::create(context)); + tests.push_back(timeline_tests::MemoryReferenceTest::create(context)); tests.push_back(timeline_tests::PlayerOptionsTest::create(context)); tests.push_back(timeline_tests::PlayerTest::create(context)); tests.push_back(timeline_tests::TimelineTest::create(context)); @@ -228,12 +230,12 @@ int main(int argc, char* argv[]) std::vector > tests; //tests.push_back(core_tests::PathTest::create(context)); - coreTests(tests, context); - glTests(tests, context); - ioTests(tests, context); + //coreTests(tests, context); + //glTests(tests, context); + //ioTests(tests, context); timelineTests(tests, context); - appTests(tests, context); - qtTests(tests, context); + //appTests(tests, context); + //qtTests(tests, context); for (const auto& test : tests) { From 97bb4ad9818dfd9717b1387cc2fb647ed594a956 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 15:18:13 -0700 Subject: [PATCH 06/10] Add tests --- tests/tlTimelineTest/TimelineTest.cpp | 5 +++++ tests/tltest/main.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index b494f7042..012015558 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -206,6 +207,10 @@ namespace tl #endif // TLRENDER_FFMPEG // Test timelines. + for (const auto& path : getPaths(file::Path("."), file::PathOptions(), _context)) + { + _print(string::Format("Path: {0}").arg(path.get())); + } { auto timeline = Timeline::create(fileName, _context); TLRENDER_ASSERT(timeline->getTimeline()); diff --git a/tests/tltest/main.cpp b/tests/tltest/main.cpp index 073e33031..c2604ddfe 100644 --- a/tests/tltest/main.cpp +++ b/tests/tltest/main.cpp @@ -230,12 +230,12 @@ int main(int argc, char* argv[]) std::vector > tests; //tests.push_back(core_tests::PathTest::create(context)); - //coreTests(tests, context); - //glTests(tests, context); - //ioTests(tests, context); + coreTests(tests, context); + glTests(tests, context); + ioTests(tests, context); timelineTests(tests, context); - //appTests(tests, context); - //qtTests(tests, context); + appTests(tests, context); + qtTests(tests, context); for (const auto& test : tests) { From 016b232af5788742542a58206ab5b6554584056f Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 16:43:17 -0700 Subject: [PATCH 07/10] Add tests --- CMakeLists.txt | 1 + tests/tlTimelineTest/PlayerTest.cpp | 62 ++++++++++++++------------- tests/tlTimelineTest/TimelineTest.cpp | 39 ++++++++++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bcfae64c6..0b6b8dd5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ if(CMAKE_BUILD_TYPE MATCHES "^Debug$") endif() if(TLRENDER_TESTS) + add_definitions(-DTLRENDER_SAMPLE_DATA="${CMAKE_CURRENT_SOURCE_DIR}/etc/SampleData") set(CTEST_OUTPUT_ON_FAILURE ON) enable_testing() endif() diff --git a/tests/tlTimelineTest/PlayerTest.cpp b/tests/tlTimelineTest/PlayerTest.cpp index 8940cca14..bdf662015 100644 --- a/tests/tlTimelineTest/PlayerTest.cpp +++ b/tests/tlTimelineTest/PlayerTest.cpp @@ -84,7 +84,7 @@ namespace tl void PlayerTest::_player() { - // Write an OTIO timeline. + /*// Write an OTIO timeline. auto otioTrack = new otio::Track(); auto otioClip = new otio::Clip; otioClip->set_media_reference(new otio::ImageSequenceReference( @@ -155,33 +155,34 @@ namespace tl write->writeVideo(otime::RationalTime(i, 24.0), image); } } -#endif // TLRENDER_FFMPEG +#endif // TLRENDER_FFMPEG*/ // Test timeline players. + const std::vector paths = + { + //file::Path(TLRENDER_SAMPLE_DATA, "AudioTones.otio"), + //file::Path(TLRENDER_SAMPLE_DATA, "AudioTonesAndVideo.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "Gap.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "MovieAndSeq.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio") + }; + for (const auto& path : paths) { - auto timeline = Timeline::create(fileName, _context); + auto timeline = Timeline::create(path, _context); auto player = Player::create(timeline, _context); TLRENDER_ASSERT(player->getTimeline()); - TLRENDER_ASSERT(fileName == player->getPath().get()); - TLRENDER_ASSERT(Options() == player->getOptions()); - TLRENDER_ASSERT(time::compareExact(timeRange, player->getTimeRange())); - TLRENDER_ASSERT(!player->getIOInfo().video.empty()); - TLRENDER_ASSERT(timeRange.duration().rate() == player->getDefaultSpeed()); + TLRENDER_ASSERT(path == player->getPath()); _player(player); } + for (const auto& path : paths) { - const file::Path path(fileName); auto otioTimeline = timeline::create(path, _context); TLRENDER_ASSERT(otioTimeline); toMemoryReferences(otioTimeline, path.getDirectory()); auto timeline = Timeline::create(otioTimeline, _context); auto player = Player::create(timeline, _context); TLRENDER_ASSERT(player->getTimeline()); - TLRENDER_ASSERT(fileName == player->getPath().get()); - TLRENDER_ASSERT(Options() == player->getOptions()); - TLRENDER_ASSERT(time::compareExact(timeRange, player->getTimeRange())); - TLRENDER_ASSERT(!player->getIOInfo().video.empty()); - TLRENDER_ASSERT(timeRange.duration().rate() == player->getDefaultSpeed()); + TLRENDER_ASSERT(path == player->getPath()); _player(player); } } @@ -241,13 +242,13 @@ namespace tl for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { player->tick(); - time::sleep(std::chrono::microseconds(1000000 / 24)); + time::sleep(std::chrono::milliseconds(1)); } player->setPlayback(Playback::Reverse); for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { player->tick(); - time::sleep(std::chrono::microseconds(1000000 / 24)); + time::sleep(std::chrono::milliseconds(1)); } } player->setPlayback(Playback::Stop); @@ -301,24 +302,25 @@ namespace tl }); player->seek(timeRange.start_time()); TLRENDER_ASSERT(timeRange.start_time() == currentTime); - player->seek(timeRange.start_time() + otime::RationalTime(1.0, 24.0)); - TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(1.0, 24.0) == currentTime); + const double rate = timeRange.duration().rate(); + player->seek( + timeRange.start_time() + otime::RationalTime(1.0, rate)); + TLRENDER_ASSERT( + timeRange.start_time() + otime::RationalTime(1.0, rate) == + currentTime); player->end(); TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); player->start(); TLRENDER_ASSERT(timeRange.start_time() == currentTime); player->frameNext(); - TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(1.0, 24.0) == currentTime); + TLRENDER_ASSERT( + timeRange.start_time() + otime::RationalTime(1.0, rate) == + currentTime); player->timeAction(TimeAction::FrameNextX10); - TLRENDER_ASSERT(timeRange.start_time() + otime::RationalTime(11.0, 24.0) == currentTime); player->timeAction(TimeAction::FrameNextX100); - TLRENDER_ASSERT(timeRange.start_time() == currentTime); player->framePrev(); - TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); player->timeAction(TimeAction::FramePrevX10); - TLRENDER_ASSERT(timeRange.end_time_inclusive() - otime::RationalTime(10.0, 24.0) == currentTime); player->timeAction(TimeAction::FramePrevX100); - TLRENDER_ASSERT(timeRange.end_time_inclusive() == currentTime); // Test the in/out points. otime::TimeRange inOutRange = time::invalidTimeRange; @@ -330,17 +332,17 @@ namespace tl }); player->setInOutRange(otime::TimeRange( timeRange.start_time(), - otime::RationalTime(33.0, 24.0))); + otime::RationalTime(10.0, rate))); TLRENDER_ASSERT(otime::TimeRange( timeRange.start_time(), - otime::RationalTime(33.0, 24.0)) == inOutRange); - player->seek(timeRange.start_time() + otime::RationalTime(2.0, 24.0)); + otime::RationalTime(10.0, rate)) == inOutRange); + player->seek(timeRange.start_time() + otime::RationalTime(1.0, rate)); player->setInPoint(); - player->seek(timeRange.start_time() + otime::RationalTime(22.0, 24.0)); + player->seek(timeRange.start_time() + otime::RationalTime(10.0, rate)); player->setOutPoint(); TLRENDER_ASSERT(otime::TimeRange( - timeRange.start_time() + otime::RationalTime(2.0, 24.0), - otime::RationalTime(21.0, 24.0)) == inOutRange); + timeRange.start_time() + otime::RationalTime(1.0, rate), + otime::RationalTime(10.0, rate)) == inOutRange); player->resetInPoint(); player->resetOutPoint(); TLRENDER_ASSERT(otime::TimeRange(timeRange.start_time(), timeRange.duration()) == inOutRange); diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index 012015558..d690fbabe 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -61,6 +61,13 @@ namespace tl ss << "Timeline extension: " << i; _print(ss.str()); } + for (const auto& path : getPaths( + file::Path(TLRENDER_SAMPLE_DATA), + file::PathOptions(), + _context)) + { + _print(string::Format("Path: {0}").arg(path.get())); + } } void TimelineTest::_transitions() @@ -137,7 +144,7 @@ namespace tl void TimelineTest::_timeline() { // Write an OTIO timeline. - auto otioClip = new otio::Clip; + /*auto otioClip = new otio::Clip; otioClip->set_media_reference(new otio::ImageSequenceReference( "file://", "Timeline Test.", ".ppm", 0, 1, 1, 0)); otioClip->set_source_range(otime::TimeRange( @@ -204,33 +211,33 @@ namespace tl write->writeVideo(otime::RationalTime(i, 24.0), image); } } -#endif // TLRENDER_FFMPEG +#endif // TLRENDER_FFMPEG*/ // Test timelines. - for (const auto& path : getPaths(file::Path("."), file::PathOptions(), _context)) + const std::vector paths = { - _print(string::Format("Path: {0}").arg(path.get())); - } + //file::Path(TLRENDER_SAMPLE_DATA, "AudioTones.otio"), + //file::Path(TLRENDER_SAMPLE_DATA, "AudioTonesAndVideo.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "Gap.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "MovieAndSeq.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio") + }; + for (const auto& path : paths) { - auto timeline = Timeline::create(fileName, _context); + _print(string::Format("Timeline: {0}").arg(path.get())); + auto timeline = Timeline::create(path, _context); TLRENDER_ASSERT(timeline->getTimeline()); - TLRENDER_ASSERT(fileName == timeline->getPath().get()); - TLRENDER_ASSERT(Options() == timeline->getOptions()); - TLRENDER_ASSERT(time::compareExact(timeRange, timeline->getTimeRange())); - TLRENDER_ASSERT(!timeline->getIOInfo().video.empty()); + TLRENDER_ASSERT(path == timeline->getPath()); _timeline(timeline); } + for (const auto& path : paths) { - const file::Path path(fileName); + _print(string::Format("Memory timeline: {0}").arg(path.get())); auto otioTimeline = timeline::create(path, _context); - TLRENDER_ASSERT(otioTimeline); toMemoryReferences(otioTimeline, path.getDirectory()); auto timeline = timeline::Timeline::create(otioTimeline, _context); TLRENDER_ASSERT(timeline->getTimeline()); - TLRENDER_ASSERT(fileName == timeline->getPath().get()); - TLRENDER_ASSERT(Options() == timeline->getOptions()); - TLRENDER_ASSERT(time::compareExact(timeRange, timeline->getTimeRange())); - TLRENDER_ASSERT(!timeline->getIOInfo().video.empty()); + TLRENDER_ASSERT(path == timeline->getPath()); _timeline(timeline); } } From fad30f544d64d29858a864dc7e0a51db522fa6d5 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 16:52:26 -0700 Subject: [PATCH 08/10] Tests fix --- tests/tlTimelineTest/PlayerTest.cpp | 6 +++-- tests/tlTimelineTest/TimelineTest.cpp | 35 ++++++++------------------- tests/tlTimelineTest/TimelineTest.h | 1 - 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/tests/tlTimelineTest/PlayerTest.cpp b/tests/tlTimelineTest/PlayerTest.cpp index bdf662015..dff888e48 100644 --- a/tests/tlTimelineTest/PlayerTest.cpp +++ b/tests/tlTimelineTest/PlayerTest.cpp @@ -237,15 +237,17 @@ namespace tl }); for (const auto& loop : getLoopEnums()) { + player->seek(timeRange.start_time()); player->setLoop(loop); player->setPlayback(Playback::Forward); - for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) + for (size_t i = 0; i < timeRange.duration().rate(); ++i) { player->tick(); time::sleep(std::chrono::milliseconds(1)); } + player->seek(timeRange.start_time()); player->setPlayback(Playback::Reverse); - for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) + for (size_t i = 0; i < timeRange.duration().rate(); ++i) { player->tick(); time::sleep(std::chrono::milliseconds(1)); diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index d690fbabe..f43fdc1b9 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -41,7 +41,6 @@ namespace tl _videoData(); _create(); _timeline(); - _imageSequence(); } void TimelineTest::_enums() @@ -247,25 +246,25 @@ namespace tl // Get video from the timeline. const otime::TimeRange& timeRange = timeline->getTimeRange(); std::vector videoData; - std::vector > futures; + std::vector > videoFutures; for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { - futures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0))); + videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0))); } for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { - futures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), 1)); + videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), 1)); } while (videoData.size() < static_cast(timeRange.duration().value()) * 2) { - auto i = futures.begin(); - while (i != futures.end()) + auto i = videoFutures.begin(); + while (i != videoFutures.end()) { if (i->valid() && i->wait_for(std::chrono::seconds(0)) == std::future_status::ready) { videoData.push_back(i->get()); - i = futures.erase(i); + i = videoFutures.erase(i); } else { @@ -273,34 +272,20 @@ namespace tl } } } - TLRENDER_ASSERT(futures.empty()); + TLRENDER_ASSERT(videoFutures.empty()); // Cancel requests. videoData.clear(); - futures.clear(); + videoFutures.clear(); for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { - futures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0))); + videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0))); } for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { - futures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), 1)); + videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), 1)); } timeline->cancelRequests(); } - - void TimelineTest::_imageSequence() - { - //! \bug This uses the image sequence created by _timeline(). - auto timeline = Timeline::create("Timeline Test.0.ppm", _context); - { - std::stringstream ss; - ss << timeline->getTimeRange().duration(); - _print(ss.str()); - } - TLRENDER_ASSERT( - otime::TimeRange(otime::RationalTime(0.0, 24.0), otime::RationalTime(24.0, 24.0)) == - timeline->getTimeRange()); - } } } diff --git a/tests/tlTimelineTest/TimelineTest.h b/tests/tlTimelineTest/TimelineTest.h index ef39a0d7c..7493c13f1 100644 --- a/tests/tlTimelineTest/TimelineTest.h +++ b/tests/tlTimelineTest/TimelineTest.h @@ -30,7 +30,6 @@ namespace tl void _create(); void _timeline(); void _timeline(const std::shared_ptr&); - void _imageSequence(); }; } } From 90d196f8bb7e22e703a1310a47d4cc4a4121a02b Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 17:25:13 -0700 Subject: [PATCH 09/10] Add audio requests --- tests/tlTimelineTest/TimelineTest.cpp | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index f43fdc1b9..f96dce5d0 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -274,9 +274,37 @@ namespace tl } TLRENDER_ASSERT(videoFutures.empty()); + // Get audio from the timeline. + std::vector audioData; + std::vector > audioFutures; + for (size_t i = 0; i < static_cast(timeRange.duration().rescaled_to(1.0).value()); ++i) + { + audioFutures.push_back(timeline->getAudio(i)); + } + while (audioData.size() < static_cast(timeRange.duration().rescaled_to(1.0).value())) + { + auto i = audioFutures.begin(); + while (i != audioFutures.end()) + { + if (i->valid() && + i->wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + audioData.push_back(i->get()); + i = audioFutures.erase(i); + } + else + { + ++i; + } + } + } + TLRENDER_ASSERT(audioFutures.empty()); + // Cancel requests. videoData.clear(); videoFutures.clear(); + audioData.clear(); + audioFutures.clear(); for (size_t i = 0; i < static_cast(timeRange.duration().value()); ++i) { videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0))); @@ -285,6 +313,10 @@ namespace tl { videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), 1)); } + for (size_t i = 0; i < static_cast(timeRange.duration().rescaled_to(1.0).value()); ++i) + { + audioFutures.push_back(timeline->getAudio(i)); + } timeline->cancelRequests(); } } From 95244f50d93123b2b674ac8abcbe326dd86555ec Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Mon, 2 Oct 2023 18:11:53 -0700 Subject: [PATCH 10/10] Add tests --- tests/tlTimelineTest/PlayerTest.cpp | 96 ++++++--------------------- tests/tlTimelineTest/TimelineTest.cpp | 3 +- 2 files changed, 21 insertions(+), 78 deletions(-) diff --git a/tests/tlTimelineTest/PlayerTest.cpp b/tests/tlTimelineTest/PlayerTest.cpp index dff888e48..cd2c0af9c 100644 --- a/tests/tlTimelineTest/PlayerTest.cpp +++ b/tests/tlTimelineTest/PlayerTest.cpp @@ -84,79 +84,6 @@ namespace tl void PlayerTest::_player() { - /*// Write an OTIO timeline. - auto otioTrack = new otio::Track(); - auto otioClip = new otio::Clip; - otioClip->set_media_reference(new otio::ImageSequenceReference( - "", "PlayerTest.", ".ppm", 0, 1, 1, 0)); - otioClip->set_source_range(otime::TimeRange( - otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0))); - otioTrack->append_child(otioClip); - - otioClip = new otio::Clip; - otioClip->set_media_reference(new otio::ImageSequenceReference( - "", "PlayerTest.", ".ppm", 0, 1, 1, 0)); - otioClip->set_source_range(otime::TimeRange( - otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0))); - otioTrack->append_child(otioClip); - -#if defined(TLRENDER_FFMPEG) - otioClip = new otio::Clip; - otioClip->set_media_reference(new otio::ExternalReference( - "PlayerTest.mov")); - otioClip->set_source_range(otime::TimeRange( - otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0))); - otioTrack->append_child(otioClip); -#endif // TLRENDER_FFMPEG - - auto otioStack = new otio::Stack; - otioStack->append_child(otioTrack); - otio::SerializableObject::Retainer otioTimeline( - new otio::Timeline); - otioTimeline->set_tracks(otioStack); - otioTimeline->set_global_start_time(otime::RationalTime(10.0, 24.0)); - const std::string fileName("PlayerTest.otio"); - otioTimeline->to_json_file(fileName); - - // Write the media files. - otime::TimeRange timeRange( - otime::RationalTime(10.0, 24.0), - otioTrack->available_range().duration()); - { - image::Info imageInfo(16, 16, image::PixelType::RGB_U8); - imageInfo.layout.endian = memory::Endian::MSB; - const auto image = image::Image::create(imageInfo); - io::Info ioInfo; - ioInfo.video.push_back(imageInfo); - ioInfo.videoTime = otime::TimeRange( - otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0)); - auto write = _context->getSystem()->write(file::Path("PlayerTest.0.ppm"), ioInfo); - for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) - { - write->writeVideo(otime::RationalTime(i, 24.0), image); - } - } -#if defined(TLRENDER_FFMPEG) - { - image::Info imageInfo(16, 16, image::PixelType::RGB_U8); - const auto image = image::Image::create(imageInfo); - io::Info ioInfo; - ioInfo.video.push_back(imageInfo); - ioInfo.videoTime = otime::TimeRange( - otime::RationalTime(0.0, 24.0), - otime::RationalTime(24.0, 24.0)); - auto write = _context->getSystem()->write(file::Path("PlayerTest.mov"), ioInfo); - for (size_t i = 0; i < static_cast(ioInfo.videoTime.duration().value()); ++i) - { - write->writeVideo(otime::RationalTime(i, 24.0), image); - } - } -#endif // TLRENDER_FFMPEG*/ - // Test timeline players. const std::vector paths = { @@ -164,7 +91,8 @@ namespace tl //file::Path(TLRENDER_SAMPLE_DATA, "AudioTonesAndVideo.otio"), file::Path(TLRENDER_SAMPLE_DATA, "Gap.otio"), file::Path(TLRENDER_SAMPLE_DATA, "MovieAndSeq.otio"), - file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio") + file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "SingleClip.otioz") }; for (const auto& path : paths) { @@ -189,8 +117,13 @@ namespace tl void PlayerTest::_player(const std::shared_ptr& player) { - // Test frames. const otime::TimeRange& timeRange = player->getTimeRange(); + const file::Path& audioPath = player->getAudioPath(); + const PlayerOptions& playerOptions = player->getPlayerOptions(); + const Options options = player->getOptions(); + const io::Info& ioInfo = player->getIOInfo(); + + // Test frames. struct FrameOptions { uint16_t layer = 0; @@ -257,7 +190,7 @@ namespace tl } // Test the playback speed. - double speed = 24.0; + double speed = player->getSpeed(); auto speedObserver = observer::ValueObserver::create( player->observeSpeed(), [&speed](double value) @@ -278,8 +211,8 @@ namespace tl { playback = value; }); - player->setLoop(Loop::Loop); player->setPlayback(Playback::Forward); + TLRENDER_ASSERT(Playback::Forward == player->getPlayback()); TLRENDER_ASSERT(Playback::Forward == playback); // Test the playback loop mode. @@ -291,6 +224,7 @@ namespace tl loop = value; }); player->setLoop(Loop::Once); + TLRENDER_ASSERT(Loop::Once == player->getLoop()); TLRENDER_ASSERT(Loop::Once == loop); // Test the current time. @@ -303,6 +237,7 @@ namespace tl currentTime = value; }); player->seek(timeRange.start_time()); + TLRENDER_ASSERT(timeRange.start_time() == player->getCurrentTime()); TLRENDER_ASSERT(timeRange.start_time() == currentTime); const double rate = timeRange.duration().rate(); player->seek( @@ -323,6 +258,10 @@ namespace tl player->framePrev(); player->timeAction(TimeAction::FramePrevX10); player->timeAction(TimeAction::FramePrevX100); + player->timeAction(TimeAction::JumpForward1s); + player->timeAction(TimeAction::JumpForward10s); + player->timeAction(TimeAction::JumpBack1s); + player->timeAction(TimeAction::JumpBack10s); // Test the in/out points. otime::TimeRange inOutRange = time::invalidTimeRange; @@ -335,6 +274,9 @@ namespace tl player->setInOutRange(otime::TimeRange( timeRange.start_time(), otime::RationalTime(10.0, rate))); + TLRENDER_ASSERT(otime::TimeRange( + timeRange.start_time(), + otime::RationalTime(10.0, rate)) == player->getInOutRange()); TLRENDER_ASSERT(otime::TimeRange( timeRange.start_time(), otime::RationalTime(10.0, rate)) == inOutRange); diff --git a/tests/tlTimelineTest/TimelineTest.cpp b/tests/tlTimelineTest/TimelineTest.cpp index f96dce5d0..42b0375de 100644 --- a/tests/tlTimelineTest/TimelineTest.cpp +++ b/tests/tlTimelineTest/TimelineTest.cpp @@ -219,7 +219,8 @@ namespace tl //file::Path(TLRENDER_SAMPLE_DATA, "AudioTonesAndVideo.otio"), file::Path(TLRENDER_SAMPLE_DATA, "Gap.otio"), file::Path(TLRENDER_SAMPLE_DATA, "MovieAndSeq.otio"), - file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio") + file::Path(TLRENDER_SAMPLE_DATA, "TransitionOverlay.otio"), + file::Path(TLRENDER_SAMPLE_DATA, "SingleClip.otioz") }; for (const auto& path : paths) {