]> git.sesse.net Git - nageru/commitdiff
Make it possible to queue and play clips with no cue-out set (infinite clips). Note...
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 26 Feb 2019 23:35:19 +0000 (00:35 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 26 Feb 2019 23:35:19 +0000 (00:35 +0100)
futatabi/export.cpp
futatabi/mainwindow.cpp
futatabi/mainwindow.h
futatabi/player.cpp
futatabi/player.h

index d513cf0dacf5a6f6f74ff9cbe14ffde737cee615..a865ac6e9369331a3806ef430c70c82b12d33392 100644 (file)
@@ -227,7 +227,7 @@ void export_interpolated_clip(const string &filename, const vector<Clip> &clips)
        for (const Clip &clip : clips) {
                clips_with_id.emplace_back(ClipWithID{ clip, 0 });
        }
-       double total_length = compute_total_time(clips_with_id);
+       TimeRemaining total_length = compute_total_time(clips_with_id);
 
        promise<void> done_promise;
        future<void> done = done_promise.get_future();
@@ -237,8 +237,8 @@ void export_interpolated_clip(const string &filename, const vector<Clip> &clips)
        player.set_done_callback([&done_promise] {
                done_promise.set_value();
        });
-       player.set_progress_callback([&current_value, total_length](const std::map<uint64_t, double> &player_progress, double time_remaining) {
-               current_value = 1.0 - time_remaining / total_length;
+       player.set_progress_callback([&current_value, total_length](const std::map<uint64_t, double> &player_progress, TimeRemaining time_remaining) {
+               current_value = 1.0 - time_remaining.t / total_length.t;  // Nothing to do about the infinite clips.
        });
        player.play(clips_with_id);
        while (done.wait_for(std::chrono::milliseconds(100)) != future_status::ready && !progress.wasCanceled()) {
index 9b6b47845a46b62b2549eeb2dddd71c127f6ecd0..9bea809b8c63dc2ebe0ac840e9900a313402cd09 100644 (file)
@@ -246,7 +246,7 @@ MainWindow::MainWindow()
                        live_player_done();
                });
        });
