mirror of https://github.com/mpv-player/mpv
vo: ensure that frames are not eaten on reconfig
This avoids clearing the queued frame and the currently displayed one on VO reconfiguration requests that happen when new frames arrive. Instead, let those frames be fully displayed. Fixes mf:// playback issues introduced after commitef11d31
. Instead of removing the frame timing check embrace and fix it to wake up the playloop as needed. The frame display duration is problematic to handle as both VO and playloop thread would already be sleeping, but in certain use cases it is needed to display frames in full, so in this case, let the VO sleep to the end of frame, wake up the core as requested and go back sleeping. Note that this patch series reintroduces0c9ac5835
, which is esenitally fixed in this commit. It is still not perfect, but it is better than just busy waiting on playloop, even if those events when this would be needed are quite rare.
This commit is contained in:
parent
a329bb546c
commit
5098a27e66
|
@ -768,17 +768,28 @@ void vo_wakeup(struct vo *vo)
|
|||
mp_mutex_unlock(&in->lock);
|
||||
}
|
||||
|
||||
static int64_t get_current_frame_end(struct vo *vo)
|
||||
{
|
||||
struct vo_internal *in = vo->in;
|
||||
if (!in->current_frame)
|
||||
return -1;
|
||||
return in->current_frame->pts + MPMAX(in->current_frame->duration, 0);
|
||||
}
|
||||
|
||||
static bool still_displaying(struct vo *vo)
|
||||
{
|
||||
struct vo_internal *in = vo->in;
|
||||
int64_t now = mp_time_ns();
|
||||
int64_t frame_end = 0;
|
||||
if (in->current_frame) {
|
||||
frame_end = in->current_frame->pts + MPMAX(in->current_frame->duration, 0);
|
||||
if (in->current_frame->display_synced)
|
||||
frame_end = in->current_frame->num_vsyncs > 0 ? INT64_MAX : 0;
|
||||
}
|
||||
return (now < frame_end || in->rendering || in->frame_queued) && in->hasframe;
|
||||
bool working = in->rendering || in->frame_queued;
|
||||
if (working)
|
||||
goto done;
|
||||
|
||||
int64_t frame_end = get_current_frame_end(vo);
|
||||
if (frame_end < 0)
|
||||
goto done;
|
||||
working = mp_time_ns() < frame_end;
|
||||
|
||||
done:
|
||||
return working && in->hasframe;
|
||||
}
|
||||
|
||||
// Return true if there is still a frame being displayed (or queued).
|
||||
|
@ -790,7 +801,7 @@ bool vo_still_displaying(struct vo *vo)
|
|||
return res;
|
||||
}
|
||||
|
||||
// Make vo issue a wakeup once vo_still_displaying() becomes true.
|
||||
// Make vo issue a wakeup once vo_still_displaying() becomes false.
|
||||
void vo_request_wakeup_on_done(struct vo *vo)
|
||||
{
|
||||
struct vo_internal *in = vo->in;
|
||||
|
@ -1037,10 +1048,6 @@ static bool render_frame(struct vo *vo)
|
|||
done:
|
||||
if (!vo->driver->frame_owner || in->dropped_frame)
|
||||
talloc_free(frame);
|
||||
if (in->wakeup_on_done && !still_displaying(vo)) {
|
||||
in->wakeup_on_done = false;
|
||||
wakeup_core(vo);
|
||||
}
|
||||
mp_mutex_unlock(&in->lock);
|
||||
|
||||
return more_frames;
|
||||
|
@ -1116,6 +1123,8 @@ static MP_THREAD_VOID vo_thread(void *ptr)
|
|||
bool working = render_frame(vo);
|
||||
int64_t now = mp_time_ns();
|
||||
int64_t wait_until = now + MP_TIME_S_TO_NS(working ? 0 : 1000);
|
||||
bool wakeup_on_done = false;
|
||||
int64_t wakeup_core_after = 0;
|
||||
|
||||
mp_mutex_lock(&in->lock);
|
||||
if (in->wakeup_pts) {
|
||||
|
@ -1130,6 +1139,14 @@ static MP_THREAD_VOID vo_thread(void *ptr)
|
|||
in->want_redraw = true;
|
||||
wakeup_core(vo);
|
||||
}
|
||||
if ((!working && !in->rendering && !in->frame_queued) && in->wakeup_on_done) {
|
||||
// At this point we know VO is going to sleep
|
||||
int64_t frame_end = get_current_frame_end(vo);
|
||||
if (frame_end >= 0)
|
||||
wakeup_core_after = frame_end;
|
||||
wakeup_on_done = true;
|
||||
in->wakeup_on_done = false;
|
||||
}
|
||||
vo->want_redraw = false;
|
||||
bool redraw = in->request_redraw;
|
||||
bool send_reset = in->send_reset;
|
||||
|
@ -1152,6 +1169,17 @@ static MP_THREAD_VOID vo_thread(void *ptr)
|
|||
if (wait_until <= now)
|
||||
continue;
|
||||
|
||||
if (wakeup_on_done) {
|
||||
// At this point wait_until should be longer than frame duration
|
||||
if (wakeup_core_after >= 0 && wait_until >= wakeup_core_after) {
|
||||
wait_vo(vo, wakeup_core_after);
|
||||
mp_mutex_lock(&in->lock);
|
||||
in->need_wakeup = true;
|
||||
mp_mutex_unlock(&in->lock);
|
||||
}
|
||||
wakeup_core(vo);
|
||||
}
|
||||
|
||||
wait_vo(vo, wait_until);
|
||||
}
|
||||
forget_frames(vo); // implicitly synchronized
|
||||
|
|
Loading…
Reference in New Issue