diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 7f4d1fd76..83880359c 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -38,6 +38,7 @@ set(OLIVE_SOURCES common/functiontimer.h common/lerp.h common/memorypool.cpp + common/otioutils.h common/memorypool.h common/ocioutils.cpp common/ocioutils.h 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/common/rational.cpp b/app/common/rational.cpp index fa4bfd133..62c9af3e0 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 0d548523b..95c369d1b 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/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index c7510939d..6e84c7745 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -38,8 +38,6 @@ #include "node/project/sequence/sequence.h" #include "widget/timelinewidget/timelineundo.h" -#define OTIO opentimelineio::v1_0 - namespace olive { LoadOTIOTask::LoadOTIOTask(const QString& s) : @@ -243,4 +241,4 @@ bool LoadOTIOTask::Run() } -#endif +#endif // USE_OTIO diff --git a/app/task/project/loadotio/loadotio.h b/app/task/project/loadotio/loadotio.h index 55579fcd7..702d8e73a 100644 --- a/app/task/project/loadotio/loadotio.h +++ b/app/task/project/loadotio/loadotio.h @@ -23,6 +23,7 @@ #ifdef USE_OTIO +#include "common/otioutils.h" #include "node/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 791821772..a683b058a 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "node/block/transition/transition.h" @@ -48,7 +49,7 @@ bool SaveOTIOTask::Run() return false; } - std::vector serialized; + std::vector serialized; foreach (Sequence* seq, sequences) { auto otio_timeline = SerializeTimeline(seq); @@ -69,7 +70,7 @@ bool SaveOTIOTask::Run() } } - opentimelineio::v1_0::ErrorStatus es; + OTIO::ErrorStatus es; if (serialized.size() == 1) { // Serialize timeline on its own @@ -78,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(); @@ -88,12 +89,16 @@ bool SaveOTIOTask::Run() } } - return (es == opentimelineio::v1_0::ErrorStatus::OK); + return (es == OTIO::ErrorStatus::OK); } -opentimelineio::v1_0::Timeline *SaveOTIOTask::SerializeTimeline(Sequence *sequence) +OTIO::Timeline *SaveOTIOTask::SerializeTimeline(Sequence *sequence) { - auto otio_timeline = new opentimelineio::v1_0::Timeline(sequence->GetLabel().toStdString()); + auto otio_timeline = new OTIO::Timeline(sequence->GetLabel().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->track_list(Track::kVideo), otio_timeline) || !SerializeTrackList(sequence->track_list(Track::kAudio), otio_timeline)) { @@ -104,11 +109,11 @@ opentimelineio::v1_0::Timeline *SaveOTIOTask::SerializeTimeline(Sequence *sequen return otio_timeline; } -opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(Track *track) +OTIO::Track *SaveOTIOTask::SerializeTrack(Track *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->type()) { case Track::kVideo: @@ -123,19 +128,19 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(Track *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(), - block->length().toRationalTime())); + otio_clip->set_source_range(OTIO::TimeRange(block->in().toRationalTime(), + block->length().toRationalTime())); QVector media_nodes = block->FindInputNodes(); if (!media_nodes.isEmpty()) { - auto media_ref = new opentimelineio::v1_0::ExternalReference(media_nodes.first()->filename().toStdString()); + auto media_ref = new OTIO::ExternalReference(media_nodes.first()->filename().toStdString()); otio_clip->set_media_reference(media_ref); } @@ -144,22 +149,22 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(Track *track) } case Block::kGap: { - otio_block = new opentimelineio::v1_0::Gap( - opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), block->length().toRationalTime()), - block->GetLabel().toStdString() - ); + otio_block = new OTIO::Gap(OTIO::TimeRange(block->in().toRationalTime(), + block->length().toRationalTime()), + block->GetLabel().toStdString() + ); break; } 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; } } @@ -171,7 +176,7 @@ opentimelineio::v1_0::Track *SaveOTIOTask::SerializeTrack(Track *track) otio_track->append_child(otio_block, &es); - if (es != opentimelineio::v1_0::ErrorStatus::OK) { + if (es != OTIO::ErrorStatus::OK) { goto fail; } } @@ -184,9 +189,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 (Track* track, list->GetTracks()) { auto otio_track = SerializeTrack(track); @@ -197,7 +202,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; } @@ -208,4 +213,4 @@ bool SaveOTIOTask::SerializeTrackList(TrackList *list, opentimelineio::v1_0::Tim } -#endif +#endif // USE_OTIO diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index 658849de6..076a0470d 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -26,6 +26,7 @@ #include #include +#include "common/otioutils.h" #include "node/project/project.h" #include "task/task.h" @@ -41,11 +42,11 @@ protected: virtual bool Run() override; private: - opentimelineio::v1_0::Timeline* SerializeTimeline(Sequence* sequence); + OTIO::Timeline* SerializeTimeline(Sequence* sequence); - opentimelineio::v1_0::Track* SerializeTrack(Track* track); + OTIO::Track* SerializeTrack(Track* track); - bool SerializeTrackList(TrackList* list, opentimelineio::v1_0::Timeline *otio_timeline); + bool SerializeTrackList(TrackList* list, OTIO::Timeline *otio_timeline); Project* project_;