-       live_player->set_progress_callback([this](const map<uint64_t, double> &progress, double time_remaining) {
+       live_player->set_progress_callback([this](const map<uint64_t, double> &progress, TimeRemaining time_remaining) {
                post_to_main_thread([this, progress, time_remaining] {
                        live_player_clip_progress(progress, time_remaining);
                });
@@ -424,11 +424,9 @@ void MainWindow::queue_clicked()
        if (!selected->hasSelection()) {
                Clip clip = *cliplist_clips->back();
                clip.stream_idx = 0;
-               if (clip.pts_out != -1) {
-                       playlist_clips->add_clip(clip);
-                       playlist_selection_changed();
-                       ui->playlist->scrollToBottom();
-               }
+               playlist_clips->add_clip(clip);
+               playlist_selection_changed();
+               ui->playlist->scrollToBottom();
                return;
        }
 
@@ -440,15 +438,13 @@ void MainWindow::queue_clicked()
                clip.stream_idx = ui->preview_display->get_stream_idx();
        }
 
-       if (clip.pts_out != -1) {
-               playlist_clips->add_clip(clip);
-               playlist_selection_changed();
-               ui->playlist->scrollToBottom();
-               if (!ui->playlist->selectionModel()->hasSelection()) {
-                       // TODO: Figure out why this doesn't always seem to actually select the row.
-                       QModelIndex bottom = playlist_clips->index(playlist_clips->size() - 1, 0);
-                       ui->playlist->setCurrentIndex(bottom);
-               }
+       playlist_clips->add_clip(clip);
+       playlist_selection_changed();
+       ui->playlist->scrollToBottom();
+       if (!ui->playlist->selectionModel()->hasSelection()) {
+               // TODO: Figure out why this doesn't always seem to actually select the row.
+               QModelIndex bottom = playlist_clips->index(playlist_clips->size() - 1, 0);
+               ui->playlist->setCurrentIndex(bottom);
        }
 }
 
@@ -487,6 +483,9 @@ void MainWindow::preview_clicked()
        } else {
                clip.stream_idx = ui->preview_display->get_stream_idx();
        }
+       if (clip.pts_out == -1) {
+               clip.pts_out = clip.pts_in + int64_t(TIMEBASE) * 86400 * 7;  // One week; effectively infinite, but without overflow issues.
+       }
        preview_player->play(clip);
        preview_playing = true;
        enable_or_disable_preview_button();
@@ -688,7 +687,11 @@ void MainWindow::play_clicked()
 
        vector<ClipWithID> clips;
        for (unsigned row = start_row; row < playlist_clips->size(); ++row) {
-               clips.emplace_back(*playlist_clips->clip_with_id(row));
+               ClipWithID clip = *playlist_clips->clip_with_id(row);
+               if (clip.clip.pts_out == -1) {
+                       clip.clip.pts_out = clip.clip.pts_in + int64_t(TIMEBASE) * 86400 * 7;  // One week; effectively infinite, but without overflow issues.
+               }
+               clips.emplace_back(clip);
        }
        live_player->play(clips);
        playlist_clips->set_progress({ { start_row, 0.0f } });
@@ -743,7 +746,7 @@ void MainWindow::live_player_done()
        playlist_selection_changed();
 }
 
-void MainWindow::live_player_clip_progress(const map<uint64_t, double> &progress, double time_remaining)
+void MainWindow::live_player_clip_progress(const map<uint64_t, double> &progress, TimeRemaining time_remaining)
 {
        playlist_clips->set_progress(progress);
        set_output_status(format_duration(time_remaining) + " left");
@@ -1009,7 +1012,7 @@ void MainWindow::playlist_selection_changed()
                for (size_t row = selected->selectedRows().front().row(); row < playlist_clips->size(); ++row) {
                        clips.emplace_back(*playlist_clips->clip_with_id(row));
                }
-               double remaining = compute_total_time(clips);
+               TimeRemaining remaining = compute_total_time(clips);
                set_output_status(format_duration(remaining) + " ready");
        }
 }
@@ -1279,15 +1282,7 @@ void MainWindow::enable_or_disable_queue_button()
        if (cliplist_clips->empty()) {
                enabled = false;
        } else {
-               QItemSelectionModel *selected = ui->clip_list->selectionModel();
-               if (!selected->hasSelection()) {
-                       Clip clip = *cliplist_clips->back();
-                       enabled = clip.pts_out != -1;
-               } else {
-                       QModelIndex index = selected->currentIndex();
-                       Clip clip = *cliplist_clips->clip(index.row());
-                       enabled = clip.pts_out != -1;
-               }
+               enabled = true;
        }
 
        ui->queue_btn->setEnabled(enabled);
index 7328a5e4bca0128cabc7dbaada2e70bc5eda4d30..592309ab6208a72d0e396c5de2e83db749657ca1 100644 (file)
@@ -4,6 +4,7 @@
 #include "clip_list.h"
 #include "db.h"
 #include "midi_mapper.h"
+#include "player.h"
 #include "state.pb.h"
 
 #include <QLabel>
@@ -143,7 +144,7 @@ private:
        void speed_lock_clicked();
        void preview_player_done();
        void live_player_done();
-       void live_player_clip_progress(const std::map<uint64_t, double> &progress, double time_remaining);
+       void live_player_clip_progress(const std::map<uint64_t, double> &progress, TimeRemaining time_remaining);
        void set_output_status(const std::string &status);
        void playlist_duplicate();
        void playlist_remove();
index 876c8dcac6b95684e54a4cfb3f354eed8331806c..fa094be98b3bfb715730ed4eab3d3b74e0255900 100644 (file)
@@ -272,7 +272,7 @@ void Player::play_playlist_once()
                        // NOTE: None of this will take into account any snapping done below.
                        double clip_progress = calc_progress(*clip, in_pts_for_progress);
                        map<uint64_t, double> progress{ { clip_list[clip_idx].id, clip_progress } };
