reworked viewer timers

This commit is contained in:
itsmattkc
2022-01-02 16:56:11 -08:00
parent ee3ea5990b
commit 2afa7ecafe
9 changed files with 183 additions and 222 deletions
+64 -142
View File
@@ -81,13 +81,13 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
display_widget_ = new ViewerDisplayWidget();
display_widget_->setAcceptDrops(true);
display_widget_->SetShowWidgetBackground(true);
playback_devices_.append(display_widget_);
connect(display_widget_, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(display_widget_, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor);
connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
connect(display_widget_, &ViewerDisplayWidget::VisibilityChanged, this, &ViewerWidget::Pause);
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
@@ -207,9 +207,8 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n)
ColorManager* color_manager = n->project()->color_manager();
display_widget_->ConnectColorManager(color_manager);
foreach (ViewerWindow* window, windows_) {
window->display_widget()->ConnectColorManager(color_manager);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->ConnectColorManager(color_manager);
}
UpdateStack();
@@ -247,9 +246,8 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
// Effectively disables the viewer and clears the state
SetViewerResolution(0, 0);
display_widget_->DisconnectColorManager();
foreach (ViewerWindow* window, windows_) {
window->display_widget()->DisconnectColorManager();
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->DisconnectColorManager();
}
waveform_view_->SetViewer(nullptr);
@@ -299,9 +297,8 @@ void ViewerWidget::SetColorMenuEnabled(bool enabled)
void ViewerWidget::SetMatrix(const QMatrix4x4 &mat)
{
display_widget_->SetMatrixCrop(mat);
foreach (ViewerWindow* vw, windows_) {
vw->display_widget()->SetMatrixCrop(mat);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetMatrixCrop(mat);
}
}
@@ -343,9 +340,11 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
vw->display_widget()->SetImage(QVariant::fromValue(display_widget()->GetCurrentTexture()));
(*vw->queue()) = playback_queue_;
playback_devices_.append(vw->display_widget());
(*vw->display_widget()->queue()) = *playback_devices_.first()->queue();
if (IsPlaying()) {
vw->Play(GetTimestamp(), playback_speed_, timebase());
vw->display_widget()->Play(GetTimestamp(), playback_speed_, timebase());
}
windows_.insert(screen, vw);
@@ -402,10 +401,8 @@ bool ViewerWidget::ShouldForceWaveform() const
void ViewerWidget::SetEmptyImage()
{
display_widget()->SetBlank();
foreach (ViewerWindow *vw, windows_) {
vw->display_widget()->SetBlank();
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetBlank();
}
}
@@ -539,85 +536,30 @@ void ViewerWidget::UpdateTextureFromNode()
return;
}
if (IsPlaying()) {
qDebug() << "UpdateTextureFromNode called while playing";
return;
}
rational time = GetTime();
bool frame_exists_at_time = FrameExistsAtTime(time);
bool frame_might_be_still = ViewerMightBeAStill();
// Check playback queue for a frame
if (IsPlaying()) {
// We still run the playback queue even when FrameExistsAtTime returns false because we might be
// playing backwards and about to start showing frames, so the queue should be prepared for
// that.
bool popped = false;
if (playback_queue_.empty()) {
ForceRequeueFromCurrentTime();
} else {
while (!playback_queue_.empty()) {
ViewerPlaybackFrame pf = playback_queue_.front();
if (pf.timestamp == time) {
// Frame was in queue, no need to decode anything
SetDisplayImage(pf.frame, true);
return;
} else if (pf.timestamp > time) {
// The next frame in the queue is too new, so just do a regular update. Either the
// frame we want will arrive in time, or we'll just have to skip it.
break;
} else {
// Frame was too old, skip this frame
PopOldestFrameFromPlaybackQueue();
if (popped) {
// We've already popped a frame in this loop, meaning a frame has been skipped
display_widget_->IncrementSkippedFrames();
} else {
// Shown a frame and progressed to the next one
display_widget_->IncrementFrameCount();
popped = true;
}
if (playback_queue_.empty()) {
ForceRequeueFromCurrentTime();
break;
}
}
}
}
}
if (frame_exists_at_time || frame_might_be_still) {
// Frame was not in queue, will require rendering or decoding from cache
if (IsPlaying()) {
// Is playing, yet the queue above failed to retrieve the frame. We effectively do a quick
// reboot of the queue here, assuming the above loop has emptied it so far.
display_widget_->update();
} else {
// Not playing, run a task to get the frame either from the cache or the renderer
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("start", QDateTime::currentMSecsSinceEpoch());
watcher->setProperty("time", QVariant::fromValue(time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
nonqueue_watchers_.append(watcher);
// Not playing, run a task to get the frame either from the cache or the renderer
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("start", QDateTime::currentMSecsSinceEpoch());
watcher->setProperty("time", QVariant::fromValue(time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
nonqueue_watchers_.append(watcher);
// Clear queue because we want this frame more than any others
if (!GetConnectedNode()->GetVideoAutoCacheEnabled() && !auto_cacher_.IsRenderingCustomRange()) {
ClearVideoAutoCacherQueue();
}
watcher->SetTicket(GetFrame(time, true));
// Clear queue because we want this frame more than any others
if (!GetConnectedNode()->GetVideoAutoCacheEnabled() && !auto_cacher_.IsRenderingCustomRange()) {
ClearVideoAutoCacherQueue();
}
watcher->SetTicket(GetFrame(time, true));
} else {
// There is definitely no frame here, we can immediately flip to showing nothing
nonqueue_watchers_.clear();
@@ -673,6 +615,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
if (prequeue_length_ > 0) {
prequeuing_video_ = true;
prequeue_count_ = 0;
// We "prioritize" the frames, which means they're pushed to the top of the render queue,
// we queue in reverse so that they're still queued in order
@@ -715,16 +658,13 @@ void ViewerWidget::PauseInternal()
playback_speed_ = 0;
controls_->ShowPlayButton();
disconnect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
foreach (ViewerWindow* window, windows_) {
window->Pause();
foreach (ViewerDisplayWidget *dw, playback_devices_){
dw->Pause();
}
qDeleteAll(queue_watchers_);
queue_watchers_.clear();
playback_queue_.clear();
playback_backup_timer_.stop();
// Handle audio
@@ -811,14 +751,10 @@ bool ViewerWidget::ViewerMightBeAStill()
return GetConnectedNode() && GetConnectedNode()->GetConnectedTextureOutput() && GetConnectedNode()->GetVideoLength().isNull();
}
void ViewerWidget::SetDisplayImage(QVariant frame, bool main_only)
void ViewerWidget::SetDisplayImage(QVariant frame)
{
display_widget_->SetImage(frame);
if (!main_only) {
foreach (ViewerWindow* vw, windows_) {
vw->display_widget()->SetImage(frame);
}
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetImage(frame);
}
}
@@ -876,19 +812,15 @@ void ViewerWidget::FinishPlayPreprocess()
GetTime(), playback_speed_);
}
playback_timer_.Start(playback_start_time, playback_speed_, timebase_dbl());
display_widget_->ResetFPSTimer();
foreach (ViewerWindow* window, windows_) {
window->Play(playback_start_time, playback_speed_, timebase());
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->Play(playback_start_time, playback_speed_, timebase());
}
if (display_widget_->isVisible()) {
connect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else {
playback_backup_timer_.setInterval(qFloor(timebase_dbl()));
playback_backup_timer_.start();
}
// This is our timer for loading the queue and setting the time
playback_backup_timer_.setInterval(qFloor(timebase_dbl()));
playback_backup_timer_.start();
PlaybackTimerUpdate();
}
@@ -909,15 +841,6 @@ int ViewerWidget::DeterminePlaybackQueueSize()
return qMin(kMaxPreQueueSize, remaining_frames);
}
void ViewerWidget::PopOldestFrameFromPlaybackQueue()
{
playback_queue_.pop_front();
if (int(playback_queue_.size()) < DeterminePlaybackQueueSize()) {
RequestNextFrameForQueue();
}
}
void ViewerWidget::UpdateStack()
{
rational new_tb;
@@ -970,7 +893,9 @@ void ViewerWidget::ContextMenuSetCustomSafeMargins()
void ViewerWidget::WindowAboutToClose()
{
windows_.remove(windows_.key(static_cast<ViewerWindow*>(sender())));
ViewerWindow *vw = static_cast<ViewerWindow*>(sender());
windows_.remove(windows_.key(vw));
playback_devices_.removeOne(vw->display_widget());
}
void ViewerWidget::RendererGeneratedFrame()
@@ -1017,13 +942,12 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
if (IsPlaying() || prequeuing_video_) {
rational ts = watcher->property("time").value<rational>();
playback_queue_.AppendTimewise({ts, frame}, playback_speed_);
foreach (ViewerWindow* window, windows_) {
window->queue()->AppendTimewise({ts, frame}, playback_speed_);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->queue()->AppendTimewise({ts, frame}, playback_speed_);
}
prequeue_count_++;
if (prequeuing_video_ && int(playback_queue_.size()) == prequeue_length_) {
if (prequeuing_video_ && prequeue_count_ == prequeue_length_) {
prequeuing_video_ = false;
FinishPlayPreprocess();
}
@@ -1251,10 +1175,8 @@ void ViewerWidget::SetColorTransform(const ColorTransform &transform)
void ViewerWidget::SetSignalCursorColorEnabled(bool e)
{
display_widget_->SetSignalCursorColorEnabled(e);
foreach (ViewerWindow* vw, windows_) {
vw->display_widget()->SetSignalCursorColorEnabled(e);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetSignalCursorColorEnabled(e);
}
}
@@ -1270,7 +1192,7 @@ void ViewerWidget::TimebaseChangedEvent(const rational &timebase)
void ViewerWidget::PlaybackTimerUpdate()
{
rational current_time = Timecode::timestamp_to_time(playback_timer_.GetTimestampNow(), timebase());
rational current_time = Timecode::timestamp_to_time(display_widget_->timer()->GetTimestampNow(), timebase());
rational min_time, max_time;
@@ -1352,14 +1274,15 @@ void ViewerWidget::PlaybackTimerUpdate()
}
}
if (display_widget_->isVisible()) {
// Updating display widget
UpdateTextureFromNode();
} else if (!windows_.empty()) {
// We still run the queue if windows are visible even if our own display widget isn't visible
while (!playback_queue_.empty() && playback_queue_.front().timestamp != GetTime()) {
PopOldestFrameFromPlaybackQueue();
}
// We still run the queue if windows are visible even if our own display widget isn't visible
/*while (!playback_queue_.empty() && playback_queue_.front().timestamp != GetTime()) {
PopOldestFrameFromPlaybackQueue();
}*/
// NOTE: There should be some calculation here to determine how many frames need to be queued
RequestNextFrameForQueue();
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->queue()->PurgeBefore(current_time, playback_speed_);
}
}
@@ -1398,10 +1321,10 @@ void ViewerWidget::LengthChangedSlot(const rational &length)
void ViewerWidget::InterlacingChangedSlot(VideoParams::Interlacing interlacing)
{
// Automatically set a "sane" deinterlacing option
display_widget_->SetDeinterlacing(interlacing != VideoParams::kInterlaceNone);
bool deint = interlacing != VideoParams::kInterlaceNone;
foreach (ViewerWindow* vw, windows_) {
vw->display_widget()->SetDeinterlacing(interlacing != VideoParams::kInterlaceNone);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetDeinterlacing(deint);
}
}
@@ -1409,9 +1332,8 @@ void ViewerWidget::UpdateRendererVideoParameters()
{
VideoParams vp = GetConnectedNode()->GetVideoParams();
display_widget_->SetVideoParams(vp);
foreach (ViewerWindow* window, windows_) {
window->display_widget()->SetVideoParams(vp);
foreach (ViewerDisplayWidget *dw, playback_devices_) {
dw->SetVideoParams(vp);
}
}