diff --git a/app/core.cpp b/app/core.cpp index 15e2a32f1..16cab3c1e 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -240,19 +240,6 @@ void Core::CreateNewFolder() active_project_panel->Edit(new_folder.get()); } -// FIXME: Test code -#include "node/blend/alphaover/alphaover.h" -#include "node/color/opacity/opacity.h" -#include "node/output/timeline/timeline.h" -#include "node/output/track/track.h" -#include "node/output/viewer/viewer.h" -#include "node/processor/renderer/renderer.h" -#include "panel/panelmanager.h" -#include "panel/node/node.h" -#include "panel/timeline/timeline.h" -#include "panel/viewer/viewer.h" -// End test code - void Core::CreateNewSequence() { // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) @@ -295,49 +282,11 @@ void Core::CreateNewSequence() folder, new_sequence); - TimelineOutput* tb = new TimelineOutput(); - tb->SetTimebase(new_sequence->video_time_base()); - new_sequence->AddNode(tb); - - RendererProcessor* rp = new RendererProcessor(); - - // Set renderer's parameters based on sequence's parameters - rp->SetParameters(new_sequence->video_width(), - new_sequence->video_height(), - olive::PIX_FMT_RGBA16F, // FIXME: Make this configurable - olive::RenderMode::kOffline, - 2); - - // Set the "cache name" only here to aid the cache ID's uniqueness - rp->SetCacheName(new_sequence->name()); - rp->SetTimebase(new_sequence->video_time_base()); - - new_sequence->AddNode(rp); - - ViewerOutput* vo = new ViewerOutput(); - vo->SetTimebase(new_sequence->video_time_base()); - new_sequence->AddNode(vo); - - TrackOutput* to = new TrackOutput(); - new_sequence->AddNode(to); - - // Connect track to renderer - NodeParam::ConnectEdge(to->texture_output(), rp->texture_input()); - - // Connect renderer to viewer - NodeParam::ConnectEdge(rp->texture_output(), vo->texture_input()); - - // Connect track to timeline - NodeParam::ConnectEdge(to->track_output(), tb->track_input()); - - // Connect timeline end point to renderer - NodeParam::ConnectEdge(tb->length_output(), rp->length_input()); - - olive::panel_manager->MostRecentlyFocused()->ConnectViewerNode(vo); - olive::panel_manager->MostRecentlyFocused()->ConnectTimelineNode(tb); - olive::panel_manager->MostRecentlyFocused()->SetGraph(new_sequence.get()); + new_sequence->AddDefaultNodes(); olive::undo_stack.push(aic); + + Sequence::Open(new_sequence); } } diff --git a/app/node/graph.cpp b/app/node/graph.cpp index 1e71aca58..185bdb0f4 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -59,6 +59,11 @@ void NodeGraph::TakeNode(Node *node, QObject* new_parent) return; } + if (!node->CanBeDeleted()) { + qWarning() << "Tried to delete a Node that's been flagged as not deletable"; + return; + } + node->DisconnectAll(); disconnect(node, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); diff --git a/app/node/node.cpp b/app/node/node.cpp index 28c6b4d96..7645ee169 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -25,7 +25,8 @@ #include "common/qobjectlistcast.h" Node::Node() : - last_processed_time_(-1) + last_processed_time_(-1), + can_be_deleted_(true) { } @@ -132,6 +133,16 @@ void Node::CopyInputs(Node *source, Node *destination) } } +bool Node::CanBeDeleted() +{ + return can_be_deleted_; +} + +void Node::SetCanBeDeleted(bool s) +{ + can_be_deleted_ = s; +} + rational Node::LastProcessedTime() { rational t; diff --git a/app/node/node.h b/app/node/node.h index 5c3faa83f..958b0689b 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -222,6 +222,16 @@ public: */ static void CopyInputs(Node* source, Node* destination); + /** + * @brief Return whether this Node can be deleted or not + */ + bool CanBeDeleted(); + + /** + * @brief Set whether + */ + void SetCanBeDeleted(bool s); + protected: /** * @brief Add a parameter to this node @@ -317,6 +327,11 @@ private: */ QMutex run_lock_; + /** + * @brief Internal variable for whether this Node can be deleted or not + */ + bool can_be_deleted_; + private slots: void InputChanged(rational start, rational end); diff --git a/app/node/processor/renderer/renderer.cpp b/app/node/processor/renderer/renderer.cpp index f8a924ef8..2fce8ae46 100644 --- a/app/node/processor/renderer/renderer.cpp +++ b/app/node/processor/renderer/renderer.cpp @@ -131,6 +131,10 @@ void RendererProcessor::InvalidateCache(const rational &start_range, const ratio { Q_UNUSED(from) + if (timebase_.isNull()) { + return; + } + //ClearCachedValuesInParameters(start_range, end_range); texture_input_->ClearCachedValue(); length_input_->ClearCachedValue(); diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 13f7a86cc..42eccdae2 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -23,12 +23,63 @@ #include #include "common/channellayout.h" +#include "common/timecodefunctions.h" +#include "panel/panelmanager.h" +#include "panel/node/node.h" +#include "panel/timeline/timeline.h" +#include "panel/viewer/viewer.h" #include "ui/icons/icons.h" -Sequence::Sequence() +Sequence::Sequence() : + timeline_output_(nullptr), + renderer_processor_(nullptr), + viewer_output_(nullptr), + track_output_(nullptr) { } +void Sequence::Open(SequencePtr sequence) +{ + olive::panel_manager->MostRecentlyFocused()->ConnectViewerNode(sequence->viewer_output_); + olive::panel_manager->MostRecentlyFocused()->ConnectTimelineNode(sequence->timeline_output_); + olive::panel_manager->MostRecentlyFocused()->SetGraph(sequence.get()); +} + +void Sequence::AddDefaultNodes() +{ + timeline_output_ = new TimelineOutput(); + timeline_output_->SetCanBeDeleted(false); + AddNode(timeline_output_); + + renderer_processor_ = new RendererProcessor(); + renderer_processor_->SetCanBeDeleted(false); + AddNode(renderer_processor_); + + viewer_output_ = new ViewerOutput(); + viewer_output_->SetCanBeDeleted(false); + AddNode(viewer_output_); + + track_output_ = new TrackOutput(); + track_output_->SetCanBeDeleted(false); + AddNode(track_output_); + + // Connect track to renderer + NodeParam::ConnectEdge(track_output_->texture_output(), renderer_processor_->texture_input()); + + // Connect renderer to viewer + NodeParam::ConnectEdge(renderer_processor_->texture_output(), viewer_output_->texture_input()); + + // Connect track to timeline + NodeParam::ConnectEdge(track_output_->track_output(), timeline_output_->track_input()); + + // Connect timeline end point to renderer + NodeParam::ConnectEdge(timeline_output_->length_output(), renderer_processor_->length_input()); + + // Update the timebase on these nodes + set_video_time_base(video_time_base_); + update_parameters(); +} + Item::Type Sequence::type() const { return kSequence; @@ -39,6 +90,19 @@ QIcon Sequence::icon() return olive::icon::Sequence; } +QString Sequence::duration() +{ + if (timeline_output_ == nullptr) { + return QString(); + } + + rational timeline_length = timeline_output_->length_output()->get_value(0).value(); + + int64_t timestamp = olive::time_to_timestamp(timeline_length, video_time_base_); + + return olive::timestamp_to_timecode(timestamp, video_time_base_, olive::CurrentTimecodeDisplay()); +} + QString Sequence::rate() { return QCoreApplication::translate("Sequence", "%1 FPS").arg(video_time_base_.flipped().toDouble()); @@ -52,6 +116,8 @@ const int &Sequence::video_width() void Sequence::set_video_width(const int &width) { video_width_ = width; + + update_parameters(); } const int &Sequence::video_height() const @@ -62,6 +128,8 @@ const int &Sequence::video_height() const void Sequence::set_video_height(const int &height) { video_height_ = height; + + update_parameters(); } const rational &Sequence::video_time_base() @@ -72,6 +140,15 @@ const rational &Sequence::video_time_base() void Sequence::set_video_time_base(const rational &time_base) { video_time_base_ = time_base; + + if (timeline_output_ != nullptr) + timeline_output_->SetTimebase(video_time_base_); + + if (viewer_output_ != nullptr) + viewer_output_->SetTimebase(video_time_base_); + + if (renderer_processor_ != nullptr) + renderer_processor_->SetTimebase(video_time_base_); } const rational &Sequence::audio_time_base() @@ -104,3 +181,18 @@ void Sequence::SetDefaultParameters() set_audio_time_base(rational(1, 48000)); set_audio_channel_layout(AV_CH_LAYOUT_STEREO); } + +void Sequence::update_parameters() +{ + if (renderer_processor_ != nullptr) { + // Set renderer's parameters based on sequence's parameters + renderer_processor_->SetParameters(video_width_, + video_height_, + olive::PIX_FMT_RGBA16F, // FIXME: Make this configurable + olive::RenderMode::kOffline, + 2); + + // Set the "cache name" only here to aid the cache ID's uniqueness + renderer_processor_->SetCacheName(name()); + } +} diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index 16cd44622..173ce8052 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -23,8 +23,14 @@ #include "common/rational.h" #include "node/graph.h" +#include "node/output/timeline/timeline.h" +#include "node/output/viewer/viewer.h" +#include "node/processor/renderer/renderer.h" #include "project/item/item.h" +class Sequence; +using SequencePtr = std::shared_ptr; + /** * @brief The main timeline object, an graph of edited clips that forms a complete edit */ @@ -33,6 +39,10 @@ class Sequence : public Item, public NodeGraph public: Sequence(); + static void Open(SequencePtr sequence); + + void AddDefaultNodes(); + /** * @brief Item::Type() override */ @@ -40,6 +50,7 @@ public: virtual QIcon icon() override; + virtual QString duration() override; virtual QString rate() override; /* VIDEO GETTER/SETTER FUNCTIONS */ @@ -64,6 +75,13 @@ public: void SetDefaultParameters(); private: + void update_parameters(); + + TimelineOutput* timeline_output_; + RendererProcessor* renderer_processor_; + ViewerOutput* viewer_output_; + TrackOutput* track_output_; + int video_width_; int video_height_; rational video_time_base_; @@ -72,6 +90,4 @@ private: uint64_t audio_channel_layout_; }; -using SequencePtr = std::shared_ptr; - #endif // SEQUENCE_H