diff --git a/configure.ac b/configure.ac index 012c5566e..e5c8b8308 100644 --- a/configure.ac +++ b/configure.ac @@ -2426,7 +2426,8 @@ then CXXFLAGS="`$PKG_CONFIG --cflags-only-I Qt5Gui ` $CXXFLAGS" CFLAGS="`$PKG_CONFIG --cflags-only-I Qt5Gui ` $CFLAGS" - ADD_MODULE("display_preview", "src/video_display/preview.o", "$QT_LIBS") + ADD_MODULE("display_preview", "src/video_display/preview.o src/shared_mem_frame.o", "$QT_LIBS") + ADD_MODULE("capture_filter_preview", "src/capture_filter/preview.o src/shared_mem_frame.o", "$QT_LIBS") AC_PATH_PROGS(QMAKE, [qmake-qt5 qmake], [:], [/usr/lib/qt5/bin:$PATH]) GUI_TARGET=gui/QT/uv-qt diff --git a/gui/QT/previewWidget.cpp b/gui/QT/previewWidget.cpp index 35b502e7e..53e6b1abe 100644 --- a/gui/QT/previewWidget.cpp +++ b/gui/QT/previewWidget.cpp @@ -109,9 +109,6 @@ void PreviewWidget::initializeGL(){ vidW = 1280; vidH = 720; - - shared_mem.setKey("ultragrid_preview"); - } void PreviewWidget::calculateScale(){ @@ -179,9 +176,8 @@ void PreviewWidget::paintGL(){ f->glUniform2fv(loc, 1, scaleVec); f->glBindTexture(GL_TEXTURE_2D, texture); - if(shared_mem.attach()){ - shared_mem.lock(); - struct Shared_mem_frame *sframe = (Shared_mem_frame*) shared_mem.data(); + struct Shared_mem_frame *sframe = shared_mem.get_frame_and_lock(); + if(sframe){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, sframe->width, sframe->height, 0, GL_RGB, GL_UNSIGNED_BYTE, sframe->pixels); setVidSize(sframe->width, sframe->height); shared_mem.unlock(); diff --git a/gui/QT/previewWidget.hpp b/gui/QT/previewWidget.hpp index 4269d8012..ee7345c82 100644 --- a/gui/QT/previewWidget.hpp +++ b/gui/QT/previewWidget.hpp @@ -7,6 +7,8 @@ #include #include +#include "shared_mem_frame.hpp" + class PreviewWidget : public QOpenGLWidget{ public: PreviewWidget(QWidget *parent) : QOpenGLWidget(parent) { @@ -35,7 +37,7 @@ private: void setVidSize(int w, int h); void calculateScale(); - QSharedMemory shared_mem; + Shared_mem shared_mem; QTimer timer; }; diff --git a/gui/QT/shared_mem_frame.hpp b/gui/QT/shared_mem_frame.hpp deleted file mode 100644 index 297243143..000000000 --- a/gui/QT/shared_mem_frame.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef SHARED_MEM_FRAME_HPP -#define SHARED_MEM_FRAME_HPP - -struct Shared_mem_frame{ - int width, height; - unsigned char pixels[]; -}; - - -#endif diff --git a/gui/QT/uv-qt.pro b/gui/QT/uv-qt.pro index 0dc657a3d..13627cd7f 100644 --- a/gui/QT/uv-qt.pro +++ b/gui/QT/uv-qt.pro @@ -6,6 +6,9 @@ TEMPLATE = app TARGET = uv-qt INCLUDEPATH += . INCLUDEPATH += ../../tools/ +INCLUDEPATH += ../../src + +DEFINES += GUI_BUILD QT += widgets @@ -30,6 +33,7 @@ v4l2.hpp \ previewWidget.hpp \ log_window.hpp \ ../../tools/astat.h \ +../../src/shared_mem_frame.hpp \ vuMeterWidget.hpp \ settings_window.hpp \ @@ -44,4 +48,5 @@ SOURCES += ultragrid_window.cpp \ log_window.cpp \ vuMeterWidget.cpp \ settings_window.cpp \ + ../../src/shared_mem_frame.cpp \ main.cpp diff --git a/src/capture_filter/preview.cpp b/src/capture_filter/preview.cpp new file mode 100644 index 000000000..52983a577 --- /dev/null +++ b/src/capture_filter/preview.cpp @@ -0,0 +1,60 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif /* HAVE_CONFIG_H */ + +#include "capture_filter.h" + +#include "debug.h" +#include "lib_common.h" + +#include "video.h" +#include "video_codec.h" + +#include "shared_mem_frame.hpp" + +struct module; + +static int init(struct module *parent, const char *cfg, void **state); +static void done(void *state); +static struct video_frame *filter(void *state, struct video_frame *in); + +struct state_preview{ + Shared_mem shared_mem; +}; + + +static int init(struct module *parent, const char *cfg, void **state){ + UNUSED(parent); + UNUSED(cfg); + + struct state_preview *s = new state_preview(); + s->shared_mem.create(); + + *state = s; + + return 0; +} + +static void done(void *state){ + delete (state_preview *) state; +} + +static struct video_frame *filter(void *state, struct video_frame *in){ + struct state_preview *s = (state_preview *) state; + + s->shared_mem.put_frame(in); + + return in; +} + + +static const struct capture_filter_info capture_filter_preview = { + .init = init, + .done = done, + .filter = filter, +}; + +REGISTER_MODULE(preview, &capture_filter_preview, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION); + diff --git a/src/shared_mem_frame.cpp b/src/shared_mem_frame.cpp new file mode 100644 index 000000000..c5dda0308 --- /dev/null +++ b/src/shared_mem_frame.cpp @@ -0,0 +1,184 @@ +#include "shared_mem_frame.hpp" + +#ifndef GUI_BUILD +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#include "video_codec.h" +#include "video_frame.h" +#endif // GUI_BUILD + +#include + +Shared_mem::Shared_mem(const char *key) : + key(key), + mem_size(4096), + locked(false) +{ + shared_mem.setKey(key); +} + +Shared_mem::Shared_mem() : Shared_mem("ultragrid_preview") { } + +bool Shared_mem::create(){ + if(shared_mem.create(mem_size) == false){ + /* Creating shared memory could fail because of shared memory + * left over after crash. Here we try to release such memory.*/ + shared_mem.attach(); + shared_mem.detach(); + if(shared_mem.create(mem_size) == false){ + fprintf(stderr, "Can't create shared memory!\n"); + return false; + } + } + + Shared_mem_frame *frame = get_frame_and_lock(); + if(!frame) + return false; + frame->width = 20; + frame->height = 20; + frame->should_detach = false; + unlock(); + return true; +} + +bool Shared_mem::attach(){ + return shared_mem.attach(); +} + +bool Shared_mem::detach(){ + if(locked) + unlock(); + + return shared_mem.detach(); +} + +bool Shared_mem::isAttached(){ + return shared_mem.isAttached(); +} + +bool Shared_mem::lock(){ + if(locked){ + printf("LOCKED\n"); + printf("LOCKED\n"); + printf("LOCKED\n"); + } + if(shared_mem.lock()){ + locked = true; + return true; + } + return false; +} + +bool Shared_mem::unlock(){ + if(shared_mem.unlock()){ + locked = false; + return true; + } + return false; +} + +Shared_mem_frame *Shared_mem::get_frame_and_lock(){ +#ifndef GUI_BUILD + if(reconfiguring){ + if(shared_mem.attach()){ + // Shared mem is still not detached by the GUI + shared_mem.detach(); + return nullptr; + } else { + if(shared_mem.create(mem_size) == false){ + fprintf(stderr, "Can't create shared memory!\n"); + } + lock(); + struct Shared_mem_frame *sframe = (Shared_mem_frame*) shared_mem.data(); + sframe->width = scaledW_pad; + sframe->height = scaledH; + sframe->should_detach = false; + reconfiguring = false; + } + } else { + if(!isAttached()) attach(); + lock(); + } +#else + if(!isAttached()) attach(); + lock(); +#endif // GUI_BUILD + + struct Shared_mem_frame *sframe = (Shared_mem_frame*) shared_mem.data(); + if(sframe && sframe->should_detach){ + detach(); + return nullptr; + } + + return (Shared_mem_frame *) shared_mem.data(); +} + +#ifndef GUI_BUILD + +void Shared_mem::check_reconf(struct video_desc in_desc){ + if (video_desc_eq(desc, in_desc)) + return; + + desc = in_desc; + + /* We need to destroy the shared memory segment + * and recreate it with a new size. To destroy it all processes + * must detach it. We detach here and then wait until the GUI detaches */ + reconfiguring = true; + Shared_mem_frame *sframe = get_frame_and_lock(); + if(sframe){ + sframe->should_detach = true; + } + detach(); + + const float target_width = 960; + const float target_height = 540; + + float scale = ((in_desc.width / target_width) + (in_desc.height / target_height)) / 2.f; + if(scale < 1) + scale = 1; + scale = std::round(scale); + scaleF = (int) scale; + + scaledW = in_desc.width / scaleF; + //OpenGL wants the width to be divisable by 4 + scaledW_pad = ((scaledW + 4 - 1) / 4) * 4; + scaledH = in_desc.height / scaleF; + scaled_frame.resize(get_bpp(in_desc.color_spec) * scaledW * scaledH); + mem_size = get_bpp(preview_codec) * scaledW_pad * scaledH + sizeof(Shared_mem_frame); +} + +void Shared_mem::put_frame(struct video_frame *frame){ + check_reconf(video_desc_from_frame(frame)); + + struct Shared_mem_frame *sframe = get_frame_and_lock(); + + if(!sframe) + return; + + decoder_t dec = get_decoder_from_to(frame->color_spec, preview_codec, true); + + int src_line_len = vc_get_linesize(desc.width, frame->color_spec); + int block_size = get_pf_block_size(frame->color_spec); + int dst = 0; + for(unsigned y = 0; y < desc.height; y += scaleF){ + for(int x = 0; x + scaleF * block_size <= src_line_len; x += scaleF * block_size){ + memcpy(scaled_frame.data() + dst, frame->tiles[0].data + y*src_line_len + x, block_size); + dst += block_size; + } + } + int dst_line_len_pad = vc_get_linesize(scaledW_pad, preview_codec); + int dst_line_len = vc_get_linesize(scaledW, preview_codec); + src_line_len = vc_get_linesize(scaledW, frame->color_spec); + for(int i = 0; i < scaledH; i++){ + dec(sframe->pixels + dst_line_len_pad * i, + scaled_frame.data() + src_line_len * i, + dst_line_len, + 0, 8, 16); + } + + unlock(); +} + +#endif // GUI_BUILD diff --git a/src/shared_mem_frame.hpp b/src/shared_mem_frame.hpp new file mode 100644 index 000000000..40e9f7fae --- /dev/null +++ b/src/shared_mem_frame.hpp @@ -0,0 +1,54 @@ +#ifndef SHARED_MEM_FRAME_HPP +#define SHARED_MEM_FRAME_HPP + +#include + +#ifndef GUI_BUILD +#include "types.h" +#endif // GUI_BUILD + +struct Shared_mem_frame{ + int width, height; + bool should_detach; + unsigned char pixels[]; +}; + +class Shared_mem{ +public: + Shared_mem(const char *key); + Shared_mem(); + bool create(); + bool attach(); + bool detach(); + bool isAttached(); + + bool lock(); + bool unlock(); + +#ifndef GUI_BUILD + void put_frame(struct video_frame *frame); +#endif // GUI_BUILD + + Shared_mem_frame *get_frame_and_lock(); + +private: + const char *key; + size_t mem_size; + bool locked; + QSharedMemory shared_mem; + +#ifndef GUI_BUILD + void check_reconf(struct video_desc in_desc); + static const codec_t preview_codec = RGB; + int scaledW, scaledH; + int scaleF; + int scaledW_pad; + struct video_desc desc = {}; + std::vector scaled_frame; + + bool reconfiguring = false; +#endif // GUI_BUILD +}; + + +#endif diff --git a/src/video_display/preview.cpp b/src/video_display/preview.cpp index 8b834f6a1..e2ba265b3 100644 --- a/src/video_display/preview.cpp +++ b/src/video_display/preview.cpp @@ -77,7 +77,7 @@ struct state_preview_common { mutex lock; condition_variable cv; - QSharedMemory shared_mem; + Shared_mem shared_mem; bool reconfiguring; size_t mem_size; codec_t frame_fmt; @@ -134,31 +134,7 @@ static void *display_preview_init(struct module *parent, const char *fmt, unsign s->common = shared_ptr(new state_preview_common()); s->common->parent = parent; - s->common->shared_mem.setKey("ultragrid_preview"); - s->common->mem_size = 4096; - s->common->frame_fmt = RGB; - if(s->common->shared_mem.create(s->common->mem_size) == false){ - /* Creating shared memory could fail because of shared memory - * left over after crash. Here we try to release such memory. */ - s->common->shared_mem.attach(); - s->common->shared_mem.detach(); - if(s->common->shared_mem.create(s->common->mem_size) == false){ - fprintf(stderr, "Can't create shared memory!\n"); - return &display_init_noerr; - } - } - - s->common->reconfiguring = false; - s->common->shared_mem.lock(); - - struct Shared_mem_frame *sframe = (Shared_mem_frame*) s->common->shared_mem.data(); - sframe->width = 20; - sframe->height = 20; - - s->common->shared_mem.unlock(); - - s->common->scaleF = 4; - + s->common->shared_mem.create(); return s; } @@ -169,27 +145,6 @@ static void check_reconf(struct state_preview_common *s, struct video_desc desc) s->display_desc = desc; fprintf(stderr, "RECONFIGURED\n"); - /* We need to destroy the shared memory segment - * and recreate it with a new size. To destroy it all processes - * must detach it. We detach here and then wait until the GUI detaches */ - s->reconfiguring = true; - - const float target_width = 960; - const float target_height = 540; - - float scale = ((desc.width / target_width) + (desc.height / target_height)) / 2.f; - if(scale < 1) - scale = 1; - scale = std::round(scale); - s->scaleF = (int) scale; - - s->scaledW = desc.width / s->scaleF; - //OpenGL wants the width to be divisable by 4 - s->scaledW_pad = ((s->scaledW + 4 - 1) / 4) * 4; - s->scaledH = desc.height / s->scaleF; - s->scaled_frame.resize(get_bpp(desc.color_spec) * s->scaledW * s->scaledH); - s->shared_mem.detach(); - s->mem_size = get_bpp(s->frame_fmt) * s->scaledW_pad * s->scaledH + sizeof(Shared_mem_frame); } static void display_preview_run(void *state) @@ -219,50 +174,8 @@ static void display_preview_run(void *state) check_reconf(s.get(), video_desc_from_frame(frame)); - if(s->reconfiguring){ - if(s->shared_mem.attach()){ - // Shared mem is still not detached by the GUI - s->shared_mem.detach(); - vf_free(frame); - continue; - } else { - if(s->shared_mem.create(s->mem_size) == false){ - fprintf(stderr, "Can't create shared memory!\n"); - } - s->shared_mem.lock(); - struct Shared_mem_frame *sframe = (Shared_mem_frame*) s->shared_mem.data(); - sframe->width = s->scaledW_pad; - sframe->height = s->scaledH; - s->reconfiguring = false; - } - } else { - s->shared_mem.lock(); - } + s->shared_mem.put_frame(frame); - struct Shared_mem_frame *sframe = (Shared_mem_frame*) s->shared_mem.data(); - - decoder_t dec = get_decoder_from_to(frame->color_spec, s->frame_fmt, true); - - int src_line_len = vc_get_linesize(s->display_desc.width, frame->color_spec); - int block_size = get_pf_block_size(frame->color_spec); - int dst = 0; - for(unsigned y = 0; y < s->display_desc.height; y += s->scaleF){ - for(int x = 0; x + s->scaleF * block_size <= src_line_len; x += s->scaleF * block_size){ - memcpy(s->scaled_frame.data() + dst, frame->tiles[0].data + y*src_line_len + x, block_size); - dst += block_size; - } - } - int dst_line_len_pad = vc_get_linesize(s->scaledW_pad, s->frame_fmt); - int dst_line_len = vc_get_linesize(s->scaledW, s->frame_fmt); - src_line_len = vc_get_linesize(s->scaledW, frame->color_spec); - for(int i = 0; i < s->scaledH; i++){ - dec(sframe->pixels + dst_line_len_pad * i, - s->scaled_frame.data() + src_line_len * i, - dst_line_len, - 0, 8, 16); - } - - s->shared_mem.unlock(); vf_free(frame); } } @@ -289,7 +202,7 @@ static int display_preview_putf(void *state, struct video_frame *frame, int flag } else { unique_lock lg(s->lock); if (s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) { - fprintf(stderr, "Multiplier: queue full!\n"); + fprintf(stderr, "Preview: queue full!\n"); } if (flags == PUTF_NONBLOCK && s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) { vf_free(frame); diff --git a/src/video_display/shared_mem_frame.hpp b/src/video_display/shared_mem_frame.hpp deleted file mode 100644 index 297243143..000000000 --- a/src/video_display/shared_mem_frame.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef SHARED_MEM_FRAME_HPP -#define SHARED_MEM_FRAME_HPP - -struct Shared_mem_frame{ - int width, height; - unsigned char pixels[]; -}; - - -#endif