From 4bbc75392a6da1b675266af573304a28836c51c5 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 15 Jul 2021 21:00:18 -0700 Subject: [PATCH] nodes: rewrote and simplified length signaling system --- app/node/block/block.cpp | 26 ++++- app/node/block/block.h | 4 + app/node/block/clip/clip.cpp | 6 +- app/node/block/clip/clip.h | 2 +- app/node/node.cpp | 8 +- app/node/node.h | 10 +- app/node/output/track/track.cpp | 61 +++--------- app/node/output/track/track.h | 10 +- app/node/output/viewer/viewer.cpp | 10 +- app/node/output/viewer/viewer.h | 8 +- app/render/audioplaybackcache.cpp | 34 +------ app/render/audioplaybackcache.h | 2 - app/render/framehashcache.cpp | 13 +-- app/render/framehashcache.h | 4 - app/render/playbackcache.cpp | 110 ++++++++------------- app/render/playbackcache.h | 42 +++----- app/task/precache/precachetask.cpp | 11 ++- app/widget/timelinewidget/timelineundo.cpp | 8 +- app/widget/timelinewidget/timelineundo.h | 9 +- app/widget/timeruler/timeruler.cpp | 11 ++- 20 files changed, 148 insertions(+), 241 deletions(-) diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 47fecec22..646736ccf 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -22,6 +22,7 @@ #include +#include "core.h" #include "node/output/track/track.h" #include "transition/transition.h" #include "widget/slider/floatslider.h" @@ -29,6 +30,8 @@ namespace olive { +#define super Node + const QString Block::kLengthInput = QStringLiteral("length_in"); const QString Block::kMediaInInput = QStringLiteral("media_in_in"); const QString Block::kEnabledInput = QStringLiteral("enabled_in"); @@ -47,7 +50,6 @@ Block::Block() : SetInputProperty(kLengthInput, QStringLiteral("min"), QVariant::fromValue(rational(0, 1))); SetInputProperty(kLengthInput, QStringLiteral("view"), RationalSlider::kTime); SetInputProperty(kLengthInput, QStringLiteral("viewlock"), true); - IgnoreInvalidationsFrom(kLengthInput); IgnoreHashingFrom(kLengthInput); AddInput(kMediaInInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); @@ -221,7 +223,7 @@ void Block::set_length_internal(const rational &length) void Block::Retranslate() { - Node::Retranslate(); + super::Retranslate(); SetInputName(kLengthInput, tr("Length")); SetInputName(kMediaInInput, tr("Media In")); @@ -235,4 +237,24 @@ void Block::Hash(const QString &, QCryptographicHash &, const rational &, const // A block does nothing by default, so we hash nothing } +void Block::InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) +{ + TimeRange r; + + if (from == kLengthInput) { + // We must intercept the signal here + r = TimeRange(qMin(length(), last_length_), RATIONAL_MAX); + + if (!Core::instance()->EffectsSliderIsBeingDragged()) { + last_length_ = length(); + } + + options.insert(QStringLiteral("lengthevent"), true); + } else { + r = range; + } + + super::InvalidateCache(r, from, element, options); +} + } diff --git a/app/node/block/block.h b/app/node/block/block.h index f8c6ab8ed..7593b1a81 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -155,6 +155,8 @@ public: virtual void Hash(const QString& output, QCryptographicHash &hash, const rational &time, const VideoParams& video_params) const override; + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1, InvalidateCacheOptions options = InvalidateCacheOptions()) override; + static const QString kLengthInput; static const QString kMediaInInput; static const QString kEnabledInput; @@ -193,6 +195,8 @@ private: QVector block_links_; + rational last_length_; + }; } diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index d6b66b1ad..7db010721 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -53,7 +53,7 @@ QString ClipBlock::Description() const return tr("A time-based node that represents a media source."); } -void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int element) +void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) { Q_UNUSED(element) @@ -63,10 +63,10 @@ void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int rational start = MediaToSequenceTime(range.in()); rational end = MediaToSequenceTime(range.out()); - super::InvalidateCache(TimeRange(start, end), from, element); + super::InvalidateCache(TimeRange(start, end), from, element, options); } else { // Otherwise, pass signal along normally - super::InvalidateCache(range, from, element); + super::InvalidateCache(range, from, element, options); } } diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index e5d7ecbbe..c81d3b510 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -42,7 +42,7 @@ public: virtual QString id() const override; virtual QString Description() const override; - virtual void InvalidateCache(const TimeRange& range, const QString& from, int element) override; + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override; virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override; diff --git a/app/node/node.cpp b/app/node/node.cpp index 19294529a..f758b849a 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1019,12 +1019,12 @@ NodeValueTable Node::Value(const QString& output, NodeValueDatabase &value) cons return value.Merge(); } -void Node::InvalidateCache(const TimeRange &range, const QString &from, int element) +void Node::InvalidateCache(const TimeRange &range, const QString &from, int element, InvalidateCacheOptions options) { Q_UNUSED(from) Q_UNUSED(element) - SendInvalidateCache(range); + SendInvalidateCache(range, options); } void Node::BeginOperation() @@ -1173,14 +1173,14 @@ Node *Node::CopyNodeInGraph(const Node *node, MultiUndoCommand *command) return copy; } -void Node::SendInvalidateCache(const TimeRange &range) +void Node::SendInvalidateCache(const TimeRange &range, const InvalidateCacheOptions &options) { if (GetOperationStack() == 0) { for (const OutputConnection& conn : output_connections_) { // Send clear cache signal to the Node const NodeInput& in = conn.second; - in.node()->InvalidateCache(range, in.input(), in.element()); + in.node()->InvalidateCache(range, in.input(), in.element(), options); } } } diff --git a/app/node/node.h b/app/node/node.h index 939bc37d0..5cb8d13b1 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -623,6 +623,8 @@ public: */ static T* ValueToPtr(const QVariant& ptr); + using InvalidateCacheOptions = QHash; + /** * @brief Signal all dependent Nodes that anything cached between start_range and end_range is now invalid and * requires re-rendering @@ -632,11 +634,11 @@ public: * the DAG. Even if the time needs to be transformed somehow (e.g. converting media time to sequence time), you can * call this function with transformed time and relay the signal that way. */ - virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1); + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1, InvalidateCacheOptions options = InvalidateCacheOptions()); - void InvalidateCache(const TimeRange& range, const NodeInput& from) + void InvalidateCache(const TimeRange& range, const NodeInput& from, const InvalidateCacheOptions &options = InvalidateCacheOptions()) { - InvalidateCache(range, from.input(), from.element()); + InvalidateCache(range, from.input(), from.element(), options); } /** @@ -882,7 +884,7 @@ protected: SetInputProperty(id, QStringLiteral("combo_str"), strings); } - void SendInvalidateCache(const TimeRange &range); + void SendInvalidateCache(const TimeRange &range, const InvalidateCacheOptions &options); /** * @brief Don't send cache invalidation signals if `input` is connected or disconnected diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 3a79d8001..4632b1ca4 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -41,8 +41,6 @@ const QString Track::kMutedInput = QStringLiteral("muted_in"); Track::Track() : track_type_(Track::kNone), track_length_(0), - midop_track_length_(0), - preop_track_length_(0), index_(-1), locked_(false) { @@ -431,7 +429,7 @@ QVector Track::BlocksAtTimeRange(const TimeRange &range) const return list; } -void Track::InvalidateCache(const TimeRange& range, const QString& from, int element) +void Track::InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) { if (GetOperationStack() != 0) { return; @@ -443,7 +441,8 @@ void Track::InvalidateCache(const TimeRange& range, const QString& from, int ele if (from == kBlockInput && element >= 0 - && (b = dynamic_cast(GetConnectedOutput(from, element).node()))) { + && (b = dynamic_cast(GetConnectedOutput(from, element).node())) + && !options.value(QStringLiteral("lengthevent")).toBool()) { // Limit the range signal to the corresponding block if (range.out() <= b->in() || range.in() >= b->out()) { return; @@ -451,11 +450,14 @@ void Track::InvalidateCache(const TimeRange& range, const QString& from, int ele limited = TimeRange(qMax(range.in(), b->in()), qMin(range.out(), b->out())); } else { - limited = TimeRange(qMax(range.in(), rational(0)), qMin(range.out(), qMax(preop_track_length_, track_length()))); - preop_track_length_ = track_length_; + limited = range; } - Node::InvalidateCache(limited, from, element); + // NOTE: For now, I figure we drop this key, but we may find in the future that it's advantageous + // to keep it + options.remove(QStringLiteral("lengthevent")); + + Node::InvalidateCache(limited, from, element, options); } void Track::InsertBlockBefore(Block* block, Block* after) @@ -600,15 +602,6 @@ void Track::Hash(const QString &output, QCryptographicHash &hash, const rational } } -void Track::EndOperation() -{ - super::EndOperation(); - - if (track_length_ != midop_track_length_) { - SetLengthInternal(midop_track_length_); - } -} - void Track::SetMuted(bool e) { SetStandardValue(kMutedInput, e); @@ -658,21 +651,10 @@ int Track::GetCacheIndexFromArrayIndex(int index) const return block_array_indexes_.indexOf(index); } -void Track::SetLengthInternal(const rational &r, bool invalidate) +void Track::SetLengthInternal(const rational &r) { - // Hold track length until operation stack is empty - midop_track_length_ = r; - - if (GetOperationStack() == 0 && track_length_ != r) { - TimeRange invalidate_range(track_length_, r); - track_length_ = r; - preop_track_length_ = qMax(preop_track_length_, track_length_); - emit TrackLengthChanged(); - - if (invalidate) { - Node::InvalidateCache(invalidate_range, kBlockInput); - } - } + track_length_ = r; + emit TrackLengthChanged(); } void Track::BlockLengthChanged() @@ -680,26 +662,7 @@ void Track::BlockLengthChanged() // Assumes sender is a Block Block* b = static_cast(sender()); - rational old_out = b->out(); - UpdateInOutFrom(blocks_.indexOf(b)); - - rational new_out = b->out(); - - TimeRange invalidate_region(qMin(old_out, new_out), track_length()); - - // The cache won't start while dragging, so we store up our invalidations if it's held down - // and release them once the mouse is no longer pressed - if (qApp->mouseButtons() & Qt::LeftButton) { - block_length_pending_invalidations_.insert(invalidate_region); - } else if (!block_length_pending_invalidations_.isEmpty()) { - foreach (const TimeRange& r, block_length_pending_invalidations_) { - Node::InvalidateCache(r, kBlockInput); - } - block_length_pending_invalidations_.clear(); - } - - Node::InvalidateCache(invalidate_region, kBlockInput); } uint qHash(const Track::Reference &r, uint seed) diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index ee31c3da6..bcd1b8418 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -286,7 +286,7 @@ public: return blocks_; } - virtual void InvalidateCache(const TimeRange& range, const QString& from, int element) override; + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override; /** * @brief Adds Block `block` at the very beginning of the Sequence before all other clips @@ -345,8 +345,6 @@ public: return waveform_; } - virtual void EndOperation() override; - static const double kTrackHeightDefault; static const double kTrackHeightMinimum; static const double kTrackHeightInterval; @@ -420,7 +418,7 @@ private: int GetCacheIndexFromArrayIndex(int index) const; - void SetLengthInternal(const rational& r, bool invalidate = true); + void SetLengthInternal(const rational& r); TimeRangeList block_length_pending_invalidations_; @@ -431,10 +429,6 @@ private: rational track_length_; - rational midop_track_length_; - - rational preop_track_length_; - double track_height_; int index_; diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 3b0fd9356..910480576 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -222,7 +222,7 @@ void ViewerOutput::ShiftCache(const rational &from, const rational &to) ShiftAudioCache(from, to); } -void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from, int element) +void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) { Q_UNUSED(element) @@ -242,7 +242,7 @@ void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from, VerifyLength(); - super::InvalidateCache(range, from, element); + super::InvalidateCache(range, from, element, options); } QVector ViewerOutput::inputs_for_output(const QString &output) const @@ -300,14 +300,8 @@ void ViewerOutput::Retranslate() void ViewerOutput::VerifyLength() { video_length_ = VerifyLengthInternal(Track::kVideo); - if (video_cache_enabled_) { - video_frame_cache_.SetLength(video_length_); - } audio_length_ = VerifyLengthInternal(Track::kAudio); - if (audio_cache_enabled_) { - audio_playback_cache_.SetLength(audio_length_); - } rational subtitle_length = VerifyLengthInternal(Track::kSubtitle); diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 9891829cd..df5fda49d 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -66,7 +66,7 @@ public: void ShiftAudioCache(const rational& from, const rational& to); void ShiftCache(const rational& from, const rational& to); - virtual void InvalidateCache(const TimeRange& range, const QString& from, int element) override; + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override; virtual QVector inputs_for_output(const QString& output) const override; @@ -154,6 +154,9 @@ public: virtual NodeOutput GetConnectedSampleOutput(); + void SetViewerVideoCacheEnabled(bool e) { video_cache_enabled_ = e; } + void SetViewerAudioCacheEnabled(bool e) { audio_cache_enabled_ = e; } + static const QString kVideoParamsInput; static const QString kAudioParamsInput; @@ -202,9 +205,6 @@ protected: int AddStream(Track::Type type, const QVariant &value); - void SetViewerVideoCacheEnabled(bool e) { video_cache_enabled_ = e; } - void SetViewerAudioCacheEnabled(bool e) { audio_cache_enabled_ = e; } - private: rational last_length_; rational video_length_; diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index 50e004ad4..0f9a1183a 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -166,14 +166,13 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range) void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational &to_in_time) { - if (from_in_time == to_in_time || from_in_time >= GetLength()) { - // Nothing to be done - return; - } - qint64 to = params_.time_to_bytes_per_channel(to_in_time); qint64 from = params_.time_to_bytes_per_channel(from_in_time); + if (from >= playlist_.GetLength()) { + return; + } + int to_seg_index = playlist_.GetIndexOfPosition(to); int from_seg_index = playlist_.GetIndexOfPosition(from); @@ -265,31 +264,6 @@ void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational } } -void AudioPlaybackCache::LengthChangedEvent(const rational& old, const rational& newlen) -{ - Q_UNUSED(old) - - if (!params_.is_valid()) { - return; - } - - qint64 new_len_in_bytes = params_.time_to_bytes_per_channel(newlen); - - while (new_len_in_bytes < playlist_.GetLength()) { - Segment& last_seg = playlist_.back(); - - if (playlist_.GetLength() - last_seg.size() < new_len_in_bytes) { - // Truncate this segment rather than removing it - qint64 diff = playlist_.GetLength() - new_len_in_bytes; - - TrimSegmentOut(&last_seg, last_seg.size() - diff); - } else { - // Remove last segment - RemoveSegmentFromArray(playlist_.size() - 1); - } - } -} - AudioPlaybackCache::Segment AudioPlaybackCache::CloneSegment(const AudioPlaybackCache::Segment &s) const { Segment new_seg = s; diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 9bbe8717f..4e4bc76de 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -202,8 +202,6 @@ signals: protected: virtual void ShiftEvent(const rational& from, const rational& to) override; - virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; - private: static const qint64 kDefaultSegmentSizePerChannel; diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index 4922afcba..6317e4a7a 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -92,7 +92,7 @@ void FrameHashCache::SetTimebase(const rational &tb) void FrameHashCache::ValidateFramesWithHash(const QByteArray &hash) { - const TimeRangeList& invalidated_ranges = GetInvalidatedRanges(); + auto invalidated_ranges = GetInvalidatedRanges(ToTime(GetMapSize())); for (int64_t i=0; i time_hash_map(); - /** * @brief Return the path of the cached image at this time */ @@ -70,8 +68,6 @@ public: void SetHash(const olive::rational &time, const QByteArray& hash, bool frame_exists); protected: - virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; - virtual void ShiftEvent(const rational& from, const rational& to) override; virtual void InvalidateEvent(const TimeRange& range) override; diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 73cb827aa..1f50f736d 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -27,58 +27,25 @@ namespace olive { -void PlaybackCache::Invalidate(const TimeRange &r) +void PlaybackCache::Invalidate(const TimeRange &r, bool signal) { if (r.in() == r.out()) { qWarning() << "Tried to invalidate zero-length range"; return; } - invalidated_.insert(r); + validated_.remove(r); InvalidateEvent(r); - emit Invalidated(r); + if (signal) { + emit Invalidated(r); + } } void PlaybackCache::InvalidateAll() { - if (length_.isNull()) { - return; - } - - Invalidate(TimeRange(0, length_)); -} - -void PlaybackCache::SetLength(const rational &r) -{ - if (length_ == r) { - // Same length - do nothing - return; - } - - LengthChangedEvent(length_, r); - - TimeRange range_diff(length_, r); - - if (r.isNull()) { - invalidated_.clear(); - } else if (r > length_) { - // If new length is greater, simply extend the invalidated range for now - invalidated_.insert(range_diff); - } else { - // If new length is smaller, removed hashes - invalidated_.remove(range_diff); - } - - rational old_length = length_; - length_ = r; - - if (r > old_length) { - emit Invalidated(range_diff); - } else { - emit Validated(range_diff); - } + Invalidate(TimeRange(0, RATIONAL_MAX)); } void PlaybackCache::Shift(rational from, rational to) @@ -87,54 +54,33 @@ void PlaybackCache::Shift(rational from, rational to) return; } - if (from > length_) { - if (to > from) { - // No-op - return; - } else if (to >= length_) { - // No-op - return; - } else { - from = length_; - } - } - // An region between `from` and `to` will be inserted or spliced out - TimeRangeList ranges_to_shift = invalidated_.Intersects(TimeRange(from, RATIONAL_MAX)); + TimeRangeList ranges_to_shift = validated_.Intersects(TimeRange(from, RATIONAL_MAX)); // Remove everything from the minimum point TimeRange remove_range = TimeRange(qMin(from, to), RATIONAL_MAX); - Validate(remove_range); + Invalidate(remove_range, false); // Shift invalidated ranges // (`diff` is POSITIVE when moving forward -> and NEGATIVE when moving backward <-) rational diff = to - from; foreach (const TimeRange& r, ranges_to_shift) { - Invalidate(r + diff); + Validate(r + diff, false); } ShiftEvent(from, to); - length_ += diff; - - if (diff > 0) { - // If shifting forward, add this section to the invalidated region - Invalidate(TimeRange(from, to)); - } - // Emit signals emit Shifted(from, to); } -void PlaybackCache::Validate(const TimeRange &r) +void PlaybackCache::Validate(const TimeRange &r, bool signal) { - invalidated_.remove(r); + validated_.insert(r); - emit Validated(r); -} - -void PlaybackCache::LengthChangedEvent(const rational &, const rational &) -{ + if (signal) { + emit Validated(r); + } } void PlaybackCache::InvalidateEvent(const TimeRange &) @@ -156,6 +102,29 @@ Project *PlaybackCache::GetProject() const return viewer->project(); } +TimeRangeList PlaybackCache::GetInvalidatedRanges(TimeRange intersecting) +{ + TimeRangeList invalidated; + + // Prevent TimeRange from being below 0, some other behavior in Olive relies on this behavior + // and it seemed reasonable to have safety code in here + intersecting.set_out(qMax(rational(0), intersecting.out())); + intersecting.set_in(qMax(rational(0), intersecting.in())); + + invalidated.insert(intersecting); + + foreach (const TimeRange &range, validated_) { + invalidated.remove(range); + } + + return invalidated; +} + +bool PlaybackCache::HasInvalidatedRanges(const TimeRange &intersecting) +{ + return !validated_.contains(intersecting); +} + QString PlaybackCache::GetCacheDirectory() const { Project* project = GetProject(); @@ -167,4 +136,9 @@ QString PlaybackCache::GetCacheDirectory() const } } +ViewerOutput *PlaybackCache::viewer_parent() const +{ + return dynamic_cast(parent()); +} + } diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 5036ccc2e..1f66994d2 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -30,46 +30,38 @@ namespace olive { class Project; +class ViewerOutput; class PlaybackCache : public QObject { Q_OBJECT public: PlaybackCache(QObject* parent = nullptr) : - QObject(parent), - length_(0) + QObject(parent) { } - const rational& GetLength() + TimeRangeList GetInvalidatedRanges(TimeRange intersecting); + TimeRangeList GetInvalidatedRanges(const rational &length) { - return length_; + return GetInvalidatedRanges(TimeRange(0, length)); } - bool IsFullyValidated() + bool HasInvalidatedRanges(const TimeRange &intersecting); + bool HasInvalidatedRanges(const rational &length) { - return invalidated_.isEmpty(); - } - - const TimeRangeList& GetInvalidatedRanges() - { - return invalidated_; - } - - bool HasInvalidatedRanges() - { - return !invalidated_.isEmpty(); + return HasInvalidatedRanges(TimeRange(0, length)); } QString GetCacheDirectory() const; + ViewerOutput *viewer_parent() const; + + void Invalidate(const TimeRange& r, bool signal = true); + public slots: - void Invalidate(const TimeRange& r); - void InvalidateAll(); - void SetLength(const rational& r); - void Shift(rational from, rational to); signals: @@ -79,12 +71,8 @@ signals: void Shifted(const olive::rational& from, const olive::rational& to); - void LengthChanged(const olive::rational& r); - protected: - void Validate(const TimeRange& r); - - virtual void LengthChangedEvent(const rational& old, const rational& newlen); + void Validate(const TimeRange& r, bool signal = true); virtual void InvalidateEvent(const TimeRange& range); @@ -93,9 +81,7 @@ protected: Project* GetProject() const; private: - TimeRangeList invalidated_; - - rational length_; + TimeRangeList validated_; }; diff --git a/app/task/precache/precachetask.cpp b/app/task/precache/precachetask.cpp index 6add67a25..2f207cf9c 100644 --- a/app/task/precache/precachetask.cpp +++ b/app/task/precache/precachetask.cpp @@ -57,13 +57,18 @@ PreCacheTask::~PreCacheTask() bool PreCacheTask::Run() { // Get list of invalidated ranges - TimeRangeList video_range = viewer()->video_frame_cache()->GetInvalidatedRanges(); + TimeRange intersection; - // If we're caching only in-out, limit the range to that if (footage_->GetTimelinePoints()->workarea()->enabled()) { - video_range = video_range.Intersects(footage_->GetTimelinePoints()->workarea()->range()); + // If we're caching only in-out, limit the range to that + intersection = footage_->GetTimelinePoints()->workarea()->range(); + } else { + // Otherwise use full length + intersection = TimeRange(0, footage_->GetVideoLength()); } + TimeRangeList video_range = viewer()->video_frame_cache()->GetInvalidatedRanges(intersection); + Render(project_->color_manager(), video_range, TimeRangeList(), diff --git a/app/widget/timelinewidget/timelineundo.cpp b/app/widget/timelinewidget/timelineundo.cpp index 51625ead2..0f9aa229a 100644 --- a/app/widget/timelinewidget/timelineundo.cpp +++ b/app/widget/timelinewidget/timelineundo.cpp @@ -271,18 +271,16 @@ void TrackReplaceBlockWithGapCommand::redo() } else { // Block is at the end of the track, simply remove it - - // Determine if it's proceeded by a gap, and remove that gap if so Block* preceding = block_->previous(); + track_->RippleRemoveBlock(block_); + + // Determine if it's preceded by a gap, and remove that gap if so if (dynamic_cast(preceding)) { track_->RippleRemoveBlock(preceding); preceding->setParent(&memory_manager_); existing_merged_gap_ = static_cast(preceding); } - - // Remove block in question - track_->RippleRemoveBlock(block_); } } diff --git a/app/widget/timelinewidget/timelineundo.h b/app/widget/timelinewidget/timelineundo.h index da1239527..cb2caedd7 100644 --- a/app/widget/timelinewidget/timelineundo.h +++ b/app/widget/timelinewidget/timelineundo.h @@ -1368,6 +1368,8 @@ public: virtual void redo() override { + TimeRangeList ranges_to_invalidate; + // Determine if we need to add tracks if (track_index_ >= timeline_->GetTracks().size()) { if (add_track_commands_.isEmpty()) { @@ -1400,6 +1402,7 @@ public: } gap_->setParent(track->parent()); track->AppendBlock(gap_); + ranges_to_invalidate.insert(gap_->range()); } track->AppendBlock(insert_); @@ -1429,8 +1432,10 @@ public: track->EndOperation(); - if (ripple_remove_command_) { - track->Node::InvalidateCache(TimeRange(insert_->in(), insert_->out()), Track::kBlockInput); + ranges_to_invalidate.insert(insert_->range()); + + foreach (const TimeRange &r, ranges_to_invalidate) { + track->Node::InvalidateCache(r, Track::kBlockInput); } for (int i=0; i(&TimeRuler::update)); disconnect(playback_cache_, &PlaybackCache::Validated, this, static_cast(&TimeRuler::update)); - disconnect(playback_cache_, &PlaybackCache::LengthChanged, this, static_cast(&TimeRuler::update)); + disconnect(playback_cache_, &PlaybackCache::Shifted, this, static_cast(&TimeRuler::update)); } playback_cache_ = cache; @@ -77,7 +77,7 @@ void TimeRuler::SetPlaybackCache(PlaybackCache *cache) if (playback_cache_) { connect(playback_cache_, &PlaybackCache::Invalidated, this, static_cast(&TimeRuler::update)); connect(playback_cache_, &PlaybackCache::Validated, this, static_cast(&TimeRuler::update)); - connect(playback_cache_, &PlaybackCache::LengthChanged, this, static_cast(&TimeRuler::update)); + connect(playback_cache_, &PlaybackCache::Shifted, this, static_cast(&TimeRuler::update)); } update(); @@ -254,14 +254,17 @@ void TimeRuler::paintEvent(QPaintEvent *) // If cache status is enabled if (show_cache_status_ && playback_cache_) { - int cache_screen_length = qMin(TimeToScreen(playback_cache_->GetLength()), width()); + // FIXME: Hardcoded to get video length, if we ever need audio length, this will have to change + rational len = playback_cache_->viewer_parent()->GetVideoLength(); + + int cache_screen_length = qMin(TimeToScreen(len), width()); if (cache_screen_length > 0) { int cache_y = height() - cache_status_height_; p.fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green); - foreach (const TimeRange& range, playback_cache_->GetInvalidatedRanges()) { + foreach (const TimeRange& range, playback_cache_->GetInvalidatedRanges(len)) { int range_left = TimeToScreen(range.in()); if (range_left >= width()) { continue;