From a472dcd2c9faec3e191539fb647237195047bbd4 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 1 Nov 2015 20:28:53 +0100 Subject: [PATCH] Make NUM_CARDS into a command-line flag. --- Makefile | 2 +- flags.cpp | 32 ++++++++++++++++++++++++++++++++ flags.h | 11 +++++++++++ glwidget.cpp | 3 ++- main.cpp | 2 ++ mixer.cpp | 37 ++++++++++++++++++++++++++----------- mixer.h | 11 ++++++----- 7 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 flags.cpp create mode 100644 flags.h diff --git a/Makefile b/Makefile index 4c44024..65cf5a6 100644 --- 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 index 0000000..e0c638b --- /dev/null +++ b/flags.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#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 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) diff --git a/glwidget.cpp b/glwidget.cpp index daadaf2..da5be6f 100644 --- a/glwidget.cpp +++ b/glwidget.cpp @@ -16,6 +16,7 @@ #include #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(); }); diff --git a/main.cpp b/main.cpp index b39208f..5917c7e 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,7 @@ #include #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); diff --git a/mixer.cpp b/mixer.cpp index 2e34368..9158b34 100644 --- 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 lock(bmusb_mutex); cards[card_index].should_quit = true; // Unblock thread. @@ -208,7 +209,7 @@ void deinterleave_samples(const vector &in, vector *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 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 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 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 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 a94cf92..9f32f2a 100644 --- 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 resource_pool; @@ -137,9 +138,9 @@ private: std::unique_ptr resampler; // Under audio_mutex. int last_timecode = -1; // Unwrapped. }; - CaptureCard cards[NUM_CARDS]; // protected by + CaptureCard cards[MAX_CARDS]; // protected by - RefCountedFrame bmusb_current_rendering_frame[NUM_CARDS]; + RefCountedFrame bmusb_current_rendering_frame[MAX_CARDS]; class OutputChannel { public: -- 2.39.2