timeline: add options for manually caching and discarding parts of clips
This commit is contained in:
@@ -136,6 +136,18 @@ void ClipBlock::SetAutocache(bool e)
|
||||
SetStandardValue(kAutoCacheInput, e);
|
||||
}
|
||||
|
||||
void ClipBlock::DiscardCache()
|
||||
{
|
||||
if (Node *connected = GetConnectedOutput(kBufferIn)) {
|
||||
Track::Type type = GetTrackType();
|
||||
if (type == Track::kVideo) {
|
||||
connected->video_frame_cache()->Invalidate(TimeRange(RATIONAL_MIN, RATIONAL_MAX));
|
||||
} else if (type == Track::kAudio) {
|
||||
connected->audio_playback_cache()->Invalidate(TimeRange(RATIONAL_MIN, RATIONAL_MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rational ClipBlock::SequenceToMediaTime(const rational &sequence_time, uint64_t flags) const
|
||||
{
|
||||
// These constants are not considered "values" per se, so we don't modify them
|
||||
@@ -237,13 +249,18 @@ void ClipBlock::RequestRangeFromConnected(const TimeRange &range)
|
||||
}
|
||||
}
|
||||
|
||||
void ClipBlock::RequestInvalidatedFromConnected()
|
||||
void ClipBlock::RequestInvalidatedFromConnected(bool force_all, const TimeRange &intersect)
|
||||
{
|
||||
Track::Type type = GetTrackType();
|
||||
|
||||
if (type == Track::kVideo || type == Track::kAudio) {
|
||||
if (Node *connected = GetConnectedOutput(kBufferIn)) {
|
||||
TimeRange max_range = media_range();
|
||||
|
||||
if (!intersect.length().isNull()) {
|
||||
max_range = max_range.Intersected(intersect);
|
||||
}
|
||||
|
||||
if (type == Track::kVideo) {
|
||||
// Handle thumbnails
|
||||
TimeRange thumb_range = max_range;
|
||||
@@ -252,7 +269,7 @@ void ClipBlock::RequestInvalidatedFromConnected()
|
||||
}
|
||||
|
||||
// Handle video cache
|
||||
if (IsAutocaching()) {
|
||||
if (IsAutocaching() || force_all) {
|
||||
RequestInvalidatedForCache(connected->video_frame_cache(), max_range);
|
||||
}
|
||||
} else if (type == Track::kAudio) {
|
||||
@@ -262,7 +279,7 @@ void ClipBlock::RequestInvalidatedFromConnected()
|
||||
}
|
||||
|
||||
// Handle audio cache
|
||||
if (IsAutocaching()) {
|
||||
if (IsAutocaching() || force_all) {
|
||||
RequestInvalidatedForCache(connected->audio_playback_cache(), max_range);
|
||||
}
|
||||
}
|
||||
@@ -391,6 +408,10 @@ void ClipBlock::InputConnectedEvent(const QString &input, int element, Node *out
|
||||
super::InputConnectedEvent(input, element, output);
|
||||
|
||||
if (input == kBufferIn) {
|
||||
connect(output->thumbnail_cache(), &FrameHashCache::Invalidated, this, &Block::PreviewChanged);
|
||||
connect(output->waveform_cache(), &AudioPlaybackCache::Invalidated, this, &Block::PreviewChanged);
|
||||
connect(output->video_frame_cache(), &FrameHashCache::Invalidated, this, &Block::PreviewChanged);
|
||||
connect(output->audio_playback_cache(), &AudioPlaybackCache::Invalidated, this, &Block::PreviewChanged);
|
||||
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);
|
||||
@@ -403,6 +424,10 @@ void ClipBlock::InputDisconnectedEvent(const QString &input, int element, Node *
|
||||
super::InputDisconnectedEvent(input, element, output);
|
||||
|
||||
if (input == kBufferIn) {
|
||||
disconnect(output->thumbnail_cache(), &FrameHashCache::Invalidated, this, &Block::PreviewChanged);
|
||||
disconnect(output->waveform_cache(), &AudioPlaybackCache::Invalidated, this, &Block::PreviewChanged);
|
||||
disconnect(output->video_frame_cache(), &FrameHashCache::Invalidated, this, &Block::PreviewChanged);
|
||||
disconnect(output->audio_playback_cache(), &AudioPlaybackCache::Invalidated, this, &Block::PreviewChanged);
|
||||
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);
|
||||
|
||||
@@ -63,6 +63,8 @@ public:
|
||||
bool IsAutocaching() const { return GetStandardValue(kAutoCacheInput).toBool(); }
|
||||
void SetAutocache(bool e);
|
||||
|
||||
void DiscardCache();
|
||||
|
||||
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;
|
||||
@@ -73,7 +75,7 @@ public:
|
||||
|
||||
virtual void Retranslate() override;
|
||||
|
||||
void RerequestCaches() { RequestInvalidatedFromConnected(); }
|
||||
void RequestInvalidatedFromConnected(bool force_all = false, const TimeRange &intersect = TimeRange());
|
||||
|
||||
double speed() const
|
||||
{
|
||||
@@ -227,7 +229,6 @@ private:
|
||||
rational MediaToSequenceTime(const rational& media_time) const;
|
||||
|
||||
void RequestRangeFromConnected(const TimeRange &range);
|
||||
void RequestInvalidatedFromConnected();
|
||||
|
||||
void RequestRangeForCache(PlaybackCache *cache, const TimeRange &max_range, const TimeRange &range, bool invalidate, bool request);
|
||||
void RequestInvalidatedForCache(PlaybackCache *cache, const TimeRange &max_range);
|
||||
|
||||
@@ -1110,10 +1110,26 @@ void TimelineWidget::ShowContextMenu()
|
||||
menu.addSeparator();
|
||||
|
||||
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(selected.first())) {
|
||||
QAction *autocache_action = menu.addAction(tr("Auto-Cache"));
|
||||
autocache_action->setCheckable(true);
|
||||
autocache_action->setChecked(clip->IsAutocaching());
|
||||
connect(autocache_action, &QAction::triggered, this, &TimelineWidget::SetSelectedClipsAutocaching);
|
||||
{
|
||||
Menu *cache_menu = new Menu(tr("Cache"), &menu);
|
||||
menu.addMenu(cache_menu);
|
||||
|
||||
QAction *autocache_action = cache_menu->addAction(tr("Auto-Cache"));
|
||||
autocache_action->setCheckable(true);
|
||||
autocache_action->setChecked(clip->IsAutocaching());
|
||||
connect(autocache_action, &QAction::triggered, this, &TimelineWidget::SetSelectedClipsAutocaching);
|
||||
|
||||
cache_menu->addSeparator();
|
||||
|
||||
auto cache_clip = cache_menu->addAction(tr("Cache All"));
|
||||
connect(cache_clip, &QAction::triggered, this, &TimelineWidget::CacheClips);
|
||||
|
||||
auto cache_inout = cache_menu->addAction(tr("Cache In/Out"));
|
||||
connect(cache_inout, &QAction::triggered, this, &TimelineWidget::CacheClipsInOut);
|
||||
|
||||
auto cache_discard = cache_menu->addAction(tr("Discard"));
|
||||
connect(cache_discard, &QAction::triggered, this, &TimelineWidget::CacheDiscard);
|
||||
}
|
||||
|
||||
if (clip->connected_viewer()) {
|
||||
QAction *reveal_in_footage_viewer = menu.addAction(tr("Reveal in Footage Viewer"));
|
||||
@@ -1145,7 +1161,7 @@ void TimelineWidget::ShowContextMenu()
|
||||
menu.addMenu(thumbnail_menu);
|
||||
|
||||
thumbnail_menu->AddActionWithData(tr("Disabled"), Timeline::kThumbnailOff, OLIVE_CONFIG("TimelineThumbnailMode"));
|
||||
thumbnail_menu->AddActionWithData(tr("Only At In/Out Points"), Timeline::kThumbnailInOut, OLIVE_CONFIG("TimelineThumbnailMode"));
|
||||
thumbnail_menu->AddActionWithData(tr("Only At In Points"), Timeline::kThumbnailInOut, OLIVE_CONFIG("TimelineThumbnailMode"));
|
||||
thumbnail_menu->AddActionWithData(tr("Enabled"), Timeline::kThumbnailOn, OLIVE_CONFIG("TimelineThumbnailMode"));
|
||||
|
||||
connect(thumbnail_menu, &Menu::triggered, this, &TimelineWidget::SetViewThumbnailsEnabled);
|
||||
@@ -1311,6 +1327,50 @@ void TimelineWidget::SetSelectedClipsAutocaching(bool e)
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void TimelineWidget::CacheClips()
|
||||
{
|
||||
for (Block *b : selected_blocks_) {
|
||||
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(b)) {
|
||||
clip->RequestInvalidatedFromConnected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::CacheClipsInOut()
|
||||
{
|
||||
if (!this->sequence() || !this->sequence()->GetWorkArea()->enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeTargetObject tto;
|
||||
tto.SetTimeTarget(this->sequence());
|
||||
|
||||
const TimeRange &r = this->sequence()->GetWorkArea()->range();
|
||||
for (Block *b : qAsConst(selected_blocks_)) {
|
||||
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(b)) {
|
||||
if (Node *connected = clip->GetConnectedOutput(clip->kBufferIn)) {
|
||||
TimeRange adjusted = tto.GetAdjustedTime(this->sequence(), connected, r, true);
|
||||
clip->RequestInvalidatedFromConnected(true, adjusted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::CacheDiscard()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Discard Cache"),
|
||||
tr("This will discard all cache for this clip. "
|
||||
"If the clip has auto-cache enabled, it will be recached immediately. "
|
||||
"This cannot be undone.\n\n"
|
||||
"Do you wish to continue?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
for (Block *b : selected_blocks_) {
|
||||
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(b)) {
|
||||
clip->DiscardCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
|
||||
{
|
||||
ghost_items_.append(ghost);
|
||||
|
||||
@@ -440,6 +440,10 @@ private slots:
|
||||
|
||||
void SetSelectedClipsAutocaching(bool e);
|
||||
|
||||
void CacheClips();
|
||||
void CacheClipsInOut();
|
||||
void CacheDiscard();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ void ImportTool::DropGhosts(bool insert)
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
|
||||
while (!imported_clips.empty()) {
|
||||
imported_clips.front()->RerequestCaches();
|
||||
imported_clips.front()->RequestInvalidatedFromConnected();
|
||||
imported_clips.pop_front();
|
||||
}
|
||||
|
||||
@@ -523,7 +523,6 @@ TimelineViewGhostItem* ImportTool::CreateGhost(const TimeRange &range, const rat
|
||||
snap_points_.push_back(ghost->GetIn());
|
||||
snap_points_.push_back(ghost->GetOut());
|
||||
|
||||
|
||||
ghost->SetMode(Timeline::kMove);
|
||||
|
||||
parent()->AddGhost(ghost);
|
||||
|
||||
Reference in New Issue
Block a user