]> git.sesse.net Git - nageru/commitdiff
Make NUM_CARDS into a command-line flag.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Nov 2015 19:28:53 +0000 (20:28 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Nov 2015 19:28:53 +0000 (20:28 +0100)
Makefile
flags.cpp [new file with mode: 0644]
flags.h [new file with mode: 0644]
glwidget.cpp
main.cpp
mixer.cpp
mixer.h

index 4c440240a6d65e6fe0c0d3236a440139fdcfc89f..65cf5a66691250fc0d212b580db0f0b07e44f736 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o
 OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o
 
 # Mixer objects
-OBJS += h264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampler.o httpd.o ebu_r128_proc.o
+OBJS += h264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampler.o httpd.o ebu_r128_proc.o flags.o
 
 %.o: %.cpp
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
diff --git a/flags.cpp b/flags.cpp
new file mode 100644 (file)
index 0000000..e0c638b
--- /dev/null
+++ b/flags.cpp
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "flags.h"
+
+Flags global_flags;
+
+void parse_flags(int argc, char * const argv[])
+{
+       static const option long_options[] = {
+               { "num-cards", required_argument, 0, 'c' },
+               { 0, 0, 0, 0 }
+       };
+       for ( ;; ) {
+               int option_index = 0;
+               int c = getopt_long(argc, argv, "c:", long_options, &option_index);
+
+               if (c == -1) {
+                       break;
+               }
+               switch (c) {
+               case 'c':
+                       global_flags.num_cards = atoi(optarg);
+                       break;
+               default:
+                       fprintf(stderr, "Unknown option '%s'\n", argv[option_index]);
+                       exit(1);
+               }
+       }
+}
diff --git a/flags.h b/flags.h
new file mode 100644 (file)
index 0000000..bfb51da
--- /dev/null
+++ b/flags.h
@@ -0,0 +1,11 @@
+#ifndef _FLAGS_H
+#define _FLAGS_H
+
+struct Flags {
+       int num_cards = 2;
+};
+extern Flags global_flags;
+
+void parse_flags(int argc, char * const argv[]);
+
+#endif  // !defined(_FLAGS_H)
index daadaf2f8d0e222efca7403e60226e20e86bfa46..da5be6f88221373eedaddf8860291a2ad95f5ab2 100644 (file)
@@ -16,6 +16,7 @@
 #include <mutex>
 
 #include "context.h"
+#include "flags.h"
 #include "mixer.h"
 #include "ref_counted_gl_sync.h"
 #include "vumeter.h"
@@ -47,7 +48,7 @@ void GLWidget::initializeGL()
 
        static std::once_flag flag;
        std::call_once(flag, [this]{
-               global_mixer = new Mixer(QGLFormat::toSurfaceFormat(format()));
+               global_mixer = new Mixer(QGLFormat::toSurfaceFormat(format()), global_flags.num_cards);
                global_mainwindow->mixer_created(global_mixer);
                global_mixer->start();
        });
index b39208fab53630eda018d94201d19ce94d366596..5917c7efa9838521132bb8d035fb8e41d3157e3f 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -8,6 +8,7 @@
 #include <QSurfaceFormat>
 
 #include "context.h"
+#include "flags.h"
 #include "mainwindow.h"
 #include "mixer.h"
 
@@ -16,6 +17,7 @@ int main(int argc, char *argv[])
        setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0);
        setlinebuf(stdout);
        av_register_all();
+       parse_flags(argc, argv);
 
        QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
        QApplication app(argc, argv);
index 2e3436884c515e82f3a56b153d3c8239bf46fa0e..9158b3478a3f6db6a194f7086301ae686a57a799 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -70,8 +70,9 @@ void convert_fixed24_to_fp32(float *dst, size_t out_channels, const uint8_t *src
 
 }  // namespace
 
-Mixer::Mixer(const QSurfaceFormat &format)
+Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
        : httpd("test.ts", WIDTH, HEIGHT),
+         num_cards(num_cards),
          mixer_surface(create_surface(format)),
          h264_encoder_surface(create_surface(format))
 {
@@ -106,7 +107,7 @@ Mixer::Mixer(const QSurfaceFormat &format)
 
        h264_encoder.reset(new H264Encoder(h264_encoder_surface, WIDTH, HEIGHT, &httpd));
 
-       for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                printf("Configuring card %d...\n", card_index);
                CaptureCard *card = &cards[card_index];
                card->usb = new BMUSBCapture(card_index);
@@ -132,7 +133,7 @@ Mixer::Mixer(const QSurfaceFormat &format)
 
        BMUSBCapture::start_bm_thread();
 
-       for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                cards[card_index].usb->start_bm_capture();
        }
 
@@ -160,7 +161,7 @@ Mixer::~Mixer()
        resource_pool->release_glsl_program(cbcr_program_num);
        BMUSBCapture::stop_bm_thread();
 
