]> git.sesse.net Git - nageru/commitdiff
Fix some jerkiness when playing back with no interpolation.
authorSteinar H. Gunderson <steinar+nageru@gunderson.no>
Mon, 21 Oct 2019 19:32:34 +0000 (21:32 +0200)
committerBigscreen user <bigscreen@bigscreen.party.solskogen.no>
Mon, 21 Oct 2019 20:35:48 +0000 (22:35 +0200)
When hitting a frame exactly, we'd choose [pts_of_previous_frame, pts]
as our candidate range, and always pick the lower. This would make us
jerk around a lot, which would be a particular problem with audio.

Fix by taking a two-pronged approach: First, if we hit a frame exactly,
just send [pts,pts]. Second, activate snapping even when interpolation
is off.

We still have a problem when playing back audio in the case of dropped
video frames (we'll output the same audio twice), but better audio
handling is somewhat outside the scope of this commit.

futatabi/player.cpp

index 779e685ec10dc62484cd16deee7e9fe080bd7072..442144918559bebe00c106f4d705e4592875b525 100644 (file)
@@ -355,15 +355,6 @@ void Player::play_playlist_once()
                                subtitle = ss.str();
                        }
 
-                       // If there's nothing to interpolate between, or if interpolation is turned off,
-                       // or we're a preview, then just display the frame.
-                       if (frame_lower.pts == frame_upper.pts || global_flags.interpolation_quality == 0 || video_stream == nullptr) {
-                               display_single_frame(primary_stream_idx, frame_lower, secondary_stream_idx,
-                                                    secondary_frame, fade_alpha, next_frame_start, /*snapped=*/false,
-                                                    subtitle, play_audio);
-                               continue;
-                       }
-
                        // Snap to input frame: If we can do so with less than 1% jitter
                        // (ie., move less than 1% of an _output_ frame), do so.
                        // TODO: Snap secondary (fade-to) clips in the same fashion.
@@ -383,6 +374,15 @@ void Player::play_playlist_once()
                                continue;
                        }
 
+                       // If there's nothing to interpolate between, or if interpolation is turned off,
+                       // or we're a preview, then just display the frame.
+                       if (frame_lower.pts == frame_upper.pts || global_flags.interpolation_quality == 0 || video_stream == nullptr) {
+                               display_single_frame(primary_stream_idx, frame_lower, secondary_stream_idx,
+                                                    secondary_frame, fade_alpha, next_frame_start, /*snapped=*/false,
+                                                    subtitle, play_audio);
+                               continue;
+                       }
+
                        // The snapping above makes us lock to the input framerate, even in the presence
                        // of pts drift, for most typical cases where it's needed, like converting 60 → 2x60
                        // or 60 → 2x59.94. However, there are some corner cases like 25 → 2x59.94, where we'd
@@ -487,6 +487,7 @@ void Player::display_single_frame(int primary_stream_idx, const FrameOnDisk &pri
 }
 
 // Find the frame immediately before and after this point.
+// If we have an exact match, return it immediately.
 bool Player::find_surrounding_frames(int64_t pts, int stream_idx, FrameOnDisk *frame_lower, FrameOnDisk *frame_upper)
 {
        lock_guard<mutex> lock(frame_mu);
@@ -498,6 +499,12 @@ bool Player::find_surrounding_frames(int64_t pts, int stream_idx, FrameOnDisk *f
        }
        *frame_upper = *it;
 
+       // If we have an exact match, return it immediately.
+       if (frame_upper->pts == pts) {
+               *frame_lower = *it;
+               return true;
+       }
+
        // Find the last frame such that in_pts <= frame.pts (if any).
        if (it == frames[stream_idx].begin()) {
                *frame_lower = *it;