diff --git a/app/core.cpp b/app/core.cpp index 64cea253a..1fa22e666 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -273,9 +273,9 @@ void Core::CreateNewProject() #ifdef USE_OTIO void Core::ExportActiveSequenceAsOTIO() { - ViewerOutput* sequence = GetSequenceToExport(); + ProjectPtr project = GetActiveProject(); - if (sequence) { + if (project) { QString fn = QFileDialog::getSaveFileName(main_window_, tr("Export as OpenTimelineIO"), QString(), @@ -284,7 +284,7 @@ void Core::ExportActiveSequenceAsOTIO() if (!fn.isEmpty()) { fn = FileFunctions::EnsureFilenameExtension(fn, QStringLiteral("otio")); - ExportOTIOTask* task = new ExportOTIOTask(sequence, fn); + ExportOTIOTask* task = new ExportOTIOTask(project, fn); TaskDialog* dialog = new TaskDialog(task, tr("Export Sequence"), main_window_); dialog->open(); } diff --git a/app/task/project/exportotio/exportotiotask.cpp b/app/task/project/exportotio/exportotiotask.cpp index 193f1f84b..f7cb131f2 100644 --- a/app/task/project/exportotio/exportotiotask.cpp +++ b/app/task/project/exportotio/exportotiotask.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "node/block/transition/transition.h" @@ -30,29 +31,80 @@ OLIVE_NAMESPACE_ENTER -ExportOTIOTask::ExportOTIOTask(ViewerOutput *sequence, const QString &filename) : - sequence_(sequence), +ExportOTIOTask::ExportOTIOTask(ProjectPtr project, const QString &filename) : + project_(project), filename_(filename) { - SetTitle(tr("Saving '%1' as OpenTimelineIO").arg(sequence_->media_name())); + SetTitle(tr("Exporting project to OpenTimelineIO")); } bool ExportOTIOTask::Run() { - auto otio_timeline = new opentimelineio::v1_0::Timeline(); + QList sequences = project_->get_items_of_type(Item::kSequence); - opentimelineio::v1_0::ErrorStatus es; - - if (!SerializeTrackList(sequence_->track_list(Timeline::kTrackTypeVideo), otio_timeline) - || !SerializeTrackList(sequence_->track_list(Timeline::kTrackTypeAudio), otio_timeline)) { + if (sequences.isEmpty()) { + SetError(tr("Project contains no sequences to export.")); return false; } - otio_timeline->to_json_file(filename_.toStdString(), &es); + std::vector serialized; + + foreach (ItemPtr item, sequences) { + SequencePtr seq = std::static_pointer_cast(sequences.first()); + + auto otio_timeline = SerializeTimeline(seq); + + if (otio_timeline) { + // Append to list + serialized.push_back(otio_timeline); + } else { + // Delete all existing timelines + foreach (auto s, serialized) { + s->possibly_delete(); + } + + // Error out of function + SetError(tr("Failed to serialize sequence \"%1\"").arg(seq->name())); + + return false; + } + } + + opentimelineio::v1_0::ErrorStatus es; + + if (serialized.size() == 1) { + // Serialize timeline on its own + auto t = serialized.front(); + t->to_json_file(filename_.toStdString(), &es); + t->possibly_delete(); + } else { + // Serialize all into a SerializableCollection + auto collection = new opentimelineio::v1_0::SerializableCollection("Sequences", serialized); + collection->to_json_file(filename_.toStdString(), &es); + collection->possibly_delete(); + + // Delete all existing timelines + foreach (auto s, serialized) { + s->possibly_delete(); + } + } return (es == opentimelineio::v1_0::ErrorStatus::OK); } +opentimelineio::v1_0::Timeline *ExportOTIOTask::SerializeTimeline(SequencePtr sequence) +{ + auto otio_timeline = new opentimelineio::v1_0::Timeline(sequence->name().toStdString()); + + if (!SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeVideo), otio_timeline) + || !SerializeTrackList(sequence->viewer_output()->track_list(Timeline::kTrackTypeAudio), otio_timeline)) { + otio_timeline->possibly_delete(); + return nullptr; + } + + return otio_timeline; +} + opentimelineio::v1_0::Track *ExportOTIOTask::SerializeTrack(TrackOutput *track) { auto otio_track = new opentimelineio::v1_0::Track(); @@ -77,7 +129,7 @@ opentimelineio::v1_0::Track *ExportOTIOTask::SerializeTrack(TrackOutput *track) switch (block->type()) { case Block::kClip: { - auto otio_clip = new opentimelineio::v1_0::Clip(); + auto otio_clip = new opentimelineio::v1_0::Clip(block->GetLabel().toStdString()); otio_clip->set_source_range(opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), block->length().toRationalTime())); @@ -93,17 +145,15 @@ opentimelineio::v1_0::Track *ExportOTIOTask::SerializeTrack(TrackOutput *track) } case Block::kGap: { - auto otio_gap = new opentimelineio::v1_0::Gap(); - - otio_gap->set_source_range(opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), - block->length().toRationalTime())); - - otio_block = otio_gap; + otio_block = new opentimelineio::v1_0::Gap( + opentimelineio::v1_0::TimeRange(block->in().toRationalTime(), block->length().toRationalTime()), + block->GetLabel().toStdString() + ); break; } case Block::kTransition: { - auto otio_transition = new opentimelineio::v1_0::Transition(); + auto otio_transition = new opentimelineio::v1_0::Transition(block->GetLabel().toStdString()); TransitionBlock* our_transition = static_cast(block); @@ -149,6 +199,7 @@ bool ExportOTIOTask::SerializeTrackList(TrackList *list, opentimelineio::v1_0::T otio_timeline->tracks()->append_child(otio_track, &es); if (es != opentimelineio::v1_0::ErrorStatus::OK) { + otio_track->possibly_delete(); return false; } } diff --git a/app/task/project/exportotio/exportotiotask.h b/app/task/project/exportotio/exportotiotask.h index e7defe029..64f2b71c0 100644 --- a/app/task/project/exportotio/exportotiotask.h +++ b/app/task/project/exportotio/exportotiotask.h @@ -24,7 +24,7 @@ #include #include -#include "project/item/sequence/sequence.h" +#include "project/project.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER @@ -33,17 +33,19 @@ class ExportOTIOTask : public Task { Q_OBJECT public: - ExportOTIOTask(ViewerOutput* sequence, const QString& filename); + ExportOTIOTask(ProjectPtr project, const QString& filename); protected: virtual bool Run() override; private: + opentimelineio::v1_0::Timeline* SerializeTimeline(SequencePtr sequence); + opentimelineio::v1_0::Track* SerializeTrack(TrackOutput* track); bool SerializeTrackList(TrackList* list, opentimelineio::v1_0::Timeline *otio_timeline); - ViewerOutput* sequence_; + ProjectPtr project_; QString filename_;