Skip to content

Commit

Permalink
Merge pull request #18 from darbyjohnston/otioz2
Browse files Browse the repository at this point in the history
Initial support for .otioz and .otiod
  • Loading branch information
darbyjohnston authored Nov 14, 2024
2 parents 7d0afc4 + 39ff73f commit 67d8935
Show file tree
Hide file tree
Showing 19 changed files with 342 additions and 131 deletions.
22 changes: 6 additions & 16 deletions bin/toucan-render/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <toucan/ImageEffectHost.h>
#include <toucan/ImageGraph.h>
#include <toucan/Timeline.h>
#include <toucan/Util.h>

#include <OpenImageIO/imagebufalgo.h>
Expand Down Expand Up @@ -147,22 +148,11 @@ namespace toucan
const size_t outputNumberPadding = getNumberPadding(outputSplit.second);

// Open the timeline.
OTIO_NS::ErrorStatus errorStatus;
auto timeline = OTIO_NS::SerializableObject::Retainer<OTIO_NS::Timeline>(
dynamic_cast<OTIO_NS::Timeline*>(OTIO_NS::Timeline::from_json_file(inputPath.string(), &errorStatus)));
if (!timeline)
{
std::stringstream ss;
ss << inputPath.string() << ": " << errorStatus.full_description << std::endl;
throw std::runtime_error(ss.str());
}
auto timeline = std::make_shared<Timeline>(inputPath);

// Compute time values.
const OTIO_NS::RationalTime startTime = timeline->global_start_time().has_value() ?
timeline->global_start_time().value() :
OTIO_NS::RationalTime(0.0, timeline->duration().rate());
const OTIO_NS::TimeRange timeRange(startTime, timeline->duration());
const OTIO_NS::RationalTime timeInc(1.0, timeline->duration().rate());
// Get time values.
const OTIO_NS::TimeRange& timeRange = timeline->getTimeRange();
const OTIO_NS::RationalTime timeInc(1.0, timeRange.duration().rate());
const int frames = timeRange.duration().value();

// Create the image graph.
Expand Down Expand Up @@ -235,7 +225,7 @@ namespace toucan

