From 2172cf784ca2d7497c0abca4994b28cdb860b6ec Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 11 Nov 2020 21:53:44 +0000 Subject: [PATCH 1/8] Rational: conversion to opentime take framerate Add a frame rate option to the conversion to opentime rationals as otio generaly expects rationals to be in the form value/framerate. Also add a check to make sure the rational is not in the form 0/0 as this can cause errors with OTIO. --- app/common/rational.cpp | 6 ++++-- app/common/rational.h | 3 ++- app/task/project/saveotio/saveotio.cpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/common/rational.cpp b/app/common/rational.cpp index 2160e3f0e..ff44bbd89 100644 --- a/app/common/rational.cpp +++ b/app/common/rational.cpp @@ -103,10 +103,12 @@ AVRational rational::toAVRational() const } #ifdef USE_OTIO -opentime::RationalTime rational::toRationalTime() const +opentime::RationalTime rational::toRationalTime(double framerate) const { // Is this the best way of doing this? - return opentime::RationalTime::from_seconds(toDouble()); + // Olive can store rationals as 0/0 which causes errors in OTIO + opentime::RationalTime time = opentime::RationalTime(numer_, denom_ == 0 ? 1 : denom_); + return time.rescaled_to(framerate); } #endif diff --git a/app/common/rational.h b/app/common/rational.h index 358ea9697..8074c9b07 100644 --- a/app/common/rational.h +++ b/app/common/rational.h @@ -101,7 +101,8 @@ public: AVRational toAVRational() const; #ifdef USE_OTIO - opentime::RationalTime toRationalTime() const; + // Convert Olive ratioanls to opentime rationals with the given framerate (defaults to 24) + opentime::RationalTime toRationalTime(double framerate = 24) const; #endif // Produce "flipped" version diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index 0fdb91b61..890d11dfd 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -144,8 +144,8 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) } case Block::kGap: { - otio_block = new opentimelineio::v1_0::Gap( - opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), block->length().toRationalTime()), + otio_block = new opentimelineio::v1_0::Gap(opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), + block->length().toRationalTime()), block->GetLabel().toStdString() ); break; From cea436b7031590bbf93fa390115264bb37870a56 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 11 Nov 2020 21:57:45 +0000 Subject: [PATCH 2/8] saveoitio: Add fix for to_json_file The function to_json_file can delete it's SerializableObject if it doesn't have a Retainer associated with it. This fix adds said Retainer. Retainers clean them selves up when possibly_delete is called on their associated object. --- app/task/project/saveotio/saveotio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index 890d11dfd..ab3933ed9 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -24,11 +24,14 @@ #include #include #include +#include #include #include "node/block/transition/transition.h" #include "node/input/media/media.h" +#define OTIO opentimelineio::OPENTIMELINEIO_VERSION + OLIVE_NAMESPACE_ENTER SaveOTIOTask::SaveOTIOTask(ProjectPtr project) : @@ -94,6 +97,7 @@ bool SaveOTIOTask::Run() opentimelineio::v1_0::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) { auto otio_timeline = new opentimelineio::v1_0::Timeline(sequence->name().toStdString()); + OTIO::Timeline::Retainer* time_retainer = new OTIO::Timeline::Retainer(otio_timeline); if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) || !SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeAudio), otio_timeline)) { From a1d967efe69432d19426b144d17762848cdf6e41 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 11 Nov 2020 22:13:14 +0000 Subject: [PATCH 3/8] OTIO: Use macro OTIO for opentimelineio::v1_0 Exapnd the use of the OTIO macro and add the version number macro. --- app/task/project/loadotio/loadotio.cpp | 2 +- app/task/project/saveotio/saveotio.cpp | 42 ++++++++++++-------------- app/task/project/saveotio/saveotio.h | 8 +++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index 78799e389..25b83658f 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -34,7 +34,7 @@ #include "project/item/folder/folder.h" #include "project/item/sequence/sequence.h" -#define OTIO opentimelineio::v1_0 +#define OTIO opentimelineio::OPENTIMELINEIO_VERSION OLIVE_NAMESPACE_ENTER diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index ab3933ed9..37e8f5f90 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -30,8 +30,6 @@ #include "node/block/transition/transition.h" #include "node/input/media/media.h" -#define OTIO opentimelineio::OPENTIMELINEIO_VERSION - OLIVE_NAMESPACE_ENTER SaveOTIOTask::SaveOTIOTask(ProjectPtr project) : @@ -49,7 +47,7 @@ bool SaveOTIOTask::Run() return false; } - std::vector serialized; + std::vector serialized; foreach (ItemPtr item, sequences) { SequencePtr seq = std::static_pointer_cast(sequences.first()); @@ -72,7 +70,7 @@ bool SaveOTIOTask::Run() } } - opentimelineio::v1_0::ErrorStatus es; + OTIO::ErrorStatus es; if (serialized.size() == 1) { // Serialize timeline on its own @@ -81,7 +79,7 @@ bool SaveOTIOTask::Run() t->possibly_delete(); } else { // Serialize all into a SerializableCollection - auto collection = new opentimelineio::v1_0::SerializableCollection("Sequences", serialized); + auto collection = new OTIO::SerializableCollection("Sequences", serialized); collection->to_json_file(project_->filename().toStdString(), &es); collection->possibly_delete(); @@ -91,12 +89,12 @@ bool SaveOTIOTask::Run() } } - return (es == opentimelineio::v1_0::ErrorStatus::OK); + return (es == OTIO::ErrorStatus::OK); } -opentimelineio::v1_0::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) +OTIO::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) { - auto otio_timeline = new opentimelineio::v1_0::Timeline(sequence->name().toStdString()); + auto otio_timeline = new OTIO::Timeline(sequence->name().toStdString()); OTIO::Timeline::Retainer* time_retainer = new OTIO::Timeline::Retainer(otio_timeline); if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) @@ -108,11 +106,11 @@ opentimelineio::v1_0::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequ return otio_timeline; } -opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) +OTIO::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) { - auto otio_track = new opentimelineio::v1_0::Track(); + auto otio_track = new OTIO::Track(); - opentimelineio::v1_0::ErrorStatus es; + OTIO::ErrorStatus es; switch (track->track_type()) { case Timeline::kTrackTypeVideo: @@ -127,19 +125,19 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) } foreach (Block* block, track->Blocks()) { - opentimelineio::v1_0::Composable* otio_block = nullptr; + OTIO::Composable* otio_block = nullptr; switch (block->type()) { case Block::kClip: { - auto otio_clip = new opentimelineio::v1_0::Clip(block->GetLabel().toStdString()); + auto otio_clip = new OTIO::Clip(block->GetLabel().toStdString()); - otio_clip->set_source_range(opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), + otio_clip->set_source_range(OTIO::TimeRange(block->in().toRationalTime(), block->length().toRationalTime())); QList media_nodes = block->FindInputNodes(); if (!media_nodes.isEmpty()) { - auto media_ref = new opentimelineio::v1_0::ExternalReference(media_nodes.first()->stream()->footage()->filename().toStdString()); + auto media_ref = new OTIO::ExternalReference(media_nodes.first()->stream()->footage()->filename().toStdString()); otio_clip->set_media_reference(media_ref); } @@ -148,7 +146,7 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) } case Block::kGap: { - otio_block = new opentimelineio::v1_0::Gap(opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), + otio_block = new OTIO::Gap(OTIO::TimeRange(block->in().toRationalTime(), block->length().toRationalTime()), block->GetLabel().toStdString() ); @@ -156,14 +154,14 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) } case Block::kTransition: { - auto otio_transition = new opentimelineio::v1_0::Transition(block->GetLabel().toStdString()); + auto otio_transition = new OTIO::Transition(block->GetLabel().toStdString()); TransitionBlock* our_transition = static_cast(block); otio_transition->set_in_offset(our_transition->in_offset().toRationalTime()); otio_transition->set_out_offset(our_transition->out_offset().toRationalTime()); - otio_block = new opentimelineio::v1_0::Transition(); + otio_block = new OTIO::Transition(); break; } } @@ -175,7 +173,7 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) otio_track->append_child(otio_block, &es); - if (es != opentimelineio::v1_0::ErrorStatus::OK) { + if (es != OTIO::ErrorStatus::OK) { goto fail; } } @@ -188,9 +186,9 @@ fail: return nullptr; } -bool SaveOTIOTask::SerializeTrackList(TrackList *list, opentimelineio::v1_0::Timeline* otio_timeline) +bool SaveOTIOTask::SerializeTrackList(TrackList *list, OTIO::Timeline* otio_timeline) { - opentimelineio::v1_0::ErrorStatus es; + OTIO::ErrorStatus es; foreach (TrackOutput* track, list->GetTracks()) { auto otio_track = SerializeTrack(track); @@ -201,7 +199,7 @@ bool SaveOTIOTask::SerializeTrackList(TrackList *list, opentimelineio::v1_0::Tim otio_timeline->tracks()->append_child(otio_track, &es); - if (es != opentimelineio::v1_0::ErrorStatus::OK) { + if (es != OTIO::ErrorStatus::OK) { otio_track->possibly_delete(); return false; } diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index 2a380cddc..b939739d9 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -27,6 +27,8 @@ #include "project/project.h" #include "task/task.h" +#define OTIO opentimelineio::OPENTIMELINEIO_VERSION + OLIVE_NAMESPACE_ENTER class SaveOTIOTask : public Task @@ -39,11 +41,11 @@ protected: virtual bool Run() override; private: - opentimelineio::v1_0::Timeline* SerializeTimeline(SequencePtr sequence); + OTIO::Timeline* SerializeTimeline(SequencePtr sequence); - opentimelineio::v1_0::Track* SerializeTrack(TrackOutput* track); + OTIO::Track* SerializeTrack(TrackOutput* track); - bool SerializeTrackList(TrackList* list, opentimelineio::v1_0::Timeline *otio_timeline); + bool SerializeTrackList(TrackList* list, OTIO::Timeline *otio_timeline); ProjectPtr project_; From 7f4b6763188be326b88e3301696546bf808a9ace Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Thu, 12 Nov 2020 13:44:50 +0000 Subject: [PATCH 4/8] Move OTIO macro to define.h Move the OTIO macro to define.h to avoid having to add it to all required files. Also add some cleanup. --- app/common/define.h | 2 ++ app/task/project/loadotio/loadotio.cpp | 2 -- app/task/project/saveotio/saveotio.cpp | 6 +++--- app/task/project/saveotio/saveotio.h | 2 -- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/common/define.h b/app/common/define.h index aa968fcf7..4421b9f3a 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -27,6 +27,8 @@ #define OLIVE_NAMESPACE_EXIT } +#define OTIO opentimelineio::OPENTIMELINEIO_VERSION + OLIVE_NAMESPACE_ENTER const int kHSVChannels = 3; diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index 25b83658f..763139560 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -34,8 +34,6 @@ #include "project/item/folder/folder.h" #include "project/item/sequence/sequence.h" -#define OTIO opentimelineio::OPENTIMELINEIO_VERSION - OLIVE_NAMESPACE_ENTER LoadOTIOTask::LoadOTIOTask(const QString& s) : diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index 37e8f5f90..bc706fcef 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -95,7 +95,7 @@ bool SaveOTIOTask::Run() OTIO::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) { auto otio_timeline = new OTIO::Timeline(sequence->name().toStdString()); - OTIO::Timeline::Retainer* time_retainer = new OTIO::Timeline::Retainer(otio_timeline); + OTIO::Timeline::Retainer* timeline_retainer = new OTIO::Timeline::Retainer(otio_timeline); if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) || !SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeAudio), otio_timeline)) { @@ -147,8 +147,8 @@ OTIO::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) case Block::kGap: { otio_block = new OTIO::Gap(OTIO::TimeRange(block->in().toRationalTime(), - block->length().toRationalTime()), - block->GetLabel().toStdString() + block->length().toRationalTime()), + block->GetLabel().toStdString() ); break; } diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index b939739d9..69338f16a 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -27,8 +27,6 @@ #include "project/project.h" #include "task/task.h" -#define OTIO opentimelineio::OPENTIMELINEIO_VERSION - OLIVE_NAMESPACE_ENTER class SaveOTIOTask : public Task From 3b68f027f879c854df885e959730f7afa57ec9a7 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Thu, 12 Nov 2020 13:48:24 +0000 Subject: [PATCH 5/8] More cleanup --- app/task/project/saveotio/saveotio.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index bc706fcef..a8a95da33 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -95,6 +95,7 @@ bool SaveOTIOTask::Run() OTIO::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) { auto otio_timeline = new OTIO::Timeline(sequence->name().toStdString()); + // Retainers clean themselves up when the final user is removed OTIO::Timeline::Retainer* timeline_retainer = new OTIO::Timeline::Retainer(otio_timeline); if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) @@ -149,7 +150,7 @@ OTIO::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) otio_block = new OTIO::Gap(OTIO::TimeRange(block->in().toRationalTime(), block->length().toRationalTime()), block->GetLabel().toStdString() - ); + ); break; } case Block::kTransition: From f9e2a83ee4f4726bbf7df06dfa93f5326df97a29 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 16 Nov 2020 16:47:31 +0000 Subject: [PATCH 6/8] Create OTIO namespace in otioutils.h --- app/common/CMakeLists.txt | 1 + app/common/define.h | 1 - app/common/otioutils.h | 29 ++++++++++++++++++++++++++++ app/task/project/loadotio/loadotio.h | 2 ++ app/task/project/saveotio/saveotio.h | 1 + 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 app/common/otioutils.h diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 99521453c..5c2daad49 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -37,6 +37,7 @@ set(OLIVE_SOURCES common/lerp.h common/memorypool.h common/memorypool.cpp + common/otioutils.h common/qtutils.h common/qtutils.cpp common/range.h diff --git a/app/common/define.h b/app/common/define.h index 4421b9f3a..28c400b8b 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -27,7 +27,6 @@ #define OLIVE_NAMESPACE_EXIT } -#define OTIO opentimelineio::OPENTIMELINEIO_VERSION OLIVE_NAMESPACE_ENTER diff --git a/app/common/otioutils.h b/app/common/otioutils.h new file mode 100644 index 000000000..1a3a32dd0 --- /dev/null +++ b/app/common/otioutils.h @@ -0,0 +1,29 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef OTIOUTILS_H +#define OTIOUTILS_H + +#ifdef USE_OTIO +#include +namespace OTIO = opentimelineio::OPENTIMELINEIO_VERSION; +#endif + +#endif // OTIOUTILS diff --git a/app/task/project/loadotio/loadotio.h b/app/task/project/loadotio/loadotio.h index 5e44bb67d..639884310 100644 --- a/app/task/project/loadotio/loadotio.h +++ b/app/task/project/loadotio/loadotio.h @@ -21,6 +21,8 @@ #ifndef OTIODECODER_H #define OTIODECODER_H + +#include "common/otioutils.h" #include "project/project.h" #include "task/project/load/loadbasetask.h" diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index 69338f16a..a360dab5d 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -24,6 +24,7 @@ #include #include +#include "common/otioutils.h" #include "project/project.h" #include "task/task.h" From 8433e4093a082de47636b6eb4b5410f248134fa2 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 16 Nov 2020 16:57:08 +0000 Subject: [PATCH 7/8] Cleanup --- app/common/define.h | 1 - app/task/project/loadotio/loadotio.h | 1 - app/task/project/saveotio/saveotio.cpp | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/common/define.h b/app/common/define.h index 28c400b8b..aa968fcf7 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -27,7 +27,6 @@ #define OLIVE_NAMESPACE_EXIT } - OLIVE_NAMESPACE_ENTER const int kHSVChannels = 3; diff --git a/app/task/project/loadotio/loadotio.h b/app/task/project/loadotio/loadotio.h index 639884310..da156f68c 100644 --- a/app/task/project/loadotio/loadotio.h +++ b/app/task/project/loadotio/loadotio.h @@ -21,7 +21,6 @@ #ifndef OTIODECODER_H #define OTIODECODER_H - #include "common/otioutils.h" #include "project/project.h" #include "task/project/load/loadbasetask.h" diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index a8a95da33..586bc8570 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -134,7 +134,7 @@ OTIO::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) auto otio_clip = new OTIO::Clip(block->GetLabel().toStdString()); otio_clip->set_source_range(OTIO::TimeRange(block->in().toRationalTime(), - block->length().toRationalTime())); + block->length().toRationalTime())); QList media_nodes = block->FindInputNodes(); if (!media_nodes.isEmpty()) { From 0cf640fb094550e84599d74adf87725e3d44d9aa Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Fri, 4 Dec 2020 19:20:42 +0000 Subject: [PATCH 8/8] Suppress unused variable warning. --- app/task/project/saveotio/saveotio.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index b477b4ec5..7143d05e2 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -97,6 +97,8 @@ OTIO::Timeline *SaveOTIOTask::SerializeTimeline(SequencePtr sequence) auto otio_timeline = new OTIO::Timeline(sequence->name().toStdString()); // Retainers clean themselves up when the final user is removed OTIO::Timeline::Retainer* timeline_retainer = new OTIO::Timeline::Retainer(otio_timeline); + // Suppress unused variable warning + Q_UNUSED(timeline_retainer); if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) || !SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeAudio), otio_timeline)) {