-       for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                {
                        unique_lock<mutex> lock(bmusb_mutex);
                        cards[card_index].should_quit = true;  // Unblock thread.
@@ -208,7 +209,7 @@ void deinterleave_samples(const vector<float> &in, vector<float> *out_l, vector<
 
 }  // namespace
 
-void Mixer::bm_frame(int card_index, uint16_t timecode,
+void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                      FrameAllocator::Frame video_frame, size_t video_offset, uint16_t video_format,
                     FrameAllocator::Frame audio_frame, size_t audio_offset, uint16_t audio_format)
 {
@@ -348,7 +349,7 @@ void Mixer::thread_func()
        int dropped_frames = 0;
 
        while (!should_quit) {
-               CaptureCard card_copy[NUM_CARDS];
+               CaptureCard card_copy[MAX_CARDS];
 
                {
                        unique_lock<mutex> lock(bmusb_mutex);
@@ -357,7 +358,7 @@ void Mixer::thread_func()
                        // TODO: Make configurable, and with a timeout.
                        cards[0].new_data_ready_changed.wait(lock, [this]{ return cards[0].new_data_ready; });
 
-                       for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+                       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                                CaptureCard *card = &cards[card_index];
                                card_copy[card_index].usb = card->usb;
                                card_copy[card_index].new_data_ready = card->new_data_ready;
@@ -374,7 +375,7 @@ void Mixer::thread_func()
                vector<float> samples_out;
                // TODO: Allow using audio from the other card(s) as well.
                for (unsigned frame_num = 0; frame_num < card_copy[0].dropped_frames + 1; ++frame_num) {
-                       for (unsigned card_index = 0; card_index < NUM_CARDS; ++card_index) {
+                       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                                samples_out.resize((48000 / 60) * 2);
                                {
                                        unique_lock<mutex> lock(cards[card_index].audio_mutex);
@@ -408,6 +409,16 @@ void Mixer::thread_func()
                                             loudness_i, loudness_range_low, loudness_range_high);
                }
 
+               for (unsigned card_index = 1; card_index < num_cards; ++card_index) {
+                       if (card_copy[card_index].new_data_ready && card_copy[card_index].new_frame->len == 0) {
+                               ++card_copy[card_index].dropped_frames;
+                       }
+                       if (card_copy[card_index].dropped_frames > 0) {
+                               printf("Card %u dropped %d frames before this\n",
+                                       card_index, int(card_copy[card_index].dropped_frames));
+                       }
+               }
+
                // If the first card is reporting a corrupted or otherwise dropped frame,
                // just increase the pts (skipping over this frame) and don't try to compute anything new.
                if (card_copy[0].new_frame->len == 0) {
@@ -416,7 +427,7 @@ void Mixer::thread_func()
                        continue;
                }
 
-               for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+               for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                        CaptureCard *card = &card_copy[card_index];
                        if (!card->new_data_ready || card->new_frame->len == 0)
                                continue;
@@ -471,7 +482,7 @@ void Mixer::thread_func()
                // input frames needed, so that they are not released back
                // until the rendering is done.
                vector<RefCountedFrame> input_frames;
-               for (int card_index = 0; card_index < NUM_CARDS; ++card_index) {
+               for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                        input_frames.push_back(bmusb_current_rendering_frame[card_index]);
                }
                const int64_t av_delay = TIMEBASE / 10;  // Corresponds to the fixed delay in resampler.h. TODO: Make less hard-coded.
@@ -498,7 +509,11 @@ void Mixer::thread_func()
                        display_frame.chain = chain.first;
                        display_frame.setup_chain = chain.second;
                        display_frame.ready_fence = fence;
-                       display_frame.input_frames = { bmusb_current_rendering_frame[0], bmusb_current_rendering_frame[1] };  // FIXME: possible to do better?
+
+                       // FIXME: possible to do better?
+                       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
+                               display_frame.input_frames.push_back(bmusb_current_rendering_frame[card_index]);
+                       }
                        display_frame.temp_textures = {};
                        output_channel[i].output_frame(display_frame);
                }
diff --git a/mixer.h b/mixer.h
index a94cf922fce2b0600521caef8ff87b01ff1939cb..9f32f2ac2d79f5c6d86156bb38f0af5ea6d17564 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -20,7 +20,7 @@
 #include "httpd.h"
 #include "ebu_r128_proc.h"
 
-#define NUM_CARDS 2
+#define MAX_CARDS 16
 
 namespace movit {
 class YCbCrInput;
@@ -31,7 +31,7 @@ class QSurfaceFormat;
 class Mixer {
 public:
        // The surface format is used for offscreen destinations for OpenGL contexts we need.
-       Mixer(const QSurfaceFormat &format);
+       Mixer(const QSurfaceFormat &format, unsigned num_cards);
        ~Mixer();
        void start();
        void quit();
@@ -93,7 +93,7 @@ public:
        }
 
 private:
-       void bm_frame(int card_index, uint16_t timecode,
+       void bm_frame(unsigned card_index, uint16_t timecode,
                FrameAllocator::Frame video_frame, size_t video_offset, uint16_t video_format,
                FrameAllocator::Frame audio_frame, size_t audio_offset, uint16_t audio_format);
        void place_rectangle(movit::Effect *resample_effect, movit::Effect *padding_effect, float x0, float y0, float x1, float y1);
@@ -103,6 +103,7 @@ private:
        double pts() { return double(pts_int) / TIMEBASE; }
 
        HTTPD httpd;
+       unsigned num_cards;
 
        QSurface *mixer_surface, *h264_encoder_surface;
        std::unique_ptr<movit::ResourcePool> resource_pool;
@@ -137,9 +138,9 @@ private:
                std::unique_ptr<Resampler> resampler;  // Under audio_mutex.
                int last_timecode = -1;  // Unwrapped.
        };
-       CaptureCard cards[NUM_CARDS];  // protected by <bmusb_mutex>
+       CaptureCard cards[MAX_CARDS];  // protected by <bmusb_mutex>
 
-       RefCountedFrame bmusb_current_rendering_frame[NUM_CARDS];
+       RefCountedFrame bmusb_current_rendering_frame[MAX_CARDS];
 
        class OutputChannel {
        public: