+
+TimeRemaining compute_time_left(const vector<ClipWithID> &clips, size_t currently_playing_idx, double progress_currently_playing)
+{
+ // Look at the last clip and then start counting from there.
+ TimeRemaining remaining { 0, 0.0 };
+ double last_fade_time_seconds = 0.0;
+ for (size_t row = currently_playing_idx; row < clips.size(); ++row) {
+ const Clip &clip = clips[row].clip;
+ double clip_length = double(clip.pts_out - clip.pts_in) / TIMEBASE / clip.speed;
+ if (clip_length >= 86400.0) { // More than one day.
+ ++remaining.num_infinite;
+ } else {
+ if (row == currently_playing_idx) {
+ // A clip we're playing: Subtract the part we've already played.
+ remaining.t = clip_length * (1.0 - progress_currently_playing);
+ } else {
+ // A clip we haven't played yet: Subtract the part that's overlapping
+ // with a previous clip (due to fade).
+ remaining.t += max(clip_length - last_fade_time_seconds, 0.0);
+ }
+ }
+ last_fade_time_seconds = min(clip_length, clip.fade_time_seconds);
+ }
+ return remaining;
+}
+
+string format_duration(TimeRemaining t)
+{
+ int t_ms = lrint(t.t * 1e3);
+
+ int ms = t_ms % 1000;
+ t_ms /= 1000;
+ int s = t_ms % 60;
+ t_ms /= 60;
+ int m = t_ms;
+
+ char buf[256];
+ if (t.num_infinite > 1 && t.t > 0.0) {
+ snprintf(buf, sizeof(buf), "%zu clips + %d:%02d.%03d", t.num_infinite, m, s, ms);
+ } else if (t.num_infinite > 1) {
+ snprintf(buf, sizeof(buf), "%zu clips", t.num_infinite);
+ } else if (t.num_infinite == 1 && t.t > 0.0) {
+ snprintf(buf, sizeof(buf), "%zu clip + %d:%02d.%03d", t.num_infinite, m, s, ms);
+ } else if (t.num_infinite == 1) {
+ snprintf(buf, sizeof(buf), "%zu clip", t.num_infinite);
+ } else {
+ snprintf(buf, sizeof(buf), "%d:%02d.%03d", m, s, ms);
+ }
+ return buf;
+}