This is basically just mostly ad hoc from looking at numbers. A large
speed change is defined as a greater than 50% difference between the
previous time frame value and the newly calculated one right after a
speed change (arbitrary). When this is satisfied, there are two distinct
possibilities: the time frame is either negative or positive.
The negative case is actually surprisingly easy to solve. Negative time
frame values are unacceptable since mpv is guaranteed to seek forward
since the audio hasn't caught up yet. So just simply add a tiny negative
value to mpctx->delay (to avoid AV from running away forever) and wait
until the buffer goes positive again before returning back to normal.
This prevents the frames from skipping forwards to weird places for at
least normalish cases.
The positive case is the tricky one. It has a bad tendency to lead to
non-monotonic frame order (i.e. it can skip ahead, then go backwards,
then back forwards again, etc.). This is because the initial frame after
the speed change lingers on the screen for far too long which
essentially causes havoc on the calculations and subsequent passes
through the renderloop overcorrect in both directions until it settles
on the "correct" frame and then proceeds normally.
"Fix" this by basically doing some hacks. Since the source of the
problem is mpctx->time_frame being too big, let's just arbitrarily
reduce the value for a arbitrary amount of frames. Essentially what this
does is smoothen out the change for a short period of time before we
trust that the values are sane enough to allow the normal rendering to
proceed. Up to 8x speed, this seems to work OK for me and the frames
increas monotonically. This is probably about where the limit with this
method is although going any higher will guarentee a/v desync anyways
(you don't actually use speeds this stupid do you).
The final thing here to consider is the display sync code path. It has
similar problems, and the cause in this case is the calculated a_pos
having a dramatic offset from the video pts which causes skipping frames
when changing speed (mostly when you decreaase the speed though). In
this case, what we do is simply hold the a_pos to the video pts until
the a_pos catches back up to a reasonable difference. After that, allow
the normal syncing to happen again.