+ double time_left_this_clip = double(clip.pts_out - in_pts) / TIMEBASE / speed;
+ if (!got_next_clip && next_clip_callback != nullptr && time_left_this_clip <= clip.fade_time_seconds) {
+ // Find the next clip so that we can begin a fade.
+ tie(next_clip, next_clip_idx) = next_clip_callback();
+ if (next_clip.pts_in != -1) {
+ got_next_clip = true;
+
+ double duration_next_clip = (next_clip.pts_out - next_clip.pts_in) / TIMEBASE / speed;
+ next_clip_fade_time = std::min(time_left_this_clip, duration_next_clip);
+ in_pts_start_next_clip = next_clip.pts_in + lrint(next_clip_fade_time * TIMEBASE * speed);
+ }
+ }
+
+ // pts not affected by the swapping below.
+ int64_t in_pts_for_progress = in_pts, in_pts_secondary_for_progress = -1;
+
+ int primary_stream_idx = stream_idx;
+ FrameOnDisk secondary_frame;
+ int secondary_stream_idx = -1;
+ float fade_alpha = 0.0f;
+ if (got_next_clip && time_left_this_clip <= next_clip_fade_time) {
+ secondary_stream_idx = next_clip.stream_idx;
+ int64_t in_pts_secondary = lrint(next_clip.pts_in + (next_clip_fade_time - time_left_this_clip) * TIMEBASE * speed);
+ in_pts_secondary_for_progress = in_pts_secondary;
+ fade_alpha = 1.0f - time_left_this_clip / next_clip_fade_time;
+
+ // If more than half-way through the fade, interpolate the next clip
+ // instead of the current one, since it's more visible.
+ if (fade_alpha >= 0.5f) {
+ swap(primary_stream_idx, secondary_stream_idx);
+ swap(in_pts, in_pts_secondary);
+ fade_alpha = 1.0f - fade_alpha;
+ }
+
+ FrameOnDisk frame_lower, frame_upper;
+ bool ok = find_surrounding_frames(in_pts_secondary, secondary_stream_idx, &frame_lower, &frame_upper);
+ if (ok) {
+ secondary_frame = frame_lower;
+ }
+ }
+
+ if (progress_callback != nullptr) {
+ // NOTE: None of this will take into account any snapping done below.
+ double played_this_clip = double(in_pts_for_progress - clip.pts_in) / TIMEBASE / speed;
+ double total_length = double(clip.pts_out - clip.pts_in) / TIMEBASE / speed;
+ map<size_t, double> progress{{ clip_idx, played_this_clip / total_length }};
+
+ if (got_next_clip && time_left_this_clip <= next_clip_fade_time) {
+ double played_next_clip = double(in_pts_secondary_for_progress - next_clip.pts_in) / TIMEBASE / speed;
+ double total_next_length = double(next_clip.pts_out - next_clip.pts_in) / TIMEBASE / speed;
+ progress[next_clip_idx] = played_next_clip / total_next_length;
+ }
+ progress_callback(progress);
+ }
+
+ FrameOnDisk frame_lower, frame_upper;
+ bool ok = find_surrounding_frames(in_pts, primary_stream_idx, &frame_lower, &frame_upper);
+ if (!ok) {