Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loadotio: refactor code for clarity #1823

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 137 additions & 102 deletions app/task/project/loadotio/loadotio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <opentimelineio/clip.h>
#include <opentimelineio/externalReference.h>
#include <opentimelineio/gap.h>
#include <opentimelineio/serializableCollection.h>
#include <opentimelineio/timeline.h>
#include <opentimelineio/transition.h>
#include <QApplication>
Expand All @@ -34,8 +33,6 @@

#include "core.h"
#include "node/audio/volume/volume.h"
#include "node/block/clip/clip.h"
#include "node/block/gap/gap.h"
#include "node/block/transition/crossdissolve/crossdissolvetransition.h"
#include "node/distort/transform/transformdistortnode.h"
#include "node/generator/matrix/matrix.h"
Expand All @@ -50,7 +47,10 @@
namespace olive {

LoadOTIOTask::LoadOTIOTask(const QString& s) :
ProjectLoadBaseTask(s)
ProjectLoadBaseTask(s),
previous_block_(nullptr),
prev_block_transition_(false),
transition_flag_(false)
{
}

Expand Down Expand Up @@ -88,7 +88,6 @@ bool LoadOTIOTask::Run()
}

// Keep track of imported footage
QMap<QString, Footage*> imported_footage;
QMap<OTIO::Timeline*, Sequence*> timeline_sequnce_map;

// Variables used for loading bar
Expand All @@ -108,7 +107,7 @@ bool LoadOTIOTask::Run()
QString label = tr("Sequence %1").arg(unnamed_sequence_count);
sequence->SetLabel(QString::fromStdString(label.toStdString()));
}
// Set default params incase they aren't edited.
// Set default params in case they aren't edited.
sequence->set_default_parameters();
timeline_sequnce_map.insert(timeline, sequence);

Expand Down Expand Up @@ -143,6 +142,8 @@ bool LoadOTIOTask::Run()
sequence_footage->setParent(project_);
FolderAddChild(project_->root(), sequence_footage).redo_now();



// Iterate through tracks
for (auto c : timeline->tracks()->children()) {
auto otio_track = static_cast<OTIO::Track*>(c.value);
Expand Down Expand Up @@ -176,8 +177,8 @@ bool LoadOTIOTask::Run()
return false;
}

Block* previous_block = nullptr;
bool prev_block_transition = false;
previous_block_ = nullptr;
prev_block_transition_ = false;

for (auto otio_block_retainer : clip_map) {

Expand All @@ -187,145 +188,179 @@ bool LoadOTIOTask::Run()

if (otio_block->schema_name() == "Clip") {

block = new ClipBlock();
block = LoadClip(otio_block, track, sequence, sequence_footage);

} else if (otio_block->schema_name() == "Gap") {

block = new GapBlock();
block = LoadGap(otio_block, track, sequence);

} else if (otio_block->schema_name() == "Transition") {

// Todo: Look into OTIO supported transitions and add them to Olive
block = new CrossDissolveTransition();
block = LoadTransition(otio_block, track, sequence);

} else {

// We don't know what this is yet, just create a gap for now so that *something* is there
// TODO: Add a UI warning message listing unkown block types (see ProjectImportErrorDialog)
qWarning() << "Found unknown block type:" << otio_block->schema_name().c_str();
block = new GapBlock();
LoadGap(otio_block, track, sequence);
}

block->setParent(project_);
block->SetLabel(QString::fromStdString(otio_block->name()));
// If the previous block was a transition, connect the current block to it
// Also checks for the rare case where we start the track with a transition
if (prev_block_transition_ && previous_block_) {
TransitionBlock* previous_transition_block = static_cast<TransitionBlock*>(previous_block_);
Node::ConnectEdge(block, NodeInput(previous_transition_block, TransitionBlock::kInBlockInput));
NodeSetPositionCommand add_previous(block, previous_block_, QPointF(-1, 0.5));
add_previous.redo_now();
prev_block_transition_ = false;
}

track->AppendBlock(block);
if (transition_flag_) {
prev_block_transition_ = true;
transition_flag_ = false;
}

rational start_time;
rational duration;
previous_block_ = block;

clips_done++;
emit ProgressChanged(clips_done / number_of_clips);
}
}
}

if (otio_block->schema_name() == "Clip" || otio_block->schema_name() == "Gap") {
start_time =
rational::fromDouble(static_cast<OTIO::Item*>(otio_block)->source_range()->start_time().to_seconds());
duration =
rational::fromDouble(static_cast<OTIO::Item*>(otio_block)->source_range()->duration().to_seconds());
project_->moveToThread(qApp->thread());

if (otio_block->schema_name() == "Clip") {
static_cast<ClipBlock*>(block)->set_media_in(start_time);
}
block->set_length_and_media_out(duration);
}
return true;
}

