From 7a8794fe8850d2e41ba1c4e06b42e58c2e09cd88 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 3 Jun 2022 15:48:16 -0700 Subject: [PATCH] ui: draw clip cache on timeline --- app/node/block/clip/clip.cpp | 4 ++ app/node/block/clip/clip.h | 9 ++++ app/render/playbackcache.cpp | 30 ++++++++++++- app/render/playbackcache.h | 17 ++++++-- .../timelinewidget/view/timelineview.cpp | 7 +++ app/widget/timeruler/timeruler.cpp | 43 +++++-------------- app/widget/timeruler/timeruler.h | 2 - 7 files changed, 71 insertions(+), 41 deletions(-) diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 018984bce..9d7044be5 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -292,6 +292,8 @@ void ClipBlock::InputConnectedEvent(const QString &input, int element, Node *out if (input == kBufferIn) { connect(output->thumbnail_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged); connect(output->waveform_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged); + connect(output->video_frame_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged); + connect(output->audio_playback_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged); } } @@ -302,6 +304,8 @@ void ClipBlock::InputDisconnectedEvent(const QString &input, int element, Node * if (input == kBufferIn) { disconnect(output->thumbnail_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged); disconnect(output->waveform_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged); + disconnect(output->video_frame_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged); + disconnect(output->audio_playback_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged); } } diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 26e76e5ce..114c556e0 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -122,6 +122,15 @@ public: return block_links_; } + const FrameHashCache *connected_video_cache() const + { + if (Node *n = GetConnectedOutput(kBufferIn)) { + return n->video_frame_cache(); + } else { + return nullptr; + } + } + const FrameHashCache *thumbnails() { if (Node *n = GetConnectedOutput(kBufferIn)) { diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 80384fb63..fc28b7a21 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -127,6 +127,32 @@ void PlaybackCache::SaveState() } } +void PlaybackCache::Draw(QPainter *p, const rational &start, double scale, const QRect &rect) const +{ + p->fillRect(rect, Qt::red); + + foreach (const TimeRange& range, GetValidatedRanges()) { + int range_left = rect.left() + (range.in() - start).toDouble() * scale; + if (range_left >= rect.right()) { + continue; + } + + int range_right = rect.left() + (range.out() - start).toDouble() * scale; + if (range_right < rect.left()) { + continue; + } + + int adjusted_left = std::max(range_left, rect.left()); + int adjusted_right = std::min(range_right, rect.right()); + + p->fillRect(adjusted_left, + rect.top(), + adjusted_right - adjusted_left, + rect.height(), + Qt::green); + } +} + void PlaybackCache::InvalidateAll() { Invalidate(TimeRange(0, RATIONAL_MAX)); @@ -156,7 +182,7 @@ PlaybackCache::PlaybackCache(QObject *parent) : uuid_ = QUuid::createUuid(); } -TimeRangeList PlaybackCache::GetInvalidatedRanges(TimeRange intersecting) +TimeRangeList PlaybackCache::GetInvalidatedRanges(TimeRange intersecting) const { TimeRangeList invalidated; @@ -174,7 +200,7 @@ TimeRangeList PlaybackCache::GetInvalidatedRanges(TimeRange intersecting) return invalidated; } -bool PlaybackCache::HasInvalidatedRanges(const TimeRange &intersecting) +bool PlaybackCache::HasInvalidatedRanges(const TimeRange &intersecting) const { return !validated_.contains(intersecting); } diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index c36edd1b3..2b49dc618 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "common/jobtime.h" @@ -43,14 +44,14 @@ public: const QUuid &GetUuid() const { return uuid_; } void SetUuid(const QUuid &u) { uuid_ = u; } - TimeRangeList GetInvalidatedRanges(TimeRange intersecting); - TimeRangeList GetInvalidatedRanges(const rational &length) + TimeRangeList GetInvalidatedRanges(TimeRange intersecting) const; + TimeRangeList GetInvalidatedRanges(const rational &length) const { return GetInvalidatedRanges(TimeRange(0, length)); } - bool HasInvalidatedRanges(const TimeRange &intersecting); - bool HasInvalidatedRanges(const rational &length) + bool HasInvalidatedRanges(const TimeRange &intersecting) const; + bool HasInvalidatedRanges(const rational &length) const { return HasInvalidatedRanges(TimeRange(0, length)); } @@ -59,6 +60,7 @@ public: void Invalidate(const TimeRange& r); + bool HasValidatedRanges() const { return !validated_.isEmpty(); } const TimeRangeList &GetValidatedRanges() const { return validated_; } Node *parent() const; @@ -69,6 +71,13 @@ public: void LoadState(); void SaveState(); + void Draw(QPainter *painter, const rational &start, double scale, const QRect &rect) const; + + static int GetCacheIndicatorHeight() + { + return QFontMetrics(QFont()).height()/4; + } + public slots: void InvalidateAll(); diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 7adf8f38d..4f4167bdd 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -603,6 +603,13 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q } } } + + if (const FrameHashCache *cache = clip->connected_video_cache()) { + if (cache->HasValidatedRanges()) { + QRect cache_rect = r.adjusted(0, r.height() - PlaybackCache::GetCacheIndicatorHeight(), 0, 0).toRect(); + cache->Draw(painter, clip->media_in(), GetScale(), cache_rect); + } + } } // For transitions, show lines representing a transition diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index 642e160df..59a234176 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -46,7 +46,6 @@ TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* pare setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); // Text height is used to calculate widget height - cache_status_height_ = text_height() / 4; // Get the "minimum" space allowed between two line markers on the ruler (in screen pixels) // Mediocre but reliable way of scaling UI objects by font/DPI size @@ -181,7 +180,7 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect) int line_bottom = height(); if (show_cache_status_) { - line_bottom -= cache_status_height_; + line_bottom -= PlaybackCache::GetCacheIndicatorHeight(); } int long_height = fm.height(); @@ -255,38 +254,16 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect) // If cache status is enabled if (show_cache_status_ && playback_cache_) { // FIXME: Hardcoded to get video length, if we ever need audio length, this will have to change + int h = PlaybackCache::GetCacheIndicatorHeight(); + QRect cache_rect(0, height() - h, width(), h); + if (ViewerOutput *viewer = dynamic_cast(playback_cache_->parent())) { - rational len = viewer->GetVideoLength(); - int lim_left = GetScroll(); - int lim_right = lim_left + width(); + int right = TimeToScene(viewer->GetVideoLength()); + cache_rect.setWidth(std::max(0, right)); + } - int cache_screen_length = TimeToScene(len); - - 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(len)) { - int range_left = TimeToScene(range.in()); - if (range_left >= width()) { - continue; - } - - int range_right = TimeToScene(range.out()); - if (range_right < 0) { - continue; - } - - int adjusted_left = qMax(lim_left, range_left); - - p->fillRect(adjusted_left, - cache_y, - qMin(lim_right, range_right) - adjusted_left, - cache_status_height_, - Qt::red); - } - } + if (cache_rect.width() > 0) { + playback_cache_->Draw(p, SceneToTime(GetScroll()), GetScale(), cache_rect); } } @@ -338,7 +315,7 @@ void TimeRuler::UpdateHeight() // Add cache status height if (show_cache_status_) { - height += cache_status_height_; + height += PlaybackCache::GetCacheIndicatorHeight(); } // Add marker height diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 372e0e602..f23571634 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -53,8 +53,6 @@ private: int CacheStatusHeight() const; - int cache_status_height_; - int minimum_gap_between_lines_; bool text_visible_;