cache: use render job times to synchronize cache

Ensure old inaccurate jobs are never prioritized over current jobs.
This commit is contained in:
itsmattkc
2020-06-04 16:48:23 +10:00
parent cc34f0e251
commit 9ff9817b95
13 changed files with 106 additions and 40 deletions
+16 -18
View File
@@ -162,30 +162,28 @@ void TimeRangeList::InsertTimeRange(const TimeRange &range)
void TimeRangeList::RemoveTimeRange(const TimeRange &range)
{
for (int i=0;i<size();i++) {
const TimeRange& compare = at(i);
RemoveTimeRange(this, range);
}
if (range.Contains(compare)) {
void TimeRangeList::RemoveTimeRange(QList<TimeRange> *list, const TimeRange &remove)
{
for (int i=0;i<list->size();i++) {
TimeRange& compare = (*list)[i];
if (remove.Contains(compare)) {
// This element is entirely encompassed in this range, remove it
removeAt(i);
list->removeAt(i);
i--;
} else if (compare.Contains(range, false, false)) {
} else if (compare.Contains(remove, false, false)) {
// The remove range is within this element, only choice is to split the element into two
TimeRange first(compare.in(), range.in());
TimeRange last(range.out(), compare.out());
replace(i, first);
append(last);
} else if (compare.in() < range.in() && compare.out() > range.in()) {
list->append(TimeRange(remove.out(), compare.out()));
compare.set_out(remove.in());
} else if (compare.in() < remove.in() && compare.out() > remove.in()) {
// This element's out point overlaps the range's in, we'll trim it
TimeRange trimmed = compare;
trimmed.set_out(range.in());
replace(i, trimmed);
} else if (compare.in() < range.out() && compare.out() > range.out()) {
compare.set_out(remove.in());
} else if (compare.in() < remove.out() && compare.out() > remove.out()) {
// This element's in point overlaps the range's out, we'll trim it
TimeRange trimmed = compare;
trimmed.set_in(range.out());
replace(i, trimmed);
compare.set_in(remove.out());
}
}
}
+2
View File
@@ -75,6 +75,8 @@ public:
void RemoveTimeRange(const TimeRange& range);
static void RemoveTimeRange(QList<TimeRange>* list, const TimeRange& remove);
bool ContainsTimeRange(const TimeRange& range, bool in_inclusive = true, bool out_inclusive = true) const;
TimeRangeList Intersects(const TimeRange& range) const;
+12 -1
View File
@@ -63,10 +63,14 @@ void AudioPlaybackCache::SetParameters(const AudioRenderingParams &params)
emit Invalidated(invalidate_range);
}
void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr samples)
void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr samples, const qint64 &job_time)
{
QMutexLocker locker(lock());
if (!JobIsCurrent(range, job_time)) {
return;
}
QFile f(filename_);
if (f.open(QFile::ReadWrite)) {
qint64 start_offset = params_.time_to_bytes(range.in());
@@ -193,6 +197,13 @@ void AudioPlaybackCache::ShiftEvent(const rational &from, const rational &to)
}
}
void AudioPlaybackCache::LengthChangedEvent(const rational& old, const rational& newlen)
{
if (newlen < old) {
QFile(filename_).resize(params_.time_to_bytes(newlen));
}
}
const QString &AudioPlaybackCache::GetCacheFilename() const
{
return filename_;
+3 -1
View File
@@ -40,7 +40,7 @@ public:
void SetParameters(const AudioRenderingParams& params);
void WritePCM(const TimeRange &range, SampleBufferPtr samples);
void WritePCM(const TimeRange &range, SampleBufferPtr samples, const qint64& job_time);
void WriteSilence(const TimeRange &range);
@@ -52,6 +52,8 @@ signals:
protected:
virtual void ShiftEvent(const rational& from, const rational& to) override;
virtual void LengthChangedEvent(const rational& old, const rational& newlen) override;
private:
QString filename_;
-2
View File
@@ -351,8 +351,6 @@ void RenderBackend::WorkerFinished()
if (viewer_node_) {
RunNextJob();
} else {
qDebug() << "Ignored job finish because no viewer";
}
}
+5 -1
View File
@@ -41,10 +41,14 @@ QByteArray FrameHashCache::GetHash(const rational &time)
return time_hash_map_.value(time);
}
void FrameHashCache::SetHash(const rational &time, const QByteArray &hash)
void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const qint64& job_time)
{
QMutexLocker locker(lock());
if (!JobIsCurrent(TimeRange(time, time), job_time)) {
return;
}
time_hash_map_.insert(time, hash);
TimeRange validated_range(time, time + timebase_);
+1 -1
View File
@@ -39,7 +39,7 @@ public:
QByteArray GetHash(const rational& time);
void SetHash(const rational& time, const QByteArray& hash);
void SetHash(const rational& time, const QByteArray& hash, const qint64 &job_time);
void SetTimebase(const rational& tb);
+44 -11
View File
@@ -20,6 +20,8 @@
#include "playbackcache.h"
#include <QDateTime>
OLIVE_NAMESPACE_ENTER
void PlaybackCache::Invalidate(const TimeRange &r)
@@ -89,21 +91,13 @@ void PlaybackCache::Shift(const rational &from, const rational &to)
emit Shifted(from, to);
}
void PlaybackCache::Validate(const TimeRange &r)
{
QMutexLocker locker(&lock_);
NoLockValidate(r);
locker.unlock();
emit Validated(r);
}
void PlaybackCache::NoLockInvalidate(const TimeRange &r)
{
invalidated_.InsertTimeRange(r);
RemoveRangeFromJobs(r);
jobs_.append({r, QDateTime::currentMSecsSinceEpoch()});
InvalidateEvent(r);
}
@@ -132,6 +126,20 @@ void PlaybackCache::NoLockSetLength(const rational &r)
length_ = r;
}
bool PlaybackCache::JobIsCurrent(const TimeRange &r, qint64 job_time)
{
for (int i=jobs_.size()-1; i>=0; i--) {
const JobIdentifier& job = jobs_.at(i);
if (job.range.Contains(r, true, r.in() != r.out())
&& job_time >= job.job_time) {
return true;
}
}
return false;
}
void PlaybackCache::LengthChangedEvent(const rational &, const rational &)
{
}
@@ -144,4 +152,29 @@ void PlaybackCache::ShiftEvent(const rational &, const rational &)
{
}
void PlaybackCache::RemoveRangeFromJobs(const TimeRange &remove)
{
// Code shamelessly copied from TimeRangeList::RemoveTimeRange
for (int i=0;i<jobs_.size();i++) {
JobIdentifier& job = jobs_[i];
TimeRange& compare = job.range;
if (remove.Contains(compare)) {
// This element is entirely encompassed in this range, remove it
jobs_.removeAt(i);
i--;
} else if (compare.Contains(remove, false, false)) {
// The remove range is within this element, only choice is to split the element into two
jobs_.append({TimeRange(remove.out(), compare.out()), job.job_time});
compare.set_out(remove.in());
} else if (compare.in() < remove.in() && compare.out() > remove.in()) {
// This element's out point overlaps the range's in, we'll trim it
compare.set_out(remove.in());
} else if (compare.in() < remove.out() && compare.out() > remove.out()) {
// This element's in point overlaps the range's out, we'll trim it
compare.set_in(remove.out());
}
}
}
OLIVE_NAMESPACE_EXIT
+11 -2
View File
@@ -80,14 +80,14 @@ signals:
void LengthChanged(const OLIVE_NAMESPACE::rational& r);
protected:
void Validate(const TimeRange& r);
void NoLockInvalidate(const TimeRange& r);
void NoLockValidate(const TimeRange& r);
void NoLockSetLength(const rational& r);
bool JobIsCurrent(const TimeRange& r, qint64 job_time);
const rational& NoLockGetLength() const
{
return length_;
@@ -110,10 +110,19 @@ protected:
}
private:
void RemoveRangeFromJobs(const TimeRange& remove);
QMutex lock_;
TimeRangeList invalidated_;
struct JobIdentifier {
TimeRange range;
qint64 job_time;
};
QList<JobIdentifier> jobs_;
rational length_;
};
+2 -2
View File
@@ -65,14 +65,14 @@ QFuture<void> CacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
void CacheTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> &times)
{
foreach (const rational& t, times) {
viewer()->video_frame_cache()->SetHash(t, hash);
viewer()->video_frame_cache()->SetHash(t, hash, job_time());
}
}
void CacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
{
if (samples) {
viewer()->audio_playback_cache()->WritePCM(range, samples);
viewer()->audio_playback_cache()->WritePCM(range, samples, job_time());
} else {
viewer()->audio_playback_cache()->WriteSilence(range);
}
+1 -1
View File
@@ -177,7 +177,7 @@ void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples
adjusted_range -= params_.custom_range().in();
}
audio_data_.WritePCM(adjusted_range, samples);
audio_data_.WritePCM(adjusted_range, samples, job_time());
}
OLIVE_NAMESPACE_EXIT
+2
View File
@@ -29,6 +29,8 @@ RenderTask::RenderTask(ViewerOutput* viewer, const VideoRenderingParams &vparams
video_params_(vparams),
audio_params_(aparams)
{
job_time_ = QDateTime::currentMSecsSinceEpoch();
// FIXME: This makes a full copy of the node graph every time it starts, there must be a better
// way.
backend_.SetViewerNode(viewer_);
+7
View File
@@ -63,6 +63,11 @@ protected:
void SetAnchorPoint(const rational& r);
const qint64& job_time() const
{
return job_time_;
}
private:
ViewerOutput* viewer_;
@@ -74,6 +79,8 @@ private:
OpenGLBackend backend_;
qint64 job_time_;
};
OLIVE_NAMESPACE_EXIT