mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Bug fixes and new implementations
- Video format MJPEG implemented (libjpeg/qimage) - Inactive priorities are now skipped correctly (PriorityMuxer.cpp line 297) - v4l configuration section replaced with an object (preparation for #542)
This commit is contained in:
parent
4aab0ad55c
commit
0a8af60726
@ -268,6 +268,18 @@ find_package(libusb-1.0 REQUIRED)
|
|||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
add_definitions(${QT_DEFINITIONS})
|
add_definitions(${QT_DEFINITIONS})
|
||||||
|
|
||||||
|
# Add jpeg library
|
||||||
|
if (ENABLE_V4L2)
|
||||||
|
find_package(JPEG)
|
||||||
|
if (JPEG_FOUND)
|
||||||
|
add_definitions(-DHAVE_JPEG)
|
||||||
|
message( STATUS "Using JPEG library: ${JPEG_LIBRARIES}")
|
||||||
|
include_directories(${JPEG_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
message( STATUS "JPEG library not found, MJPEG camera format won't work in V4L2 grabber.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# TODO[TvdZ]: This linking directory should only be added if we are cross compiling
|
# TODO[TvdZ]: This linking directory should only be added if we are cross compiling
|
||||||
#if(NOT APPLE)
|
#if(NOT APPLE)
|
||||||
# link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
|
# link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
|
||||||
|
@ -26,7 +26,7 @@ Note: call the script with `./docker-compile.sh -h` for more options
|
|||||||
|
|
||||||
```
|
```
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev
|
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**on RPI you need the videocore IV headers**
|
**on RPI you need the videocore IV headers**
|
||||||
|
@ -27,7 +27,7 @@ $(document).ready( function() {
|
|||||||
//v4l
|
//v4l
|
||||||
$('#conf_cont').append(createRow('conf_cont_v4l'))
|
$('#conf_cont').append(createRow('conf_cont_v4l'))
|
||||||
$('#conf_cont_v4l').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2'));
|
$('#conf_cont_v4l').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2'));
|
||||||
$('#conf_cont_v4l').append(createHelpTable(schema.grabberV4L2.items.properties, $.i18n("edt_conf_v4l2_heading_title")));
|
$('#conf_cont_v4l').append(createHelpTable(schema.grabberV4L2.properties, $.i18n("edt_conf_v4l2_heading_title")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -114,26 +114,24 @@
|
|||||||
/// * sDHOffsetMax : area for signal detection - horizontal maximum offset value. Values between 0.0 and 1.0
|
/// * sDHOffsetMax : area for signal detection - horizontal maximum offset value. Values between 0.0 and 1.0
|
||||||
/// * sDVOffsetMax : area for signal detection - vertical maximum offset value. Values between 0.0 and 1.0
|
/// * sDVOffsetMax : area for signal detection - vertical maximum offset value. Values between 0.0 and 1.0
|
||||||
"grabberV4L2" :
|
"grabberV4L2" :
|
||||||
[
|
{
|
||||||
{
|
"device" : "auto",
|
||||||
"device" : "auto",
|
"standard" : "NO_CHANGE",
|
||||||
"standard" : "NO_CHANGE",
|
"sizeDecimation" : 8,
|
||||||
"sizeDecimation" : 8,
|
"priority" : 240,
|
||||||
"priority" : 240,
|
"cropLeft" : 0,
|
||||||
"cropLeft" : 0,
|
"cropRight" : 0,
|
||||||
"cropRight" : 0,
|
"cropTop" : 0,
|
||||||
"cropTop" : 0,
|
"cropBottom" : 0,
|
||||||
"cropBottom" : 0,
|
"redSignalThreshold" : 5,
|
||||||
"redSignalThreshold" : 5,
|
"greenSignalThreshold" : 5,
|
||||||
"greenSignalThreshold" : 5,
|
"blueSignalThreshold" : 5,
|
||||||
"blueSignalThreshold" : 5,
|
"signalDetection" : false,
|
||||||
"signalDetection" : false,
|
"sDVOffsetMin" : 0.25,
|
||||||
"sDVOffsetMin" : 0.25,
|
"sDHOffsetMin" : 0.25,
|
||||||
"sDHOffsetMin" : 0.25,
|
"sDVOffsetMax" : 0.75,
|
||||||
"sDVOffsetMax" : 0.75,
|
"sDHOffsetMax" : 0.75
|
||||||
"sDHOffsetMax" : 0.75
|
},
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
/// The configuration for the frame-grabber, contains the following items:
|
/// The configuration for the frame-grabber, contains the following items:
|
||||||
/// * type : type of grabber. (auto|osx|dispmanx|amlogic|x11|framebuffer|qt) [auto]
|
/// * type : type of grabber. (auto|osx|dispmanx|amlogic|x11|framebuffer|qt) [auto]
|
||||||
|
@ -57,25 +57,23 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"grabberV4L2" :
|
"grabberV4L2" :
|
||||||
[
|
{
|
||||||
{
|
"device" : "auto",
|
||||||
"device" : "auto",
|
"standard" : "NO_CHANGE",
|
||||||
"standard" : "NO_CHANGE",
|
"sizeDecimation" : 8,
|
||||||
"sizeDecimation" : 8,
|
"cropLeft" : 0,
|
||||||
"cropLeft" : 0,
|
"cropRight" : 0,
|
||||||
"cropRight" : 0,
|
"cropTop" : 0,
|
||||||
"cropTop" : 0,
|
"cropBottom" : 0,
|
||||||
"cropBottom" : 0,
|
"redSignalThreshold" : 5,
|
||||||
"redSignalThreshold" : 5,
|
"greenSignalThreshold" : 5,
|
||||||
"greenSignalThreshold" : 5,
|
"blueSignalThreshold" : 5,
|
||||||
"blueSignalThreshold" : 5,
|
"signalDetection" : false,
|
||||||
"signalDetection" : false,
|
"sDVOffsetMin" : 0.25,
|
||||||
"sDVOffsetMin" : 0.25,
|
"sDHOffsetMin" : 0.25,
|
||||||
"sDHOffsetMin" : 0.25,
|
"sDVOffsetMax" : 0.75,
|
||||||
"sDVOffsetMax" : 0.75,
|
"sDHOffsetMax" : 0.75
|
||||||
"sDHOffsetMax" : 0.75
|
},
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
"framegrabber" :
|
"framegrabber" :
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,13 @@
|
|||||||
#include <utils/PixelFormat.h>
|
#include <utils/PixelFormat.h>
|
||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
#include <grabber/VideoStandard.h>
|
#include <grabber/VideoStandard.h>
|
||||||
|
#include <utils/Components.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
#include <QImage>
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <csetjmp>
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Capture class for V4L2 devices
|
/// Capture class for V4L2 devices
|
||||||
///
|
///
|
||||||
@ -78,6 +85,8 @@ public slots:
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
void componentStateChanged(const hyperion::Components component, bool enable);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newFrame(const Image<ColorRgb> & image);
|
void newFrame(const Image<ColorRgb> & image);
|
||||||
void readError(const char* err);
|
void readError(const char* err);
|
||||||
@ -111,7 +120,7 @@ private:
|
|||||||
|
|
||||||
bool process_image(const void *p, int size);
|
bool process_image(const void *p, int size);
|
||||||
|
|
||||||
void process_image(const uint8_t *p);
|
void process_image(const uint8_t *p, int size);
|
||||||
|
|
||||||
int xioctl(int request, void *arg);
|
int xioctl(int request, void *arg);
|
||||||
|
|
||||||
@ -120,17 +129,41 @@ private:
|
|||||||
void throw_errno_exception(const QString &error);
|
void throw_errno_exception(const QString &error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum io_method {
|
enum io_method
|
||||||
|
{
|
||||||
IO_METHOD_READ,
|
IO_METHOD_READ,
|
||||||
IO_METHOD_MMAP,
|
IO_METHOD_MMAP,
|
||||||
IO_METHOD_USERPTR
|
IO_METHOD_USERPTR
|
||||||
};
|
};
|
||||||
|
|
||||||
struct buffer {
|
struct buffer
|
||||||
|
{
|
||||||
void *start;
|
void *start;
|
||||||
size_t length;
|
size_t length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
struct errorManager
|
||||||
|
{
|
||||||
|
jpeg_error_mgr pub;
|
||||||
|
jmp_buf setjmp_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void errorHandler(j_common_ptr cInfo)
|
||||||
|
{
|
||||||
|
errorManager* mgr = reinterpret_cast<errorManager*>(cInfo->err);
|
||||||
|
longjmp(mgr->setjmp_buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outputHandler(j_common_ptr cInfo)
|
||||||
|
{
|
||||||
|
// Suppress fprintf warnings.
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_decompress_struct* _decompress;
|
||||||
|
errorManager* _error;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _deviceName;
|
QString _deviceName;
|
||||||
std::map<QString,QString> _v4lDevices;
|
std::map<QString,QString> _v4lDevices;
|
||||||
@ -156,7 +189,7 @@ private:
|
|||||||
double _x_frac_max;
|
double _x_frac_max;
|
||||||
double _y_frac_max;
|
double _y_frac_max;
|
||||||
|
|
||||||
QSocketNotifier * _streamNotifier;
|
QSocketNotifier *_streamNotifier;
|
||||||
|
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
bool _deviceAutoDiscoverEnabled;
|
bool _deviceAutoDiscoverEnabled;
|
||||||
|
@ -12,6 +12,9 @@ enum PixelFormat {
|
|||||||
PIXELFORMAT_BGR24,
|
PIXELFORMAT_BGR24,
|
||||||
PIXELFORMAT_RGB32,
|
PIXELFORMAT_RGB32,
|
||||||
PIXELFORMAT_BGR32,
|
PIXELFORMAT_BGR32,
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
PIXELFORMAT_MJPEG,
|
||||||
|
#endif
|
||||||
PIXELFORMAT_NO_CHANGE
|
PIXELFORMAT_NO_CHANGE
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,6 +47,12 @@ inline PixelFormat parsePixelFormat(QString pixelFormat)
|
|||||||
{
|
{
|
||||||
return PIXELFORMAT_BGR32;
|
return PIXELFORMAT_BGR32;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
else if (pixelFormat == "mjpeg")
|
||||||
|
{
|
||||||
|
return PIXELFORMAT_MJPEG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// return the default NO_CHANGE
|
// return the default NO_CHANGE
|
||||||
return PIXELFORMAT_NO_CHANGE;
|
return PIXELFORMAT_NO_CHANGE;
|
||||||
|
@ -10,3 +10,7 @@ target_link_libraries(v4l2-grabber
|
|||||||
hyperion
|
hyperion
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (JPEG_FOUND)
|
||||||
|
target_link_libraries(v4l2-grabber ${JPEG_LIBRARY})
|
||||||
|
endif()
|
||||||
|
@ -16,11 +16,15 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include "grabber/V4L2Grabber.h"
|
#include "grabber/V4L2Grabber.h"
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
#define CLEAR(x) memset(&(x), 0, sizeof(x))
|
#define CLEAR(x) memset(&(x), 0, sizeof(x))
|
||||||
|
|
||||||
V4L2Grabber::V4L2Grabber(const QString & device
|
V4L2Grabber::V4L2Grabber(const QString & device
|
||||||
@ -55,6 +59,10 @@ V4L2Grabber::V4L2Grabber(const QString & device
|
|||||||
setPixelDecimation(pixelDecimation);
|
setPixelDecimation(pixelDecimation);
|
||||||
getV4Ldevices();
|
getV4Ldevices();
|
||||||
|
|
||||||
|
// listen for component change for build-in grabber only
|
||||||
|
if (Hyperion::_hyperion)
|
||||||
|
connect(Hyperion::getInstance(), &Hyperion::componentStateChanged, this, &V4L2Grabber::componentStateChanged);
|
||||||
|
|
||||||
// init
|
// init
|
||||||
setDeviceVideoStandard(device, videoStandard);
|
setDeviceVideoStandard(device, videoStandard);
|
||||||
}
|
}
|
||||||
@ -70,11 +78,7 @@ void V4L2Grabber::uninit()
|
|||||||
if (_initialized)
|
if (_initialized)
|
||||||
{
|
{
|
||||||
Debug(_log,"uninit grabber: %s", QSTRING_CSTR(_deviceName));
|
Debug(_log,"uninit grabber: %s", QSTRING_CSTR(_deviceName));
|
||||||
|
|
||||||
stop();
|
stop();
|
||||||
uninit_device();
|
|
||||||
close_device();
|
|
||||||
_initialized = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,6 +237,9 @@ void V4L2Grabber::stop()
|
|||||||
{
|
{
|
||||||
stop_capturing();
|
stop_capturing();
|
||||||
_streamNotifier->setEnabled(false);
|
_streamNotifier->setEnabled(false);
|
||||||
|
uninit_device();
|
||||||
|
close_device();
|
||||||
|
_initialized = false;
|
||||||
Info(_log, "Stopped");
|
Info(_log, "Stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,74 +525,109 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
// set the requested pixel format
|
// set the requested pixel format
|
||||||
switch (_pixelFormat)
|
switch (_pixelFormat)
|
||||||
{
|
{
|
||||||
case PIXELFORMAT_UYVY:
|
case PIXELFORMAT_UYVY:
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
||||||
break;
|
break;
|
||||||
case PIXELFORMAT_YUYV:
|
case PIXELFORMAT_YUYV:
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||||
break;
|
break;
|
||||||
case PIXELFORMAT_RGB32:
|
case PIXELFORMAT_RGB32:
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
||||||
break;
|
break;
|
||||||
case PIXELFORMAT_NO_CHANGE:
|
#ifdef HAVE_JPEG
|
||||||
default:
|
case PIXELFORMAT_MJPEG:
|
||||||
// No change to device settings
|
{
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case PIXELFORMAT_NO_CHANGE:
|
||||||
|
default:
|
||||||
|
// No change to device settings
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Does never accept own sizes? use always _imageResampler instead
|
|
||||||
/*
|
|
||||||
|
|
||||||
// calc the size based on pixelDecimation
|
|
||||||
fmt.fmt.pix.width = fmt.fmt.pix.width / _pixelDecimation;
|
|
||||||
fmt.fmt.pix.height = fmt.fmt.pix.height / _pixelDecimation;
|
|
||||||
|
|
||||||
// set the settings
|
// set the settings
|
||||||
|
fmt.fmt.pix.width = _width;
|
||||||
|
fmt.fmt.pix.height = _height;
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
|
if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
|
||||||
{
|
{
|
||||||
throw_errno_exception("VIDIOC_S_FMT");
|
throw_errno_exception("VIDIOC_S_FMT");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the format settings again
|
// initialize current width and height
|
||||||
// (the size may not have been accepted without an error)
|
|
||||||
if (-1 == xioctl(VIDIOC_G_FMT, &fmt))
|
|
||||||
{
|
|
||||||
throw_errno_exception("VIDIOC_G_FMT");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// set the line length
|
|
||||||
_lineLength = fmt.fmt.pix.bytesperline;
|
|
||||||
|
|
||||||
// store width & height
|
|
||||||
_width = fmt.fmt.pix.width;
|
_width = fmt.fmt.pix.width;
|
||||||
_height = fmt.fmt.pix.height;
|
_height = fmt.fmt.pix.height;
|
||||||
|
|
||||||
// display the used width and height
|
// display the used width and height
|
||||||
Debug(_log, "width=%d height=%d", _width, _height );
|
Debug(_log, "width=%d height=%d", _width, _height );
|
||||||
|
|
||||||
|
// Trying to set frame rate
|
||||||
|
struct v4l2_streamparm streamparms;
|
||||||
|
CLEAR(streamparms);
|
||||||
|
streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
if (-1 == xioctl(VIDIOC_G_PARM, &streamparms))
|
||||||
|
{
|
||||||
|
throw_errno_exception("VIDIOC_G_PARM");
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check the capability flag is set to V4L2_CAP_TIMEPERFRAME
|
||||||
|
if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME)
|
||||||
|
{
|
||||||
|
// Driver supports the feature. Set required framerate
|
||||||
|
streamparms.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
|
||||||
|
streamparms.parm.capture.timeperframe.numerator = 1;
|
||||||
|
streamparms.parm.capture.timeperframe.denominator = 30;
|
||||||
|
if(-1 == xioctl(VIDIOC_S_PARM, &streamparms))
|
||||||
|
{
|
||||||
|
throw_errno_exception("VIDIOC_S_PARM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the line length
|
||||||
|
_lineLength = fmt.fmt.pix.bytesperline;
|
||||||
|
|
||||||
// check pixel format and frame size
|
// check pixel format and frame size
|
||||||
switch (fmt.fmt.pix.pixelformat)
|
switch (fmt.fmt.pix.pixelformat)
|
||||||
{
|
{
|
||||||
case V4L2_PIX_FMT_UYVY:
|
case V4L2_PIX_FMT_UYVY:
|
||||||
_pixelFormat = PIXELFORMAT_UYVY;
|
{
|
||||||
_frameByteSize = _width * _height * 2;
|
_pixelFormat = PIXELFORMAT_UYVY;
|
||||||
Debug(_log, "Pixel format=UYVY");
|
_frameByteSize = _width * _height * 2;
|
||||||
|
Debug(_log, "Pixel format=UYVY");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case V4L2_PIX_FMT_YUYV:
|
case V4L2_PIX_FMT_YUYV:
|
||||||
_pixelFormat = PIXELFORMAT_YUYV;
|
{
|
||||||
_frameByteSize = _width * _height * 2;
|
_pixelFormat = PIXELFORMAT_YUYV;
|
||||||
Debug(_log, "Pixel format=YUYV");
|
_frameByteSize = _width * _height * 2;
|
||||||
|
Debug(_log, "Pixel format=YUYV");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case V4L2_PIX_FMT_RGB32:
|
case V4L2_PIX_FMT_RGB32:
|
||||||
_pixelFormat = PIXELFORMAT_RGB32;
|
{
|
||||||
_frameByteSize = _width * _height * 4;
|
_pixelFormat = PIXELFORMAT_RGB32;
|
||||||
Debug(_log, "Pixel format=RGB32");
|
_frameByteSize = _width * _height * 4;
|
||||||
|
Debug(_log, "Pixel format=RGB32");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
#ifdef HAVE_JPEG
|
||||||
throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported");
|
case V4L2_PIX_FMT_MJPEG:
|
||||||
|
{
|
||||||
|
_pixelFormat = PIXELFORMAT_MJPEG;
|
||||||
|
Debug(_log, "Pixel format=MJPEG");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,107 +756,108 @@ int V4L2Grabber::read_frame()
|
|||||||
{
|
{
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
|
|
||||||
switch (_ioMethod) {
|
switch (_ioMethod)
|
||||||
case IO_METHOD_READ:
|
{
|
||||||
int size;
|
case IO_METHOD_READ:
|
||||||
if ((size = read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) == -1)
|
int size;
|
||||||
{
|
if ((size = read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) == -1)
|
||||||
switch (errno)
|
|
||||||
{
|
{
|
||||||
case EAGAIN:
|
switch (errno)
|
||||||
return 0;
|
{
|
||||||
|
case EAGAIN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
case EIO:
|
case EIO:
|
||||||
/* Could ignore EIO, see spec. */
|
/* Could ignore EIO, see spec. */
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw_errno_exception("read");
|
throw_errno_exception("read");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = process_image(_buffers[0].start, size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_METHOD_MMAP:
|
||||||
|
CLEAR(buf);
|
||||||
|
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
switch (errno)
|
||||||
|
{
|
||||||
|
case EAGAIN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case EIO:
|
||||||
|
/* Could ignore EIO, see spec. */
|
||||||
|
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw_errno_exception("VIDIOC_DQBUF");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(buf.index < _buffers.size());
|
||||||
|
|
||||||
|
rc = process_image(_buffers[buf.index].start, buf.bytesused);
|
||||||
|
|
||||||
|
if (-1 == xioctl(VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
throw_errno_exception("VIDIOC_QBUF");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
rc = process_image(_buffers[0].start, size);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case IO_METHOD_MMAP:
|
case IO_METHOD_USERPTR:
|
||||||
CLEAR(buf);
|
CLEAR(buf);
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_USERPTR;
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
|
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
|
||||||
{
|
|
||||||
switch (errno)
|
|
||||||
{
|
{
|
||||||
case EAGAIN:
|
switch (errno)
|
||||||
return 0;
|
{
|
||||||
|
case EAGAIN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
case EIO:
|
case EIO:
|
||||||
/* Could ignore EIO, see spec. */
|
/* Could ignore EIO, see spec. */
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw_errno_exception("VIDIOC_DQBUF");
|
throw_errno_exception("VIDIOC_DQBUF");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _buffers.size(); ++i)
|
||||||
|
{
|
||||||
|
if (buf.m.userptr == (unsigned long)_buffers[i].start && buf.length == _buffers[i].length)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = process_image((void *)buf.m.userptr, buf.bytesused);
|
||||||
|
|
||||||
|
if (-1 == xioctl(VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
throw_errno_exception("VIDIOC_QBUF");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(buf.index < _buffers.size());
|
|
||||||
|
|
||||||
rc = process_image(_buffers[buf.index].start, buf.bytesused);
|
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_QBUF, &buf))
|
|
||||||
{
|
|
||||||
throw_errno_exception("VIDIOC_QBUF");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IO_METHOD_USERPTR:
|
|
||||||
CLEAR(buf);
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
buf.memory = V4L2_MEMORY_USERPTR;
|
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_DQBUF, &buf))
|
|
||||||
{
|
|
||||||
switch (errno)
|
|
||||||
{
|
|
||||||
case EAGAIN:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case EIO:
|
|
||||||
/* Could ignore EIO, see spec. */
|
|
||||||
|
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw_errno_exception("VIDIOC_DQBUF");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < _buffers.size(); ++i)
|
|
||||||
{
|
|
||||||
if (buf.m.userptr == (unsigned long)_buffers[i].start && buf.length == _buffers[i].length)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = process_image((void *)buf.m.userptr, buf.bytesused);
|
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_QBUF, &buf))
|
|
||||||
{
|
|
||||||
throw_errno_exception("VIDIOC_QBUF");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
@ -828,23 +871,101 @@ int V4L2Grabber::read_frame()
|
|||||||
bool V4L2Grabber::process_image(const void *p, int size)
|
bool V4L2Grabber::process_image(const void *p, int size)
|
||||||
{
|
{
|
||||||
// We do want a new frame...
|
// We do want a new frame...
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
if (size != _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG)
|
||||||
|
#else
|
||||||
if (size != _frameByteSize)
|
if (size != _frameByteSize)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
Error(_log, "Frame too small: %d != %d", size, _frameByteSize);
|
Error(_log, "Frame too small: %d != %d", size, _frameByteSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
process_image(reinterpret_cast<const uint8_t *>(p));
|
process_image(reinterpret_cast<const uint8_t *>(p), size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void V4L2Grabber::process_image(const uint8_t * data)
|
void V4L2Grabber::process_image(const uint8_t * data, int size)
|
||||||
{
|
{
|
||||||
Image<ColorRgb> image(0, 0);
|
Image<ColorRgb> image(_width, _height);
|
||||||
_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image);
|
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
if (_pixelFormat == PIXELFORMAT_MJPEG)
|
||||||
|
{
|
||||||
|
_decompress = new jpeg_decompress_struct;
|
||||||
|
_error = new errorManager;
|
||||||
|
|
||||||
|
_decompress->err = jpeg_std_error(&_error->pub);
|
||||||
|
_error->pub.error_exit = &errorHandler;
|
||||||
|
_error->pub.output_message = &outputHandler;
|
||||||
|
|
||||||
|
jpeg_create_decompress(_decompress);
|
||||||
|
|
||||||
|
if (setjmp(_error->setjmp_buffer))
|
||||||
|
{
|
||||||
|
jpeg_abort_decompress(_decompress);
|
||||||
|
jpeg_destroy_decompress(_decompress);
|
||||||
|
delete _decompress;
|
||||||
|
delete _error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_mem_src(_decompress, const_cast<uint8_t*>(data), size);
|
||||||
|
|
||||||
|
if (jpeg_read_header(_decompress, (bool) TRUE) != JPEG_HEADER_OK)
|
||||||
|
{
|
||||||
|
jpeg_abort_decompress(_decompress);
|
||||||
|
jpeg_destroy_decompress(_decompress);
|
||||||
|
delete _decompress;
|
||||||
|
delete _error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_start_decompress(_decompress);
|
||||||
|
|
||||||
|
QImage imageFrame = QImage(_decompress->output_width, _decompress->output_height, QImage::Format_RGB888);
|
||||||
|
|
||||||
|
int y = 0;
|
||||||
|
while (_decompress->output_scanline < _decompress->output_height)
|
||||||
|
{
|
||||||
|
uchar *row = imageFrame.scanLine(_decompress->output_scanline);
|
||||||
|
jpeg_read_scanlines(_decompress, &row, 1);
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_finish_decompress(_decompress);
|
||||||
|
jpeg_destroy_decompress(_decompress);
|
||||||
|
delete _decompress;
|
||||||
|
delete _error;
|
||||||
|
|
||||||
|
if (imageFrame.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QRect rect(_cropLeft, _cropTop, imageFrame.width() - _cropLeft - _cropRight, imageFrame.height() - _cropTop - _cropBottom);
|
||||||
|
imageFrame = imageFrame.copy(rect);
|
||||||
|
imageFrame = imageFrame.scaled(imageFrame.width() / _pixelDecimation, imageFrame.height() / _pixelDecimation,Qt::KeepAspectRatio);
|
||||||
|
|
||||||
|
if ((image.width() != unsigned(imageFrame.width())) && (image.height() != unsigned(imageFrame.height())))
|
||||||
|
image.resize(imageFrame.width(), imageFrame.height());
|
||||||
|
|
||||||
|
for (int y=0; y<imageFrame.height(); ++y)
|
||||||
|
{
|
||||||
|
for (int x=0; x<imageFrame.width(); ++x)
|
||||||
|
{
|
||||||
|
const QRgb inPixel = imageFrame.pixel(x,y);
|
||||||
|
ColorRgb & outPixel = image(x,y);
|
||||||
|
outPixel.red = (inPixel & 0xff0000) >> 16;
|
||||||
|
outPixel.green = (inPixel & 0xff00) >> 8;
|
||||||
|
outPixel.blue = (inPixel & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image);
|
||||||
|
|
||||||
if (_signalDetectionEnabled)
|
if (_signalDetectionEnabled)
|
||||||
{
|
{
|
||||||
@ -963,3 +1084,19 @@ void V4L2Grabber::setDeviceVideoStandard(QString device, VideoStandard videoStan
|
|||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V4L2Grabber::componentStateChanged(const hyperion::Components component, bool enable)
|
||||||
|
{
|
||||||
|
if (component == COMP_V4L)
|
||||||
|
{
|
||||||
|
if (_initialized != enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
if(init()) start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
uninit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -294,7 +294,7 @@ void PriorityMuxer::setCurrentTime(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// timeoutTime of -100 is awaiting data (inactive); skip
|
// timeoutTime of -100 is awaiting data (inactive); skip
|
||||||
if(infoIt->timeoutTime_ms >= -100)
|
if(infoIt->timeoutTime_ms > -100)
|
||||||
newPriority = qMin(newPriority, infoIt->priority);
|
newPriority = qMin(newPriority, infoIt->priority);
|
||||||
|
|
||||||
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
||||||
|
@ -1,208 +1,200 @@
|
|||||||
{
|
{
|
||||||
"type":"array",
|
"type" : "object",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"title" : "edt_conf_v4l2_heading_title",
|
"title" : "edt_conf_v4l2_heading_title",
|
||||||
"minItems": 1,
|
"properties" :
|
||||||
"maxItems": 1,
|
|
||||||
"items":
|
|
||||||
{
|
{
|
||||||
"type" : "object",
|
"device" :
|
||||||
"required" : true,
|
|
||||||
"title" : "edt_conf_v4l2_heading_title",
|
|
||||||
"properties" :
|
|
||||||
{
|
{
|
||||||
"device" :
|
"type" : "string",
|
||||||
{
|
"title" : "edt_conf_v4l2_device_title",
|
||||||
"type" : "string",
|
"default" : "auto",
|
||||||
"title" : "edt_conf_v4l2_device_title",
|
"minLength" : 4,
|
||||||
"default" : "auto",
|
"required" : true,
|
||||||
"minLength" : 4,
|
"propertyOrder" : 1
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 1
|
|
||||||
},
|
|
||||||
"standard" :
|
|
||||||
{
|
|
||||||
"type" : "string",
|
|
||||||
"title" : "edt_conf_v4l2_standard_title",
|
|
||||||
"enum" : ["PAL","NTSC","SECAM","NO_CHANGE"],
|
|
||||||
"default" : "NO_CHANGE",
|
|
||||||
"options" : {
|
|
||||||
"enum_titles" : ["edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM", "edt_conf_enum_NO_CHANGE"]
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 2
|
|
||||||
},
|
|
||||||
"sizeDecimation" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_sizeDecimation_title",
|
|
||||||
"minimum" : 1,
|
|
||||||
"maximum" : 30,
|
|
||||||
"default" : 6,
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 3
|
|
||||||
},
|
|
||||||
"cropLeft" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_cropLeft_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"default" : 0,
|
|
||||||
"append" : "edt_append_pixel",
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 4
|
|
||||||
},
|
|
||||||
"cropRight" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_cropRight_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"default" : 0,
|
|
||||||
"append" : "edt_append_pixel",
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 5
|
|
||||||
},
|
|
||||||
"cropTop" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_cropTop_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"default" : 0,
|
|
||||||
"append" : "edt_append_pixel",
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 6
|
|
||||||
},
|
|
||||||
"cropBottom" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_cropBottom_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"default" : 0,
|
|
||||||
"append" : "edt_append_pixel",
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 7
|
|
||||||
},
|
|
||||||
"signalDetection" :
|
|
||||||
{
|
|
||||||
"type" : "boolean",
|
|
||||||
"title" : "edt_conf_v4l2_signalDetection_title",
|
|
||||||
"default" : false,
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 8
|
|
||||||
},
|
|
||||||
"redSignalThreshold" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_redSignalThreshold_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"maximum" : 100,
|
|
||||||
"default" : 5,
|
|
||||||
"append" : "edt_append_percent",
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 9
|
|
||||||
},
|
|
||||||
"greenSignalThreshold" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_greenSignalThreshold_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"maximum" : 100,
|
|
||||||
"default" : 5,
|
|
||||||
"append" : "edt_append_percent",
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 10
|
|
||||||
},
|
|
||||||
"blueSignalThreshold" :
|
|
||||||
{
|
|
||||||
"type" : "integer",
|
|
||||||
"title" : "edt_conf_v4l2_blueSignalThreshold_title",
|
|
||||||
"minimum" : 0,
|
|
||||||
"maximum" : 100,
|
|
||||||
"default" : 5,
|
|
||||||
"append" : "edt_append_percent",
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 11
|
|
||||||
},
|
|
||||||
"sDVOffsetMin" :
|
|
||||||
{
|
|
||||||
"type" : "number",
|
|
||||||
"title" : "edt_conf_v4l2_sDVOffsetMin_title",
|
|
||||||
"minimum" : 0.0,
|
|
||||||
"maximum" : 1.0,
|
|
||||||
"default" : 0.25,
|
|
||||||
"step" : 0.01,
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 12
|
|
||||||
},
|
|
||||||
"sDVOffsetMax" :
|
|
||||||
{
|
|
||||||
"type" : "number",
|
|
||||||
"title" : "edt_conf_v4l2_sDVOffsetMax_title",
|
|
||||||
"minimum" : 0.0,
|
|
||||||
"maximum" : 1.0,
|
|
||||||
"default" : 0.75,
|
|
||||||
"step" : 0.01,
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 13
|
|
||||||
},
|
|
||||||
"sDHOffsetMin" :
|
|
||||||
{
|
|
||||||
"type" : "number",
|
|
||||||
"title" : "edt_conf_v4l2_sDHOffsetMin_title",
|
|
||||||
"minimum" : 0.0,
|
|
||||||
"maximum" : 1.0,
|
|
||||||
"default" : 0.25,
|
|
||||||
"step" : 0.01,
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 14
|
|
||||||
},
|
|
||||||
"sDHOffsetMax" :
|
|
||||||
{
|
|
||||||
"type" : "number",
|
|
||||||
"title" : "edt_conf_v4l2_sDHOffsetMax_title",
|
|
||||||
"minimum" : 0.0,
|
|
||||||
"maximum" : 1.0,
|
|
||||||
"default" : 0.75,
|
|
||||||
"step" : 0.01,
|
|
||||||
"options": {
|
|
||||||
"dependencies": {
|
|
||||||
"signalDetection": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required" : true,
|
|
||||||
"propertyOrder" : 15
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
"standard" :
|
||||||
|
{
|
||||||
|
"type" : "string",
|
||||||
|
"title" : "edt_conf_v4l2_standard_title",
|
||||||
|
"enum" : ["PAL","NTSC","SECAM","NO_CHANGE"],
|
||||||
|
"default" : "NO_CHANGE",
|
||||||
|
"options" : {
|
||||||
|
"enum_titles" : ["edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM", "edt_conf_enum_NO_CHANGE"]
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 2
|
||||||
|
},
|
||||||
|
"sizeDecimation" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_sizeDecimation_title",
|
||||||
|
"minimum" : 1,
|
||||||
|
"maximum" : 30,
|
||||||
|
"default" : 6,
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 3
|
||||||
|
},
|
||||||
|
"cropLeft" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_cropLeft_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_pixel",
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 4
|
||||||
|
},
|
||||||
|
"cropRight" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_cropRight_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_pixel",
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 5
|
||||||
|
},
|
||||||
|
"cropTop" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_cropTop_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_pixel",
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 6
|
||||||
|
},
|
||||||
|
"cropBottom" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_cropBottom_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_pixel",
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 7
|
||||||
|
},
|
||||||
|
"signalDetection" :
|
||||||
|
{
|
||||||
|
"type" : "boolean",
|
||||||
|
"title" : "edt_conf_v4l2_signalDetection_title",
|
||||||
|
"default" : false,
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 8
|
||||||
|
},
|
||||||
|
"redSignalThreshold" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_redSignalThreshold_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"maximum" : 100,
|
||||||
|
"default" : 5,
|
||||||
|
"append" : "edt_append_percent",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 9
|
||||||
|
},
|
||||||
|
"greenSignalThreshold" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_greenSignalThreshold_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"maximum" : 100,
|
||||||
|
"default" : 5,
|
||||||
|
"append" : "edt_append_percent",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 10
|
||||||
|
},
|
||||||
|
"blueSignalThreshold" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_v4l2_blueSignalThreshold_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"maximum" : 100,
|
||||||
|
"default" : 5,
|
||||||
|
"append" : "edt_append_percent",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 11
|
||||||
|
},
|
||||||
|
"sDVOffsetMin" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_conf_v4l2_sDVOffsetMin_title",
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0,
|
||||||
|
"default" : 0.25,
|
||||||
|
"step" : 0.01,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 12
|
||||||
|
},
|
||||||
|
"sDVOffsetMax" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_conf_v4l2_sDVOffsetMax_title",
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0,
|
||||||
|
"default" : 0.75,
|
||||||
|
"step" : 0.01,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 13
|
||||||
|
},
|
||||||
|
"sDHOffsetMin" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_conf_v4l2_sDHOffsetMin_title",
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0,
|
||||||
|
"default" : 0.25,
|
||||||
|
"step" : 0.01,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 14
|
||||||
|
},
|
||||||
|
"sDHOffsetMax" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_conf_v4l2_sDHOffsetMax_title",
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0,
|
||||||
|
"default" : 0.75,
|
||||||
|
"step" : 0.01,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"signalDetection": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" : true,
|
||||||
|
"propertyOrder" : 15
|
||||||
|
}
|
||||||
|
},
|
||||||
"additionalProperties" : false
|
"additionalProperties" : false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,10 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
|
|||||||
rgb.red = data[index+2];
|
rgb.red = data[index+2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
case PIXELFORMAT_MJPEG:
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case PIXELFORMAT_NO_CHANGE:
|
case PIXELFORMAT_NO_CHANGE:
|
||||||
Error(Logger::getInstance("ImageResampler"), "Invalid pixel format given");
|
Error(Logger::getInstance("ImageResampler"), "Invalid pixel format given");
|
||||||
break;
|
break;
|
||||||
|
@ -60,7 +60,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
Option & argDevice = parser.add<Option> ('d', "device", "The device to use, can be /dev/video0 [default: %1 (auto detected)]", "auto");
|
Option & argDevice = parser.add<Option> ('d', "device", "The device to use, can be /dev/video0 [default: %1 (auto detected)]", "auto");
|
||||||
SwitchOption<VideoStandard> & argVideoStandard= parser.add<SwitchOption<VideoStandard>>('v', "video-standard", "The used video standard. Valid values are PAL, NTSC, SECAM or no-change. [default: %1]", "no-change");
|
SwitchOption<VideoStandard> & argVideoStandard= parser.add<SwitchOption<VideoStandard>>('v', "video-standard", "The used video standard. Valid values are PAL, NTSC, SECAM or no-change. [default: %1]", "no-change");
|
||||||
SwitchOption<PixelFormat> & argPixelFormat = parser.add<SwitchOption<PixelFormat>> (0x0, "pixel-format", "The use pixel format. Valid values are YUYV, UYVY, RGB32 or no-change. [default: %1]", "no-change");
|
SwitchOption<PixelFormat> & argPixelFormat = parser.add<SwitchOption<PixelFormat>> (0x0, "pixel-format", "The use pixel format. Valid values are YUYV, UYVY, RGB32, MJPEG or no-change. [default: %1]", "no-change");
|
||||||
IntOption & argCropWidth = parser.add<IntOption> (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: %1]", "0");
|
IntOption & argCropWidth = parser.add<IntOption> (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: %1]", "0");
|
||||||
IntOption & argCropHeight = parser.add<IntOption> (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: %1]", "0");
|
IntOption & argCropHeight = parser.add<IntOption> (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: %1]", "0");
|
||||||
IntOption & argCropLeft = parser.add<IntOption> (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)");
|
IntOption & argCropLeft = parser.add<IntOption> (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)");
|
||||||
@ -96,6 +96,9 @@ int main(int argc, char** argv)
|
|||||||
argPixelFormat.addSwitch("yuyv", PIXELFORMAT_YUYV);
|
argPixelFormat.addSwitch("yuyv", PIXELFORMAT_YUYV);
|
||||||
argPixelFormat.addSwitch("uyvy", PIXELFORMAT_UYVY);
|
argPixelFormat.addSwitch("uyvy", PIXELFORMAT_UYVY);
|
||||||
argPixelFormat.addSwitch("rgb32", PIXELFORMAT_RGB32);
|
argPixelFormat.addSwitch("rgb32", PIXELFORMAT_RGB32);
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
|
argPixelFormat.addSwitch("mjpeg", PIXELFORMAT_MJPEG);
|
||||||
|
#endif
|
||||||
argPixelFormat.addSwitch("no-change", PIXELFORMAT_NO_CHANGE);
|
argPixelFormat.addSwitch("no-change", PIXELFORMAT_NO_CHANGE);
|
||||||
|
|
||||||
// parse all options
|
// parse all options
|
||||||
@ -212,9 +215,11 @@ int main(int argc, char** argv)
|
|||||||
// Connect the screen capturing to flatbuf connection processing
|
// Connect the screen capturing to flatbuf connection processing
|
||||||
QObject::connect(&grabber, SIGNAL(newFrame(const Image<ColorRgb> &)), &flatbuf, SLOT(setImage(Image<ColorRgb>)));
|
QObject::connect(&grabber, SIGNAL(newFrame(const Image<ColorRgb> &)), &flatbuf, SLOT(setImage(Image<ColorRgb>)));
|
||||||
|
|
||||||
if (grabber.start())
|
// Start the capturing
|
||||||
QCoreApplication::exec();
|
grabber.start();
|
||||||
grabber.stop();
|
|
||||||
|
// Start the application
|
||||||
|
app.exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error & e)
|
catch (const std::runtime_error & e)
|
||||||
|
@ -57,7 +57,7 @@ HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObje
|
|||||||
, _webserver(nullptr)
|
, _webserver(nullptr)
|
||||||
, _jsonServer(nullptr)
|
, _jsonServer(nullptr)
|
||||||
, _udpListener(nullptr)
|
, _udpListener(nullptr)
|
||||||
, _v4l2Grabbers()
|
, _v4l2Grabbers(nullptr)
|
||||||
, _dispmanx(nullptr)
|
, _dispmanx(nullptr)
|
||||||
, _x11Grabber(nullptr)
|
, _x11Grabber(nullptr)
|
||||||
, _amlGrabber(nullptr)
|
, _amlGrabber(nullptr)
|
||||||
@ -162,14 +162,10 @@ void HyperionDaemon::freeObjects()
|
|||||||
delete _fbGrabber;
|
delete _fbGrabber;
|
||||||
delete _osxGrabber;
|
delete _osxGrabber;
|
||||||
delete _qtGrabber;
|
delete _qtGrabber;
|
||||||
|
delete _v4l2Grabbers;
|
||||||
for(V4L2Wrapper* grabber : _v4l2Grabbers)
|
|
||||||
{
|
|
||||||
delete grabber;
|
|
||||||
}
|
|
||||||
delete _stats;
|
delete _stats;
|
||||||
|
|
||||||
_v4l2Grabbers.clear();
|
_v4l2Grabbers = nullptr;
|
||||||
_bonjourBrowserWrapper = nullptr;
|
_bonjourBrowserWrapper = nullptr;
|
||||||
_amlGrabber = nullptr;
|
_amlGrabber = nullptr;
|
||||||
_dispmanx = nullptr;
|
_dispmanx = nullptr;
|
||||||
@ -386,19 +382,9 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
}
|
}
|
||||||
else if(type == settings::V4L2)
|
else if(type == settings::V4L2)
|
||||||
{
|
{
|
||||||
// stop
|
|
||||||
if(_v4l2Grabbers.size()>0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned v4lEnableCount = 0;
|
#ifdef ENABLE_V4L2
|
||||||
|
const QJsonObject & grabberConfig = config.object();
|
||||||
const QJsonArray & v4lArray = config.array();
|
|
||||||
for ( signed idx=0; idx<v4lArray.size(); idx++)
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_V4L2
|
|
||||||
|
|
||||||
const QJsonObject & grabberConfig = v4lArray.at(idx).toObject();
|
|
||||||
bool enableV4l = grabberConfig["enable"].toBool(true);
|
|
||||||
|
|
||||||
V4L2Wrapper* grabber = new V4L2Wrapper(
|
V4L2Wrapper* grabber = new V4L2Wrapper(
|
||||||
grabberConfig["device"].toString("auto"),
|
grabberConfig["device"].toString("auto"),
|
||||||
@ -425,15 +411,9 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
// connect to HyperionDaemon signal
|
// connect to HyperionDaemon signal
|
||||||
connect(this, &HyperionDaemon::videoMode, grabber, &V4L2Wrapper::setVideoMode);
|
connect(this, &HyperionDaemon::videoMode, grabber, &V4L2Wrapper::setVideoMode);
|
||||||
connect(this, &HyperionDaemon::settingsChanged, grabber, &V4L2Wrapper::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, grabber, &V4L2Wrapper::handleSettingsUpdate);
|
||||||
|
#else
|
||||||
if (enableV4l)
|
Error(_log, "The v4l2 grabber can not be instantiated, because it has been left out from the build");
|
||||||
v4lEnableCount++;
|
#endif
|
||||||
|
|
||||||
_v4l2Grabbers.push_back(grabber);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorIf( (v4lEnableCount>0 && _v4l2Grabbers.size()==0), _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +429,7 @@ void HyperionDaemon::createGrabberDispmanx()
|
|||||||
|
|
||||||
Info(_log, "DISPMANX frame grabber created");
|
Info(_log, "DISPMANX frame grabber created");
|
||||||
#else
|
#else
|
||||||
Error( _log, "The dispmanx framegrabber can not be instantiated, because it has been left out from the build");
|
Error(_log, "The dispmanx framegrabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,7 +446,7 @@ void HyperionDaemon::createGrabberAmlogic()
|
|||||||
|
|
||||||
Info(_log, "AMLOGIC grabber created");
|
Info(_log, "AMLOGIC grabber created");
|
||||||
#else
|
#else
|
||||||
Error( _log, "The AMLOGIC grabber can not be instantiated, because it has been left out from the build");
|
Error(_log, "The AMLOGIC grabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ private:
|
|||||||
WebServer* _webserver;
|
WebServer* _webserver;
|
||||||
JsonServer* _jsonServer;
|
JsonServer* _jsonServer;
|
||||||
UDPListener* _udpListener;
|
UDPListener* _udpListener;
|
||||||
std::vector<V4L2Wrapper*> _v4l2Grabbers;
|
V4L2Wrapper* _v4l2Grabbers;
|
||||||
DispmanxWrapper* _dispmanx;
|
DispmanxWrapper* _dispmanx;
|
||||||
X11Wrapper* _x11Grabber;
|
X11Wrapper* _x11Grabber;
|
||||||
AmlogicWrapper* _amlGrabber;
|
AmlogicWrapper* _amlGrabber;
|
||||||
|
Loading…
Reference in New Issue
Block a user