Merge branch 'master' into hashremoval
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user