// Render the timeline frames.
int filmstripX = 0;
for (OTIO_NS::RationalTime time = startTime;
for (OTIO_NS::RationalTime time = timeRange.start_time();
time <= timeRange.end_time_inclusive();
time += timeInc)
{
Expand Down
2 changes: 1 addition & 1 deletion cmake/SuperBuild/Builddtk-deps.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(ExternalProject)

set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
set(dtk_GIT_TAG "fe708a58fda5dc65141e492ae5fa24b199ff3edc")
set(dtk_GIT_TAG "ff2b7dcbbaf6eb8dc3568922f7c84b7c34c2c8dd")

set(dtk-deps_ARGS
${toucan_EXTERNAL_PROJECT_ARGS}
Expand Down
2 changes: 1 addition & 1 deletion cmake/SuperBuild/Builddtk.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(ExternalProject)

set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
set(dtk_GIT_TAG "fe708a58fda5dc65141e492ae5fa24b199ff3edc")
set(dtk_GIT_TAG "ff2b7dcbbaf6eb8dc3568922f7c84b7c34c2c8dd")

set(dtk_DEPS dtk-deps)
set(dtk_ARGS
Expand Down
5 changes: 4 additions & 1 deletion lib/toucan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(HEADERS
PropertySet.h
Read.h
TimeWarp.h
Timeline.h
Util.h)
set(HEADERS_PRIVATE
ImageEffect_p.h)
Expand All @@ -25,14 +26,16 @@ set(SOURCE
PropertySet.cpp
Read.cpp
TimeWarp.cpp
Timeline.cpp
Util.cpp)
if(WIN32)
list(APPEND SOURCE
PluginWin32.cpp
UtilWin32.cpp)
else()
list(APPEND SOURCE
PluginUnix.cpp)
PluginUnix.cpp
UtilUnix.cpp)
endif()

add_library(toucan ${HEADERS} ${HEADERS_PRIVATE} ${SOURCE})
Expand Down
105 changes: 49 additions & 56 deletions lib/toucan/ImageGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,57 +24,60 @@ namespace toucan

ImageGraph::ImageGraph(
const std::filesystem::path& path,
const OTIO_NS::SerializableObject::Retainer<OTIO_NS::Timeline>& timeline,
const std::shared_ptr<Timeline>& timeline,
const ImageGraphOptions& options) :
_path(path),
_timeline(timeline),
_timeRange(timeline->getTimeRange()),
_options(options)
{
const auto globalStartTime = timeline->global_start_time();
_globalStartTime = globalStartTime.has_value() ? globalStartTime.value() :
OTIO_NS::RationalTime(0.0, timeline->duration().rate());

_loadCache.setMax(10);

// Get the image size from the first clip.
for (auto clip : _timeline->find_clips())
// Get the image size from the first video clip.
for (auto track : _timeline->otio()->find_children<OTIO_NS::Track>())
{
if (auto externalRef = dynamic_cast<OTIO_NS::ExternalReference*>(clip->media_reference()))
if (OTIO_NS::Track::Kind::video == track->kind())
{
const std::filesystem::path path = _getMediaPath(externalRef->target_url());
const OIIO::ImageBuf buf(path.string());
const auto& spec = buf.spec();
if (spec.width > 0)
for (auto clip : track->find_clips())
{
_imageSize.x = spec.width;
_imageSize.y = spec.height;
break;
}
}
else if (auto sequenceRef = dynamic_cast<OTIO_NS::ImageSequenceReference*>(clip->media_reference()))
{
const std::filesystem::path path = getSequenceFrame(
_getMediaPath(sequenceRef->target_url_base()),
sequenceRef->name_prefix(),
sequenceRef->start_frame(),
sequenceRef->frame_zero_padding(),
sequenceRef->name_suffix());
const OIIO::ImageBuf buf(path.string());
const auto& spec = buf.spec();
if (spec.width > 0)
{
_imageSize.x = spec.width;
_imageSize.y = spec.height;
break;
}
}
else if (auto generatorRef = dynamic_cast<OTIO_NS::GeneratorReference*>(clip->media_reference()))
{
auto parameters = generatorRef->parameters();
auto i = parameters.find("size");
if (i != parameters.end() && i->second.has_value())
{
anyToVec(std::any_cast<OTIO_NS::AnyVector>(i->second), _imageSize);
if (auto externalRef = dynamic_cast<OTIO_NS::ExternalReference*>(clip->media_reference()))
{
const std::filesystem::path path = _timeline->getMediaPath(externalRef->target_url());
const OIIO::ImageBuf buf(path.string());
const auto& spec = buf.spec();
if (spec.width > 0)
{
_imageSize.x = spec.width;
_imageSize.y = spec.height;
break;
}
}
else if (auto sequenceRef = dynamic_cast<OTIO_NS::ImageSequenceReference*>(clip->media_reference()))
{
const std::filesystem::path path = getSequenceFrame(
_timeline->getMediaPath(sequenceRef->target_url_base()),
sequenceRef->name_prefix(),
sequenceRef->start_frame(),
sequenceRef->frame_zero_padding(),
sequenceRef->name_suffix());
const OIIO::ImageBuf buf(path.string());
const auto& spec = buf.spec();
if (spec.width > 0)
{
_imageSize.x = spec.width;
_imageSize.y = spec.height;
break;
}
}
else if (auto generatorRef = dynamic_cast<OTIO_NS::GeneratorReference*>(clip->media_reference()))
{
auto parameters = generatorRef->parameters();
auto i = parameters.find("size");
if (i != parameters.end() && i->second.has_value())
{
anyToVec(std::any_cast<OTIO_NS::AnyVector>(i->second), _imageSize);
}
}
}
}
}
Expand All @@ -99,15 +102,15 @@ namespace toucan
std::shared_ptr<IImageNode> node = host->createNode("toucan:Fill", metaData);

// Loop over the tracks.
auto stack = _timeline->tracks();
auto stack = _timeline->otio()->tracks();
for (const auto& i : stack->children())
{
if (auto track = OTIO_NS::dynamic_retainer_cast<OTIO_NS::Track>(i))
{
if (track->kind() == OTIO_NS::Track::Kind::video && !track->find_clips().empty())
{
// Process this track.
auto trackNode = _track(host, time - _globalStartTime, track);
auto trackNode = _track(host, time - _timeRange.start_time(), track);

// Get the track effects.
const auto& effects = track->effects();
Expand Down Expand Up @@ -141,7 +144,7 @@ namespace toucan
}

// Set the time.
node->setTime(time - _globalStartTime);
node->setTime(time - _timeRange.start_time());

return node;
}
Expand Down Expand Up @@ -291,7 +294,7 @@ namespace toucan
std::shared_ptr<ReadNode> read;
if (!_loadCache.get(externalRef, read))
{
const std::filesystem::path path = _getMediaPath(externalRef->target_url());
const std::filesystem::path path = _timeline->getMediaPath(externalRef->target_url());
read = std::make_shared<ReadNode>(path);
_loadCache.add(externalRef, read);
}
Expand All @@ -309,7 +312,7 @@ namespace toucan
}
else if (auto sequenceRef = dynamic_cast<OTIO_NS::ImageSequenceReference*>(clip->media_reference()))
{
const std::filesystem::path path = _getMediaPath(sequenceRef->target_url_base());
const std::filesystem::path path = _timeline->getMediaPath(sequenceRef->target_url_base());
auto read = std::make_shared<SequenceReadNode>(
path,
sequenceRef->name_prefix(),
Expand Down Expand Up @@ -374,14 +377,4 @@ namespace toucan
}
return out;
}

std::filesystem::path ImageGraph::_getMediaPath(const std::string& url) const
{
std::filesystem::path path = splitURLProtocol(url).second;
if (!path.is_absolute())
{
path = _path / path;
}
return path;
}
}
11 changes: 4 additions & 7 deletions lib/toucan/ImageGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@

#include <toucan/ImageNode.h>
#include <toucan/MessageLog.h>
#include <toucan/Timeline.h>

#include <dtk/core/LRUCache.h>

#include <opentimelineio/clip.h>
#include <opentimelineio/timeline.h>
#include <opentimelineio/track.h>
#include <opentimelineio/transition.h>

Expand All @@ -32,7 +31,7 @@ namespace toucan
public:
ImageGraph(
const std::filesystem::path&,
const OTIO_NS::SerializableObject::Retainer<OTIO_NS::Timeline>&,
const std::shared_ptr<Timeline>&,
const ImageGraphOptions& = ImageGraphOptions());

~ImageGraph();
Expand Down Expand Up @@ -62,11 +61,9 @@ namespace toucan
const std::vector<OTIO_NS::SerializableObject::Retainer<OTIO_NS::Effect> >&,
const std::shared_ptr<IImageNode>&);

std::filesystem::path _getMediaPath(const std::string&) const;

std::filesystem::path _path;
OTIO_NS::SerializableObject::Retainer<OTIO_NS::Timeline> _timeline;
OTIO_NS::RationalTime _globalStartTime;
std::shared_ptr<Timeline> _timeline;
OTIO_NS::TimeRange _timeRange;
ImageGraphOptions _options;
IMATH_NAMESPACE::V2i _imageSize = IMATH_NAMESPACE::V2i(0, 0);
dtk::LRUCache<OTIO_NS::MediaReference*, std::shared_ptr<ReadNode> > _loadCache;
Expand Down
Loading

0 comments on commit 67d8935

Please sign in to comment.