-                       double time_remaining;
+                       TimeRemaining time_remaining;
                        if (next_clip != nullptr && time_left_this_clip <= next_clip_fade_time) {
                                double next_clip_progress = calc_progress(*next_clip, in_pts_secondary_for_progress);
                                progress[clip_list[clip_idx + 1].id] = next_clip_progress;
@@ -340,7 +340,7 @@ void Player::play_playlist_once()
                                ss.imbue(locale("C"));
                                ss.precision(3);
                                ss << "Futatabi " NAGERU_VERSION ";PLAYING;";
-                               ss << fixed << time_remaining;
+                               ss << fixed << time_remaining.t;
                                ss << ";" << format_duration(time_remaining) << " left";
                                subtitle = ss.str();
                        }
@@ -603,30 +603,34 @@ void Player::release_queue_spot()
        new_clip_changed.notify_all();
 }
 
-double compute_time_left(const vector<ClipWithID> &clips, size_t currently_playing_idx, double progress_currently_playing)
+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.
-       double remaining = 0.0;
+       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 (row == currently_playing_idx) {
-                       // A clip we're playing: Subtract the part we've already played.
-                       remaining = clip_length * (1.0 - progress_currently_playing);
+               if (clip_length >= 86400.0) {  // More than one day.
+                       ++remaining.num_infinite;
                } else {
-                       // A clip we haven't played yet: Subtract the part that's overlapping
-                       // with a previous clip (due to fade).
-                       remaining += max(clip_length - last_fade_time_seconds, 0.0);
+                       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(double t)
+string format_duration(TimeRemaining t)
 {
-       int t_ms = lrint(t * 1e3);
+       int t_ms = lrint(t.t * 1e3);
 
        int ms = t_ms % 1000;
        t_ms /= 1000;
@@ -635,6 +639,16 @@ string format_duration(double t)
        int m = t_ms;
 
        char buf[256];
-       snprintf(buf, sizeof(buf), "%d:%02d.%03d", m, s, ms);
+       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;
 }
index 79ab64db4a1788430aa9658287db9621119b0001..da5a4435da936778dbec3c606c39a312e45af953 100644 (file)
@@ -20,6 +20,11 @@ class VideoStream;
 class QSurface;
 class QSurfaceFormat;
 
+struct TimeRemaining {
+       size_t num_infinite;
+       double t;
+};
+
 class Player : public QueueInterface {
 public:
        enum StreamOutput {
@@ -79,7 +84,7 @@ public:
        // Not thread-safe to set concurrently with playing.
        // Will be called back from the player thread.
        // The keys in the given map are row members in the vector given to play().
-       using progress_callback_func = std::function<void(const std::map<uint64_t, double> &progress, double time_remaining)>;
+       using progress_callback_func = std::function<void(const std::map<uint64_t, double> &progress, TimeRemaining time_remaining)>;
        void set_progress_callback(progress_callback_func cb) { progress_callback = cb; }
 
        // QueueInterface.
@@ -141,13 +146,13 @@ private:
        const StreamOutput stream_output;
 };
 
-double compute_time_left(const std::vector<ClipWithID> &clips, size_t currently_playing_idx, double progress_currently_playing);
+TimeRemaining compute_time_left(const std::vector<ClipWithID> &clips, size_t currently_playing_idx, double progress_currently_playing);
 
-static inline double compute_total_time(const std::vector<ClipWithID> &clips)
+static inline TimeRemaining compute_total_time(const std::vector<ClipWithID> &clips)
 {
        return compute_time_left(clips, 0, 0.0);
 }
 
-std::string format_duration(double t);
+std::string format_duration(TimeRemaining t);
 
 #endif  // !defined(_PLAYER_H)