nodes: moved hashing to nodes so they can override behavior if they wish
This commit is contained in:
@@ -234,6 +234,18 @@ void Block::SaveInternal(QXmlStreamWriter *writer) const
|
||||
}
|
||||
}
|
||||
|
||||
QList<NodeInput *> Block::GetInputsToHash() const
|
||||
{
|
||||
QList<NodeInput*> 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());
|
||||
|
||||
@@ -126,6 +126,8 @@ protected:
|
||||
|
||||
virtual void SaveInternal(QXmlStreamWriter* writer) const override;
|
||||
|
||||
virtual QList<NodeInput*> GetInputsToHash() const override;
|
||||
|
||||
Block* previous_;
|
||||
Block* next_;
|
||||
|
||||
|
||||
@@ -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<const char*>(&all_prog), sizeof(double));
|
||||
hash.addData(reinterpret_cast<const char*>(&in_prog), sizeof(double));
|
||||
hash.addData(reinterpret_cast<const char*>(&out_prog), sizeof(double));
|
||||
}
|
||||
|
||||
double TransitionBlock::GetInternalTransitionTime(const rational &time) const
|
||||
{
|
||||
return time.toDouble() - in().toDouble();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <QFile>
|
||||
|
||||
#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<NodeInput *> 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<NodeInput*> 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<StreamPtr>();
|
||||
|
||||
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<ImageStream>(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<VideoStream*>(stream.get())->start_time()).toUtf8());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
|
||||
{
|
||||
Q_ASSERT(source->id() == destination->id());
|
||||
|
||||
@@ -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<NodeInput*> GetInputsToHash() const;
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<StreamPtr>();
|
||||
return input->get_standard_value().value<StreamPtr>();
|
||||
}
|
||||
|
||||
DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
|
||||
|
||||
@@ -75,7 +75,7 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con
|
||||
hasher.addData(reinterpret_cast<const char*>(&vfmt), sizeof(PixelFormat::Format));
|
||||
hasher.addData(reinterpret_cast<const char*>(&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<const TrackOutput*>(n)->BlockAtTime(time);
|
||||
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add this Node's ID
|
||||
hash->addData(n->id().toUtf8());
|
||||
|
||||
if (n->IsBlock() && static_cast<const Block*>(n)->type() == Block::kTransition) {
|
||||
const TransitionBlock* transition = static_cast<const TransitionBlock*>(n);
|
||||
|
||||
double all_prog = transition->GetTotalProgress(time);
|
||||
double in_prog = transition->GetInProgress(time);
|
||||
double out_prog = transition->GetOutProgress(time);
|
||||
|
||||
hash->addData(reinterpret_cast<const char*>(&all_prog), sizeof(double));
|
||||
hash->addData(reinterpret_cast<const char*>(&in_prog), sizeof(double));
|
||||
hash->addData(reinterpret_cast<const char*>(&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<NodeInput*>(param);
|
||||
|
||||
if (n->IsBlock()) {
|
||||
const Block* b = static_cast<const Block*>(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<ImageStream>(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<VideoStream*>(stream.get())->start_time()).toUtf8());
|
||||
/*Decoder::RetrieveState state = decoder->GetRetrieveState(input_time);
|
||||
|
||||
if (state == Decoder::kReady) {
|
||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user