From a5df4d76d64fa6fdffb1af7f0f2c3dfd4cfdde3c Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 4 Oct 2015 23:52:56 +0200 Subject: [PATCH] Move all mixer stuff into a class. --- glwidget.cpp | 9 +++--- main.cpp | 2 +- mainwindow.cpp | 2 +- mixer.cpp | 69 +++++++++++------------------------------- mixer.h | 81 +++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 92 insertions(+), 71 deletions(-) diff --git a/glwidget.cpp b/glwidget.cpp index 319592e..7f7e008 100644 --- a/glwidget.cpp +++ b/glwidget.cpp @@ -39,7 +39,7 @@ void GLWidget::initializeGL() //printf("threads: %p %p\n", QThread::currentThread(), qGuiApp->thread()); GLWidget *t = this; - set_frame_ready_fallback([t]{ + global_mixer->set_frame_ready_fallback([t]{ QMetaObject::invokeMethod(t, "update", Qt::AutoConnection); }); @@ -48,7 +48,8 @@ void GLWidget::initializeGL() QSurface *surface2 = create_surface(fmt); QSurface *surface3 = create_surface(fmt); QSurface *surface4 = create_surface(fmt); - start_mixer(surface, surface2, surface3, surface4); + global_mixer = new Mixer; + global_mixer->start(surface, surface2, surface3, surface4); // Prepare the shaders to actually get the texture shown (ick). glDisable(GL_BLEND); @@ -103,8 +104,8 @@ void GLWidget::resizeGL(int width, int height) void GLWidget::paintGL() { - DisplayFrame frame; - if (!mixer_get_display_frame(&frame)) { + Mixer::DisplayFrame frame; + if (!global_mixer->get_display_frame(&frame)) { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); return; diff --git a/main.cpp b/main.cpp index f92b12e..d3206f7 100644 --- a/main.cpp +++ b/main.cpp @@ -35,6 +35,6 @@ int main(int argc, char *argv[]) mainWindow.show(); int rc = app.exec(); - mixer_quit(); + global_mixer->quit(); return rc; } diff --git a/mainwindow.cpp b/mainwindow.cpp index b8d9e67..badc236 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -19,5 +19,5 @@ MainWindow::MainWindow() void MainWindow::cut() { static int i = 0; - mixer_cut(Source((++i) % 3)); + global_mixer->cut(Mixer::Source((++i) % 3)); } diff --git a/mixer.cpp b/mixer.cpp index fec83ff..057efb9 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -1,7 +1,3 @@ -#define GL_GLEXT_PROTOTYPES 1 -#define NO_SDL_GLEXT 1 -#define NUM_CARDS 2 - #define WIDTH 1280 #define HEIGHT 720 @@ -52,36 +48,11 @@ using namespace movit; using namespace std; using namespace std::placeholders; -Source current_source = SOURCE_INPUT1; - -ResourcePool *resource_pool; - -std::mutex display_frame_mutex; -DisplayFrame current_display_frame, ready_display_frame; // protected by -bool has_current_display_frame = false, has_ready_display_frame = false; // protected by - -std::mutex bmusb_mutex; -struct CaptureCard { - BMUSBCapture *usb; - - // Threading stuff - bool thread_initialized; - QSurface *surface; - QOpenGLContext *context; +Mixer *global_mixer = nullptr; - bool new_data_ready; // Whether new_frame contains anything. - PBOFrameAllocator::Frame new_frame; - GLsync new_data_ready_fence; // Whether new_frame is ready for rendering. - std::condition_variable new_data_ready_changed; // Set whenever new_data_ready is changed. -}; -CaptureCard cards[NUM_CARDS]; // protected by - -new_frame_ready_callback_t new_frame_ready_callback; -bool has_new_frame_ready_callback = false; - -void bm_frame(int 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 Mixer::bm_frame(int 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) { CaptureCard *card = &cards[card_index]; if (!card->thread_initialized) { @@ -133,7 +104,7 @@ void bm_frame(int card_index, uint16_t timecode, card->usb->get_audio_frame_allocator()->release_frame(audio_frame); } -void place_rectangle(Effect *resample_effect, Effect *padding_effect, float x0, float y0, float x1, float y1) +void Mixer::place_rectangle(Effect *resample_effect, Effect *padding_effect, float x0, float y0, float x1, float y1) { float srcx0 = 0.0f; float srcx1 = 1.0f; @@ -195,9 +166,7 @@ void place_rectangle(Effect *resample_effect, Effect *padding_effect, float x0, CHECK(padding_effect->set_float("border_offset_bottom", y1 - (floor(y0) + height))); } -static bool quit = false; - -void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4) +void Mixer::thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4) { cards[0].surface = surface3; #if NUM_CARDS == 2 @@ -264,7 +233,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3 printf("Configuring first card...\n"); cards[0].usb = new BMUSBCapture(0x1edb, 0xbd3b); // 0xbd4f //cards[0].usb = new BMUSBCapture(0x1edb, 0xbd4f); - cards[0].usb->set_frame_callback(std::bind(bm_frame, 0, _1, _2, _3, _4, _5, _6, _7)); + cards[0].usb->set_frame_callback(std::bind(&Mixer::bm_frame, this, 0, _1, _2, _3, _4, _5, _6, _7)); std::unique_ptr pbo_allocator1(new PBOFrameAllocator(1280 * 750 * 2 + 44)); cards[0].usb->set_video_frame_allocator(pbo_allocator1.get()); cards[0].usb->configure_card(); @@ -273,7 +242,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3 if (NUM_CARDS == 2) { printf("Configuring second card...\n"); cards[1].usb = new BMUSBCapture(0x1edb, 0xbd4f); - cards[1].usb->set_frame_callback(std::bind(bm_frame, 1, _1, _2, _3, _4, _5, _6, _7)); + cards[1].usb->set_frame_callback(std::bind(&Mixer::bm_frame, this, 1, _1, _2, _3, _4, _5, _6, _7)); cards[1].usb->set_video_frame_allocator(pbo_allocator2.get()); cards[1].usb->configure_card(); } @@ -323,7 +292,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3 glGenVertexArrays(1, &vao); check_error(); - while (!quit) { + while (!should_quit) { ++frame; //int width0 = lrintf(848 * (1.0 + 0.2 * sin(frame * 0.02))); @@ -392,7 +361,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3 // The first card is the master timer, so wait for it to have a new frame. // TODO: Make configurable, and with a timeout. - cards[0].new_data_ready_changed.wait(lock, []{ return cards[0].new_data_ready; }); + 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) { CaptureCard *card = &cards[card_index]; @@ -551,7 +520,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3 BMUSBCapture::stop_bm_thread(); } -bool mixer_get_display_frame(DisplayFrame *frame) +bool Mixer::get_display_frame(DisplayFrame *frame) { std::unique_lock lock(display_frame_mutex); if (!has_current_display_frame && !has_ready_display_frame) { @@ -576,28 +545,26 @@ bool mixer_get_display_frame(DisplayFrame *frame) return true; } -void set_frame_ready_fallback(new_frame_ready_callback_t callback) +void Mixer::set_frame_ready_fallback(new_frame_ready_callback_t callback) { new_frame_ready_callback = callback; has_new_frame_ready_callback = true; } -std::thread mixer_thread; - -void start_mixer(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4) +void Mixer::start(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4) { - mixer_thread = std::thread([surface, surface2, surface3, surface4]{ - mixer_thread_func(surface, surface2, surface3, surface4); + mixer_thread = std::thread([this, surface, surface2, surface3, surface4]{ + thread_func(surface, surface2, surface3, surface4); }); } -void mixer_quit() +void Mixer::quit() { - quit = true; + should_quit = true; mixer_thread.join(); } -void mixer_cut(Source source) +void Mixer::cut(Source source) { current_source = source; } diff --git a/mixer.h b/mixer.h index 70953bd..2dffe6d 100644 --- a/mixer.h +++ b/mixer.h @@ -1,30 +1,83 @@ #ifndef _MIXER_H #define _MIXER_H 1 +// The actual video mixer, running in its own separate background thread. + #include #include +#include "bmusb.h" #include "ref_counted_gl_sync.h" +#define NUM_CARDS 2 + +namespace movit { +class Effect; +class ResourcePool; +} +class QOpenGLContext; class QSurface; -void start_mixer(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4); -void mixer_quit(); +class Mixer { +public: + void start(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4); + void quit(); -enum Source { - SOURCE_INPUT1, - SOURCE_INPUT2, - SOURCE_SBS, -}; -void mixer_cut(Source source); + enum Source { + SOURCE_INPUT1, + SOURCE_INPUT2, + SOURCE_SBS, + }; + void cut(Source source); + + struct DisplayFrame { + GLuint texnum; + RefCountedGLsync ready_fence; // Asserted when the texture is done rendering. + }; + // Implicitly frees the previous one if there's a new frame available. + bool get_display_frame(DisplayFrame *frame); + + typedef std::function new_frame_ready_callback_t; + void set_frame_ready_fallback(new_frame_ready_callback_t callback); + +private: + void bm_frame(int 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); + void thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4); + + Source current_source = SOURCE_INPUT1; + + movit::ResourcePool *resource_pool; + + std::mutex display_frame_mutex; + DisplayFrame current_display_frame, ready_display_frame; // protected by + bool has_current_display_frame = false, has_ready_display_frame = false; // protected by + + std::mutex bmusb_mutex; + struct CaptureCard { + BMUSBCapture *usb; + + // Threading stuff + bool thread_initialized; + QSurface *surface; + QOpenGLContext *context; + + bool new_data_ready; // Whether new_frame contains anything. + FrameAllocator::Frame new_frame; + GLsync new_data_ready_fence; // Whether new_frame is ready for rendering. + std::condition_variable new_data_ready_changed; // Set whenever new_data_ready is changed. + }; + CaptureCard cards[NUM_CARDS]; // protected by + + new_frame_ready_callback_t new_frame_ready_callback; + bool has_new_frame_ready_callback = false; -struct DisplayFrame { - GLuint texnum; - RefCountedGLsync ready_fence; // Asserted when the texture is done rendering. + std::thread mixer_thread; + bool should_quit; }; -bool mixer_get_display_frame(DisplayFrame *frame); // Implicitly frees the previous one if there's a new frame available. -typedef std::function new_frame_ready_callback_t; -void set_frame_ready_fallback(new_frame_ready_callback_t callback); +extern Mixer *global_mixer; #endif // !defined(_MIXER_H) -- 2.39.2