From 42ba84bf5f069f053c4c5dd167133c55a4e73e87 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 3 Oct 2022 17:24:09 -0700 Subject: [PATCH] multicam: finished UI implementation --- app/node/input/multicam/multicamnode.cpp | 64 +++++- app/node/input/multicam/multicamnode.h | 27 ++- app/node/node.cpp | 20 ++ app/node/node.h | 198 +++++++++++-------- app/node/traverser.cpp | 8 +- app/render/previewautocacher.cpp | 45 +++-- app/render/previewautocacher.h | 2 + app/render/renderprocessor.cpp | 8 +- app/widget/multicam/multicamwidget.cpp | 18 +- app/widget/multicam/multicamwidget.h | 3 + app/widget/timelinewidget/timelinewidget.cpp | 88 ++++++--- app/widget/timelinewidget/timelinewidget.h | 1 - app/widget/viewer/viewer.cpp | 19 +- app/widget/viewer/viewer.h | 6 +- 14 files changed, 354 insertions(+), 153 deletions(-) diff --git a/app/node/input/multicam/multicamnode.cpp b/app/node/input/multicam/multicamnode.cpp index 8bdb5a5dd..9dd96e6a4 100644 --- a/app/node/input/multicam/multicamnode.cpp +++ b/app/node/input/multicam/multicamnode.cpp @@ -1,11 +1,15 @@ #include "multicamnode.h" +#include "node/project/sequence/sequence.h" + namespace olive { #define super Node const QString MultiCamNode::kCurrentInput = QStringLiteral("current_in"); const QString MultiCamNode::kSourcesInput = QStringLiteral("sources_in"); +const QString MultiCamNode::kSequenceInput = QStringLiteral("sequence_in"); +const QString MultiCamNode::kSequenceTypeInput = QStringLiteral("sequence_type_in"); MultiCamNode::MultiCamNode() { @@ -17,6 +21,11 @@ MultiCamNode::MultiCamNode() AddInput(kSourcesInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray)); SetInputProperty(kSourcesInput, QStringLiteral("arraystart"), 1); + + AddInput(kSequenceInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable)); + AddInput(kSequenceTypeInput, NodeValue::kCombo, InputFlags(kInputFlagStatic | kInputFlagHidden)); + + sequence_ = nullptr; } QString MultiCamNode::Name() const @@ -43,7 +52,7 @@ Node::ActiveElements MultiCamNode::GetActiveElementsAtTime(const QString &input, { if (input == kSourcesInput) { int src = GetCurrentSource(); - if (src >= 0 && src < InputArraySize(kSourcesInput)) { + if (src >= 0 && src < GetSourceCount()) { Node::ActiveElements a; a.add(src); return a; @@ -71,12 +80,65 @@ void MultiCamNode::IndexToRowCols(int index, int total_rows, int total_cols, int *row = index/total_cols; } +Node *MultiCamNode::GetConnectedRenderOutput(const QString &input, int element) const +{ + if (sequence_ && input == kSourcesInput && element >= 0 && element < GetSourceCount()) { + return GetTrackList()->GetTrackAt(element); + } else { + return Node::GetConnectedRenderOutput(input, element); + } +} + +bool MultiCamNode::IsInputConnectedForRender(const QString &input, int element) const +{ + if (sequence_ && input == kSourcesInput && element >= 0 && element < GetSourceCount()) { + return true; + } else { + return Node::IsInputConnectedForRender(input, element); + } +} + +void MultiCamNode::InputConnectedEvent(const QString &input, int element, Node *output) +{ + if (input == kSequenceInput) { + if (Sequence *s = dynamic_cast(output)) { + SetInputFlags(kSequenceTypeInput, GetInputFlags(kSequenceTypeInput) & InputFlag(~kInputFlagHidden)); + sequence_ = s; + } + } +} + +void MultiCamNode::InputDisconnectedEvent(const QString &input, int element, Node *output) +{ + if (input == kSequenceInput) { + SetInputFlags(kSequenceTypeInput, GetInputFlags(kSequenceTypeInput) | kInputFlagHidden); + sequence_ = nullptr; + } +} + +TrackList *MultiCamNode::GetTrackList() const +{ + return sequence_->track_list(static_cast(GetStandardValue(kSequenceTypeInput).toInt())); +} + void MultiCamNode::Retranslate() { super::Retranslate(); SetInputName(kCurrentInput, tr("Current")); SetInputName(kSourcesInput, tr("Sources")); + SetInputName(kSequenceInput, tr("Sequence")); + SetInputName(kSequenceTypeInput, tr("Sequence Type")); + SetComboBoxStrings(kSequenceTypeInput, {tr("Video"), tr("Audio")}); +} + +int MultiCamNode::GetSourceCount() const +{ + if (sequence_) { + return GetTrackList()->GetTrackCount(); + } else { + return InputArraySize(kSourcesInput); + } } void MultiCamNode::GetRowsAndColumns(int sources, int *rows_in, int *cols_in) diff --git a/app/node/input/multicam/multicamnode.h b/app/node/input/multicam/multicamnode.h index 56a9ed858..cec77a88a 100644 --- a/app/node/input/multicam/multicamnode.h +++ b/app/node/input/multicam/multicamnode.h @@ -2,9 +2,12 @@ #define MULTICAMNODE_H #include "node/node.h" +#include "node/output/track/tracklist.h" namespace olive { +class Sequence; + class MultiCamNode : public Node { Q_OBJECT @@ -26,16 +29,15 @@ public: static const QString kCurrentInput; static const QString kSourcesInput; + static const QString kSequenceInput; + static const QString kSequenceTypeInput; int GetCurrentSource() const { return GetStandardValue(kCurrentInput).toInt(); } - int GetSourceCount() const - { - return InputArraySize(kSourcesInput); - } + int GetSourceCount() const; static void GetRowsAndColumns(int sources, int *rows, int *cols); void GetRowsAndColumns(int *rows, int *cols) const @@ -43,6 +45,11 @@ public: return GetRowsAndColumns(GetSourceCount(), rows, cols); } + void SetSequenceType(Track::Type t) + { + SetStandardValue(kSequenceTypeInput, t); + } + static void IndexToRowCols(int index, int total_rows, int total_cols, int *row, int *col); static int RowsColsToIndex(int row, int col, int total_rows, int total_cols) @@ -50,6 +57,18 @@ public: return col + row * total_cols; } + virtual Node *GetConnectedRenderOutput(const QString& input, int element = -1) const override; + virtual bool IsInputConnectedForRender(const QString& input, int element = -1) const override; + +protected: + virtual void InputConnectedEvent(const QString &input, int element, Node *output) override; + virtual void InputDisconnectedEvent(const QString &input, int element, Node *output) override; + +private: + TrackList *GetTrackList() const; + + Sequence *sequence_; + }; } diff --git a/app/node/node.cpp b/app/node/node.cpp index c677b130f..1d8cb3f4c 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1287,6 +1287,26 @@ int Node::GetInternalInputArraySize(const QString &input) return array_immediates_.value(input).size(); } +void FindWaysNodeArrivesHereRecursively(const Node *output, const Node *input, QVector &v) +{ + for (auto it=input->input_connections().cbegin(); it!=input->input_connections().cend(); it++) { + if (it->second == output) { + v.append(it->first); + } else { + FindWaysNodeArrivesHereRecursively(output, it->second, v); + } + } +} + +QVector Node::FindWaysNodeArrivesHere(const Node *output) const +{ + QVector v; + + FindWaysNodeArrivesHereRecursively(output, this, v); + + return v; +} + void Node::SetInputName(const QString &id, const QString &name) { Input* i = GetInternalInputData(id); diff --git a/app/node/node.h b/app/node/node.h index 3ac69a6f9..e6ffa724c 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -418,6 +418,15 @@ public: return IsInputConnected(input.input(), input.element()); } + virtual bool IsInputConnectedForRender(const QString& input, int element = -1) const + { + return IsInputConnected(input, element); + } + bool IsInputConnectedForRender(const NodeInput& input) const + { + return IsInputConnectedForRender(input.input(), input.element()); + } + bool IsInputStatic(const QString& input, int element = -1) const { return !IsInputConnected(input, element) && !IsInputKeyframing(input, element); @@ -435,6 +444,16 @@ public: return GetConnectedOutput(input.input(), input.element()); } + virtual Node *GetConnectedRenderOutput(const QString& input, int element = -1) const + { + return GetConnectedOutput(input, element); + } + + Node *GetConnectedRenderOutput(const NodeInput& input) const + { + return GetConnectedRenderOutput(input.input(), input.element()); + } + bool IsUsingStandardValue(const QString& input, int track, int element = -1) const; NodeValue::Type GetInputDataType(const QString& id) const; @@ -796,6 +815,15 @@ public: */ bool InputsFrom(const QString& id, bool recursively) const; + + /** + * @brief Find inputs that `output` outputs to in order to arrive at this node + * + * Traverse this node's inputs recursively looking for `output`, and return a list of + * edges that `output` uses to get to `this` node. + */ + QVector FindWaysNodeArrivesHere(const Node *output) const; + /** * @brief Determines how many paths go from this node out to another node */ @@ -967,6 +995,90 @@ public: folder_ = folder; } + class ArrayInsertCommand : public UndoCommand + { + public: + ArrayInsertCommand(Node* node, const QString& input, int index) : + node_(node), + input_(input), + index_(index) + { + } + + virtual Project* GetRelevantProject() const override; + + protected: + virtual void redo() override + { + node_->InputArrayInsert(input_, index_, false); + } + + virtual void undo() override + { + node_->InputArrayRemove(input_, index_, false); + } + + private: + Node* node_; + QString input_; + int index_; + + }; + + class ArrayResizeCommand : public UndoCommand + { + public: + ArrayResizeCommand(Node* node, const QString& input, int size) : + node_(node), + input_(input), + size_(size) + {} + + virtual Project* GetRelevantProject() const override; + + protected: + virtual void redo() override + { + old_size_ = node_->InputArraySize(input_); + + if (old_size_ > size_) { + // Decreasing in size, disconnect any extraneous edges + for (int i=size_; iinput_connections().at(input); + + removed_connections_[input] = output; + + DisconnectEdge(output, input); + } catch (std::out_of_range&) {} + } + } + + node_->ArrayResizeInternal(input_, size_); + } + + virtual void undo() override + { + for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) { + ConnectEdge(it->second, it->first); + } + removed_connections_.clear(); + + node_->ArrayResizeInternal(input_, old_size_); + } + + private: + Node* node_; + QString input_; + int size_; + int old_size_; + + InputConnections removed_connections_; + + }; + class ArrayRemoveCommand : public UndoCommand { public: @@ -1203,90 +1315,6 @@ signals: void InputFlagsChanged(const QString &input, const InputFlags &flags); private: - class ArrayInsertCommand : public UndoCommand - { - public: - ArrayInsertCommand(Node* node, const QString& input, int index) : - node_(node), - input_(input), - index_(index) - { - } - - virtual Project* GetRelevantProject() const override; - - protected: - virtual void redo() override - { - node_->InputArrayInsert(input_, index_, false); - } - - virtual void undo() override - { - node_->InputArrayRemove(input_, index_, false); - } - - private: - Node* node_; - QString input_; - int index_; - - }; - - class ArrayResizeCommand : public UndoCommand - { - public: - ArrayResizeCommand(Node* node, const QString& input, int size) : - node_(node), - input_(input), - size_(size) - {} - - virtual Project* GetRelevantProject() const override; - - protected: - virtual void redo() override - { - old_size_ = node_->InputArraySize(input_); - - if (old_size_ > size_) { - // Decreasing in size, disconnect any extraneous edges - for (int i=size_; iinput_connections().at(input); - - removed_connections_[input] = output; - - DisconnectEdge(output, input); - } catch (std::out_of_range&) {} - } - } - - node_->ArrayResizeInternal(input_, size_); - } - - virtual void undo() override - { - for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) { - ConnectEdge(it->second, it->first); - } - removed_connections_.clear(); - - node_->ArrayResizeInternal(input_, old_size_); - } - - private: - Node* node_; - QString input_; - int size_; - int old_size_; - - InputConnections removed_connections_; - - }; - struct Input { NodeValue::Type type; InputFlags flags; @@ -1540,7 +1568,7 @@ void Node::FindOutputNodeInternal(const Node* n, QVector& list) list.append(cast_test); } - FindOutputNodeInternal(connected); + FindOutputNodeInternal(connected, list); } } diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index bb95a6463..355932af1 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -187,12 +187,12 @@ NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &vparams, const Aud NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range) { // If input is connected, retrieve value directly - if (node->IsInputConnected(input)) { + if (node->IsInputConnectedForRender(input)) { TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range); // Value will equal something from the connected node, follow it - Node *output = node->GetConnectedOutput(input); + Node *output = node->GetConnectedRenderOutput(input); NodeValueTable table = GenerateTable(output, adjusted_range, node); return table; @@ -242,8 +242,8 @@ void NodeTraverser::ProcessInputElement(NodeValueTableArray &array_tbl, const No NodeValueTable& sub_tbl = array_tbl[element]; TimeRange adjusted_range = node->InputTimeAdjustment(input, element, range); - if (node->IsInputConnected(input, element)) { - Node *output = node->GetConnectedOutput(input, element); + if (node->IsInputConnectedForRender(input, element)) { + Node *output = node->GetConnectedRenderOutput(input, element); sub_tbl = GenerateTable(output, adjusted_range, node); } else { QVariant input_value = node->GetValueAtTime(input, adjusted_range.in(), element); diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index 59ff3d3c9..08624be67 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -41,6 +41,7 @@ PreviewAutoCacher::PreviewAutoCacher(QObject *parent) : viewer_node_(nullptr), use_custom_range_(false), pause_renders_(false), + pause_thumbnails_(false), single_frame_render_(nullptr), display_color_processor_(nullptr), multicam_(nullptr), @@ -583,6 +584,14 @@ void PreviewAutoCacher::SetRendersPaused(bool e) } } +void PreviewAutoCacher::SetThumbnailsPaused(bool e) +{ + pause_thumbnails_ = e; + if (!e) { + TryRender(); + } +} + void PreviewAutoCacher::NodeAdded(Node *node) { graph_update_queue_.push_back({QueuedJob::kNodeAdded, node, NodeInput(), nullptr}); @@ -663,29 +672,31 @@ void PreviewAutoCacher::TryRender() const int max_tasks = 4; // Handle video tasks - while (!pending_video_jobs_.empty()) { - VideoJob &d = pending_video_jobs_.front(); + if (!pause_thumbnails_) { + while (!pending_video_jobs_.empty()) { + VideoJob &d = pending_video_jobs_.front(); - if (Node *copy = copy_map_.value(d.node)) { - // Queue next frames - rational t; - while (running_video_tasks_.size() < max_tasks && d.iterator.GetNext(&t)) { - RenderFrame(copy, t, d.cache, false); + if (Node *copy = copy_map_.value(d.node)) { + // Queue next frames + rational t; + while (running_video_tasks_.size() < max_tasks && d.iterator.GetNext(&t)) { + RenderFrame(copy, t, d.cache, false); - emit SignalCacheProxyTaskProgress(double(d.iterator.frame_index()) / double(d.iterator.size())); + emit SignalCacheProxyTaskProgress(double(d.iterator.frame_index()) / double(d.iterator.size())); - if (!d.iterator.HasNext()) { - emit StopCacheProxyTasks(); + if (!d.iterator.HasNext()) { + emit StopCacheProxyTasks(); + } } + } else { + qCritical() << "Failed to find node copy for video job"; } - } else { - qCritical() << "Failed to find node copy for video job"; - } - if (d.iterator.HasNext()) { - break; - } else { - pending_video_jobs_.pop_front(); + if (d.iterator.HasNext()) { + break; + } else { + pending_video_jobs_.pop_front(); + } } } diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index 28c16deb7..21efb9912 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -89,6 +89,7 @@ public: bool IsRenderingCustomRange() const; void SetRendersPaused(bool e); + void SetThumbnailsPaused(bool e); void SetMulticamNode(MultiCamNode *n) { multicam_ = n; } @@ -178,6 +179,7 @@ private: TimeRange custom_autocache_range_; bool pause_renders_; + bool pause_thumbnails_; RenderTicketPtr single_frame_render_; QMap > video_immediate_passthroughs_; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 2b42f9e67..d723d54e7 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -300,13 +300,11 @@ NodeValueDatabase RenderProcessor::GenerateDatabase(const Node *node, const Time if (const MultiCamNode *multicam = dynamic_cast(node)) { if (Node::ValueToPtr(ticket_->property("multicam")) == multicam) { - int sz = multicam->InputArraySize(multicam->kSourcesInput); - NodeValueTableArray arr; + int sz = multicam->GetSourceCount(); QVector multicam_tex(sz); for (int i=0; ikSourcesInput, i, range); - - NodeValue val = GenerateRowValueElement(multicam, multicam->kSourcesInput, i, &arr.at(i), range); + NodeValueTable t = GenerateTable(multicam->GetConnectedRenderOutput(multicam->kSourcesInput, i), range, multicam); + NodeValue val = GenerateRowValueElement(multicam, multicam->kSourcesInput, i, &t, range); ResolveJobs(val); multicam_tex[i] = val.toTexture(); diff --git a/app/widget/multicam/multicamwidget.cpp b/app/widget/multicam/multicamwidget.cpp index 6afbd9ac8..5156fd4ed 100644 --- a/app/widget/multicam/multicamwidget.cpp +++ b/app/widget/multicam/multicamwidget.cpp @@ -58,10 +58,18 @@ MulticamWidget::MulticamWidget(QWidget *parent) : void MulticamWidget::SetMulticamNodeInternal(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip) { - ConnectViewerNode(viewer); - node_ = n; - display_->SetMulticamNode(n); - clip_ = clip; + if (GetConnectedNode() != viewer) { + ConnectViewerNode(viewer); + } + + if (node_ != n) { + node_ = n; + display_->SetMulticamNode(n); + } + + if (clip_ != clip) { + clip_ = clip; + } } void MulticamWidget::SetMulticamNode(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip, const rational &time) @@ -145,6 +153,8 @@ void MulticamWidget::Switch(int source, bool split_clip) Core::instance()->undo_stack()->push(command); display_->update(); + + emit Switched(); } void MulticamWidget::DisplayClicked(const QPoint &p) diff --git a/app/widget/multicam/multicamwidget.h b/app/widget/multicam/multicamwidget.h index 8691c5668..a6e5f311a 100644 --- a/app/widget/multicam/multicamwidget.h +++ b/app/widget/multicam/multicamwidget.h @@ -42,6 +42,9 @@ protected: virtual void DisconnectNodeEvent(ViewerOutput *n) override; virtual void TimeChangedEvent(const rational &t) override; +signals: + void Switched(); + private: void SetMulticamNodeInternal(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip); diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 9941d061a..b68881868 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1235,30 +1235,23 @@ void TimelineWidget::ShowContextMenu() reveal_in_project->setData(reinterpret_cast(clip->connected_viewer())); connect(reveal_in_project, &QAction::triggered, this, &TimelineWidget::RevealInProject); - /*if (Sequence *sequence = dynamic_cast(clip->connected_viewer())) { - Menu *multicam_menu = new Menu(tr("Multi-Cam"), &menu); - menu.addMenu(multicam_menu); - - QAction *multicam_enabled = multicam_menu->addAction(tr("Enabled")); + if (Sequence *sequence = dynamic_cast(clip->connected_viewer())) { + QAction *multicam_enabled = menu.addAction(tr("Multi-Cam")); multicam_enabled->setCheckable(true); - auto mcn = sequence->FindOutputNode(); - multicam_enabled->setChecked(!mcn.empty()); + MultiCamNode *mcn = nullptr; + auto paths = clip->FindWaysNodeArrivesHere(sequence); - multicam_menu->addSeparator(); - - QAction *multicam_update = multicam_menu->addAction(tr("Update")); - multicam_update->setEnabled(!mcn.empty()); - - if (!mcn.empty()) { - auto n = mcn.first(); - multicam_enabled->setProperty("multicam", Node::PtrToValue(n)); - multicam_update->setProperty("multicam", Node::PtrToValue(n)); + for (const NodeInput &i : paths) { + if ((mcn = dynamic_cast(i.node()))) { + break; + } } + multicam_enabled->setChecked(mcn); + connect(multicam_enabled, &QAction::triggered, this, &TimelineWidget::MulticamEnabledTriggered); - connect(multicam_update, &QAction::triggered, this, &TimelineWidget::MulticamUpdateTriggered); - }*/ + } } } @@ -1492,16 +1485,57 @@ void TimelineWidget::CacheDiscard() void TimelineWidget::MulticamEnabledTriggered(bool e) { - if (e) { - // Add multicam node - } else if (MultiCamNode *m = Node::ValueToPtr(sender()->property("multicam"))) { - // Remove multicam node - } -} + MultiUndoCommand *command = new MultiUndoCommand(); -void TimelineWidget::MulticamUpdateTriggered() -{ - // Update multicam node + for (Block *b : qAsConst(selected_blocks_)) { + if (ClipBlock *c = dynamic_cast(b)) { + if (Sequence *s = dynamic_cast(c->connected_viewer())) { + if (e) { + + // Adding multicams + // Create multicam node and add it to the graph + MultiCamNode *n = new MultiCamNode(); + n->SetSequenceType(c->GetTrackType()); + command->add_child(new NodeAddCommand(s->parent(), n)); + + + // For each output the sequence has to this clip, disconnect it and + // connect to the multicam instead + QVector inputs = c->FindWaysNodeArrivesHere(s); + for (const NodeInput &i : inputs) { + command->add_child(new NodeEdgeRemoveCommand(s, i)); + command->add_child(new NodeEdgeAddCommand(n, i)); + } + + command->add_child(new NodeEdgeAddCommand(s, NodeInput(n, n->kSequenceInput))); + + // Move sequence node one unit back, and place multicam in sequence's spot + QPointF sequence_pos = c->GetNodePositionInContext(s); + command->add_child(new NodeSetPositionCommand(s, c, sequence_pos - QPointF(1, 0))); + command->add_child(new NodeSetPositionCommand(n, c, sequence_pos)); + + } else { + + // Removing multicams + // Locate first multicam that specifically ends up at this clip + QVector inputs = c->FindWaysNodeArrivesHere(s); + for (const NodeInput &i : inputs) { + if (MultiCamNode *mcn = dynamic_cast(i.node())) { + for (auto it=mcn->output_connections().cbegin(); it!=mcn->output_connections().cend(); it++) { + command->add_child(new NodeEdgeRemoveCommand(it->first, it->second)); + command->add_child(new NodeEdgeAddCommand(s, it->second)); + } + + command->add_child(new NodeRemoveAndDisconnectCommand(mcn)); + } + } + + } + } + } + } + + Core::instance()->undo_stack()->pushIfHasChildren(command); } void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost) diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 998e56869..5161f6d55 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -447,7 +447,6 @@ private slots: void CacheDiscard(); void MulticamEnabledTriggered(bool e); - void MulticamUpdateTriggered(); }; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 1ec330c19..32c1f9ebe 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -427,7 +427,15 @@ void ViewerWidget::StartCapture(TimelineWidget *source, const TimeRange &time, c void ViewerWidget::ConnectMulticamWidget(MulticamWidget *p) { + if (multicam_panel_) { + disconnect(multicam_panel_, &MulticamWidget::Switched, this, &ViewerWidget::DetectMulticamNodeNow); + } + multicam_panel_ = p; + + if (multicam_panel_) { + connect(multicam_panel_, &MulticamWidget::Switched, this, &ViewerWidget::DetectMulticamNodeNow); + } } FramePtr ViewerWidget::DecodeCachedImage(const QString &cache_path, const QUuid &cache_id, const int64_t& time) @@ -607,6 +615,11 @@ void ViewerWidget::SaveFrameAsImage() Core::instance()->OpenExportDialogForViewer(GetConnectedNode(), GetTime(), true); } +void ViewerWidget::DetectMulticamNodeNow() +{ + DetectMulticamNode(GetTime()); +} + void ViewerWidget::CloseAudioProcessor() { audio_processor_.Close(); @@ -903,7 +916,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) if (viewer != this) { viewer->PauseInternal(); } - viewer->auto_cacher_->SetRendersPaused(true); + viewer->auto_cacher_->SetThumbnailsPaused(true); } RenderManager::instance()->SetAggressiveGarbageCollection(true); @@ -1005,7 +1018,7 @@ void ViewerWidget::PauseInternal() UpdateAudioProcessor(); foreach (ViewerWidget* viewer, instances_) { - viewer->auto_cacher_->SetRendersPaused(false); + viewer->auto_cacher_->SetThumbnailsPaused(false); } UpdateTextureFromNode(); @@ -1796,7 +1809,7 @@ void ViewerWidget::SetZoomFromMenu(QAction *action) void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range) { // If our current frame is within this range, we need to update - if (GetTime() >= range.in() && (GetTime() < range.out() || range.in() == range.out())) { + if (!IsPlaying() && GetTime() >= range.in() && (GetTime() < range.out() || range.in() == range.out())) { QMetaObject::invokeMethod(this, &ViewerWidget::UpdateTextureFromNode, Qt::QueuedConnection); } } diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index c465aabc9..e4f0d7289 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -117,7 +117,7 @@ public: if (!IsPlaying()) { // If is playing, this will happen by the next frame automatically - DetectMulticamNode(GetTime()); + DetectMulticamNodeNow(); UpdateTextureFromNode(); } } @@ -128,7 +128,7 @@ public: if (!IsPlaying()) { // If is playing, this will happen by the next frame automatically - DetectMulticamNode(GetTime()); + DetectMulticamNodeNow(); UpdateTextureFromNode(); } } @@ -421,6 +421,8 @@ private slots: void SaveFrameAsImage(); + void DetectMulticamNodeNow(); + }; }