// If the previous block was a transition, connect the current block to it
if (prev_block_transition) {
TransitionBlock* previous_transition_block = static_cast<TransitionBlock*>(previous_block);
Node::ConnectEdge(block, NodeInput(previous_transition_block, TransitionBlock::kInBlockInput));
prev_block_transition = false;
}
GapBlock* LoadOTIOTask::LoadGap(OTIO::Composable* otio_block, Track* track, Sequence* sequence)
{
GapBlock* gap = new GapBlock();

if (otio_block->schema_name() == "Transition") {
TransitionBlock* transition_block = static_cast<TransitionBlock*>(block);
OTIO::Transition* otio_block_transition = static_cast<OTIO::Transition*>(otio_block);
gap->setParent(project_);
gap->SetLabel(QString::fromStdString(otio_block->name()));

// Set how far the transition eats into the previous clip
transition_block->set_offsets_and_length(rational::fromRationalTime(otio_block_transition->in_offset()), rational::fromRationalTime(otio_block_transition->out_offset()));
track->AppendBlock(gap);

if (previous_block) {
Node::ConnectEdge(previous_block, NodeInput(transition_block, TransitionBlock::kOutBlockInput));
}
prev_block_transition = true;
gap->set_length_and_media_out(
rational::fromDouble(static_cast<OTIO::Item*>(otio_block)->source_range()->duration().to_seconds()));

// Add nodes to the graph and set up contexts
block->setParent(sequence->parent());
// Add nodes to the graph and set up contexts
gap->setParent(sequence->parent());

// Position transition in its own context
block->SetNodePositionInContext(block, QPointF(0, 0));
}
// Position transition in its own context
gap->SetNodePositionInContext(gap, QPointF(0, 0));

if (otio_block->schema_name() == "Gap") {
// Add nodes to the graph and set up contexts
block->setParent(sequence->parent());
return gap;
}

// Position transition in its own context
block->SetNodePositionInContext(block, QPointF(0, 0));
}
CrossDissolveTransition* LoadOTIOTask::LoadTransition(OTIO::Composable* otio_block, Track* track,
Sequence* sequence) {
// Todo: Look into OTIO supported transitions and add them to Olive
CrossDissolveTransition* transition = new CrossDissolveTransition();

// Update this after it's used but before any continue statements
previous_block = block;
transition->setParent(project_);
transition->SetLabel(QString::fromStdString(otio_block->name()));

if (otio_block->schema_name() == "Clip") {
auto otio_clip = static_cast<OTIO::Clip*>(otio_block);
if (!otio_clip->media_reference()) {
continue;
}
if (otio_clip->media_reference()->schema_name() == "ExternalReference") {
// Link footage
QString footage_url = QString::fromStdString(static_cast<OTIO::ExternalReference*>(otio_clip->media_reference())->target_url());
track->AppendBlock(transition);

Footage* probed_item;
//TransitionBlock* transition_block = static_cast<TransitionBlock*>(block);
OTIO::Transition* otio_block_transition = static_cast<OTIO::Transition*>(otio_block);

if (imported_footage.contains(footage_url)) {
probed_item = imported_footage.value(footage_url);
} else {
probed_item = new Footage(footage_url);
imported_footage.insert(footage_url, probed_item);
probed_item->setParent(project_);
// Set how far the transition eats into the previous clip
transition->set_offsets_and_length(rational::fromRationalTime(otio_block_transition->in_offset()),
rational::fromRationalTime(otio_block_transition->out_offset()));


QFileInfo info(probed_item->filename());
probed_item->SetLabel(info.fileName());
if (previous_block_) {
Node::ConnectEdge(previous_block_, NodeInput(transition, TransitionBlock::kOutBlockInput));
NodeSetPositionCommand add_previous(previous_block_, transition, QPointF(-1, -0.5));
add_previous.redo_now();
}
transition_flag_ = true;

FolderAddChild add(sequence_footage, probed_item);
add.redo_now();
}
// Add nodes to the graph and set up contexts
transition->setParent(sequence->parent());

// Add nodes to the graph and set up contexts
block->setParent(sequence->parent());
// Position transition in its own context
transition->SetNodePositionInContext(transition, QPointF(0, 0));

// Position clip in its own context
block->SetNodePositionInContext(block, QPointF(0, 0));
return transition;
}

// Position footage in its context
block->SetNodePositionInContext(probed_item, QPointF(-2, 0));
ClipBlock* LoadOTIOTask::LoadClip(OTIO::Composable* otio_block, Track* track, Sequence* sequence, Folder* sequence_footage)
{
ClipBlock* clip = new ClipBlock();

clip->setParent(project_);
clip->SetLabel(QString::fromStdString(otio_block->name()));

if (track->type() == Track::kVideo) {
TransformDistortNode* transform = new TransformDistortNode();
transform->setParent(sequence->parent());
track->AppendBlock(clip);

Node::ConnectEdge(probed_item, NodeInput(transform, TransformDistortNode::kTextureInput));
Node::ConnectEdge(transform, NodeInput(block, ClipBlock::kBufferIn));
block->SetNodePositionInContext(transform, QPointF(-1, 0));
} else {
VolumeNode* volume_node = new VolumeNode();
volume_node->setParent(sequence->parent());
static_cast<ClipBlock*>(clip)->set_media_in(
rational::fromDouble(static_cast<OTIO::Item*>(otio_block)->source_range()->start_time().to_seconds()));
clip->set_length_and_media_out(
rational::fromDouble(static_cast<OTIO::Item*>(otio_block)->source_range()->duration().to_seconds()));

Node::ConnectEdge(probed_item, NodeInput(volume_node, VolumeNode::kSamplesInput));
Node::ConnectEdge(volume_node, NodeInput(block, ClipBlock::kBufferIn));
block->SetNodePositionInContext(volume_node, QPointF(-1, 0));
}
}
}
clips_done++;
emit ProgressChanged(clips_done / number_of_clips);
auto otio_clip = static_cast<OTIO::Clip*>(otio_block);

Footage* probed_item = nullptr;

if (otio_clip->media_reference()) {
if (otio_clip->media_reference()->schema_name() == "ExternalReference") {
// Link footage
QString footage_url =
QString::fromStdString(static_cast<OTIO::ExternalReference*>(otio_clip->media_reference())->target_url());

if (imported_footage_.contains(footage_url)) {
probed_item = imported_footage_.value(footage_url);
} else {
probed_item = new Footage(footage_url);
imported_footage_.insert(footage_url, probed_item);
probed_item->setParent(project_);

QFileInfo info(probed_item->filename());
probed_item->SetLabel(info.fileName());

FolderAddChild add(sequence_footage, probed_item);
add.redo_now();
}
}
} else {
probed_item = new Footage();
probed_item->setParent(project_);
}

project_->moveToThread(qApp->thread());
// Add nodes to the graph and set up contexts
clip->setParent(sequence->parent());

return true;
}
// Position clip in its own context
clip->SetNodePositionInContext(clip, QPointF(0, 0));

