diff --git a/app/node/input.cpp b/app/node/input.cpp index d17656194..4e75caa5b 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -1007,7 +1007,7 @@ void NodeInput::set_is_keyframable(bool k) keyframable_ = k; } -void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections) +void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections, bool traverse_arrays) { Q_ASSERT(source->id() == dest->id()); @@ -1037,8 +1037,10 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn dst_array->SetSize(src_array->GetSize()); - for (int i=0;iGetSize();i++) { - CopyValues(src_array->At(i), dst_array->At(i), include_connections); + if (traverse_arrays) { + for (int i=0;iGetSize();i++) { + CopyValues(src_array->At(i), dst_array->At(i), include_connections); + } } } diff --git a/app/node/input.h b/app/node/input.h index 4a6da4822..cbf401250 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -235,7 +235,7 @@ public: /** * @brief Copy all values including keyframe information and connections from another NodeInput */ - static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true); + static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true, bool traverse_arrays = true); /** * @brief Set an arbitrary property on this input to influence a UI representation's behavior diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 87b68d78b..2dddc700e 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -113,19 +113,20 @@ void RenderBackend::ClearVideoQueue() render_queue_.clear(); } -QFuture > RenderBackend::Hash(const QVector ×) +RenderTicketPtr RenderBackend::Hash(const QVector ×) { - return QtConcurrent::run(&pool_, [this](const QVector &t){ - QVector hashes(t.size()); + if (!viewer_node_) { + return nullptr; + } - for (int i=0;itexture_input()->get_connected_node(), - video_params_, - t.at(i)); - } + RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeHash, + QVariant::fromValue(times)); - return hashes; - }, times); + render_queue_.push_back(ticket); + + QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); + + return ticket; } RenderTicketPtr RenderBackend::RenderFrame(const rational &time) @@ -135,7 +136,7 @@ RenderTicketPtr RenderBackend::RenderFrame(const rational &time) } RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, - TimeRange(time, time)); + QVariant::fromValue(time)); render_queue_.push_back(ticket); @@ -151,7 +152,7 @@ RenderTicketPtr RenderBackend::RenderAudio(const TimeRange &r) } RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeAudio, - r); + QVariant::fromValue(r)); render_queue_.push_back(ticket); @@ -215,6 +216,11 @@ void RenderBackend::NodeGraphChanged(NodeInput *source) for (int i=0; iparentNode()->OutputsTo(queued_input, true)) { // In which case, no further copy is necessary @@ -300,7 +306,7 @@ void RenderBackend::RunNextJob() worker->SetVideoParams(video_params_); worker->SetAudioParams(audio_params_); - worker->SetVideoDownloadMatrix(video_download_matrix_); + worker->SetVideoDownloadMatrix(video_dwnload_matrix_); worker->SetRenderMode(render_mode_); if (preview_job_time_) { worker->EnablePreviewGeneration(viewer_node_->audio_playback_cache(), preview_job_time_); @@ -311,13 +317,21 @@ void RenderBackend::RunNextJob() render_queue_.pop_front(); switch (ticket->GetType()) { + case RenderTicket::kTypeHash: + QtConcurrent::run(&pool_, + worker, + &RenderWorker::Hash, + ticket, + copied_viewer_node_, + ticket->GetTime().value >()); + break; case RenderTicket::kTypeVideo: QtConcurrent::run(&pool_, worker, &RenderWorker::RenderFrame, ticket, copied_viewer_node_, - ticket->GetTime().in()); + ticket->GetTime().value()); break; case RenderTicket::kTypeAudio: QtConcurrent::run(&pool_, @@ -325,7 +339,7 @@ void RenderBackend::RunNextJob() &RenderWorker::RenderAudio, ticket, copied_viewer_node_, - ticket->GetTime()); + ticket->GetTime().value()); break; } @@ -337,27 +351,25 @@ void RenderBackend::RunNextJob() } } +//#define PRINT_UPDATE_QUEUE_INFO void RenderBackend::ProcessUpdateQueue() { +#ifdef PRINT_UPDATE_QUEUE_INFO + qint64 t = QDateTime::currentMSecsSinceEpoch(); + qDebug() << "Processing update queue of" << graph_update_queue_.size() << "elements:"; +#endif + while (!graph_update_queue_.isEmpty()) { - CopyNodeInputValue(graph_update_queue_.takeFirst()); - } -} - -QByteArray RenderBackend::HashNode(const Node *n, const VideoParams ¶ms, const rational &time) -{ - QCryptographicHash hasher(QCryptographicHash::Sha1); - - // Embed video parameters into this hash - hasher.addData(reinterpret_cast(¶ms.effective_width()), sizeof(int)); - hasher.addData(reinterpret_cast(¶ms.effective_height()), sizeof(int)); - hasher.addData(reinterpret_cast(¶ms.format()), sizeof(PixelFormat::Format)); - - if (n) { - n->Hash(hasher, time); + NodeInput* i = graph_update_queue_.takeFirst(); +#ifdef PRINT_UPDATE_QUEUE_INFO + qDebug() << " " << i->parentNode()->id() << i->id(); +#endif + CopyNodeInputValue(i); } - return hasher.result(); +#ifdef PRINT_UPDATE_QUEUE_INFO + qDebug() << "Update queue took:" << (QDateTime::currentMSecsSinceEpoch() - t); +#endif } void RenderBackend::WorkerFinished() @@ -386,6 +398,7 @@ void RenderBackend::CopyNodeInputValue(NodeInput *input) // Copy the standard/keyframe values between these two inputs NodeInput::CopyValues(input, our_copy, + false, false); // Handle connections diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index c31632aef..19ab3948f 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -69,12 +69,10 @@ public: void ProcessUpdateQueue(); - static QByteArray HashNode(const Node* n, const VideoParams& params, const rational& time); - /** * @brief Asynchronously generate a hash at a given time */ - QFuture > Hash(const QVector ×); + RenderTicketPtr Hash(const QVector ×); /** * @brief Asynchronously generate a frame at a given time diff --git a/app/render/backend/renderticket.cpp b/app/render/backend/renderticket.cpp index 85d0d46d8..1e719a5f6 100644 --- a/app/render/backend/renderticket.cpp +++ b/app/render/backend/renderticket.cpp @@ -22,7 +22,7 @@ OLIVE_NAMESPACE_ENTER -RenderTicket::RenderTicket(Type type, const TimeRange &time) : +RenderTicket::RenderTicket(Type type, const QVariant &time) : finished_(false), cancelled_(false), time_(time), diff --git a/app/render/backend/renderticket.h b/app/render/backend/renderticket.h index 3432b0df5..22fe46c8d 100644 --- a/app/render/backend/renderticket.h +++ b/app/render/backend/renderticket.h @@ -35,13 +35,14 @@ class RenderTicket : public QObject Q_OBJECT public: enum Type { + kTypeHash, kTypeVideo, kTypeAudio }; - RenderTicket(Type type, const TimeRange& time); + RenderTicket(Type type, const QVariant& time); - const TimeRange& GetTime() const + const QVariant& GetTime() const { return time_; } @@ -82,7 +83,7 @@ private: QWaitCondition wait_; - TimeRange time_; + QVariant time_; Type type_; diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 1ff861658..37de178b4 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -21,13 +21,13 @@ #include "renderworker.h" #include +#include #include "audio/audiovisualwaveform.h" #include "common/functiontimer.h" #include "config/config.h" #include "node/block/clip/clip.h" #include "task/conform/conform.h" -#include "renderbackend.h" OLIVE_NAMESPACE_ENTER @@ -40,6 +40,37 @@ RenderWorker::RenderWorker(RenderBackend* parent) : { } +void RenderWorker::Hash(RenderTicketPtr ticket, ViewerOutput *viewer, const QVector ×) +{ + QVector hashes(times.size()); + + for (int i=0;itexture_input()->get_connected_node(), + video_params_, + times.at(i)); + } + + ticket->Finish(QVariant::fromValue(hashes)); + + emit FinishedJob(); +} + +QByteArray RenderWorker::HashNode(const Node *n, const VideoParams ¶ms, const rational &time) +{ + QCryptographicHash hasher(QCryptographicHash::Sha1); + + // Embed video parameters into this hash + hasher.addData(reinterpret_cast(¶ms.effective_width()), sizeof(int)); + hasher.addData(reinterpret_cast(¶ms.effective_height()), sizeof(int)); + hasher.addData(reinterpret_cast(¶ms.format()), sizeof(PixelFormat::Format)); + + if (n) { + n->Hash(hasher, time); + } + + return hasher.result(); +} + void RenderWorker::RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, const rational &time) { NodeValueTable table = ProcessInput(viewer->texture_input(), @@ -237,7 +268,7 @@ QVariant RenderWorker::ProcessFrameGeneration(const Node* node, const GenerateJo QVariant RenderWorker::GetCachedFrame(const Node* node, const rational& time) { if (node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { - QByteArray hash = RenderBackend::HashNode(node, video_params(), time); + QByteArray hash = HashNode(node, video_params(), time); QString fn = FrameHashCache::CachePathName(hash); diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index 3f5af3f9d..65655a2b2 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -84,6 +84,8 @@ public: preview_job_time_ = job_time; } + void Hash(RenderTicketPtr ticket, ViewerOutput* viewer, const QVector& times); + /** * @brief Render the frame at this time * @@ -146,6 +148,8 @@ signals: private: DecoderPtr ResolveDecoderFromInput(StreamPtr stream); + static QByteArray HashNode(const Node* n, const VideoParams& params, const rational& time); + RenderBackend* parent_; VideoParams video_params_; diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index 31da11f17..1b93fe61e 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -107,11 +107,13 @@ void RenderTask::Render(const TimeRangeList& video_range, total_length += video_frame_sz * times.size(); - QFuture > hash_future = backend_->Hash(times); - hashes = hash_future.result(); + RenderTicketPtr hash_future = backend_->Hash(times); + hashes = hash_future->Get().value >(); - for (int i=0;iWasCancelled()) { + for (int i=0;ivideo_frame_cache()->CachePathName(cached_hash); - RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, TimeRange(t, t)); + RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, + QVariant::fromValue(t)); QtConcurrent::run(DecodeCachedImage, ticket, cache_fn, t); return ticket; @@ -875,10 +876,7 @@ void ViewerWidget::StartBackgroundCaching() cache_wait_timer_.start(); } else { - cache_background_task_ = new CacheTask(GetConnectedNode(), - GetConnectedNode()->video_params(), - GetConnectedNode()->audio_params(), - false); + cache_background_task_ = new CacheTask(renderer_, false); our_cache_background_task_ = cache_background_task_; @@ -1223,7 +1221,7 @@ void ViewerWidget::ViewerInvalidatedRange() StopAllBackgroundCacheTasks(false); if (!(qApp->mouseButtons() & Qt::LeftButton)) { - StartBackgroundCaching(); + cache_wait_timer_.start(); } }