viewer: improved playback ux

This commit is contained in:
itsmattkc
2021-09-29 02:12:20 -07:00
parent 36d0c8203e
commit efcf0ed331
2 changed files with 47 additions and 32 deletions
+44 -31
View File
@@ -58,7 +58,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
time_changed_from_timer_(false), time_changed_from_timer_(false),
prequeuing_video_(false), prequeuing_video_(false),
prequeuing_audio_(false), prequeuing_audio_(false),
active_queue_jobs_(0),
audio_playback_device_(nullptr) audio_playback_device_(nullptr)
{ {
// Set up main layout // Set up main layout
@@ -515,6 +514,16 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing()
delete watcher; delete watcher;
} }
void ViewerWidget::ForceRequeueFromCurrentTime()
{
ClearVideoAutoCacherQueue();
int queue = DeterminePlaybackQueueSize();
playback_queue_next_frame_ = GetTimestamp() + playback_speed_;
for (int i=queue_watchers_.size(); i<queue; i++) {
RequestNextFrameForQueue();
}
}
void ViewerWidget::UpdateTextureFromNode() void ViewerWidget::UpdateTextureFromNode()
{ {
rational time = GetTime(); rational time = GetTime();
@@ -529,11 +538,9 @@ void ViewerWidget::UpdateTextureFromNode()
bool popped = false; bool popped = false;
if (playback_queue_.empty()) { if (playback_queue_.empty()) {
int queue = DeterminePlaybackQueueSize();
playback_queue_next_frame_ = GetTimestamp() + playback_speed_; ForceRequeueFromCurrentTime();
for (int i=active_queue_jobs_; i<queue; i++) {
RequestNextFrameForQueue();
}
} else { } else {
while (!playback_queue_.empty()) { while (!playback_queue_.empty()) {
@@ -545,9 +552,15 @@ void ViewerWidget::UpdateTextureFromNode()
SetDisplayImage(pf.frame, true); SetDisplayImage(pf.frame, true);
return; 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 { } else {
// Skip this frame // Frame was too old, skip this frame
PopOldestFrameFromPlaybackQueue(); PopOldestFrameFromPlaybackQueue();
if (popped) { if (popped) {
// We've already popped a frame in this loop, meaning a frame has been skipped // We've already popped a frame in this loop, meaning a frame has been skipped
@@ -559,21 +572,16 @@ void ViewerWidget::UpdateTextureFromNode()
} }
if (playback_queue_.empty()) { if (playback_queue_.empty()) {
// This was the last frame left in the queue. Even though it's old, we'll show it
// just for improved user feedback ForceRequeueFromCurrentTime();
SetDisplayImage(pf.frame, true); break;
return;
} }
} }
} }
} }
// Only show warning if frame actually exists
if (frame_exists_at_time && !frame_might_be_still) {
//qWarning() << "Playback queue failed to keep up";
}
} }
if (frame_exists_at_time || frame_might_be_still) { if (frame_exists_at_time || frame_might_be_still) {
@@ -688,6 +696,9 @@ void ViewerWidget::PauseInternal()
window->Pause(); window->Pause();
} }
qDeleteAll(queue_watchers_);
queue_watchers_.clear();
playback_queue_.clear(); playback_queue_.clear();
playback_backup_timer_.stop(); playback_backup_timer_.stop();
@@ -790,7 +801,7 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
watcher->setProperty("time", QVariant::fromValue(next_time)); watcher->setProperty("time", QVariant::fromValue(next_time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
watcher->SetTicket(GetFrame(next_time, prioritize)); watcher->SetTicket(GetFrame(next_time, prioritize));
active_queue_jobs_++; queue_watchers_.append(watcher);
} }
} }
@@ -959,28 +970,30 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
{ {
RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender()); RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender());
if (watcher->HasResult()) { if (queue_watchers_.contains(watcher)) {
QVariant frame = watcher->Get(); queue_watchers_.removeOne(watcher);
// Ignore this signal if we've paused now if (watcher->HasResult()) {
if (IsPlaying() || prequeuing_video_) { QVariant frame = watcher->Get();
rational ts = watcher->property("time").value<rational>();
playback_queue_.AppendTimewise({ts, frame}, playback_speed_); // Ignore this signal if we've paused now
if (IsPlaying() || prequeuing_video_) {
rational ts = watcher->property("time").value<rational>();
foreach (ViewerWindow* window, windows_) { playback_queue_.AppendTimewise({ts, frame}, playback_speed_);
window->queue()->AppendTimewise({ts, frame}, playback_speed_);
}
if (prequeuing_video_ && int(playback_queue_.size()) == prequeue_length_) { foreach (ViewerWindow* window, windows_) {
prequeuing_video_ = false; window->queue()->AppendTimewise({ts, frame}, playback_speed_);
FinishPlayPreprocess(); }
if (prequeuing_video_ && int(playback_queue_.size()) == prequeue_length_) {
prequeuing_video_ = false;
FinishPlayPreprocess();
}
} }
} }
} }
active_queue_jobs_--;
delete watcher; delete watcher;
} }
+3 -1
View File
@@ -254,7 +254,7 @@ private:
PreviewAutoCacher auto_cacher_; PreviewAutoCacher auto_cacher_;
int active_queue_jobs_; QVector<RenderTicketWatcher*> queue_watchers_;
std::shared_ptr<PreviewAudioDevice> audio_playback_device_; std::shared_ptr<PreviewAudioDevice> audio_playback_device_;
std::list<RenderTicketWatcher*> audio_playback_queue_; std::list<RenderTicketWatcher*> audio_playback_queue_;
@@ -317,6 +317,8 @@ private slots:
void ReceivedAudioBufferForScrubbing(); void ReceivedAudioBufferForScrubbing();
void ForceRequeueFromCurrentTime();
}; };
} }