Merge branch 'master' into hashremoval

This commit is contained in:
itsmattkc
2022-05-16 09:12:49 -07:00
969 changed files with 4837 additions and 2393 deletions
+79 -12
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,12 +37,15 @@
#include "common/timecodefunctions.h"
#include "config/config.h"
#include "core.h"
#include "node/block/gap/gap.h"
#include "node/generator/shape/shapenodebase.h"
#include "node/project/project.h"
#include "render/rendermanager.h"
#include "task/taskmanager.h"
#include "viewerpreventsleep.h"
#include "widget/menu/menu.h"
#include "window/mainwindow/mainwindow.h"
#include "widget/timelinewidget/tool/add.h"
#include "widget/timeruler/timeruler.h"
namespace olive {
@@ -92,7 +95,9 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
connect(display_widget_, &ViewerDisplayWidget::QueueStarved, this, &ViewerWidget::ForceRequeueFromCurrentTime);
connect(display_widget_, &ViewerDisplayWidget::QueueStarved, this, &ViewerWidget::QueueStarved);
connect(display_widget_, &ViewerDisplayWidget::QueueNoLongerStarved, this, &ViewerWidget::QueueNoLongerStarved);
connect(display_widget_, &ViewerDisplayWidget::CreateAddableAt, this, &ViewerWidget::CreateAddableAt);
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove);
@@ -476,6 +481,48 @@ void ViewerWidget::UpdateAudioProcessor()
}
}
void ViewerWidget::CreateAddableAt(const QRectF &f)
{
if (Sequence *s = dynamic_cast<Sequence*>(GetConnectedNode())) {
Track::Type type = Track::kVideo;
int track_index = -1;
TrackList *list = s->track_list(type);
const rational &in = GetTime();
rational length = OLIVE_CONFIG("DefaultStillLength").value<rational>();
rational out = in + length;
// Find a free track where we won't overwrite anything
while (true) {
track_index++;
if (track_index >= list->GetTrackCount()) {
// Just create a new track
break;
}
Track *track = list->GetTrackAt(track_index);
if (track->IsLocked()) {
continue;
}
Block *b = track->NearestBlockBeforeOrAt(in);
if (!b || (dynamic_cast<GapBlock*>(b) && b->out() >= out)) {
break;
}
}
MultiUndoCommand *command = new MultiUndoCommand();
Node *clip = AddTool::CreateAddableClip(command, s, Track::Reference(type, track_index), in, length);
if (ShapeNodeBase *shape = dynamic_cast<ShapeNodeBase*>(clip)) {
shape->SetRect(f, s->GetVideoParams(), command);
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
SetGizmos(clip);
}
}
void ViewerWidget::CloseAudioProcessor()
{
audio_processor_.Close();
@@ -499,7 +546,7 @@ void ViewerWidget::QueueNextAudioBuffer()
RenderTicketWatcher *watcher = new RenderTicketWatcher(this);
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForPlayback);
audio_playback_queue_.push_back(watcher);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end), true));
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end), RenderTicketPriority::kHigh));
audio_playback_queue_time_ = queue_end;
}
@@ -590,6 +637,24 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing()
delete watcher;
}
void ViewerWidget::QueueStarved()
{
static const int kMaximumWaitTime = 250;
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (!queue_starved_start_) {
queue_starved_start_ = now;
} else if (now > queue_starved_start_ + kMaximumWaitTime) {
ForceRequeueFromCurrentTime();
queue_starved_start_ = 0;
}
}
void ViewerWidget::QueueNoLongerStarved()
{
queue_starved_start_ = 0;
}
void ViewerWidget::ForceRequeueFromCurrentTime()
{
ClearVideoAutoCacherQueue();
@@ -629,7 +694,7 @@ void ViewerWidget::UpdateTextureFromNode()
ClearVideoAutoCacherQueue();
}
watcher->SetTicket(GetFrame(time, true));
watcher->SetTicket(GetFrame(time, RenderTicketPriority::kHigh));
} else {
// There is definitely no frame here, we can immediately flip to showing nothing
nonqueue_watchers_.clear();
@@ -686,6 +751,8 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
controls_->ShowPauseButton();
queue_starved_start_ = 0;
// Attempt to fill playback queue
if (display_widget_->isVisible() || !windows_.isEmpty()) {
prequeue_length_ = DeterminePlaybackQueueSize();
@@ -702,7 +769,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
for (int i=0; i<prequeue_length_; i++) {
playback_queue_next_frame_ -= playback_speed_;
RequestNextFrameForQueue(true, false);
RequestNextFrameForQueue(RenderTicketPriority::kHigh, false);
}
playback_queue_next_frame_ = temp;
@@ -786,7 +853,7 @@ void ViewerWidget::PushScrubbedAudio()
RenderTicketWatcher *watcher = new RenderTicketWatcher();
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), true));
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), RenderTicketPriority::kHigh));
}
}
}
@@ -836,7 +903,7 @@ void ViewerWidget::SetDisplayImage(QVariant frame)
}
}
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
void ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority priority, bool increment)
{
rational next_time = Timecode::timestamp_to_time(playback_queue_next_frame_,
timebase());
@@ -850,17 +917,17 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
watcher->setProperty("time", QVariant::fromValue(next_time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
queue_watchers_.append(watcher);
watcher->SetTicket(GetFrame(next_time, prioritize));
watcher->SetTicket(GetFrame(next_time, priority));
}
}
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool prioritize)
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, RenderTicketPriority priority)
{
QString cache_fn = GetConnectedNode()->video_frame_cache()->CachePathName(t);
if (!QFileInfo::exists(cache_fn)) {
// Frame hasn't been cached, start render job
return auto_cacher_.GetSingleFrame(t, prioritize);
return auto_cacher_.GetSingleFrame(t, priority);
} else {
// Frame has been cached, grab the frame
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
@@ -1508,14 +1575,14 @@ void ViewerWidget::ViewerShiftedRange(const rational &from, const rational &to)
void ViewerWidget::DragEntered(QDragEnterEvent* event)
{
if (event->mimeData()->formats().contains(QStringLiteral("application/x-oliveprojectitemdata"))) {
if (event->mimeData()->formats().contains(Project::kItemMimeType)) {
event->accept();
}
}
void ViewerWidget::Dropped(QDropEvent *event)
{
QByteArray mimedata = event->mimeData()->data(QStringLiteral("application/x-oliveprojectitemdata"));
QByteArray mimedata = event->mimeData()->data(Project::kItemMimeType);
QDataStream stream(&mimedata, QIODevice::ReadOnly);
// Variables to deserialize into