summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2024-02-04 18:31:18 +0100
committerDudemanguy <random342@airmail.cc>2024-02-15 16:39:58 +0000
commit5098a27e662ba4a4779baad0408b5e6dcb85c384 (patch)
treef2cf484c4533395e6b02d10c9c2dbed08486aea4
parenta329bb546c0ce553f6fb3fb398b8b728730d63a7 (diff)
downloadmpv-5098a27e662ba4a4779baad0408b5e6dcb85c384.tar.bz2
mpv-5098a27e662ba4a4779baad0408b5e6dcb85c384.tar.xz
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 commit ef11d31. 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 reintroduces 0c9ac5835, 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.
-rw-r--r--video/out/vo.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/video/out/vo.c b/video/out/vo.c
index 3bacfcc581..6e4f41645d 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -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