]> git.sesse.net Git - nageru/commitdiff
Add an option to scan through all possible modes for the PCI cards, as a substitute...
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 4 Mar 2016 22:52:37 +0000 (23:52 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 4 Mar 2016 22:52:37 +0000 (23:52 +0100)
glwidget.cpp
mixer.cpp
mixer.h

index 9215fcad2219360a047e5878d61b0b77b0335c62..5a1325803a283fad20cf8be86478d94945b66ca5 100644 (file)
@@ -144,6 +144,7 @@ void GLWidget::show_context_menu(unsigned signal_num, const QPoint &pos)
        QActionGroup mode_group(&mode_submenu);
        std::map<uint32_t, VideoMode> video_modes = global_mixer->get_available_video_modes(current_card);
        uint32_t current_video_mode = global_mixer->get_current_video_mode(current_card);
+       bool has_auto_mode = false;
        for (const auto &mode : video_modes) {
                QString description(QString::fromStdString(mode.second.name));
                QAction *action = new QAction(description, &mode_group);
@@ -153,6 +154,19 @@ void GLWidget::show_context_menu(unsigned signal_num, const QPoint &pos)
                }
                action->setData(QList<QVariant>{"video_mode", mode.first});
                mode_submenu.addAction(action);
+
+               // TODO: Relying on the 0 value here (from bmusb.h) is ugly, it should be a named constant.
+               if (mode.first == 0) {
+                       has_auto_mode = true;
+               }
+       }
+
+       // Add a “scan” menu if there's no “auto” mode.
+       if (!has_auto_mode) {
+               QAction *action = new QAction("Scan", &mode_group);
+               action->setData(QList<QVariant>{"video_mode", 0});
+               mode_submenu.addSeparator();
+               mode_submenu.addAction(action);
        }
 
        mode_submenu.setTitle("Input mode");
@@ -175,7 +189,11 @@ void GLWidget::show_context_menu(unsigned signal_num, const QPoint &pos)
                QList<QVariant> selected = selected_item->data().toList();
                if (selected[0].toString() == "video_mode") {
                        uint32_t mode = selected[1].toUInt(nullptr);
-                       global_mixer->set_video_mode(current_card, mode);
+                       if (mode == 0 && !has_auto_mode) {
+                               global_mixer->start_mode_scanning(current_card);
+                       } else {
+                               global_mixer->set_video_mode(current_card, mode);
+                       }
                } else if (selected[0].toString() == "card") {
                        unsigned card_index = selected[1].toUInt(nullptr);
                        global_mixer->set_signal_mapping(signal_num, card_index);
index d725ad36b8fe84415d1b92f6201510b978029f2d..a1c038d5329abc21ad0e9a5015e0575f7658b959 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -329,6 +329,26 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
 {
        CaptureCard *card = &cards[card_index];
 
+       if (is_mode_scanning[card_index]) {
+               if (video_format.has_signal) {
+                       // Found a stable signal, so stop scanning.
+                       is_mode_scanning[card_index] = false;
+               } else {
+                       static constexpr double switch_time_s = 0.5;  // Should be enough time for the signal to stabilize.
+                       timespec now;
+                       clock_gettime(CLOCK_MONOTONIC, &now);
+                       double sec_since_last_switch = (now.tv_sec - last_mode_scan_change[card_index].tv_sec) +
+                               1e-9 * (now.tv_nsec - last_mode_scan_change[card_index].tv_nsec);
+                       if (sec_since_last_switch > switch_time_s) {
+                               // It isn't this mode; try the next one.
+                               mode_scanlist_index[card_index]++;
+                               mode_scanlist_index[card_index] %= mode_scanlist[card_index].size();
+                               cards[card_index].capture->set_video_mode(mode_scanlist[card_index][mode_scanlist_index[card_index]]);
+                               last_mode_scan_change[card_index] = now;
+                       }
+               }
+       }
+
        int64_t frame_length = int64_t(TIMEBASE * video_format.frame_rate_den) / video_format.frame_rate_nom;
 
        size_t num_samples = (audio_frame.len >= audio_offset) ? (audio_frame.len - audio_offset) / audio_format.num_channels / (audio_format.bits_per_sample / 8) : 0;
@@ -1037,6 +1057,23 @@ void Mixer::reset_meters()
        correlation.reset();
 }
 
+void Mixer::start_mode_scanning(unsigned card_index)
+{
+       assert(card_index < num_cards);
+       if (is_mode_scanning[card_index]) {
+               return;
+       }
+       is_mode_scanning[card_index] = true;
+       mode_scanlist[card_index].clear();
+       for (const auto &mode : cards[card_index].capture->get_available_video_modes()) {
+               mode_scanlist[card_index].push_back(mode.first);
+       }
+       assert(!mode_scanlist[card_index].empty());
+       mode_scanlist_index[card_index] = 0;
+       cards[card_index].capture->set_video_mode(mode_scanlist[card_index][0]);
+       clock_gettime(CLOCK_MONOTONIC, &last_mode_scan_change[card_index]);
+}
+
 Mixer::OutputChannel::~OutputChannel()
 {
        if (has_current_frame) {
diff --git a/mixer.h b/mixer.h
index 27ba586a7837b646e3933221d430f417d44ec157..061b38243c1adca511de97f119778da3e32c85f1 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -256,6 +256,8 @@ public:
                cards[card_index].capture->set_video_mode(mode);
        }
 
+       void start_mode_scanning(unsigned card_index);
+
 private:
        void configure_card(unsigned card_index, const QSurfaceFormat &format, CaptureInterface *capture);
        void bm_frame(unsigned card_index, uint16_t timecode,
@@ -382,6 +384,12 @@ private:
        std::mutex audio_mutex;
        std::condition_variable audio_task_queue_changed;
        std::queue<AudioTask> audio_task_queue;  // Under audio_mutex.
+
+       // For mode scanning.
+       bool is_mode_scanning[MAX_CARDS]{ false };
+       std::vector<uint32_t> mode_scanlist[MAX_CARDS];
+       unsigned mode_scanlist_index[MAX_CARDS]{ 0 };
+       timespec last_mode_scan_change[MAX_CARDS];
 };
 
 extern Mixer *global_mixer;