From 11bfe6120891cef0485c00796db9e706ecd37ee0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 2 Jun 2020 00:52:55 +1000 Subject: [PATCH] cache: began base implementation of "shifting" the cache Should be a fairly important optimization to make. --- app/node/output/viewer/viewer.cpp | 6 +++ app/node/output/viewer/viewer.h | 2 + app/render/audioplaybackcache.cpp | 68 +++++++++++++++++++++++++++++++ app/render/audioplaybackcache.h | 3 ++ app/render/framehashcache.cpp | 41 +++++++++++++++++++ app/render/framehashcache.h | 2 + app/render/playbackcache.cpp | 28 +++++++++++++ app/render/playbackcache.h | 4 ++ 8 files changed, 154 insertions(+) diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index f8da01579..0ef6ac163 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -87,6 +87,12 @@ QString ViewerOutput::Description() const return tr("Interface between a Viewer panel and the node system."); } +void ViewerOutput::ShiftCache(const rational &from, const rational &to) +{ + video_frame_cache_.Shift(from, to); + audio_playback_cache_.Shift(from, to); +} + void ViewerOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source) { emit GraphChangedFrom(source); diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 31c9dab8d..aab99fda6 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -54,6 +54,8 @@ public: virtual QList Category() const override; virtual QString Description() const override; + void ShiftCache(const rational& from, const rational& to); + NodeInput* texture_input() const { return texture_input_; } diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index 6aa389318..dc69b88c3 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -111,6 +111,74 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range) } } +void AudioPlaybackCache::ShiftEvent(const rational &from, const rational &to) +{ + QFile f(filename_); + if (f.open(QFile::ReadWrite)) { + qint64 from_offset = params_.time_to_bytes(from); + qint64 to_offset = params_.time_to_bytes(to); + qint64 chunk = qAbs(to_offset - from_offset); + + QByteArray buf(chunk, Qt::Uninitialized); + + if (to > from) { + // Shifting forwards, we must insert a new region and shift all the bytes there + + // For shifting forwards, we copy bytes starting at the back so that bytes we need don't + // get overwritten. + qint64 read_offset = f.size(); + + f.resize(f.size() + chunk); + + qint64 write_offset = f.size(); + + do { + + // Calculate how much will be read this time + qint64 chunk_sz = qMin(chunk, read_offset - from_offset); + read_offset -= chunk_sz; + + // Read that chunk + f.seek(read_offset); + f.read(buf.data(), chunk_sz); + + // Write it at the destination + write_offset -= chunk_sz; + f.seek(write_offset); + f.write(buf.data(), chunk_sz); + + } while (read_offset != from_offset); + + // Replace remainder with silence + f.seek(from_offset); + buf.fill(0); + f.write(buf); + + } else { + // Shifting backwards, we will shift bytes and truncate + + do { + // Read region to be shifted + f.seek(from_offset); + qint64 read_sz = f.read(buf.data(), buf.size()); + from_offset += read_sz; + + // Write it at the destination + f.seek(to_offset); + to_offset += f.write(buf, read_sz); + } while (from_offset != f.size()); + + // Truncate + f.resize(f.size() - chunk); + + } + + f.close(); + } else { + qWarning() << "Failed to write PCM data to" << filename_; + } +} + const QString &AudioPlaybackCache::GetCacheFilename() const { return filename_; diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 71c633af9..1f7a97217 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -48,6 +48,9 @@ public: signals: void ParametersChanged(); +protected: + virtual void ShiftEvent(const rational& from, const rational& to) override; + private: QString filename_; diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index c7429749c..c49378736 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -185,6 +185,47 @@ void FrameHashCache::InvalidateEvent(const TimeRange &r) } } +struct HashTimePair { + rational time; + QByteArray hash; +}; + +void FrameHashCache::ShiftEvent(const rational &from, const rational &to) +{ + QMap::iterator i = time_hash_map_.begin(); + + // POSITIVE if moving forward -> + // NEGATIVE if moving backward <- + rational diff = to - from; + bool diff_is_negative = (diff < rational()); + + QList shifted_times; + + while (i != time_hash_map_.end()) { + if (diff_is_negative && i.key() >= to && i.key() < from) { + + // This time will be removed in the shift so we just discard it + i = time_hash_map_.erase(i); + + } else if (i.key() >= from) { + + // This time is after the from time and must be shifted + shifted_times.append({i.key() + diff, i.value()}); + i = time_hash_map_.erase(i); + + } else { + + // Do nothing + i++; + + } + } + + foreach (const HashTimePair& p, shifted_times) { + time_hash_map_.insert(p.time, p.hash); + } +} + QString FrameHashCache::CachePathName(const QByteArray& hash, const PixelFormat::Format& pix_fmt) { QString ext = GetFormatExtension(pix_fmt); diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index 0cc19c888..e87db2304 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -75,6 +75,8 @@ protected: virtual void InvalidateEvent(const TimeRange& range) override; + virtual void ShiftEvent(const rational& from, const rational& to) override; + private: QMap time_hash_map_; diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 3220422c1..2ef2b1e87 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -61,6 +61,30 @@ bool PlaybackCache::IsFullyValidated() const return invalidated_.isEmpty(); } +void PlaybackCache::Shift(const rational &from, const rational &to) +{ + // An region between `from` and `to` will be inserted or spliced out + TimeRangeList ranges_to_shift = invalidated_.Intersects(TimeRange(from, RATIONAL_MAX)); + + // Remove everything from the minimum point + invalidated_.RemoveTimeRange(TimeRange(qMin(from, to), RATIONAL_MAX)); + + // Shift everything in our ranges to shift list + // + // `diff` is POSITIVE when moving forward -> and NEGATIVE when moving backward <- + rational diff = to - from; + foreach (const TimeRange& r, ranges_to_shift) { + invalidated_.InsertTimeRange(r + diff); + } + + ShiftEvent(from, to); + + if (diff > rational()) { + // If shifting forward, add this section to the invalidated region + Invalidate(TimeRange(from, to)); + } +} + void PlaybackCache::Validate(const TimeRange &r) { invalidated_.RemoveTimeRange(r); @@ -81,4 +105,8 @@ void PlaybackCache::InvalidateEvent(const TimeRange &) { } +void PlaybackCache::ShiftEvent(const rational &, const rational &) +{ +} + OLIVE_NAMESPACE_EXIT diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 2961fe103..7e48d4283 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -46,6 +46,8 @@ public: bool IsFullyValidated() const; + void Shift(const rational& from, const rational& to); + const TimeRangeList& GetInvalidatedRanges() const { return invalidated_; @@ -70,6 +72,8 @@ protected: virtual void InvalidateEvent(const TimeRange& range); + virtual void ShiftEvent(const rational& from, const rational& to); + private: TimeRangeList invalidated_;