+ 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.
+ bool snapped = false;
+ for (int64_t snap_pts : { in_pts_lower, in_pts_upper }) {
+ double snap_pts_as_frameno = (snap_pts - in_pts_origin) * output_framerate / TIMEBASE / speed;
+ if (fabs(snap_pts_as_frameno - frameno) < 0.01) {
+ destination->setFrame(stream_idx, snap_pts, /*interpolated=*/false, secondary_stream_idx, secondary_pts, fade_alpha);
+ if (video_stream != nullptr) {
+ if (secondary_stream_idx == -1) {
+ video_stream->schedule_original_frame(pts, stream_idx, snap_pts);
+ } else {
+ video_stream->schedule_faded_frame(pts, stream_idx, snap_pts, secondary_stream_idx, secondary_pts, fade_alpha);
+ }
+ }
+ in_pts_origin += snap_pts - in_pts;
+ snapped = true;
+ break;
+ }
+ }
+ if (snapped) {
+ continue;
+ }
+
+ if (time_behind >= milliseconds(100)) {
+ fprintf(stderr, "WARNING: %ld ms behind, dropping an interpolated frame.\n",
+ lrint(1e3 * duration<double>(time_behind).count()));
+ continue;
+ }
+
+ double alpha = double(in_pts - in_pts_lower) / (in_pts_upper - in_pts_lower);
+
+ if (video_stream == nullptr) {
+ // Previews don't do any interpolation.
+ assert(secondary_stream_idx == -1);
+ destination->setFrame(stream_idx, in_pts_lower, /*interpolated=*/false, fade_alpha);
+ } else {
+ // Calculate the interpolated frame. When it's done, the destination
+ // will be unblocked.
+ destination->setFrame(stream_idx, pts, /*interpolated=*/true, secondary_stream_idx, secondary_pts, fade_alpha);
+ video_stream->schedule_interpolated_frame(pts, stream_idx, in_pts_lower, in_pts_upper, alpha, secondary_stream_idx, secondary_pts, fade_alpha);
+ }
+ }
+
+ // The clip ended.
+
+ // Last-ditch effort to get the next clip (if e.g. the fade time was zero seconds).
+ if (!got_next_clip && next_clip_callback != nullptr) {
+ next_clip = next_clip_callback();
+ if (next_clip.pts_in != -1) {
+ got_next_clip = true;