mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
feat: SchemaChecker & V4L2 enhancement (#734)
* libjpeg-turbo, QJsonSchemaChecker, V4L2 width/height/fps Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * Implement hyperion-v4l cli args * Apply v4l2 settings during runtime * feat: Provide minimum values for input restriction * fix: merge mess Co-authored-by: brindosch <edeltraud70@gmx.de>
This commit is contained in:
parent
20a5e5dc06
commit
662872dafe
@ -298,22 +298,31 @@ 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
|
# Add JPEG library
|
||||||
if (ENABLE_V4L2)
|
if (ENABLE_V4L2)
|
||||||
|
# Turbo JPEG
|
||||||
|
find_package(TurboJPEG)
|
||||||
|
if (TURBOJPEG_FOUND)
|
||||||
|
add_definitions(-DHAVE_TURBO_JPEG)
|
||||||
|
message( STATUS "Using Turbo JPEG library: ${TurboJPEG_LIBRARY}")
|
||||||
|
include_directories(${TurboJPEG_INCLUDE_DIRS})
|
||||||
|
else()
|
||||||
|
# System JPEG
|
||||||
find_package(JPEG)
|
find_package(JPEG)
|
||||||
if (JPEG_FOUND)
|
if (JPEG_FOUND)
|
||||||
add_definitions(-DHAVE_JPEG)
|
add_definitions(-DHAVE_JPEG)
|
||||||
message( STATUS "Using JPEG library: ${JPEG_LIBRARIES}")
|
message( STATUS "Using system JPEG library: ${JPEG_LIBRARIES}")
|
||||||
include_directories(${JPEG_INCLUDE_DIR})
|
include_directories(${JPEG_INCLUDE_DIR})
|
||||||
else()
|
else()
|
||||||
message( STATUS "JPEG library not found, MJPEG camera format won't work in V4L2 grabber.")
|
message( STATUS "JPEG library not found, MJPEG camera format won't work in V4L2 grabber.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif (TurboJPEG_FOUND)
|
||||||
|
|
||||||
# TODO[TvdZ]: This linking directory should only be added if we are cross compiling
|
|
||||||
#if(NOT APPLE)
|
if (TURBOJPEG_FOUND OR JPEG_FOUND)
|
||||||
# link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
|
add_definitions(-DHAVE_JPEG_DECODER)
|
||||||
#endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
|
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
|
||||||
|
@ -40,7 +40,7 @@ wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/
|
|||||||
|
|
||||||
```
|
```
|
||||||
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 libjpeg-dev libqt5sql5-sqlite libssl-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 libturbojpeg0-dev libqt5sql5-sqlite libssl-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**on RPI you need the videocore IV headers**
|
**on RPI you need the videocore IV headers**
|
||||||
|
@ -4,14 +4,14 @@ Use a clean Raspbian Stretch Lite (on target) and Ubuntu 18/19 (on host) to exec
|
|||||||
## On the Target system (here Raspberry Pi)
|
## On the Target system (here Raspberry Pi)
|
||||||
Install required additional packages.
|
Install required additional packages.
|
||||||
```
|
```
|
||||||
sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libqt5sql5-sqlite aptitude show qt5-default rsync
|
sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite aptitude show qt5-default rsync
|
||||||
```
|
```
|
||||||
## On the Host system (here Ubuntu)
|
## On the Host system (here Ubuntu)
|
||||||
Update the Ubuntu environment to the latest stage and install required additional packages.
|
Update the Ubuntu environment to the latest stage and install required additional packages.
|
||||||
```
|
```
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get upgrade
|
sudo apt-get upgrade
|
||||||
sudo apt-get -qq -y install git rsync 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 libqt5sql5-sqlite
|
sudo apt-get -qq -y install git rsync 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 libturbojpeg0-dev libqt5sql5-sqlite
|
||||||
```
|
```
|
||||||
|
|
||||||
Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment:
|
Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment:
|
||||||
|
@ -5,7 +5,7 @@ CFG="${2:-Release}"
|
|||||||
INST="$( [ "${3:-}" = "install" ] && echo true || echo false )"
|
INST="$( [ "${3:-}" = "install" ] && echo true || echo false )"
|
||||||
|
|
||||||
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 libssl-dev || exit 1
|
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev libturbojpeg0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libssl-dev || exit 1
|
||||||
|
|
||||||
if [ -e /dev/vc-cma -a -e /dev/vc-mem ]
|
if [ -e /dev/vc-cma -a -e /dev/vc-mem ]
|
||||||
then
|
then
|
||||||
|
33
cmake/FindTurboJPEG.cmake
Normal file
33
cmake/FindTurboJPEG.cmake
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# FindTurboJPEG.cmake
|
||||||
|
# TURBOJPEG_FOUND
|
||||||
|
# TurboJPEG_INCLUDE_DIRS
|
||||||
|
# TurboJPEG_LIBRARY
|
||||||
|
|
||||||
|
find_path(TurboJPEG_INCLUDE_DIRS
|
||||||
|
NAMES turbojpeg.h
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(TurboJPEG_LIBRARY
|
||||||
|
NAMES turbojpeg turbojpeg-static
|
||||||
|
PATH_SUFFIXES bin lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
||||||
|
include(CheckCSourceCompiles)
|
||||||
|
include(CMakePushCheckState)
|
||||||
|
|
||||||
|
cmake_push_check_state(RESET)
|
||||||
|
list(APPEND CMAKE_REQUIRED_INCLUDES ${TurboJPEG_INCLUDE_DIRS})
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES ${TurboJPEG_LIBRARY})
|
||||||
|
|
||||||
|
check_c_source_compiles("#include <turbojpeg.h>\nint main(void) { tjhandle h=tjInitCompress(); return 0; }" TURBOJPEG_WORKS)
|
||||||
|
cmake_pop_check_state()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(TurboJpeg
|
||||||
|
FOUND_VAR TURBOJPEG_FOUND
|
||||||
|
REQUIRED_VARS TurboJPEG_LIBRARY TurboJPEG_INCLUDE_DIRS TURBOJPEG_WORKS
|
||||||
|
TurboJPEG_INCLUDE_DIRS TurboJPEG_LIBRARY
|
||||||
|
)
|
@ -101,6 +101,8 @@
|
|||||||
|
|
||||||
/// Configuration for the embedded V4L2 grabber
|
/// Configuration for the embedded V4L2 grabber
|
||||||
/// * device : V4L2 Device to use [default="auto"] (Auto detection)
|
/// * device : V4L2 Device to use [default="auto"] (Auto detection)
|
||||||
|
/// * width : The width of the grabbed frames (pixels) [default=0]
|
||||||
|
/// * height : The height of the grabbed frames (pixels) [default=0]
|
||||||
/// * standard : Video standard (PAL/NTSC/SECAM/NO_CHANGE) [default="NO_CHANGE"]
|
/// * standard : Video standard (PAL/NTSC/SECAM/NO_CHANGE) [default="NO_CHANGE"]
|
||||||
/// * sizeDecimation : Size decimation factor [default=8]
|
/// * sizeDecimation : Size decimation factor [default=8]
|
||||||
/// * cropLeft : Cropping from the left [default=0]
|
/// * cropLeft : Cropping from the left [default=0]
|
||||||
@ -118,6 +120,8 @@
|
|||||||
"grabberV4L2" :
|
"grabberV4L2" :
|
||||||
{
|
{
|
||||||
"device" : "auto",
|
"device" : "auto",
|
||||||
|
"width" : 0,
|
||||||
|
"height" : 0,
|
||||||
"standard" : "NO_CHANGE",
|
"standard" : "NO_CHANGE",
|
||||||
"sizeDecimation" : 8,
|
"sizeDecimation" : 8,
|
||||||
"priority" : 240,
|
"priority" : 240,
|
||||||
|
@ -60,6 +60,9 @@
|
|||||||
"grabberV4L2" :
|
"grabberV4L2" :
|
||||||
{
|
{
|
||||||
"device" : "auto",
|
"device" : "auto",
|
||||||
|
"width" : 0,
|
||||||
|
"height" : 0,
|
||||||
|
"fps" : 15,
|
||||||
"standard" : "NO_CHANGE",
|
"standard" : "NO_CHANGE",
|
||||||
"sizeDecimation" : 8,
|
"sizeDecimation" : 8,
|
||||||
"cropLeft" : 0,
|
"cropLeft" : 0,
|
||||||
|
@ -15,13 +15,23 @@
|
|||||||
#include <grabber/VideoStandard.h>
|
#include <grabber/VideoStandard.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
// general JPEG decoder includes
|
||||||
|
#ifdef HAVE_JPEG_DECODER
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// System JPEG decoder
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <csetjmp>
|
#include <csetjmp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TurboJPEG decoder
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
#include <turbojpeg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Capture class for V4L2 devices
|
/// Capture class for V4L2 devices
|
||||||
///
|
///
|
||||||
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
|
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
|
||||||
@ -31,6 +41,9 @@ class V4L2Grabber : public Grabber
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
V4L2Grabber(const QString & device,
|
V4L2Grabber(const QString & device,
|
||||||
|
const unsigned width,
|
||||||
|
const unsigned height,
|
||||||
|
const unsigned fps,
|
||||||
VideoStandard videoStandard,
|
VideoStandard videoStandard,
|
||||||
PixelFormat pixelFormat,
|
PixelFormat pixelFormat,
|
||||||
int pixelDecimation
|
int pixelDecimation
|
||||||
@ -46,11 +59,6 @@ public:
|
|||||||
|
|
||||||
int grabFrame(Image<ColorRgb> &);
|
int grabFrame(Image<ColorRgb> &);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation, as v4l doesn't use width/height
|
|
||||||
///
|
|
||||||
virtual void setWidthHeight(){};
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief set new PixelDecimation value to ImageResampler
|
/// @brief set new PixelDecimation value to ImageResampler
|
||||||
/// @param pixelDecimation The new pixelDecimation value
|
/// @param pixelDecimation The new pixelDecimation value
|
||||||
@ -84,6 +92,16 @@ public:
|
|||||||
///
|
///
|
||||||
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard);
|
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief overwrite Grabber.h implementation
|
||||||
|
///
|
||||||
|
virtual bool setFramerate(int fps);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief overwrite Grabber.h implementation
|
||||||
|
///
|
||||||
|
virtual bool setWidthHeight(int width, int height);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
bool start();
|
bool start();
|
||||||
@ -173,6 +191,11 @@ private:
|
|||||||
errorManager* _error;
|
errorManager* _error;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
tjhandle _decompress = nullptr;
|
||||||
|
int _subsamp;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _deviceName;
|
QString _deviceName;
|
||||||
std::map<QString,QString> _v4lDevices;
|
std::map<QString,QString> _v4lDevices;
|
||||||
|
@ -9,6 +9,9 @@ class V4L2Wrapper : public GrabberWrapper
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
V4L2Wrapper(const QString & device,
|
V4L2Wrapper(const QString & device,
|
||||||
|
const unsigned grabWidth,
|
||||||
|
const unsigned grabHeight,
|
||||||
|
const unsigned fps,
|
||||||
VideoStandard videoStandard,
|
VideoStandard videoStandard,
|
||||||
PixelFormat pixelFormat,
|
PixelFormat pixelFormat,
|
||||||
int pixelDecimation );
|
int pixelDecimation );
|
||||||
|
@ -40,6 +40,12 @@ public:
|
|||||||
///
|
///
|
||||||
virtual bool setWidthHeight(int width, int height);
|
virtual bool setWidthHeight(int width, int height);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new framerate (used from v4l)
|
||||||
|
/// @param fps framesPerSecond
|
||||||
|
///
|
||||||
|
virtual bool setFramerate(int fps);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation (used from x11 and qt)
|
/// @brief Apply new pixelDecimation (used from x11 and qt)
|
||||||
///
|
///
|
||||||
@ -111,6 +117,8 @@ protected:
|
|||||||
/// Height of the captured snapshot [pixels]
|
/// Height of the captured snapshot [pixels]
|
||||||
int _height;
|
int _height;
|
||||||
|
|
||||||
|
int _fps;
|
||||||
|
|
||||||
// number of pixels to crop after capturing
|
// number of pixels to crop after capturing
|
||||||
int _cropLeft, _cropRight, _cropTop, _cropBottom;
|
int _cropLeft, _cropRight, _cropTop, _cropBottom;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ enum PixelFormat {
|
|||||||
PIXELFORMAT_BGR24,
|
PIXELFORMAT_BGR24,
|
||||||
PIXELFORMAT_RGB32,
|
PIXELFORMAT_RGB32,
|
||||||
PIXELFORMAT_BGR32,
|
PIXELFORMAT_BGR32,
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG_DECODER
|
||||||
PIXELFORMAT_MJPEG,
|
PIXELFORMAT_MJPEG,
|
||||||
#endif
|
#endif
|
||||||
PIXELFORMAT_NO_CHANGE
|
PIXELFORMAT_NO_CHANGE
|
||||||
@ -47,7 +47,7 @@ inline PixelFormat parsePixelFormat(QString pixelFormat)
|
|||||||
{
|
{
|
||||||
return PIXELFORMAT_BGR32;
|
return PIXELFORMAT_BGR32;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG_DECODER
|
||||||
else if (pixelFormat == "mjpeg")
|
else if (pixelFormat == "mjpeg")
|
||||||
{
|
{
|
||||||
return PIXELFORMAT_MJPEG;
|
return PIXELFORMAT_MJPEG;
|
||||||
|
@ -187,6 +187,14 @@ private:
|
|||||||
///
|
///
|
||||||
void checkEnum(const QJsonValue & value, const QJsonValue & schema, const QJsonValue & defaultValue);
|
void checkEnum(const QJsonValue & value, const QJsonValue & schema, const QJsonValue & defaultValue);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Return the "default" value as string. If not found, an empty string is output
|
||||||
|
///
|
||||||
|
/// @param value The JSON value to search
|
||||||
|
/// @return The "default" value as string
|
||||||
|
///
|
||||||
|
QString getDefaultValue(const QJsonValue & value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The schema of the entire json-configuration
|
/// The schema of the entire json-configuration
|
||||||
QJsonObject _qSchema;
|
QJsonObject _qSchema;
|
||||||
|
@ -41,6 +41,37 @@ public:
|
|||||||
return createValue(schema, ignoreRequired);
|
return createValue(schema, ignoreRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString getDefaultValue(const QJsonValue & value)
|
||||||
|
{
|
||||||
|
QString ret;
|
||||||
|
switch (value.type())
|
||||||
|
{
|
||||||
|
case QJsonValue::Array:
|
||||||
|
{
|
||||||
|
for (const QJsonValue &v : value.toArray())
|
||||||
|
{
|
||||||
|
ret = getDefaultValue(v);
|
||||||
|
if (!ret.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QJsonValue::Object:
|
||||||
|
ret = getDefaultValue(value.toObject().find("default").value());
|
||||||
|
break;
|
||||||
|
case QJsonValue::Bool:
|
||||||
|
return value.toBool() ? "True" : "False";
|
||||||
|
case QJsonValue::Double:
|
||||||
|
return QString::number(value.toDouble());
|
||||||
|
case QJsonValue::String:
|
||||||
|
return value.toString();
|
||||||
|
case QJsonValue::Null:
|
||||||
|
case QJsonValue::Undefined:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static QJsonValue createValue(QJsonValue schema, bool ignoreRequired)
|
static QJsonValue createValue(QJsonValue schema, bool ignoreRequired)
|
||||||
|
@ -11,6 +11,8 @@ target_link_libraries(v4l2-grabber
|
|||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (JPEG_FOUND)
|
if(TURBOJPEG_FOUND)
|
||||||
|
target_link_libraries(v4l2-grabber ${TurboJPEG_LIBRARY})
|
||||||
|
elseif (JPEG_FOUND)
|
||||||
target_link_libraries(v4l2-grabber ${JPEG_LIBRARY})
|
target_link_libraries(v4l2-grabber ${JPEG_LIBRARY})
|
||||||
endif()
|
endif(TURBOJPEG_FOUND)
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
#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
|
||||||
|
, const unsigned width
|
||||||
|
, const unsigned height
|
||||||
|
, const unsigned fps
|
||||||
, VideoStandard videoStandard
|
, VideoStandard videoStandard
|
||||||
, PixelFormat pixelFormat
|
, PixelFormat pixelFormat
|
||||||
, int pixelDecimation
|
, int pixelDecimation
|
||||||
@ -59,6 +62,8 @@ V4L2Grabber::V4L2Grabber(const QString & device
|
|||||||
getV4Ldevices();
|
getV4Ldevices();
|
||||||
|
|
||||||
// init
|
// init
|
||||||
|
setWidthHeight(width, height);
|
||||||
|
setFramerate(fps);
|
||||||
setDeviceVideoStandard(device, videoStandard);
|
setDeviceVideoStandard(device, videoStandard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +566,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG_DECODER
|
||||||
case PIXELFORMAT_MJPEG:
|
case PIXELFORMAT_MJPEG:
|
||||||
{
|
{
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
@ -576,53 +581,41 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get maximum video devices resolution
|
// collect available device resolutions
|
||||||
__u32 max_width = 0, max_height = 0;
|
QString v4lDevice_res;
|
||||||
struct v4l2_fmtdesc fmtdesc;
|
|
||||||
CLEAR(fmtdesc);
|
|
||||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
fmtdesc.index = 0;
|
|
||||||
while (xioctl(VIDIOC_ENUM_FMT, &fmtdesc) >= 0)
|
|
||||||
{
|
|
||||||
v4l2_frmsizeenum frmsizeenum;
|
v4l2_frmsizeenum frmsizeenum;
|
||||||
CLEAR(frmsizeenum);
|
CLEAR(frmsizeenum);
|
||||||
frmsizeenum.pixel_format = fmtdesc.pixelformat;
|
|
||||||
frmsizeenum.index = 0;
|
frmsizeenum.index = 0;
|
||||||
|
frmsizeenum.pixel_format = fmt.fmt.pix.pixelformat;
|
||||||
while (xioctl(VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0)
|
while (xioctl(VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0)
|
||||||
{
|
{
|
||||||
switch (frmsizeenum.type)
|
switch (frmsizeenum.type)
|
||||||
{
|
{
|
||||||
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
||||||
{
|
v4lDevice_res += "\t"+ QString::number(frmsizeenum.discrete.width) + "x" + QString::number(frmsizeenum.discrete.height) + "\n";
|
||||||
max_width = std::max(max_width, frmsizeenum.discrete.width);
|
|
||||||
max_height = std::max(max_height, frmsizeenum.discrete.height);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
|
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
|
||||||
case V4L2_FRMSIZE_TYPE_STEPWISE:
|
case V4L2_FRMSIZE_TYPE_STEPWISE:
|
||||||
{
|
{
|
||||||
max_width = std::max(max_width, frmsizeenum.stepwise.max_width);
|
for(unsigned int y = frmsizeenum.stepwise.min_height; y <= frmsizeenum.stepwise.max_height; y += frmsizeenum.stepwise.step_height)
|
||||||
max_height = std::max(max_height, frmsizeenum.stepwise.max_height);
|
{
|
||||||
|
for(unsigned int x = frmsizeenum.stepwise.min_width; x <= frmsizeenum.stepwise.max_width; x += frmsizeenum.stepwise.step_width)
|
||||||
|
{
|
||||||
|
v4lDevice_res += "\t"+ QString::number(x) + "x" + QString::number(y) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frmsizeenum.index++;
|
frmsizeenum.index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmtdesc.index++;
|
// print available device resolutions in debug mode
|
||||||
}
|
if (!v4lDevice_res.isEmpty())
|
||||||
|
Debug(_log, "available V4L2 resolutions:\n%s", QSTRING_CSTR(v4lDevice_res));
|
||||||
|
|
||||||
// set the settings
|
// set the settings
|
||||||
if (max_width != 0 || max_height != 0)
|
|
||||||
{
|
|
||||||
fmt.fmt.pix.width = max_width;
|
|
||||||
fmt.fmt.pix.height = max_height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fmt.fmt.pix.width = _width;
|
fmt.fmt.pix.width = _width;
|
||||||
fmt.fmt.pix.height = _height;
|
fmt.fmt.pix.height = _height;
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
|
if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
|
||||||
{
|
{
|
||||||
@ -652,14 +645,18 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME)
|
if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME)
|
||||||
{
|
{
|
||||||
// Driver supports the feature. Set required framerate
|
// Driver supports the feature. Set required framerate
|
||||||
streamparms.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
|
CLEAR(streamparms);
|
||||||
|
streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
streamparms.parm.capture.timeperframe.numerator = 1;
|
streamparms.parm.capture.timeperframe.numerator = 1;
|
||||||
streamparms.parm.capture.timeperframe.denominator = 30;
|
streamparms.parm.capture.timeperframe.denominator = _fps;
|
||||||
if(-1 == xioctl(VIDIOC_S_PARM, &streamparms))
|
if(-1 == xioctl(VIDIOC_S_PARM, &streamparms))
|
||||||
{
|
{
|
||||||
throw_errno_exception("VIDIOC_S_PARM");
|
throw_errno_exception("VIDIOC_S_PARM");
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
// display the used framerate
|
||||||
|
Debug(_log, "Set framerate to %d fps", _fps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,7 +690,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG_DECODER
|
||||||
case V4L2_PIX_FMT_MJPEG:
|
case V4L2_PIX_FMT_MJPEG:
|
||||||
{
|
{
|
||||||
_pixelFormat = PIXELFORMAT_MJPEG;
|
_pixelFormat = PIXELFORMAT_MJPEG;
|
||||||
@ -703,7 +700,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG_DECODER
|
||||||
throw_exception("Only pixel formats UYVY, YUYV, RGB32 and MJPEG are supported");
|
throw_exception("Only pixel formats UYVY, YUYV, RGB32 and MJPEG are supported");
|
||||||
#else
|
#else
|
||||||
throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported");
|
throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported");
|
||||||
@ -955,7 +952,7 @@ 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
|
#ifdef HAVE_JPEG_DECODER
|
||||||
if (size != _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG)
|
if (size != _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG)
|
||||||
#else
|
#else
|
||||||
if (size != _frameByteSize)
|
if (size != _frameByteSize)
|
||||||
@ -976,9 +973,15 @@ void V4L2Grabber::process_image(const uint8_t * data, int size)
|
|||||||
{
|
{
|
||||||
Image<ColorRgb> image(_width, _height);
|
Image<ColorRgb> image(_width, _height);
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
/* ----------------------------------------------------------
|
||||||
|
* ----------- BEGIN of JPEG decoder related code -----------
|
||||||
|
* --------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef HAVE_JPEG_DECODER
|
||||||
if (_pixelFormat == PIXELFORMAT_MJPEG)
|
if (_pixelFormat == PIXELFORMAT_MJPEG)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_JPEG
|
||||||
_decompress = new jpeg_decompress_struct;
|
_decompress = new jpeg_decompress_struct;
|
||||||
_error = new errorManager;
|
_error = new errorManager;
|
||||||
|
|
||||||
@ -1048,7 +1051,31 @@ void V4L2Grabber::process_image(const uint8_t * data, int size)
|
|||||||
|
|
||||||
if (imageFrame.isNull() || _error->pub.num_warnings > 0)
|
if (imageFrame.isNull() || _error->pub.num_warnings > 0)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
_decompress = tjInitDecompress();
|
||||||
|
if (_decompress == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tjDecompressHeader2(_decompress, const_cast<uint8_t*>(data), size, &_width, &_height, &_subsamp) != 0)
|
||||||
|
{
|
||||||
|
tjDestroy(_decompress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage imageFrame = QImage(_width, _height, QImage::Format_RGB888);
|
||||||
|
if (tjDecompress2(_decompress, const_cast<uint8_t*>(data), size, imageFrame.bits(), _width, 0, _height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE) != 0)
|
||||||
|
{
|
||||||
|
tjDestroy(_decompress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tjDestroy(_decompress);
|
||||||
|
|
||||||
|
if (imageFrame.isNull())
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_JPEG_DECODER
|
||||||
QRect rect(_cropLeft, _cropTop, imageFrame.width() - _cropLeft - _cropRight, imageFrame.height() - _cropTop - _cropBottom);
|
QRect rect(_cropLeft, _cropTop, imageFrame.width() - _cropLeft - _cropRight, imageFrame.height() - _cropTop - _cropBottom);
|
||||||
imageFrame = imageFrame.copy(rect);
|
imageFrame = imageFrame.copy(rect);
|
||||||
imageFrame = imageFrame.scaled(imageFrame.width() / _pixelDecimation, imageFrame.height() / _pixelDecimation,Qt::KeepAspectRatio);
|
imageFrame = imageFrame.scaled(imageFrame.width() / _pixelDecimation, imageFrame.height() / _pixelDecimation,Qt::KeepAspectRatio);
|
||||||
@ -1068,6 +1095,11 @@ void V4L2Grabber::process_image(const uint8_t * data, int size)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------
|
||||||
|
* ------------ END of JPEG decoder related code ------------
|
||||||
|
* --------------------------------------------------------*/
|
||||||
|
|
||||||
_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image);
|
_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image);
|
||||||
|
|
||||||
if (_signalDetectionEnabled)
|
if (_signalDetectionEnabled)
|
||||||
@ -1171,3 +1203,27 @@ void V4L2Grabber::setDeviceVideoStandard(QString device, VideoStandard videoStan
|
|||||||
if(started) start();
|
if(started) start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool V4L2Grabber::setFramerate(int fps)
|
||||||
|
{
|
||||||
|
if(Grabber::setFramerate(fps))
|
||||||
|
{
|
||||||
|
bool started = _initialized;
|
||||||
|
uninit();
|
||||||
|
if(started) start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool V4L2Grabber::setWidthHeight(int width, int height)
|
||||||
|
{
|
||||||
|
if(Grabber::setWidthHeight(width,height))
|
||||||
|
{
|
||||||
|
bool started = _initialized;
|
||||||
|
uninit();
|
||||||
|
if(started) start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -6,11 +6,17 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
V4L2Wrapper::V4L2Wrapper(const QString &device,
|
V4L2Wrapper::V4L2Wrapper(const QString &device,
|
||||||
|
const unsigned grabWidth,
|
||||||
|
const unsigned grabHeight,
|
||||||
|
const unsigned fps,
|
||||||
VideoStandard videoStandard,
|
VideoStandard videoStandard,
|
||||||
PixelFormat pixelFormat,
|
PixelFormat pixelFormat,
|
||||||
int pixelDecimation )
|
int pixelDecimation )
|
||||||
: GrabberWrapper("V4L2:"+device, &_grabber, 0, 0, 10)
|
: GrabberWrapper("V4L2:"+device, &_grabber, grabWidth, grabHeight, 10)
|
||||||
, _grabber(device,
|
, _grabber(device,
|
||||||
|
grabWidth,
|
||||||
|
grabHeight,
|
||||||
|
fps,
|
||||||
videoStandard,
|
videoStandard,
|
||||||
pixelFormat,
|
pixelFormat,
|
||||||
pixelDecimation)
|
pixelDecimation)
|
||||||
|
@ -7,6 +7,7 @@ Grabber::Grabber(QString grabberName, int width, int height, int cropLeft, int c
|
|||||||
, _videoMode(VIDEO_2D)
|
, _videoMode(VIDEO_2D)
|
||||||
, _width(width)
|
, _width(width)
|
||||||
, _height(height)
|
, _height(height)
|
||||||
|
, _fps(15)
|
||||||
, _cropLeft(0)
|
, _cropLeft(0)
|
||||||
, _cropRight(0)
|
, _cropRight(0)
|
||||||
, _cropTop(0)
|
, _cropTop(0)
|
||||||
@ -86,3 +87,11 @@ bool Grabber::setWidthHeight(int width, int height)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Grabber::setFramerate(int fps)
|
||||||
|
{
|
||||||
|
if(fps > 0)
|
||||||
|
_fps = fps;
|
||||||
|
|
||||||
|
return fps > 0;
|
||||||
|
}
|
@ -157,6 +157,12 @@ void GrabberWrapper::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
obj["cropTop"].toInt(0),
|
obj["cropTop"].toInt(0),
|
||||||
obj["cropBottom"].toInt(0));
|
obj["cropBottom"].toInt(0));
|
||||||
|
|
||||||
|
// device resolution
|
||||||
|
_ggrabber->setWidthHeight(obj["width"].toInt(0), obj["height"].toInt(0));
|
||||||
|
|
||||||
|
// device framerate
|
||||||
|
_ggrabber->setFramerate(obj["fps"].toInt(15));
|
||||||
|
|
||||||
_ggrabber->setSignalDetectionEnable(obj["signalDetection"].toBool(true));
|
_ggrabber->setSignalDetectionEnable(obj["signalDetection"].toBool(true));
|
||||||
_ggrabber->setSignalDetectionOffset(
|
_ggrabber->setSignalDetectionOffset(
|
||||||
obj["sDHOffsetMin"].toDouble(0.25),
|
obj["sDHOffsetMin"].toDouble(0.25),
|
||||||
@ -170,7 +176,6 @@ void GrabberWrapper::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
_ggrabber->setDeviceVideoStandard(
|
_ggrabber->setDeviceVideoStandard(
|
||||||
obj["device"].toString("auto"),
|
obj["device"].toString("auto"),
|
||||||
parseVideoStandard(obj["standard"].toString("no-change")));
|
parseVideoStandard(obj["standard"].toString("no-change")));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
"items" : {
|
"items" : {
|
||||||
"type" : "integer",
|
"type" : "integer",
|
||||||
"minimum" : 0,
|
"minimum" : 0,
|
||||||
"maximum" : 255
|
"maximum" : 255,
|
||||||
|
"default" : 0
|
||||||
},
|
},
|
||||||
"minItems" : 3,
|
"minItems" : 3,
|
||||||
"maxItems" : 3,
|
"maxItems" : 3,
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
"items" : {
|
"items" : {
|
||||||
"type" : "integer",
|
"type" : "integer",
|
||||||
"minimum" : 0,
|
"minimum" : 0,
|
||||||
"maximum" : 255
|
"maximum" : 255,
|
||||||
|
"default" : 0
|
||||||
},
|
},
|
||||||
"minItems" : 3,
|
"minItems" : 3,
|
||||||
"maxItems" : 3,
|
"maxItems" : 3,
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
"type" : "string",
|
"type" : "string",
|
||||||
"title" : "edt_conf_v4l2_device_title",
|
"title" : "edt_conf_v4l2_device_title",
|
||||||
"default" : "auto",
|
"default" : "auto",
|
||||||
"minLength" : 4,
|
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 1
|
"propertyOrder" : 1
|
||||||
},
|
},
|
||||||
@ -17,14 +16,44 @@
|
|||||||
{
|
{
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"title" : "edt_conf_v4l2_standard_title",
|
"title" : "edt_conf_v4l2_standard_title",
|
||||||
"enum" : ["PAL","NTSC","SECAM","NO_CHANGE"],
|
"enum" : ["NO_CHANGE", "PAL","NTSC","SECAM"],
|
||||||
"default" : "NO_CHANGE",
|
"default" : "NO_CHANGE",
|
||||||
"options" : {
|
"options" : {
|
||||||
"enum_titles" : ["edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM", "edt_conf_enum_NO_CHANGE"]
|
"enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM"]
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 2
|
"propertyOrder" : 2
|
||||||
},
|
},
|
||||||
|
"width" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_fg_width_title",
|
||||||
|
"default" : 0,
|
||||||
|
"minimum" : 0,
|
||||||
|
"required" : true,
|
||||||
|
"access" : "expert",
|
||||||
|
"propertyOrder" : 3
|
||||||
|
},
|
||||||
|
"height" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_conf_fg_height_title",
|
||||||
|
"default" : 0,
|
||||||
|
"minimum" : 0,
|
||||||
|
"required" : true,
|
||||||
|
"access" : "expert",
|
||||||
|
"propertyOrder" : 4
|
||||||
|
},
|
||||||
|
"fps" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "Framerate",
|
||||||
|
"default" : 15,
|
||||||
|
"minimum" : 1,
|
||||||
|
"required" : true,
|
||||||
|
"access" : "expert",
|
||||||
|
"propertyOrder" : 5
|
||||||
|
},
|
||||||
"sizeDecimation" :
|
"sizeDecimation" :
|
||||||
{
|
{
|
||||||
"type" : "integer",
|
"type" : "integer",
|
||||||
@ -33,7 +62,7 @@
|
|||||||
"maximum" : 30,
|
"maximum" : 30,
|
||||||
"default" : 6,
|
"default" : 6,
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 3
|
"propertyOrder" : 6
|
||||||
},
|
},
|
||||||
"cropLeft" :
|
"cropLeft" :
|
||||||
{
|
{
|
||||||
@ -43,7 +72,7 @@
|
|||||||
"default" : 0,
|
"default" : 0,
|
||||||
"append" : "edt_append_pixel",
|
"append" : "edt_append_pixel",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 4
|
"propertyOrder" : 7
|
||||||
},
|
},
|
||||||
"cropRight" :
|
"cropRight" :
|
||||||
{
|
{
|
||||||
@ -53,7 +82,7 @@
|
|||||||
"default" : 0,
|
"default" : 0,
|
||||||
"append" : "edt_append_pixel",
|
"append" : "edt_append_pixel",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 5
|
"propertyOrder" : 8
|
||||||
},
|
},
|
||||||
"cropTop" :
|
"cropTop" :
|
||||||
{
|
{
|
||||||
@ -63,7 +92,7 @@
|
|||||||
"default" : 0,
|
"default" : 0,
|
||||||
"append" : "edt_append_pixel",
|
"append" : "edt_append_pixel",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 6
|
"propertyOrder" : 9
|
||||||
},
|
},
|
||||||
"cropBottom" :
|
"cropBottom" :
|
||||||
{
|
{
|
||||||
@ -73,7 +102,7 @@
|
|||||||
"default" : 0,
|
"default" : 0,
|
||||||
"append" : "edt_append_pixel",
|
"append" : "edt_append_pixel",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 7
|
"propertyOrder" : 10
|
||||||
},
|
},
|
||||||
"signalDetection" :
|
"signalDetection" :
|
||||||
{
|
{
|
||||||
@ -81,7 +110,7 @@
|
|||||||
"title" : "edt_conf_v4l2_signalDetection_title",
|
"title" : "edt_conf_v4l2_signalDetection_title",
|
||||||
"default" : false,
|
"default" : false,
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 8
|
"propertyOrder" : 11
|
||||||
},
|
},
|
||||||
"redSignalThreshold" :
|
"redSignalThreshold" :
|
||||||
{
|
{
|
||||||
@ -97,7 +126,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 9
|
"propertyOrder" : 12
|
||||||
},
|
},
|
||||||
"greenSignalThreshold" :
|
"greenSignalThreshold" :
|
||||||
{
|
{
|
||||||
@ -113,7 +142,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 10
|
"propertyOrder" : 13
|
||||||
},
|
},
|
||||||
"blueSignalThreshold" :
|
"blueSignalThreshold" :
|
||||||
{
|
{
|
||||||
@ -129,7 +158,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 11
|
"propertyOrder" : 14
|
||||||
},
|
},
|
||||||
"sDVOffsetMin" :
|
"sDVOffsetMin" :
|
||||||
{
|
{
|
||||||
@ -145,7 +174,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 12
|
"propertyOrder" : 15
|
||||||
},
|
},
|
||||||
"sDVOffsetMax" :
|
"sDVOffsetMax" :
|
||||||
{
|
{
|
||||||
@ -161,7 +190,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 13
|
"propertyOrder" : 16
|
||||||
},
|
},
|
||||||
"sDHOffsetMin" :
|
"sDHOffsetMin" :
|
||||||
{
|
{
|
||||||
@ -177,7 +206,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 14
|
"propertyOrder" : 17
|
||||||
},
|
},
|
||||||
"sDHOffsetMax" :
|
"sDHOffsetMax" :
|
||||||
{
|
{
|
||||||
@ -193,8 +222,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"propertyOrder" : 15
|
"propertyOrder" : 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties" : false
|
"additionalProperties" : true
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
"required" : true,
|
"required" : true,
|
||||||
"items" : {
|
"items" : {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title" : "edt_conf_net_ip_itemtitle"
|
"title" : "edt_conf_net_ip_itemtitle",
|
||||||
|
"allowEmptyArray" : true
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -121,7 +121,7 @@ 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
|
#ifdef HAVE_JPEG_DECODER
|
||||||
case PIXELFORMAT_MJPEG:
|
case PIXELFORMAT_MJPEG:
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,7 +73,7 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s
|
|||||||
QJsonObject::const_iterator defaultValue = schema.find("default");
|
QJsonObject::const_iterator defaultValue = schema.find("default");
|
||||||
|
|
||||||
if (attribute == "type")
|
if (attribute == "type")
|
||||||
checkType(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkType(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "properties")
|
else if (attribute == "properties")
|
||||||
{
|
{
|
||||||
if (value.isObject())
|
if (value.isObject())
|
||||||
@ -106,13 +106,13 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (attribute == "minimum")
|
else if (attribute == "minimum")
|
||||||
checkMinimum(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMinimum(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "maximum")
|
else if (attribute == "maximum")
|
||||||
checkMaximum(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMaximum(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "minLength")
|
else if (attribute == "minLength")
|
||||||
checkMinLength(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMinLength(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "maxLength")
|
else if (attribute == "maxLength")
|
||||||
checkMaxLength(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMaxLength(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "items")
|
else if (attribute == "items")
|
||||||
{
|
{
|
||||||
if (value.isArray())
|
if (value.isArray())
|
||||||
@ -125,19 +125,20 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (attribute == "minItems")
|
else if (attribute == "minItems")
|
||||||
checkMinItems(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMinItems(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "maxItems")
|
else if (attribute == "maxItems")
|
||||||
checkMaxItems(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkMaxItems(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "uniqueItems")
|
else if (attribute == "uniqueItems")
|
||||||
checkUniqueItems(value, attributeValue);
|
checkUniqueItems(value, attributeValue);
|
||||||
else if (attribute == "enum")
|
else if (attribute == "enum")
|
||||||
checkEnum(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null));
|
checkEnum(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null));
|
||||||
else if (attribute == "required")
|
else if (attribute == "required")
|
||||||
; // nothing to do. value is present so always oke
|
; // nothing to do. value is present so always oke
|
||||||
else if (attribute == "id")
|
else if (attribute == "id")
|
||||||
; // references have already been collected
|
; // references have already been collected
|
||||||
else if (attribute == "title" || attribute == "description" || attribute == "default" || attribute == "format"
|
else if (attribute == "title" || attribute == "description" || attribute == "default" || attribute == "format"
|
||||||
|| attribute == "defaultProperties" || attribute == "propertyOrder" || attribute == "append" || attribute == "step" || attribute == "access" || attribute == "options" || attribute == "script")
|
|| attribute == "defaultProperties" || attribute == "propertyOrder" || attribute == "append" || attribute == "step"
|
||||||
|
|| attribute == "access" || attribute == "options" || attribute == "script" || attribute == "allowEmptyArray")
|
||||||
; // nothing to do.
|
; // nothing to do.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -225,7 +226,7 @@ void QJsonSchemaChecker::checkProperties(const QJsonObject & value, const QJsonO
|
|||||||
if (_correct == "create")
|
if (_correct == "create")
|
||||||
{
|
{
|
||||||
QJsonUtils::modify(_autoCorrected, _currentPath, QJsonUtils::create(propertyValue, _ignoreRequired), property);
|
QJsonUtils::modify(_autoCorrected, _currentPath, QJsonUtils::create(propertyValue, _ignoreRequired), property);
|
||||||
setMessage("Create property: "+property+" with value: "+propertyValue.toObject().find("default").value().toString());
|
setMessage("Create property: "+property+" with value: "+QJsonUtils::getDefaultValue(propertyValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_correct == "")
|
if (_correct == "")
|
||||||
@ -391,7 +392,7 @@ void QJsonSchemaChecker::checkItems(const QJsonValue & value, const QJsonObject
|
|||||||
QJsonArray jArray = value.toArray();
|
QJsonArray jArray = value.toArray();
|
||||||
|
|
||||||
if (_correct == "remove")
|
if (_correct == "remove")
|
||||||
if (jArray.isEmpty())
|
if (jArray.isEmpty() && !schema.contains("allowEmptyArray"))
|
||||||
{
|
{
|
||||||
QJsonUtils::modify(_autoCorrected, _currentPath);
|
QJsonUtils::modify(_autoCorrected, _currentPath);
|
||||||
setMessage("Remove empty array");
|
setMessage("Remove empty array");
|
||||||
|
@ -53,6 +53,9 @@ 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, MJPEG 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 & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "15", 1, 25);
|
||||||
|
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160);
|
||||||
|
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160);
|
||||||
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)");
|
||||||
@ -105,6 +108,9 @@ int main(int argc, char** argv)
|
|||||||
// initialize the grabber
|
// initialize the grabber
|
||||||
V4L2Grabber grabber(
|
V4L2Grabber grabber(
|
||||||
argDevice.value(parser),
|
argDevice.value(parser),
|
||||||
|
argWidth.getInt(parser),
|
||||||
|
argHeight.getInt(parser),
|
||||||
|
1000 / argFps.getInt(parser),
|
||||||
argVideoStandard.switchValue(parser),
|
argVideoStandard.switchValue(parser),
|
||||||
argPixelFormat.switchValue(parser),
|
argPixelFormat.switchValue(parser),
|
||||||
std::max(1, argSizeDecimation.getInt(parser)));
|
std::max(1, argSizeDecimation.getInt(parser)));
|
||||||
|
@ -443,6 +443,9 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& settingsType, co
|
|||||||
|
|
||||||
_v4l2Grabber = new V4L2Wrapper(
|
_v4l2Grabber = new V4L2Wrapper(
|
||||||
grabberConfig["device"].toString("auto"),
|
grabberConfig["device"].toString("auto"),
|
||||||
|
grabberConfig["width"].toInt(0),
|
||||||
|
grabberConfig["height"].toInt(0),
|
||||||
|
grabberConfig["fps"].toInt(15),
|
||||||
parseVideoStandard(grabberConfig["standard"].toString("no-change")),
|
parseVideoStandard(grabberConfig["standard"].toString("no-change")),
|
||||||
parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change")),
|
parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change")),
|
||||||
grabberConfig["sizeDecimation"].toInt(8));
|
grabberConfig["sizeDecimation"].toInt(8));
|
||||||
|
Loading…
Reference in New Issue
Block a user