a first attempt at a new render system
This commit is contained in:
@@ -24,8 +24,6 @@ add_subdirectory(output)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
node/dependency.h
|
||||
node/dependency.cpp
|
||||
node/edge.h
|
||||
node/edge.cpp
|
||||
node/factory.h
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "dependency.h"
|
||||
|
||||
#include "node.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
NodeDependency::NodeDependency() :
|
||||
node_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NodeDependency::NodeDependency(const Node *node, const TimeRange &range) :
|
||||
node_(node),
|
||||
range_(range)
|
||||
{
|
||||
}
|
||||
|
||||
NodeDependency::NodeDependency(const Node *node, const rational &in, const rational &out) :
|
||||
node_(node),
|
||||
range_(in, out)
|
||||
{
|
||||
}
|
||||
|
||||
const Node *NodeDependency::node() const
|
||||
{
|
||||
return node_;
|
||||
}
|
||||
|
||||
const rational& NodeDependency::in() const
|
||||
{
|
||||
return range_.in();
|
||||
}
|
||||
|
||||
const rational &NodeDependency::out() const
|
||||
{
|
||||
return range_.out();
|
||||
}
|
||||
|
||||
const TimeRange &NodeDependency::range() const
|
||||
{
|
||||
return range_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,52 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef NODEDEPENDENCY_H
|
||||
#define NODEDEPENDENCY_H
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
#include "common/timerange.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class Node;
|
||||
|
||||
class NodeDependency {
|
||||
public:
|
||||
NodeDependency();
|
||||
NodeDependency(const Node* node, const TimeRange& range);
|
||||
NodeDependency(const Node* node, const rational& in, const rational &out);
|
||||
|
||||
const Node* node() const;
|
||||
const rational& in() const;
|
||||
const rational& out() const;
|
||||
const TimeRange& range() const;
|
||||
|
||||
private:
|
||||
const Node* node_;
|
||||
TimeRange range_;
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeDependency)
|
||||
|
||||
#endif // NODEDEPENDENCY_H
|
||||
@@ -55,7 +55,7 @@ void TrackOutput::set_track_type(const Timeline::TrackType &track_type)
|
||||
track_type_ = track_type;
|
||||
}
|
||||
|
||||
const Timeline::TrackType& TrackOutput::track_type()
|
||||
const Timeline::TrackType& TrackOutput::track_type() const
|
||||
{
|
||||
return track_type_;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class TrackOutput : public Block
|
||||
public:
|
||||
TrackOutput();
|
||||
|
||||
const Timeline::TrackType& track_type();
|
||||
const Timeline::TrackType& track_type() const;
|
||||
void set_track_type(const Timeline::TrackType& track_type);
|
||||
|
||||
virtual Type type() const override;
|
||||
|
||||
@@ -55,6 +55,8 @@ ViewerOutput::ViewerOutput()
|
||||
|
||||
// Create UUID for this node
|
||||
uuid_ = QUuid::createUuid();
|
||||
|
||||
connect(this, &ViewerOutput::LengthChanged, &video_frame_cache_, &FrameHashCache::SetLength);
|
||||
}
|
||||
|
||||
Node *ViewerOutput::copy() const
|
||||
@@ -82,22 +84,16 @@ QString ViewerOutput::Description() const
|
||||
return tr("Interface between a Viewer panel and the node system.");
|
||||
}
|
||||
|
||||
NodeInput *ViewerOutput::texture_input() const
|
||||
{
|
||||
return texture_input_;
|
||||
}
|
||||
|
||||
NodeInput *ViewerOutput::samples_input() const
|
||||
{
|
||||
return samples_input_;
|
||||
}
|
||||
|
||||
void ViewerOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
|
||||
{
|
||||
if (from == texture_input()) {
|
||||
emit VideoChangedBetween(range, source);
|
||||
emit GraphChangedFrom(from, source);
|
||||
|
||||
video_frame_cache_.Invalidate(range);
|
||||
} else if (from == samples_input()) {
|
||||
emit AudioChangedBetween(range, source);
|
||||
emit GraphChangedFrom(from, source);
|
||||
|
||||
audio_playback_cache_.Invalidate(range);
|
||||
}
|
||||
|
||||
Node::InvalidateCache(range, from, source);
|
||||
@@ -112,16 +108,6 @@ void ViewerOutput::InvalidateVisible(NodeInput* from, NodeInput *source)
|
||||
Node::InvalidateVisible(from, source);
|
||||
}
|
||||
|
||||
const VideoParams &ViewerOutput::video_params() const
|
||||
{
|
||||
return video_params_;
|
||||
}
|
||||
|
||||
const AudioParams &ViewerOutput::audio_params() const
|
||||
{
|
||||
return audio_params_;
|
||||
}
|
||||
|
||||
void ViewerOutput::set_video_params(const VideoParams &video)
|
||||
{
|
||||
video_params_ = video;
|
||||
@@ -134,34 +120,31 @@ void ViewerOutput::set_video_params(const VideoParams &video)
|
||||
void ViewerOutput::set_audio_params(const AudioParams &audio)
|
||||
{
|
||||
audio_params_ = audio;
|
||||
|
||||
emit AudioParamsChanged();
|
||||
}
|
||||
|
||||
rational ViewerOutput::Length()
|
||||
rational ViewerOutput::GetLength()
|
||||
{
|
||||
NodeTraverser traverser;
|
||||
|
||||
rational video_length;
|
||||
|
||||
if (texture_input_->IsConnected()) {
|
||||
NodeValueTable t = traverser.ProcessNode(NodeDependency(texture_input_->get_connected_node(), 0, 0));
|
||||
NodeValueTable t = traverser.GenerateTable(texture_input_->get_connected_node(), 0, 0);
|
||||
video_length = t.Get(NodeParam::kNumber, "length").value<rational>();
|
||||
}
|
||||
|
||||
rational audio_length;
|
||||
|
||||
if (samples_input_->IsConnected()) {
|
||||
NodeValueTable t = traverser.ProcessNode(NodeDependency(samples_input_->get_connected_node(), 0, 0));
|
||||
NodeValueTable t = traverser.GenerateTable(samples_input_->get_connected_node(), 0, 0);
|
||||
audio_length = t.Get(NodeParam::kNumber, "length").value<rational>();
|
||||
}
|
||||
|
||||
return qMax(video_length, qMax(audio_length, timeline_length_));
|
||||
}
|
||||
|
||||
const QUuid &ViewerOutput::uuid() const
|
||||
{
|
||||
return uuid_;
|
||||
}
|
||||
|
||||
void ViewerOutput::UpdateTrackCache()
|
||||
{
|
||||
track_cache_.clear();
|
||||
@@ -231,11 +214,6 @@ void ViewerOutput::Retranslate()
|
||||
}
|
||||
}
|
||||
|
||||
const QString &ViewerOutput::media_name() const
|
||||
{
|
||||
return media_name_;
|
||||
}
|
||||
|
||||
void ViewerOutput::set_media_name(const QString &name)
|
||||
{
|
||||
media_name_ = name;
|
||||
@@ -243,21 +221,6 @@ void ViewerOutput::set_media_name(const QString &name)
|
||||
emit MediaNameChanged(media_name_);
|
||||
}
|
||||
|
||||
const QVector<TrackOutput *>& ViewerOutput::Tracks() const
|
||||
{
|
||||
return track_cache_;
|
||||
}
|
||||
|
||||
NodeInput *ViewerOutput::track_input(Timeline::TrackType type) const
|
||||
{
|
||||
return track_inputs_.at(type);
|
||||
}
|
||||
|
||||
TrackList *ViewerOutput::track_list(Timeline::TrackType type) const
|
||||
{
|
||||
return track_lists_.at(type);
|
||||
}
|
||||
|
||||
void ViewerOutput::TrackListAddedBlock(Block *block, int index)
|
||||
{
|
||||
Timeline::TrackType type = static_cast<TrackList*>(sender())->type();
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "node/output/track/track.h"
|
||||
#include "node/output/track/tracklist.h"
|
||||
#include "node/node.h"
|
||||
#include "render/videoparams.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/audioplaybackcache.h"
|
||||
#include "render/framehashcache.h"
|
||||
#include "render/videoparams.h"
|
||||
#include "timeline/trackreference.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -52,39 +54,66 @@ public:
|
||||
virtual QList<CategoryID> Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
NodeInput* texture_input() const;
|
||||
NodeInput* samples_input() const;
|
||||
NodeInput* texture_input() const {
|
||||
return texture_input_;
|
||||
}
|
||||
|
||||
NodeInput* samples_input() const {
|
||||
return samples_input_;
|
||||
}
|
||||
|
||||
virtual void InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput* source) override;
|
||||
virtual void InvalidateVisible(NodeInput *from, NodeInput* source) override;
|
||||
|
||||
const VideoParams& video_params() const;
|
||||
const AudioParams& audio_params() const;
|
||||
const VideoParams& video_params() const {
|
||||
return video_params_;
|
||||
}
|
||||
|
||||
const AudioParams& audio_params() const {
|
||||
return audio_params_;
|
||||
}
|
||||
|
||||
void set_video_params(const VideoParams& video);
|
||||
void set_audio_params(const AudioParams& audio);
|
||||
|
||||
rational Length();
|
||||
rational GetLength();
|
||||
|
||||
const QUuid& uuid() const;
|
||||
const QUuid& uuid() const {
|
||||
return uuid_;
|
||||
}
|
||||
|
||||
const QVector<TrackOutput *> &Tracks() const;
|
||||
const QVector<TrackOutput *> &GetTracks() const {
|
||||
return track_cache_;
|
||||
}
|
||||
|
||||
NodeInput* track_input(Timeline::TrackType type) const;
|
||||
NodeInput* track_input(Timeline::TrackType type) const {
|
||||
return track_inputs_.at(type);
|
||||
}
|
||||
|
||||
TrackList* track_list(Timeline::TrackType type) const;
|
||||
TrackList* track_list(Timeline::TrackType type) const {
|
||||
return track_lists_.at(type);
|
||||
}
|
||||
|
||||
virtual void Retranslate() override;
|
||||
|
||||
const QString& media_name() const;
|
||||
const QString& media_name() const {
|
||||
return media_name_;
|
||||
}
|
||||
|
||||
void set_media_name(const QString& name);
|
||||
|
||||
FrameHashCache* video_frame_cache() {
|
||||
return &video_frame_cache_;
|
||||
}
|
||||
|
||||
AudioPlaybackCache* audio_playback_cache() {
|
||||
return &audio_playback_cache_;
|
||||
}
|
||||
|
||||
signals:
|
||||
void TimebaseChanged(const rational&);
|
||||
|
||||
void VideoChangedBetween(const TimeRange& range, NodeInput* source);
|
||||
|
||||
void AudioChangedBetween(const TimeRange& range, NodeInput* source);
|
||||
void GraphChangedFrom(NodeInput* from, NodeInput* source);
|
||||
|
||||
void VisibleInvalidated(NodeInput* source);
|
||||
|
||||
@@ -93,6 +122,7 @@ signals:
|
||||
void SizeChanged(int width, int height);
|
||||
|
||||
void VideoParamsChanged();
|
||||
void AudioParamsChanged();
|
||||
|
||||
void BlockAdded(Block* block, TrackReference track);
|
||||
void BlockRemoved(Block* block);
|
||||
@@ -125,6 +155,10 @@ private:
|
||||
|
||||
QString media_name_;
|
||||
|
||||
FrameHashCache video_frame_cache_;
|
||||
|
||||
AudioPlaybackCache audio_playback_cache_;
|
||||
|
||||
private slots:
|
||||
void UpdateTrackCache();
|
||||
|
||||
|
||||
+25
-27
@@ -24,7 +24,7 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range)
|
||||
NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range) const
|
||||
{
|
||||
NodeValueDatabase database;
|
||||
|
||||
@@ -38,7 +38,17 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
|
||||
|
||||
TimeRange input_time = node->InputTimeAdjustment(input, range);
|
||||
|
||||
NodeValueTable table = ProcessInput(input, input_time);
|
||||
NodeValueTable table;
|
||||
|
||||
if (input->IsConnected()) {
|
||||
// Value will equal something from the connected node, follow it
|
||||
table = GenerateTable(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());
|
||||
|
||||
table.Push(input->data_type(), input_value);
|
||||
}
|
||||
|
||||
// Exception for Footage types where we actually retrieve some Footage data from a decoder
|
||||
if (input->data_type() == NodeParam::kFootage) {
|
||||
@@ -63,29 +73,32 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
|
||||
return database;
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::ProcessNode(const NodeDependency& dep)
|
||||
NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& range) const
|
||||
{
|
||||
const Node* node = dep.node();
|
||||
|
||||
if (node->IsTrack()) {
|
||||
if (n->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());
|
||||
return GenerateBlockTable(static_cast<const TrackOutput*>(n), 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());
|
||||
NodeValueDatabase database = GenerateDatabase(n, range);
|
||||
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
NodeValueTable table = node->Value(database);
|
||||
NodeValueTable table = n->Value(database);
|
||||
|
||||
ProcessNodeEvent(node, dep.range(), database, table);
|
||||
ProcessNodeEvent(n, range, database, table);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::RenderBlock(const TrackOutput *track, const TimeRange &range)
|
||||
NodeValueTable NodeTraverser::GenerateTable(const Node *n, const rational &in, const rational &out) const
|
||||
{
|
||||
return GenerateTable(n, TimeRange(in, out));
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::GenerateBlockTable(const TrackOutput *track, const TimeRange &range) const
|
||||
{
|
||||
// By default, just follow the in point
|
||||
Block* active_block = track->BlockAtTime(range.in());
|
||||
@@ -93,7 +106,7 @@ NodeValueTable NodeTraverser::RenderBlock(const TrackOutput *track, const TimeRa
|
||||
NodeValueTable table;
|
||||
|
||||
if (active_block) {
|
||||
table = ProcessNode(NodeDependency(active_block, range));
|
||||
table = GenerateTable(active_block, range);
|
||||
}
|
||||
|
||||
return table;
|
||||
@@ -104,19 +117,4 @@ StreamPtr NodeTraverser::ResolveStreamFromInput(NodeInput *input)
|
||||
return input->get_standard_value().value<StreamPtr>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
+10
-9
@@ -23,7 +23,6 @@
|
||||
|
||||
#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"
|
||||
@@ -35,21 +34,23 @@ class NodeTraverser : public CancelableObject
|
||||
public:
|
||||
NodeTraverser() = default;
|
||||
|
||||
NodeValueTable ProcessNode(const NodeDependency &dep);
|
||||
NodeValueTable GenerateTable(const Node *n, const TimeRange &range) const;
|
||||
NodeValueTable GenerateTable(const Node *n, const rational &in, const rational& out) const;
|
||||
|
||||
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range);
|
||||
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range) const;
|
||||
|
||||
protected:
|
||||
virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range);
|
||||
virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange& range) const;
|
||||
|
||||
NodeValueTable ProcessInput(const NodeInput* input, const TimeRange &range);
|
||||
virtual void FootageProcessingEvent(StreamPtr, const TimeRange&, NodeValueTable*) const {}
|
||||
|
||||
virtual void FootageProcessingEvent(StreamPtr, const TimeRange&, NodeValueTable*){}
|
||||
|
||||
virtual void ProcessNodeEvent(const Node*, const TimeRange&, NodeValueDatabase&, NodeValueTable&){}
|
||||
virtual void ProcessNodeEvent(const Node*,
|
||||
const TimeRange&,
|
||||
NodeValueDatabase&,
|
||||
NodeValueTable&) const {}
|
||||
|
||||
private:
|
||||
StreamPtr ResolveStreamFromInput(NodeInput* input);
|
||||
static StreamPtr ResolveStreamFromInput(NodeInput* input);
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user