node: split off traversing functions from renderer for usage elsewhere

Fixes issue where Viewer node wouldn't pick up correct length if a tracks
weren't in use.
This commit is contained in:
itsmattkc
2020-03-13 15:31:15 +11:00
parent 41da5dbd53
commit 9e4c79699e
18 changed files with 218 additions and 142 deletions
+2
View File
@@ -46,6 +46,8 @@ set(OLIVE_SOURCES
node/output.cpp
node/param.h
node/param.cpp
node/traverser.h
node/traverser.cpp
node/value.h
node/value.cpp
PARENT_SCOPE
-5
View File
@@ -28,8 +28,3 @@ QString AudioInput::Description() const
{
return tr("Import an audio footage stream.");
}
NodeValueTable AudioInput::Value(const NodeValueDatabase &value) const
{
return value[footage_input_];
}
-3
View File
@@ -15,9 +15,6 @@ public:
virtual QString Category() const override;
virtual QString Description() const override;
protected:
virtual NodeValueTable Value(const NodeValueDatabase& value) const override;
private:
};
+14 -17
View File
@@ -20,6 +20,8 @@
#include "viewer.h"
#include "node/traverser.h"
ViewerOutput::ViewerOutput()
{
texture_input_ = new NodeInput("tex_in", NodeInput::kTexture);
@@ -28,9 +30,6 @@ ViewerOutput::ViewerOutput()
samples_input_ = new NodeInput("samples_in", NodeInput::kSamples);
AddInput(samples_input_);
length_input_ = new NodeInput("length_in", NodeInput::kRational);
AddInput(length_input_);
// Create TrackList instances
track_inputs_.resize(Timeline::kTrackTypeCount);
track_lists_.resize(Timeline::kTrackTypeCount);
@@ -91,11 +90,6 @@ NodeInput *ViewerOutput::samples_input() const
return samples_input_;
}
NodeInput *ViewerOutput::length_input() const
{
return length_input_;
}
void ViewerOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
{
Node::InvalidateCache(start_range, end_range, from);
@@ -104,8 +98,6 @@ void ViewerOutput::InvalidateCache(const rational &start_range, const rational &
emit VideoChangedBetween(TimeRange(start_range, end_range));
} else if (from == samples_input()) {
emit AudioChangedBetween(TimeRange(start_range, end_range));
} else if (from == length_input()) {
emit LengthChanged(Length());
}
SendInvalidateCache(start_range, end_range);
@@ -146,18 +138,23 @@ void ViewerOutput::set_audio_params(const AudioParams &audio)
rational ViewerOutput::Length()
{
if (!length_input_->IsConnected()) {
return timeline_length_;
NodeTraverser traverser;
rational video_length;
if (texture_input_->IsConnected()) {
NodeValueTable t = traverser.ProcessNode(NodeDependency(texture_input_->get_connected_node(), 0, 0));
video_length = t.Get(NodeParam::kNumber, "length").value<rational>();
}
Node* connected_node = length_input_->get_connected_node();
rational audio_length;
if (connected_node) {
// This is kind of messy?
return connected_node->Value(NodeValueDatabase()).Get(NodeParam::kNumber, "length").value<rational>();
if (samples_input_->IsConnected()) {
NodeValueTable t = traverser.ProcessNode(NodeDependency(samples_input_->get_connected_node(), 0, 0));
audio_length = t.Get(NodeParam::kNumber, "length").value<rational>();
}
return 0;
return qMax(video_length, qMax(audio_length, timeline_length_));
}
const QUuid &ViewerOutput::uuid() const
-3
View File
@@ -52,7 +52,6 @@ public:
NodeInput* texture_input() const;
NodeInput* samples_input() const;
NodeInput* length_input() const;
virtual void InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from = nullptr) override;
virtual void InvalidateVisible(NodeInput *from) override;
@@ -117,8 +116,6 @@ private:
NodeInput* samples_input_;
NodeInput* length_input_;
VideoParams video_params_;
AudioParams audio_params_;
+76
View File
@@ -0,0 +1,76 @@
#include "traverser.h"
#include "node.h"
NodeTraverser::NodeTraverser()
{
}
NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range)
{
NodeValueDatabase database;
// We need to insert tables into the database for each input
foreach (NodeParam* param, node->parameters()) {
if (IsCancelled()) {
return NodeValueDatabase();
}
if (param->type() == NodeParam::kInput) {
NodeInput* input = static_cast<NodeInput*>(param);
TimeRange input_time = node->InputTimeAdjustment(input, range);
NodeValueTable table = ProcessInput(input, input_time);
InputProcessingEvent(input, input_time, &table);
database.Insert(input, table);
}
}
return database;
}
NodeValueTable NodeTraverser::ProcessNode(const NodeDependency& dep)
{
const Node* node = dep.node();
if (node->IsTrack()) {
// If the range is not wholly contained in this Block, we'll need to do some extra processing
return RenderBlock(static_cast<const TrackOutput*>(node), dep.range());
}
// FIXME: Cache certain values here if we've already processed them before
// Generate database of input values of node
NodeValueDatabase database = GenerateDatabase(node, dep.range());
// By this point, the node should have all the inputs it needs to render correctly
NodeValueTable table = node->Value(database);
ProcessNodeEvent(node, dep.range(), database, &table);
return table;
}
NodeValueTable NodeTraverser::RenderBlock(const TrackOutput *track, const TimeRange &range)
{
// By default, don't bother traversing blocks
return NodeValueTable();
}
NodeValueTable NodeTraverser::ProcessInput(const NodeInput *input, const TimeRange& range)
{
if (input->IsConnected()) {
// Value will equal something from the connected node, follow it
return ProcessNode(NodeDependency(input->get_connected_node(), range));
} else {
// Push onto the table the value at this time from the input
QVariant input_value = input->get_value_at_time(range.in());
NodeValueTable table;
table.Push(input->data_type(), input_value);
return table;
}
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef NODETRAVERSER_H
#define NODETRAVERSER_H
#include "codec/decoder.h"
#include "common/cancelableobject.h"
#include "dependency.h"
#include "node/output/track/track.h"
#include "project/item/footage/stream.h"
#include "value.h"
class NodeTraverser : public CancelableObject
{
public:
NodeTraverser();
NodeValueTable ProcessNode(const NodeDependency &dep);
protected:
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range);
virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range);
NodeValueTable ProcessInput(const NodeInput* input, const TimeRange &range);
virtual void InputProcessingEvent(NodeInput*, const TimeRange&, NodeValueTable*){}
virtual void ProcessNodeEvent(const Node*, const TimeRange&, const NodeValueDatabase&, NodeValueTable*){}
};
#endif // NODETRAVERSER_H
+2 -6
View File
@@ -58,13 +58,9 @@ NodeValueTable::NodeValueTable()
QVariant NodeValueTable::Get(const NodeParam::DataType &type, const QString &tag) const
{
int value_index = GetInternal(type, tag);
NodeValue v = GetWithMeta(type, tag);
if (value_index >= 0) {
return values_.at(value_index).data();
}
return QVariant();
return v.data();
}
NodeValue NodeValueTable::GetWithMeta(const NodeParam::DataType &type, const QString &tag) const