From 38c38daf8a2bf82ced70b67f0baf3c4477ac6374 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 10 Jul 2021 15:37:06 -0700 Subject: [PATCH] framehashcache: use timestamp based vector internally I think this will be significantly faster, but I guess we'll find out! --- app/render/framehashcache.cpp | 125 +++++++++++++++++----------------- app/render/framehashcache.h | 19 +++++- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index 21b087086..84857614d 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -32,7 +32,6 @@ #include "codec/frame.h" #include "common/filefunctions.h" -#include "common/timecodefunctions.h" #include "render/diskmanager.h" namespace olive { @@ -52,9 +51,18 @@ FrameHashCache::FrameHashCache(QObject *parent) : } } +QByteArray FrameHashCache::GetHash(const int64_t &time) +{ + if (time < GetMapSize()) { + return time_hash_map_.at(time); + } else { + return QByteArray(); + } +} + QByteArray FrameHashCache::GetHash(const rational &time) { - return time_hash_map_.value(time); + return GetHash(ToTimestamp(time)); } void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const qint64& job_time, bool frame_exists) @@ -69,7 +77,15 @@ void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const } } - time_hash_map_.insert(time, hash); + int64_t ts = ToTimestamp(time); + if (ts >= GetMapSize()) { + // Reserve an extra minute to cut down on the amount of reallocations to make + time_hash_map_.reserve(ts + timebase_.flipped().toDouble() * 60); + + // Add enough entries to insert this hash + time_hash_map_.resize(ts + 1); + } + time_hash_map_[ts] = hash; TimeRange validated_range; if (frame_exists) { @@ -87,9 +103,9 @@ void FrameHashCache::ValidateFramesWithHash(const QByteArray &hash) { const TimeRangeList& invalidated_ranges = GetInvalidatedRanges(); - for (auto iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { - if (iterator.value() == hash) { - TimeRange frame_range(iterator.key(), iterator.key() + timebase_); + for (int64_t i=0; i FrameHashCache::GetFramesWithHash(const QByteArray &hash) { QList times; - for (auto iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { - if (iterator.value() == hash) { - times.append(iterator.key()); + for (int64_t i=0; i FrameHashCache::TakeFramesWithHash(const QByteArray &hash) TimeRangeList range_to_invalidate; QList times; - auto iterator = time_hash_map_.begin(); + for (int64_t i=0; i FrameHashCache::TakeFramesWithHash(const QByteArray &hash) return times; } -QMap FrameHashCache::time_hash_map() -{ - return time_hash_map_; -} - QVector FrameHashCache::GetFrameListFromTimeRange(TimeRangeList range_list, const rational &timebase) { // If timebase is null, this will be an infinite loop @@ -316,15 +324,11 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn) void FrameHashCache::LengthChangedEvent(const rational &old, const rational &newlen) { if (newlen < old) { - auto i = time_hash_map_.begin(); + // Determine length in frames by ceil-ing the time + int64_t new_ts_length = ToTimestamp(newlen, Timecode::kCeil); - while (i != time_hash_map_.end()) { - if (i.key() >= newlen) { - i = time_hash_map_.erase(i); - } else { - i++; - } - } + // Resize vector to this length, which will discard all frames after it + time_hash_map_.resize(new_ts_length); } } @@ -335,51 +339,48 @@ struct HashTimePair { void FrameHashCache::ShiftEvent(const rational &from, const rational &to) { - auto i = time_hash_map_.begin(); - // POSITIVE if moving forward -> // NEGATIVE if moving backward <- rational diff = to - from; bool diff_is_negative = (diff < 0); - 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++; + int64_t to_ts = ToTimestamp(to); + int64_t from_ts = ToTimestamp(from); + if (diff_is_negative) { + // We're moving the frames starting at `from` backwards to where `to` is + if (to_ts < GetMapSize()) { + time_hash_map_.erase(time_hash_map_.begin() + to_ts, time_hash_map_.begin() + from_ts); + } + } else { + // We're moving the frames starting at `from` forwards to where `to` is + if (from_ts < GetMapSize()) { + time_hash_map_.insert(time_hash_map_.begin() + from_ts, to_ts - from_ts, QByteArray()); } - } - - foreach (const HashTimePair& p, shifted_times) { - time_hash_map_.insert(p.time, p.hash); } } void FrameHashCache::InvalidateEvent(const TimeRange &range) { if (!timebase_.isNull()) { - QVector invalid_frames = GetFrameListFromTimeRange({range}); - - foreach (const rational& r, invalid_frames) { - time_hash_map_.remove(r); + int64_t start = ToTimestamp(range.in(), Timecode::kCeil); + int64_t end = ToTimestamp(range.out(), Timecode::kCeil); + for (int64_t i=start; i #include "common/rational.h" +#include "common/timecodefunctions.h" #include "common/timerange.h" #include "codec/frame.h" #include "render/playbackcache.h" @@ -37,8 +38,14 @@ class FrameHashCache : public PlaybackCache public: FrameHashCache(QObject* parent = nullptr); + QByteArray GetHash(const int64_t& time); QByteArray GetHash(const rational& time); + const rational &GetTimebase() const + { + return timebase_; + } + void SetTimebase(const rational& tb); void ValidateFramesWithHash(const QByteArray& hash); @@ -76,7 +83,7 @@ public: QVector GetInvalidatedFrames(const TimeRange& intersecting); public slots: - void SetHash(const olive::rational& time, const QByteArray& hash, const qint64 &job_time, bool frame_exists); + void SetHash(const olive::rational &time, const QByteArray& hash, const qint64 &job_time, bool frame_exists); protected: virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; @@ -86,7 +93,15 @@ protected: virtual void InvalidateEvent(const TimeRange& range) override; private: - QMap time_hash_map_; + rational ToTime(const int64_t &ts) const; + int64_t ToTimestamp(const rational &ts, Timecode::Rounding rounding = Timecode::kRound) const; + + int64_t GetMapSize() const + { + return int64_t(time_hash_map_.size()); + } + + std::vector time_hash_map_; rational timebase_;