diff --git a/app/common/timerange.cpp b/app/common/timerange.cpp index e98da1bb0..c352e476d 100644 --- a/app/common/timerange.cpp +++ b/app/common/timerange.cpp @@ -295,8 +295,9 @@ TimeRangeListFrameIterator::TimeRangeListFrameIterator() : TimeRangeListFrameIterator::TimeRangeListFrameIterator(const TimeRangeList &list, const rational &timebase) : list_(list), timebase_(timebase), - index_(-1), + range_index_(-1), size_(-1), + frame_index_(0), custom_range_(false) { if (!list_.isEmpty() && timebase_.isNull()) { @@ -321,12 +322,15 @@ bool TimeRangeListFrameIterator::GetNext(rational *out) // If this time is outside the current range, jump to the next one UpdateIndexIfNecessary(); + // Increment frame index + frame_index_++; + return true; } bool TimeRangeListFrameIterator::HasNext() const { - return index_ < list_.size(); + return range_index_ < list_.size(); } int TimeRangeListFrameIterator::size() @@ -355,11 +359,11 @@ int TimeRangeListFrameIterator::size() void TimeRangeListFrameIterator::UpdateIndexIfNecessary() { - while (index_ < list_.size() && (index_ == -1 || current_ >= list_.at(index_).out())) { - index_++; + while (range_index_ < list_.size() && (range_index_ == -1 || current_ >= list_.at(range_index_).out())) { + range_index_++; - if (index_ < list_.size()) { - current_ = Timecode::snap_time_to_timebase(list_.at(index_).in(), timebase_, Timecode::kCeil); + if (range_index_ < list_.size()) { + current_ = Timecode::snap_time_to_timebase(list_.at(range_index_).in(), timebase_, Timecode::kCeil); } } } diff --git a/app/common/timerange.h b/app/common/timerange.h index ef1627d8e..abb004853 100644 --- a/app/common/timerange.h +++ b/app/common/timerange.h @@ -238,6 +238,11 @@ public: custom_range_ = e; } + int frame_index() const + { + return frame_index_; + } + private: void UpdateIndexIfNecessary(); @@ -247,10 +252,12 @@ private: rational current_; - int index_; + int range_index_; int size_; + int frame_index_; + bool custom_range_; }; diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index 36fb9289f..86cfaa384 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -28,6 +28,8 @@ #include "node/project/project.h" #include "render/rendermanager.h" #include "render/renderprocessor.h" +#include "task/customcache/customcachetask.h" +#include "task/taskmanager.h" #include "widget/slider/base/numericsliderbase.h" namespace olive { @@ -661,6 +663,12 @@ void PreviewAutoCacher::TryRender() // Don't render any hash more than once RenderFrame(hash, t, false, false); } + + emit SignalCacheProxyTaskProgress(double(queued_frame_iterator_.frame_index()) / double(queued_frame_iterator_.size())); + + if (!queued_frame_iterator_.HasNext()) { + emit StopCacheProxyTasks(); + } } // Handle audio tasks @@ -724,6 +732,14 @@ void PreviewAutoCacher::RequeueFrames() queued_frame_iterator_.SetCustomRange(use_custom_range_); + emit StopCacheProxyTasks(); + + CustomCacheTask *cct = new CustomCacheTask(viewer_node_->GetLabelOrName()); + connect(this, &PreviewAutoCacher::StopCacheProxyTasks, cct, &CustomCacheTask::Finish); + connect(this, &PreviewAutoCacher::SignalCacheProxyTaskProgress, cct, &CustomCacheTask::ProgressChanged); + connect(cct, &CustomCacheTask::Cancelled, this, &PreviewAutoCacher::CacheProxyTaskCancelled); + TaskManager::instance()->AddTask(cct); + use_custom_range_ = false; TryRender(); @@ -764,6 +780,12 @@ void PreviewAutoCacher::AudioAutoCacheEnableChanged(bool e) } } +void PreviewAutoCacher::CacheProxyTaskCancelled() +{ + queued_frame_iterator_.reset(); + RequeueFrames(); +} + void PreviewAutoCacher::ForceCacheRange(const TimeRange &range) { use_custom_range_ = true; diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index f85dfe7c1..246b0d1ff 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -99,6 +99,11 @@ public: return queued_frame_iterator_.IsCustomRange() && queued_frame_iterator_.HasNext(); } +signals: + void StopCacheProxyTasks(); + + void SignalCacheProxyTaskProgress(double d); + private: void TryRender(); @@ -257,6 +262,8 @@ private slots: void AudioAutoCacheEnableChanged(bool e); + void CacheProxyTaskCancelled(); + }; } diff --git a/app/task/CMakeLists.txt b/app/task/CMakeLists.txt index 954557d8d..640946a68 100644 --- a/app/task/CMakeLists.txt +++ b/app/task/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(conform) +add_subdirectory(customcache) add_subdirectory(export) add_subdirectory(precache) add_subdirectory(project) diff --git a/app/task/customcache/CMakeLists.txt b/app/task/customcache/CMakeLists.txt new file mode 100644 index 000000000..46abd88af --- /dev/null +++ b/app/task/customcache/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + task/customcache/customcachetask.cpp + task/customcache/customcachetask.h + PARENT_SCOPE +) diff --git a/app/task/customcache/customcachetask.cpp b/app/task/customcache/customcachetask.cpp new file mode 100644 index 000000000..97d7c07fe --- /dev/null +++ b/app/task/customcache/customcachetask.cpp @@ -0,0 +1,62 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#include "customcachetask.h" + +namespace olive { + +CustomCacheTask::CustomCacheTask(const QString &sequence_name) : + cancelled_through_finish_(false) +{ + SetTitle(tr("Caching custom range for \"%1\"").arg(sequence_name)); +} + +void CustomCacheTask::Finish() +{ + mutex_.lock(); + + cancelled_through_finish_ = true; + Cancel(); + + mutex_.unlock(); +} + +bool CustomCacheTask::Run() +{ + mutex_.lock(); + + while (!IsCancelled()) { + wait_cond_.wait(&mutex_); + } + + mutex_.unlock(); + + return true; +} + +void CustomCacheTask::CancelEvent() +{ + if (!cancelled_through_finish_) { + emit Cancelled(); + } + wait_cond_.wakeOne(); +} + +} diff --git a/app/task/customcache/customcachetask.h b/app/task/customcache/customcachetask.h new file mode 100644 index 000000000..e946ae775 --- /dev/null +++ b/app/task/customcache/customcachetask.h @@ -0,0 +1,58 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#ifndef CUSTOMCACHETASK_H +#define CUSTOMCACHETASK_H + +#include +#include + +#include "task/task.h" + +namespace olive { + +class CustomCacheTask : public Task +{ + Q_OBJECT +public: + CustomCacheTask(const QString &sequence_name); + + void Finish(); + +signals: + void Cancelled(); + +protected: + virtual bool Run() override; + + virtual void CancelEvent() override; + +private: + QMutex mutex_; + + QWaitCondition wait_cond_; + + bool cancelled_through_finish_; + +}; + +} + +#endif // CUSTOMCACHETASK_H