cache: reimplemented auto-caching

Implemented a smarter auto-cache that's context sensitive. Caching will
automatically pause when playback begins or values are being changed and resume
when inactive.
This commit is contained in:
itsmattkc
2020-05-24 15:20:35 +10:00
parent a26a3cbf21
commit 89ae6e026f
19 changed files with 180 additions and 14 deletions
+3
View File
@@ -83,6 +83,9 @@ void Config::SetDefaults()
config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk;
config_map_["Loop"] = false;
config_map_["AutoCache"] = true;
config_map_["AutoCacheInterval"] = 1000;
config_map_["NodeCatColor0"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.75f));
config_map_["NodeCatColor1"] = QVariant::fromValue(Color(0.25f, 0.25f, 0.25f));
config_map_["NodeCatColor2"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.25f));
+4
View File
@@ -58,6 +58,7 @@
#include "undo/undostack.h"
#include "widget/menu/menushared.h"
#include "widget/taskview/taskviewitem.h"
#include "widget/viewer/viewer.h"
#include "window/mainwindow/mainwindow.h"
OLIVE_NAMESPACE_ENTER
@@ -1134,6 +1135,9 @@ void Core::CacheActiveSequence(bool in_out_only)
arp,
in_out_only);
// Stop any current auto-cache tasks
ViewerWidget::StopAllBackgroundCacheTasks();
TaskDialog* dialog = new TaskDialog(task, tr("Caching Sequence"), main_window_);
dialog->open();
}
+1
View File
@@ -37,6 +37,7 @@ TaskManagerPanel::TaskManagerPanel(QWidget* parent) :
connect(TaskManager::instance(), &TaskManager::TaskAdded, view_, &TaskView::AddTask);
connect(TaskManager::instance(), &TaskManager::TaskRemoved, view_, &TaskView::RemoveTask);
connect(TaskManager::instance(), &TaskManager::TaskFailed, view_, &TaskView::TaskFailed);
connect(view_, &TaskView::TaskCancelled, TaskManager::instance(), &TaskManager::CancelTask);
// Set strings
Retranslate();
+4
View File
@@ -204,6 +204,10 @@ void RenderBackend::UpdateInstance(RenderWorker *instance)
void RenderBackend::Close()
{
video_pool_.threads.clear();
audio_pool_.threads.clear();
hash_pool_.threads.clear();
CancelQueue();
video_pool_.Destroy();
+5
View File
@@ -135,6 +135,11 @@ QList<rational> FrameHashCache::GetFrameListFromTimeRange(const TimeRangeList &r
return GetFrameListFromTimeRange(range, timebase_);
}
QList<rational> FrameHashCache::GetInvalidatedFrames() const
{
return GetFrameListFromTimeRange(GetInvalidatedRanges());
}
void FrameHashCache::SaveCacheFrame(const QByteArray& hash,
char* data,
const VideoRenderingParams& vparam)
+1
View File
@@ -68,6 +68,7 @@ public:
static QList<rational> GetFrameListFromTimeRange(TimeRangeList range_list, const rational& timebase);
QList<rational> GetFrameListFromTimeRange(const TimeRangeList &range) const;
QList<rational> GetInvalidatedFrames() const;
protected:
virtual void LengthChangedEvent(const rational& old, const rational& newlen) override;
+3 -1
View File
@@ -50,12 +50,14 @@ bool CacheTask::Run()
Render(range_to_cache, QMatrix4x4(), false);
download_threads_.waitForDone();
return true;
}
QFuture<void> CacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
{
return QtConcurrent::run(FrameHashCache::SaveCacheFrame, hash, frame);
return QtConcurrent::run(&download_threads_, FrameHashCache::SaveCacheFrame, hash, frame);
}
void CacheTask::FrameDownloaded(const QByteArray &hash, const QLinkedList<rational> &times)
+2
View File
@@ -47,6 +47,8 @@ protected:
private:
bool in_out_only_;
QThreadPool download_threads_;
};
OLIVE_NAMESPACE_EXIT
+10 -4
View File
@@ -92,7 +92,7 @@ void RenderTask::Render(const TimeRangeList& range_to_cache,
QLinkedList<HashTimePair> sorted_times;
QLinkedList<HashTimePair>::iterator sorted_iterator;
// Rendering is more efficient if we cache in order
// Rendering is more efficient if we cache in order, so here we sort
QMap< QByteArray, QLinkedList<rational> >::const_iterator i;
for (i=times_to_render.constBegin(); i!=times_to_render.constEnd(); i++) {
const QByteArray& hash = i.key();
@@ -141,9 +141,10 @@ void RenderTask::Render(const TimeRangeList& range_to_cache,
QLinkedList<HashDownloadFuturePair>::iterator j;
QLinkedList<RangeSampleFuturePair>::iterator k;
while (!render_lookup_table.isEmpty()
|| !download_futures.isEmpty()
|| !audio_lookup_table.isEmpty()) {
while (!IsCancelled()
&& (!render_lookup_table.isEmpty()
|| !download_futures.isEmpty()
|| !audio_lookup_table.isEmpty())) {
i = render_lookup_table.begin();
@@ -197,4 +198,9 @@ void RenderTask::AudioDownloaded(const TimeRange &, SampleBufferPtr)
{
}
void RenderTask::SetAnchorPoint(const rational &r)
{
anchor_point_ = r;
}
OLIVE_NAMESPACE_EXIT
+4
View File
@@ -57,6 +57,8 @@ protected:
return audio_params_;
}
void SetAnchorPoint(const rational& r);
private:
ViewerOutput* viewer_;
@@ -64,6 +66,8 @@ private:
AudioRenderingParams audio_params_;
rational anchor_point_;
};
OLIVE_NAMESPACE_EXIT
+22
View File
@@ -72,6 +72,17 @@ Task *TaskManager::GetFirstTask() const
return tasks_.begin().value();
}
void TaskManager::CancelTaskAndWait(Task* t)
{
t->Cancel();
QFutureWatcher<bool>* w = tasks_.key(t);
if (w) {
w->waitForFinished();
}
}
void TaskManager::AddTask(Task* t)
{
// Create a watcher for signalling
@@ -89,6 +100,17 @@ void TaskManager::AddTask(Task* t)
emit TaskListChanged();
}
void TaskManager::CancelTask(Task *t)
{
if (failed_tasks_.contains(t)) {
failed_tasks_.removeOne(t);
emit TaskRemoved(t);
t->deleteLater();
} else {
t->Cancel();
}
}
void TaskManager::TaskFinished()
{
QFutureWatcher<bool>* watcher = static_cast<QFutureWatcher<bool>*>(sender());
+4
View File
@@ -63,6 +63,8 @@ public:
Task* GetFirstTask() const;
void CancelTaskAndWait(Task* t);
public slots:
/**
* @brief Add a new Task
@@ -81,6 +83,8 @@ public slots:
*/
void AddTask(Task *t);
void CancelTask(Task* t);
signals:
/**
* @brief Signal emitted when a Task is added by AddTask()
+1
View File
@@ -47,6 +47,7 @@ void TaskView::AddTask(Task *t)
{
// Create TaskViewItem (UI representation of a Task) and connect it
TaskViewItem* item = new TaskViewItem(t);
connect(item, &TaskViewItem::TaskCancelled, this, &TaskView::TaskCancelled);
items_.insert(t, item);
layout_->insertWidget(layout_->count()-1, item);
}
+3
View File
@@ -42,6 +42,9 @@ class TaskView : public QScrollArea
public:
TaskView(QWidget* parent);
signals:
void TaskCancelled(Task* t);
public slots:
/**
* @brief Creates a TaskViewItem, connects it to a Task, and adds it to this widget
+3 -2
View File
@@ -61,12 +61,13 @@ TaskViewItem::TaskViewItem(Task* task, QWidget *parent) :
// Connect to the task
connect(task_, &Task::ProgressChanged, this, &TaskViewItem::UpdateProgress);
connect(cancel_btn_, &QPushButton::clicked, task_, &Task::Cancel, Qt::DirectConnection);
connect(cancel_btn_, &QPushButton::clicked, this, [this] { emit TaskCancelled(task_); });
}
void TaskViewItem::Failed()
{
task_status_lbl_->setText(task_->GetError());
task_status_lbl_->setStyleSheet("color: red");
task_status_lbl_->setText(tr("Error: %1").arg(task_->GetError()));
}
void TaskViewItem::UpdateProgress(double d)
+3
View File
@@ -47,6 +47,9 @@ public:
void Failed();
signals:
void TaskCancelled(Task* t);
private:
QLabel* task_name_lbl_;
QProgressBar* progress_bar_;
+89 -7
View File
@@ -36,6 +36,7 @@
#include "project/item/sequence/sequence.h"
#include "project/project.h"
#include "render/pixelformat.h"
#include "task/taskmanager.h"
#include "widget/menu/menu.h"
#include "window/mainwindow/mainwindow.h"
@@ -43,6 +44,8 @@ OLIVE_NAMESPACE_ENTER
const int kMaxPreQueueSize = 16;
CacheTask* ViewerWidget::cache_background_task_ = nullptr;
ViewerWidget::ViewerWidget(QWidget *parent) :
TimeBasedWidget(false, true, parent),
playback_speed_(0),
@@ -102,11 +105,19 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
// FIXME: Magic number
SetScale(48.0);
// Start background renderers
// Start background renderer
renderer_ = new OpenGLBackend(this);
// Setup cache wait timer (waits a few seconds of inactivity before caching)
cache_wait_timer_.setInterval(1000);
cache_wait_timer_.setSingleShot(true);
connect(&cache_wait_timer_, &QTimer::timeout, this, &ViewerWidget::StartBackgroundCaching);
connect(TaskManager::instance(), &TaskManager::TaskRemoved, this, &ViewerWidget::BackgroundCacheFinished);
// Ensures that seeking on the waveform view updates the time as expected
connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::SetTimeAndSignal);
// Ensures renderer is updated if the global pixel format is changed
connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererParameters);
SetAutoMaxScrollBar(true);
@@ -196,6 +207,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
// Set texture to new texture (or null if no viewer node is available)
ForceUpdate();
StartBackgroundCaching();
}
void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
@@ -223,6 +236,10 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
waveform_view_->SetViewer(nullptr);
waveform_view_->ConnectTimelinePoints(nullptr);
StopAllBackgroundCacheTasks();
cache_background_task_ = nullptr;
cache_wait_timer_.stop();
}
void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n)
@@ -343,6 +360,16 @@ void ViewerWidget::SetGizmos(Node *node)
display_widget_->SetGizmos(node);
}
void ViewerWidget::StopAllBackgroundCacheTasks()
{
TaskManager::instance()->CancelTaskAndWait(cache_background_task_);
}
void ViewerWidget::SetBackgroundCacheTask(CacheTask *t)
{
cache_background_task_ = t;
}
FramePtr DecodeCachedImage(const QString &fn, const rational& time)
{
FramePtr frame = nullptr;
@@ -453,6 +480,8 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
} else {
FillPlaybackQueue();
}
StopBackgroundCache();
}
void ViewerWidget::PushScrubbedAudio()
@@ -614,6 +643,29 @@ void ViewerWidget::FinishPlayPreprocess()
}
}
VideoRenderingParams ViewerWidget::GenerateVideoParams() const
{
return VideoRenderingParams(GetConnectedNode()->video_params(),
GetCurrentPixelFormat(),
RenderMode::kOffline,
divider_);
}
AudioRenderingParams ViewerWidget::GenerateAudioParams() const
{
return AudioRenderingParams(GetConnectedNode()->audio_params(),
SampleFormat::kInternalFormat);
}
void ViewerWidget::StopBackgroundCache()
{
cache_wait_timer_.stop();
if (cache_background_task_) {
cache_background_task_->Cancel();
cache_background_task_ = nullptr;
}
}
void ViewerWidget::UpdateStack()
{
if (GetConnectedNode()
@@ -753,15 +805,38 @@ void ViewerWidget::HashGenerated()
watcher->deleteLater();
}
void ViewerWidget::StartBackgroundCaching()
{
if (Config::Current()["AutoCache"].toBool()) {
if (cache_background_task_) {
// Something else is caching right now, we don't want to do multiple at once so we'll check
// again in our next interval
cache_wait_timer_.start();
} else {
cache_background_task_ = new CacheTask(GetConnectedNode(),
GenerateVideoParams(),
GenerateAudioParams(),
false);
TaskManager::instance()->AddTask(cache_background_task_);
}
}
}
void ViewerWidget::BackgroundCacheFinished(Task* t)
{
if (cache_background_task_ == t) {
cache_background_task_ = nullptr;
}
}
void ViewerWidget::UpdateRendererParameters()
{
renderer_->SetVideoParams(VideoRenderingParams(GetConnectedNode()->video_params(),
GetCurrentPixelFormat(),
RenderMode::kOffline,
divider_));
renderer_->SetVideoParams(GenerateVideoParams());
renderer_->SetAudioParams(AudioRenderingParams(GetConnectedNode()->audio_params(),
SampleFormat::kInternalFormat));
renderer_->SetAudioParams(GenerateAudioParams());
display_widget_->SetVideoParams(GetConnectedNode()->video_params());
}
@@ -923,6 +998,7 @@ void ViewerWidget::Pause()
}
prequeuing_ = false;
StartBackgroundCaching();
}
void ViewerWidget::ShuttleLeft()
@@ -1093,6 +1169,11 @@ void ViewerWidget::ViewerInvalidatedRange(const TimeRange &range)
ForceUpdate();
}
// Restart the cache wait timer
StopBackgroundCache();
cache_wait_timer_.start();
/*
QList<rational> invalidated_frames = GetConnectedNode()->video_frame_cache()->GetFrameListFromTimeRange({range});
foreach (const rational& r, invalidated_frames) {
QFutureWatcher<QByteArray>* watcher = new QFutureWatcher<QByteArray>();
@@ -1100,6 +1181,7 @@ void ViewerWidget::ViewerInvalidatedRange(const TimeRange &range)
hash_watchers_.insert(watcher, r);
watcher->setFuture(renderer_->Hash(r, true));
}
*/
}
OLIVE_NAMESPACE_EXIT
+17
View File
@@ -33,6 +33,7 @@
#include "node/output/viewer/viewer.h"
#include "panel/scope/scope.h"
#include "render/backend/opengl/openglbackend.h"
#include "task/cache/cache.h"
#include "viewerdisplay.h"
#include "viewerplaybacktimer.h"
#include "viewerqueue.h"
@@ -97,6 +98,9 @@ public:
void SetGizmos(Node* node);
static void StopAllBackgroundCacheTasks();
static void SetBackgroundCacheTask(CacheTask* t);
public slots:
void Play(bool in_to_out_only);
@@ -192,6 +196,11 @@ private:
void FinishPlayPreprocess();
VideoRenderingParams GenerateVideoParams() const;
AudioRenderingParams GenerateAudioParams() const;
void StopBackgroundCache();
QStackedWidget* stack_;
ViewerSizer* sizer_;
@@ -235,6 +244,10 @@ private:
QHash<QFutureWatcher<QByteArray>*, rational> hash_watchers_;
QTimer cache_wait_timer_;
static CacheTask* cache_background_task_;
private slots:
void PlaybackTimerUpdate();
@@ -272,6 +285,10 @@ private slots:
void HashGenerated();
void StartBackgroundCaching();
void BackgroundCacheFinished(Task *t);
};
OLIVE_NAMESPACE_EXIT
+1
View File
@@ -62,6 +62,7 @@ void MainStatusBar::UpdateStatus()
if (manager_->GetTaskCount() == 0) {
clearMessage();
bar_->setVisible(false);
bar_->setValue(0);
} else {
Task* t = manager_->GetFirstTask();