diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index dc69b88c3..3a1d69611 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -39,6 +39,8 @@ AudioPlaybackCache::AudioPlaybackCache() void AudioPlaybackCache::SetParameters(const AudioRenderingParams ¶ms) { + QMutexLocker locker(lock()); + if (params_ == params) { return; } @@ -52,13 +54,19 @@ void AudioPlaybackCache::SetParameters(const AudioRenderingParams ¶ms) } // Our current audio cache is unusable, so we truncate it automatically - InvalidateAll(); + TimeRange invalidate_range(0, NoLockGetLength()); + NoLockInvalidate(invalidate_range); + + locker.unlock(); emit ParametersChanged(); + emit Invalidated(invalidate_range); } void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr samples) { + QMutexLocker locker(lock()); + QFile f(filename_); if (f.open(QFile::ReadWrite)) { qint64 start_offset = params_.time_to_bytes(range.in()); @@ -82,7 +90,11 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr sample f.close(); - Validate(range); + NoLockValidate(range); + + locker.unlock(); + + emit Validated(range); } else { qWarning() << "Failed to write PCM data to" << filename_; } @@ -90,6 +102,8 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr sample void AudioPlaybackCache::WriteSilence(const TimeRange &range) { + QMutexLocker locker(lock()); + QFile f(filename_); if (f.open(QFile::ReadWrite)) { qint64 start_offset = params_.time_to_bytes(range.in()); diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 1f7a97217..e3c01d5ec 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -33,7 +33,8 @@ class AudioPlaybackCache : public PlaybackCache public: AudioPlaybackCache(); - const AudioRenderingParams& GetParameters() const { + AudioRenderingParams GetParameters() { + QMutexLocker locker(lock()); return params_; } diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index c49378736..52b86bb26 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -34,25 +34,39 @@ OLIVE_NAMESPACE_ENTER -QByteArray FrameHashCache::GetHash(const rational &time) const +QByteArray FrameHashCache::GetHash(const rational &time) { + QMutexLocker locker(lock()); + return time_hash_map_.value(time); } void FrameHashCache::SetHash(const rational &time, const QByteArray &hash) { + QMutexLocker locker(lock()); + time_hash_map_.insert(time, hash); - Validate(TimeRange(time, time + timebase_)); + TimeRange validated_range(time, time + timebase_); + + NoLockValidate(validated_range); + + locker.unlock(); + + emit Validated(validated_range); } void FrameHashCache::SetTimebase(const rational &tb) { + QMutexLocker locker(lock()); + timebase_ = tb; } -QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) const +QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) { + QMutexLocker locker(lock()); + QList times; QMap::const_iterator iterator; @@ -68,6 +82,8 @@ QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) const QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) { + QMutexLocker locker(lock()); + QList times; QMap::iterator iterator = time_hash_map_.begin(); @@ -82,11 +98,23 @@ QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) } } + foreach (const rational& r, times) { + NoLockInvalidate(TimeRange(r, r + timebase_)); + } + + locker.unlock(); + + foreach (const rational& r, times) { + emit Invalidated(TimeRange(r, r + timebase_)); + } + return times; } -const QMap &FrameHashCache::time_hash_map() const +QMap FrameHashCache::time_hash_map() { + QMutexLocker locker(lock()); + return time_hash_map_; } @@ -130,14 +158,18 @@ QList FrameHashCache::GetFrameListFromTimeRange(TimeRangeList range_li return times; } -QList FrameHashCache::GetFrameListFromTimeRange(const TimeRangeList &range) const +QList FrameHashCache::GetFrameListFromTimeRange(const TimeRangeList &range) { + QMutexLocker locker(lock()); + return GetFrameListFromTimeRange(range, timebase_); } -QList FrameHashCache::GetInvalidatedFrames() const +QList FrameHashCache::GetInvalidatedFrames() { - return GetFrameListFromTimeRange(GetInvalidatedRanges()); + QMutexLocker locker(lock()); + + return GetFrameListFromTimeRange(NoLockGetInvalidatedRanges()); } void FrameHashCache::SaveCacheFrame(const QByteArray& hash, diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index e87db2304..927437623 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -37,7 +37,7 @@ class FrameHashCache : public PlaybackCache public: FrameHashCache() = default; - QByteArray GetHash(const rational& time) const; + QByteArray GetHash(const rational& time); void SetHash(const rational& time, const QByteArray& hash); @@ -46,14 +46,14 @@ public: /** * @brief Returns a list of frames that use a particular hash */ - QList GetFramesWithHash(const QByteArray& hash) const; + QList GetFramesWithHash(const QByteArray& hash); /** * @brief Same as FramesWithHash() but also removes these frames from the map */ QList TakeFramesWithHash(const QByteArray& hash); - const QMap& time_hash_map() const; + QMap time_hash_map(); /** * @brief Return the path of the cached image at this time @@ -67,8 +67,8 @@ public: static QString GetFormatExtension(const PixelFormat::Format& f); static QList GetFrameListFromTimeRange(TimeRangeList range_list, const rational& timebase); - QList GetFrameListFromTimeRange(const TimeRangeList &range) const; - QList GetInvalidatedFrames() const; + QList GetFrameListFromTimeRange(const TimeRangeList &range); + QList GetInvalidatedFrames(); protected: virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 2ef2b1e87..0a826fc54 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -22,21 +22,93 @@ OLIVE_NAMESPACE_ENTER -PlaybackCache::PlaybackCache() -{ - -} - void PlaybackCache::Invalidate(const TimeRange &r) { - invalidated_.InsertTimeRange(r); + QMutexLocker locker(&lock_); - InvalidateEvent(r); + NoLockInvalidate(r); + + locker.unlock(); emit Invalidated(r); } +void PlaybackCache::InvalidateAll() +{ + QMutexLocker locker(&lock_); + + TimeRange invalidate_range(0, length_); + + NoLockInvalidate(invalidate_range); + + locker.unlock(); + + emit Invalidated(invalidate_range); +} + void PlaybackCache::SetLength(const rational &r) +{ + QMutexLocker locker(&lock_); + + NoLockSetLength(r); +} + +void PlaybackCache::Shift(const rational &from, const rational &to) +{ + QMutexLocker locker(&lock_); + + // 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 + TimeRange invalidate_range(from, to); + + NoLockInvalidate(invalidate_range); + + locker.unlock(); + + emit Invalidated(invalidate_range); + } +} + +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); + + InvalidateEvent(r); +} + +void PlaybackCache::NoLockValidate(const TimeRange &r) +{ + invalidated_.RemoveTimeRange(r); +} + +void PlaybackCache::NoLockSetLength(const rational &r) { if (length_ == r) { // Same length - do nothing @@ -56,47 +128,6 @@ void PlaybackCache::SetLength(const rational &r) length_ = r; } -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); - - emit Validated(r); -} - -void PlaybackCache::InvalidateAll() -{ - Invalidate(TimeRange(0, length_)); -} - void PlaybackCache::LengthChangedEvent(const rational &, const rational &) { } diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 7e48d4283..566f5d6a6 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -21,6 +21,7 @@ #ifndef PLAYBACKCACHE_H #define PLAYBACKCACHE_H +#include #include #include "common/timerange.h" @@ -31,30 +32,41 @@ class PlaybackCache : public QObject { Q_OBJECT public: - PlaybackCache(); + PlaybackCache() = default; void Invalidate(const TimeRange& r); void InvalidateAll(); - const rational& GetLength() const + const rational& GetLength() { - return length_; + QMutexLocker locker(lock()); + + return NoLockGetLength(); } void SetLength(const rational& r); - bool IsFullyValidated() const; + bool IsFullyValidated() + { + QMutexLocker locker(lock()); + + return invalidated_.isEmpty(); + } void Shift(const rational& from, const rational& to); - const TimeRangeList& GetInvalidatedRanges() const + const TimeRangeList& GetInvalidatedRanges() { - return invalidated_; + QMutexLocker locker(lock()); + + return NoLockGetInvalidatedRanges(); } - bool HasInvalidatedRanges() const + bool HasInvalidatedRanges() { + QMutexLocker locker(lock()); + return !invalidated_.isEmpty(); } @@ -68,13 +80,36 @@ signals: protected: void Validate(const TimeRange& r); + void NoLockInvalidate(const TimeRange& r); + + void NoLockValidate(const TimeRange& r); + + void NoLockSetLength(const rational& r); + + const rational& NoLockGetLength() const + { + return length_; + } + + const TimeRangeList& NoLockGetInvalidatedRanges() + { + return invalidated_; + } + virtual void LengthChangedEvent(const rational& old, const rational& newlen); virtual void InvalidateEvent(const TimeRange& range); virtual void ShiftEvent(const rational& from, const rational& to); + QMutex* lock() + { + return &lock_; + } + private: + QMutex lock_; + TimeRangeList invalidated_; rational length_;