mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 23:40:26 +00:00
Add capture filter for GUI preview
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QTimer>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
60
src/capture_filter/preview.cpp
Normal file
60
src/capture_filter/preview.cpp
Normal file
@@ -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);
|
||||
|
||||
184
src/shared_mem_frame.cpp
Normal file
184
src/shared_mem_frame.cpp
Normal file
@@ -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 <stdio.h>
|
||||
|
||||
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
|
||||
54
src/shared_mem_frame.hpp
Normal file
54
src/shared_mem_frame.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef SHARED_MEM_FRAME_HPP
|
||||
#define SHARED_MEM_FRAME_HPP
|
||||
|
||||
#include <QSharedMemory>
|
||||
|
||||
#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<unsigned char> scaled_frame;
|
||||
|
||||
bool reconfiguring = false;
|
||||
#endif // GUI_BUILD
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -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<state_preview_common>(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<mutex> 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);
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user