// Position footage in its context
clip->SetNodePositionInContext(probed_item, QPointF(-2, 0));

if (track->type() == Track::kVideo) {
TransformDistortNode* transform = new TransformDistortNode();
transform->setParent(sequence->parent());

Node::ConnectEdge(probed_item, NodeInput(transform, TransformDistortNode::kTextureInput));
Node::ConnectEdge(transform, NodeInput(clip, ClipBlock::kBufferIn));
clip->SetNodePositionInContext(transform, QPointF(-1, 0));
} else {
VolumeNode* volume_node = new VolumeNode();
volume_node->setParent(sequence->parent());

Node::ConnectEdge(probed_item, NodeInput(volume_node, VolumeNode::kSamplesInput));
Node::ConnectEdge(volume_node, NodeInput(clip, ClipBlock::kBufferIn));
clip->SetNodePositionInContext(volume_node, QPointF(-1, 0));
}

return clip;
}


} //namespace olive

#endif // USE_OTIO
17 changes: 17 additions & 0 deletions app/task/project/loadotio/loadotio.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@
#define OTIODECODER_H

#ifdef USE_OTIO
#include <opentimelineio/composable.h>
#include <opentimelineio/serializableCollection.h>

#include "common/otioutils.h"
#include "node/block/clip/clip.h"
#include "node/block/gap/gap.h"
#include "node/block/transition/crossdissolve/crossdissolvetransition.h"
#include "node/project/project.h"
#include "task/project/load/loadbasetask.h"

Expand All @@ -38,6 +43,18 @@ class LoadOTIOTask : public ProjectLoadBaseTask
protected:
virtual bool Run() override;

private:
ClipBlock* LoadClip(OTIO::Composable* otio_block, Track* track, Sequence* sequence, Folder* sequence_footage);

GapBlock* LoadGap(OTIO::Composable* otio_block, Track* track, Sequence* sequence);

CrossDissolveTransition* LoadTransition(OTIO::Composable* otio_block, Track* track, Sequence* sequence);

Block* previous_block_;
bool prev_block_transition_;
bool transition_flag_;

QMap<QString, Footage*> imported_footage_;
};

}
Expand Down