From aecfa842c3cfa15678b704a04a865d8a98ba790c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 30 Apr 2020 01:56:08 +1000 Subject: [PATCH] nodes: moved hashing to nodes so they can override behavior if they wish --- app/node/block/block.cpp | 12 +++ app/node/block/block.h | 2 + app/node/block/transition/transition.cpp | 13 +++ app/node/block/transition/transition.h | 2 + app/node/input/time/timeinput.cpp | 8 ++ app/node/input/time/timeinput.h | 2 + app/node/node.cpp | 71 ++++++++++++++ app/node/node.h | 4 + app/node/output/track/track.cpp | 10 ++ app/node/output/track/track.h | 2 + app/render/backend/renderworker.cpp | 2 +- app/render/backend/videorenderworker.cpp | 113 +---------------------- app/render/backend/videorenderworker.h | 2 - 13 files changed, 128 insertions(+), 115 deletions(-) diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index ccb3f0140..06e0237f6 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -234,6 +234,18 @@ void Block::SaveInternal(QXmlStreamWriter *writer) const } } +QList Block::GetInputsToHash() const +{ + QList inputs = Node::GetInputsToHash(); + + // Ignore these inputs + inputs.removeOne(media_in_input_); + inputs.removeOne(speed_input_); + inputs.removeOne(length_input_); + + return inputs; +} + void Block::LengthInputChanged() { emit LengthChanged(length()); diff --git a/app/node/block/block.h b/app/node/block/block.h index 26df9d13a..a36f91754 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -126,6 +126,8 @@ protected: virtual void SaveInternal(QXmlStreamWriter* writer) const override; + virtual QList GetInputsToHash() const override; + Block* previous_; Block* next_; diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 91fe5adb6..cdb0b8489 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -129,6 +129,19 @@ double TransitionBlock::GetInProgress(const rational &time) const return clamp((GetInternalTransitionTime(time) - out_offset().toDouble()) / in_offset().toDouble(), 0.0, 1.0); } +void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const +{ + Block::Hash(hash, time); + + double all_prog = GetTotalProgress(time); + double in_prog = GetInProgress(time); + double out_prog = GetOutProgress(time); + + hash.addData(reinterpret_cast(&all_prog), sizeof(double)); + hash.addData(reinterpret_cast(&in_prog), sizeof(double)); + hash.addData(reinterpret_cast(&out_prog), sizeof(double)); +} + double TransitionBlock::GetInternalTransitionTime(const rational &time) const { return time.toDouble() - in().toDouble(); diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 74346c6a0..62f4280b5 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -47,6 +47,8 @@ public: double GetOutProgress(const rational& time) const; double GetInProgress(const rational& time) const; + virtual void Hash(QCryptographicHash& hash, const rational &time) const override; + private: double GetInternalTransitionTime(const rational& time) const; diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index 60b901b8b..fa15de735 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -62,4 +62,12 @@ NodeValueTable TimeInput::Value(NodeValueDatabase &value) const return table; } +void TimeInput::Hash(QCryptographicHash &hash, const rational &time) const +{ + Node::Hash(hash, time); + + // Make sure time is hashed + hash.addData(NodeParam::ValueToBytes(NodeParam::kRational, QVariant::fromValue(time))); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index 284faba4a..b912ed4b1 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -40,6 +40,8 @@ public: virtual NodeValueTable Value(NodeValueDatabase& value) const override; + virtual void Hash(QCryptographicHash& hash, const rational& time) const override; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/node/node.cpp b/app/node/node.cpp index 5b1111eba..49c48cfdb 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -25,6 +25,9 @@ #include #include "common/xmlutils.h" +#include "project/project.h" +#include "project/item/footage/footage.h" +#include "project/item/footage/imagestream.h" OLIVE_NAMESPACE_ENTER @@ -232,6 +235,11 @@ void Node::SaveInternal(QXmlStreamWriter *) const { } +QList Node::GetInputsToHash() const +{ + return GetInputsIncludingArrays(); +} + QString Node::ReadFileAsString(const QString &filename) { QFile f(filename); @@ -294,6 +302,69 @@ void Node::SetLabel(const QString &s) } } +void Node::Hash(QCryptographicHash &hash, const rational& time) const +{ + // Add this Node's ID + hash.addData(id().toUtf8()); + + QList inputs = GetInputsToHash(); + + foreach (NodeInput* input, inputs) { + // For each input, try to hash its value + + // Get time adjustment + // For a single frame, we only care about one of the times + rational input_time = InputTimeAdjustment(input, TimeRange(time, time)).in(); + + if (input->IsConnected()) { + // Traverse down this edge + input->get_connected_node()->Hash(hash, input_time); + } else { + // Grab the value at this time + QVariant value = input->get_value_at_time(input_time); + hash.addData(NodeParam::ValueToBytes(input->data_type(), value)); + } + + // We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer + if (input->data_type() == NodeParam::kFootage) { + StreamPtr stream = input->get_standard_value().value(); + + if (stream) { + // Add footage details to hash + + // Footage filename + hash.addData(stream->footage()->filename().toUtf8()); + + // Footage last modified date + hash.addData(stream->footage()->timestamp().toString().toUtf8()); + + // Footage stream + hash.addData(QString::number(stream->index()).toUtf8()); + + if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) { + ImageStreamPtr image_stream = std::static_pointer_cast(stream); + + // Current color config and space + hash.addData(image_stream->footage()->project()->color_manager()->GetConfigFilename().toUtf8()); + hash.addData(image_stream->colorspace().toUtf8()); + + // Alpha associated setting + hash.addData(QString::number(image_stream->premultiplied_alpha()).toUtf8()); + } + + // Footage timestamp + if (stream->type() == Stream::kVideo) { + hash.addData(QStringLiteral("%1/%2").arg(QString::number(input_time.numerator()), + QString::number(input_time.denominator())).toUtf8()); + + hash.addData(QString::number(static_cast(stream.get())->start_time()).toUtf8()); + + } + } + } + } +} + void Node::CopyInputs(Node *source, Node *destination, bool include_connections) { Q_ASSERT(source->id() == destination->id()); diff --git a/app/node/node.h b/app/node/node.h index 29d96313f..3b5d09f09 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -362,6 +362,8 @@ public: const QString& GetLabel() const; void SetLabel(const QString& s); + virtual void Hash(QCryptographicHash& hash, const rational &time) const; + protected: void AddInput(NodeInput* input); @@ -373,6 +375,8 @@ protected: virtual void SaveInternal(QXmlStreamWriter* writer) const; + virtual QList GetInputsToHash() const; + public slots: signals: diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 3adc7e6b7..da545cd6e 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -418,6 +418,16 @@ NodeInputArray *TrackOutput::block_input() const return block_input_; } +void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const +{ + // Resolve block list + Block* b = BlockAtTime(time); + + if (b) { + return b->Hash(hash, time); + } +} + void TrackOutput::SetTrackName(const QString &name) { track_name_ = name; diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 89f58903a..0922d54fc 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -152,6 +152,8 @@ public: NodeInputArray* block_input() const; + virtual void Hash(QCryptographicHash& hash, const rational &time) const override; + public slots: void SetTrackName(const QString& name); diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 947cb2f1e..8ba8409f2 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -78,7 +78,7 @@ void RenderWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, StreamPtr RenderWorker::ResolveStreamFromInput(NodeInput *input) { - return input->get_value_at_time(0).value(); + return input->get_standard_value().value(); } DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream) diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp index 5dabdc5cb..e9afae9f3 100644 --- a/app/render/backend/videorenderworker.cpp +++ b/app/render/backend/videorenderworker.cpp @@ -75,7 +75,7 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con hasher.addData(reinterpret_cast(&vfmt), sizeof(PixelFormat::Format)); hasher.addData(reinterpret_cast(&vmode), sizeof(RenderMode::Mode)); - HashNodeRecursively(&hasher, path.node(), path.in()); + path.node()->Hash(hasher, path.in()); hash = hasher.result(); } @@ -121,117 +121,6 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con return value; } -void VideoRenderWorker::HashNodeRecursively(QCryptographicHash *hash, const Node* n, const rational& time) -{ - // Resolve BlockList - if (n->IsTrack()) { - n = static_cast(n)->BlockAtTime(time); - - if (!n) { - return; - } - } - - // Add this Node's ID - hash->addData(n->id().toUtf8()); - - if (n->IsBlock() && static_cast(n)->type() == Block::kTransition) { - const TransitionBlock* transition = static_cast(n); - - double all_prog = transition->GetTotalProgress(time); - double in_prog = transition->GetInProgress(time); - double out_prog = transition->GetOutProgress(time); - - hash->addData(reinterpret_cast(&all_prog), sizeof(double)); - hash->addData(reinterpret_cast(&in_prog), sizeof(double)); - hash->addData(reinterpret_cast(&out_prog), sizeof(double)); - } - - foreach (NodeParam* param, n->parameters()) { - // For each input, try to hash its value - if (param->type() == NodeParam::kInput) { - NodeInput* input = static_cast(param); - - if (n->IsBlock()) { - const Block* b = static_cast(n); - - // Ignore some Block attributes when hashing - if (input == b->media_in_input() - || input == b->speed_input() - || input == b->length_input()) { - continue; - } - } - - // Get time adjustment - // For a single frame, we only care about one of the times - rational input_time = n->InputTimeAdjustment(input, TimeRange(time, time)).in(); - - if (input->IsConnected()) { - // Traverse down this edge - HashNodeRecursively(hash, input->get_connected_node(), input_time); - } else { - // Grab the value at this time - QVariant value = input->get_value_at_time(input_time); - hash->addData(NodeParam::ValueToBytes(input->data_type(), value)); - } - - // We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer - if (input->data_type() == NodeParam::kFootage) { - StreamPtr stream = ResolveStreamFromInput(input); - - if (stream) { - DecoderPtr decoder = ResolveDecoderFromInput(stream); - - if (decoder) { - - // Add footage details to hash - - // Footage filename - hash->addData(stream->footage()->filename().toUtf8()); - - // Footage last modified date - hash->addData(stream->footage()->timestamp().toString().toUtf8()); - - // Footage stream - hash->addData(QString::number(stream->index()).toUtf8()); - - if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) { - ImageStreamPtr image_stream = std::static_pointer_cast(stream); - - // Current color config and space - hash->addData(image_stream->footage()->project()->color_manager()->GetConfigFilename().toUtf8()); - hash->addData(image_stream->colorspace().toUtf8()); - - // Alpha associated setting - hash->addData(QString::number(image_stream->premultiplied_alpha()).toUtf8()); - } - - // Footage timestamp - if (stream->type() == Stream::kVideo) { - hash->addData(QStringLiteral("%1/%2").arg(QString::number(input_time.numerator()), - QString::number(input_time.denominator())).toUtf8()); - - hash->addData(QString::number(static_cast(stream.get())->start_time()).toUtf8()); - /*Decoder::RetrieveState state = decoder->GetRetrieveState(input_time); - - if (state == Decoder::kReady) { - VideoStreamPtr video_stream = std::static_pointer_cast(stream); - - int64_t timestamp_here = video_stream->get_closest_timestamp_in_frame_index(input_time); - - hash->addData(QString::number(timestamp_here).toUtf8()); - } else { - ReportUnavailableFootage(stream, state, input_time); - }*/ - } - } - } - } - } - } -} - void VideoRenderWorker::SetParameters(const VideoRenderingParams &video_params) { video_params_ = video_params; diff --git a/app/render/backend/videorenderworker.h b/app/render/backend/videorenderworker.h index 6d43dbf6f..32476f199 100644 --- a/app/render/backend/videorenderworker.h +++ b/app/render/backend/videorenderworker.h @@ -105,8 +105,6 @@ protected: ColorProcessorCache* color_cache(); private: - void HashNodeRecursively(QCryptographicHash* hash, const Node *n, const rational &time); - void Download(const rational &time, QVariant texture, QString filename); void ResizeDownloadBuffer();