viewer: smarter pre-queuing
This commit is contained in:
@@ -58,7 +58,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
|||||||
pause_autocache_during_playback_(false),
|
pause_autocache_during_playback_(false),
|
||||||
prequeuing_(false),
|
prequeuing_(false),
|
||||||
last_loaded_buffer_(nullptr),
|
last_loaded_buffer_(nullptr),
|
||||||
last_loaded_buffer_is_empty_(false)
|
last_loaded_buffer_is_empty_(false),
|
||||||
|
active_queue_jobs_(0)
|
||||||
{
|
{
|
||||||
// Set up main layout
|
// Set up main layout
|
||||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||||
@@ -460,29 +461,37 @@ void ViewerWidget::UpdateTextureFromNode()
|
|||||||
// that.
|
// that.
|
||||||
bool popped = false;
|
bool popped = false;
|
||||||
|
|
||||||
while (!playback_queue_.empty()) {
|
if (playback_queue_.empty()) {
|
||||||
|
int queue = DeterminePlaybackQueueSize();
|
||||||
|
playback_queue_next_frame_ = GetTimestamp() + playback_speed_;
|
||||||
|
for (int i=active_queue_jobs_; i<queue; i++) {
|
||||||
|
RequestNextFrameForQueue();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (!playback_queue_.empty()) {
|
||||||
|
|
||||||
const ViewerPlaybackFrame& pf = playback_queue_.front();
|
const ViewerPlaybackFrame& pf = playback_queue_.front();
|
||||||
|
|
||||||
if (pf.timestamp == time) {
|
if (pf.timestamp == time) {
|
||||||
|
|
||||||
// Frame was in queue, no need to decode anything
|
// Frame was in queue, no need to decode anything
|
||||||
SetDisplayImage(pf.frame, true);
|
SetDisplayImage(pf.frame, true);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
// Shown a frame and progressed to the next one
|
|
||||||
display_widget_->IncrementFrameCount();
|
|
||||||
popped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,14 +513,13 @@ void ViewerWidget::UpdateTextureFromNode()
|
|||||||
if (IsPlaying()) {
|
if (IsPlaying()) {
|
||||||
// Is playing, yet the queue above failed to retrieve the frame. We effectively do a quick
|
// 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.
|
// reboot of the queue here, assuming the above loop has emptied it so far.
|
||||||
playback_queue_next_frame_ = GetTimestamp() + playback_speed_;
|
|
||||||
display_widget_->update();
|
display_widget_->update();
|
||||||
} else {
|
} else {
|
||||||
// Not playing, run a task to get the frame either from the cache or the renderer
|
// Not playing, run a task to get the frame either from the cache or the renderer
|
||||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
|
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
|
||||||
nonqueue_watchers_.append(watcher);
|
nonqueue_watchers_.append(watcher);
|
||||||
watcher->SetTicket(GetFrame(time, true));
|
watcher->SetTicket(GetFrame(time, true, true));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// There is definitely no frame here, we can immediately flip to showing nothing
|
// There is definitely no frame here, we can immediately flip to showing nothing
|
||||||
@@ -569,9 +577,18 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
|
|||||||
if (prequeue_length_ > 0) {
|
if (prequeue_length_ > 0) {
|
||||||
prequeuing_ = true;
|
prequeuing_ = true;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
playback_queue_next_frame_ += playback_speed_ * prequeue_length_;
|
||||||
|
int64_t temp = playback_queue_next_frame_;
|
||||||
|
|
||||||
for (int i=0; i<prequeue_length_; i++) {
|
for (int i=0; i<prequeue_length_; i++) {
|
||||||
RequestNextFrameForQueue();
|
playback_queue_next_frame_ -= playback_speed_;
|
||||||
|
RequestNextFrameForQueue(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playback_queue_next_frame_ = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,21 +704,24 @@ void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
|||||||
emit LoadedBuffer(frame.get());
|
emit LoadedBuffer(frame.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::RequestNextFrameForQueue()
|
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
|
||||||
{
|
{
|
||||||
rational next_time = Timecode::timestamp_to_time(playback_queue_next_frame_,
|
rational next_time = Timecode::timestamp_to_time(playback_queue_next_frame_,
|
||||||
timebase());
|
timebase());
|
||||||
|
|
||||||
if (FrameExistsAtTime(next_time) || ViewerMightBeAStill()) {
|
if (FrameExistsAtTime(next_time) || ViewerMightBeAStill()) {
|
||||||
playback_queue_next_frame_ += playback_speed_;
|
if (increment) {
|
||||||
|
playback_queue_next_frame_ += playback_speed_;
|
||||||
|
}
|
||||||
|
|
||||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
|
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
|
||||||
watcher->SetTicket(GetFrame(next_time, false));
|
watcher->SetTicket(GetFrame(next_time, false, prioritize));
|
||||||
|
active_queue_jobs_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queue)
|
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queue, bool prioritize)
|
||||||
{
|
{
|
||||||
QByteArray cached_hash = GetConnectedNode()->video_frame_cache()->GetHash(t);
|
QByteArray cached_hash = GetConnectedNode()->video_frame_cache()->GetHash(t);
|
||||||
|
|
||||||
@@ -713,7 +733,7 @@ RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queu
|
|||||||
auto_cacher_.ClearVideoQueue();
|
auto_cacher_.ClearVideoQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return auto_cacher_.GetSingleFrame(t, clear_render_queue);
|
return auto_cacher_.GetSingleFrame(t, prioritize);
|
||||||
} else {
|
} else {
|
||||||
// Frame has been cached, grab the frame
|
// Frame has been cached, grab the frame
|
||||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||||
@@ -875,6 +895,8 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
active_queue_jobs_--;
|
||||||
|
|
||||||
delete watcher;
|
delete watcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,9 +187,9 @@ private:
|
|||||||
|
|
||||||
void SetDisplayImage(FramePtr frame, bool main_only);
|
void SetDisplayImage(FramePtr frame, bool main_only);
|
||||||
|
|
||||||
void RequestNextFrameForQueue();
|
void RequestNextFrameForQueue(bool prioritize = false, bool increment = true);
|
||||||
|
|
||||||
RenderTicketPtr GetFrame(const rational& t, bool clear_render_queue);
|
RenderTicketPtr GetFrame(const rational& t, bool clear_render_queue, bool prioritize);
|
||||||
|
|
||||||
void FinishPlayPreprocess();
|
void FinishPlayPreprocess();
|
||||||
|
|
||||||
@@ -252,6 +252,8 @@ private:
|
|||||||
FramePtr last_loaded_buffer_;
|
FramePtr last_loaded_buffer_;
|
||||||
bool last_loaded_buffer_is_empty_;
|
bool last_loaded_buffer_is_empty_;
|
||||||
|
|
||||||
|
int active_queue_jobs_;
|
||||||
|
|
||||||
static QVector<ViewerWidget*> instances_;
|
static QVector<ViewerWidget*> instances_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|||||||
Reference in New Issue
Block a user