summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-12-04 23:53:38 +0100
committerwm4 <wm4@nowhere>2019-12-04 23:55:42 +0100
commit000c045aa873b07cc4ba869dcb82aa4756419637 (patch)
tree57e02fc07b0fbd48fae57ee3fbac82124b311a03
parentc23b3ac53a18489ccb19dd37b22025745c0b2c58 (diff)
downloadmpv-000c045aa873b07cc4ba869dcb82aa4756419637.tar.bz2
mpv-000c045aa873b07cc4ba869dcb82aa4756419637.tar.xz
vo: redraw dropped frame if paused between queuing and drawing frame
When frame-stepping with display-sync mode enabled in high framerate video, the frame was sometimes not redrawn correctly. Only the first OSD interaction (or something similar) made it visible. In this case, the core schedules many frames as dropped (because it's ignorant of pausing/frame-stepping, as in theory the player is _not_ paused during frame-stepping, only at the end of it). There's a race between the VO rendering the queued frame, and the core calling vo_set_paused() after it has queued the frame. If the latter happens first, the existing logic to redraw the previous dropped frame does things correctly. If the former happens, the frame is not redrawn automatically, but will be redrawn on the next user input (or if OSD is enabled, and the pause state change updates it, which leads to an immediate redraw). Fix this by never actually dropping a frame in paused mode. The request by the core to drop it is simply ignored. Maybe this could be done slightly nicer by updating the pause state with the VO atomically. Then we wouldn't have the frame drop counter going up either (it's actually dropped, but then redrawn; but I doubt any user, or me in a few weeks, would understand this). But I'm not really interested in polishing this by increasing the complexity of the frame-step code.
-rw-r--r--video/out/vo.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/video/out/vo.c b/video/out/vo.c
index 0effc41285..e5f8752f07 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -883,6 +883,9 @@ static bool render_frame(struct vo *vo)
if (in->current_frame->num_vsyncs > 0)
in->current_frame->num_vsyncs -= 1;
+ // Always render when paused (it's typically the last frame for a while).
+ in->dropped_frame &= !in->paused;
+
bool use_vsync = in->current_frame->display_synced && !in->paused;
if (use_vsync && !in->expecting_vsync) // first DS frame in a row
in->prev_vsync = now;