mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00: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:
		| @@ -298,23 +298,32 @@ find_package(libusb-1.0 REQUIRED) | ||||
| find_package(Threads REQUIRED) | ||||
| add_definitions(${QT_DEFINITIONS}) | ||||
|  | ||||
| # Add jpeg library | ||||
| # 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}) | ||||
| 	# 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() | ||||
| 		message( STATUS "JPEG library not found, MJPEG camera format won't work in V4L2 grabber.") | ||||
| 		# System JPEG | ||||
| 		find_package(JPEG) | ||||
| 		if (JPEG_FOUND) | ||||
| 			add_definitions(-DHAVE_JPEG) | ||||
| 			message( STATUS "Using system 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 (TurboJPEG_FOUND) | ||||
|  | ||||
| 	 | ||||
| 	if (TURBOJPEG_FOUND OR JPEG_FOUND) | ||||
| 		add_definitions(-DHAVE_JPEG_DECODER) | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| # TODO[TvdZ]: This linking directory should only be added if we are cross compiling | ||||
| #if(NOT APPLE) | ||||
| #	link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) | ||||
| #endif() | ||||
|  | ||||
| if(APPLE) | ||||
| 	set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics") | ||||
| endif() | ||||
|   | ||||
| @@ -40,7 +40,7 @@ wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/ | ||||
|  | ||||
| ``` | ||||
| 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** | ||||
|   | ||||
| @@ -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) | ||||
| 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) | ||||
| Update the Ubuntu environment to the latest stage and install required additional packages. | ||||
| ``` | ||||
| sudo apt-get update | ||||
| 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: | ||||
|   | ||||
| @@ -5,7 +5,7 @@ CFG="${2:-Release}" | ||||
| INST="$( [ "${3:-}" = "install" ] && echo true || echo false )" | ||||
|  | ||||
| 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 ] | ||||
| 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 | ||||
| 	///  * 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"] | ||||
| 	///  * sizeDecimation       : Size decimation factor [default=8] | ||||
| 	///  * cropLeft             : Cropping from the left [default=0] | ||||
| @@ -118,6 +120,8 @@ | ||||
| 	"grabberV4L2" : | ||||
| 	{ | ||||
| 		"device"   : "auto", | ||||
| 		"width" : 0, | ||||
| 		"height" : 0, | ||||
| 		"standard" : "NO_CHANGE", | ||||
| 		"sizeDecimation"  : 8, | ||||
| 		"priority"    : 240, | ||||
|   | ||||
| @@ -59,21 +59,24 @@ | ||||
|  | ||||
| 	"grabberV4L2" : | ||||
| 	{ | ||||
| 		"device"   : "auto", | ||||
| 		"standard" : "NO_CHANGE", | ||||
| 		"sizeDecimation"  : 8, | ||||
| 		"cropLeft"    : 0, | ||||
| 		"cropRight"   : 0, | ||||
| 		"cropTop"     : 0, | ||||
| 		"cropBottom"  : 0, | ||||
| 		"redSignalThreshold"   : 5, | ||||
| 		"greenSignalThreshold" : 5, | ||||
| 		"blueSignalThreshold"  : 5, | ||||
| 		"signalDetection"      : false, | ||||
| 		"sDVOffsetMin"   : 0.25, | ||||
| 		"sDHOffsetMin" : 0.25, | ||||
| 		"sDVOffsetMax"   : 0.75, | ||||
| 		"sDHOffsetMax" : 0.75 | ||||
| 		"device"		: "auto", | ||||
| 		"width"			: 0, | ||||
| 		"height"		: 0, | ||||
| 		"fps"			: 15, | ||||
| 		"standard"		: "NO_CHANGE", | ||||
| 		"sizeDecimation" 	: 8, | ||||
| 		"cropLeft"		: 0, | ||||
| 		"cropRight"		: 0, | ||||
| 		"cropTop"		: 0, | ||||
| 		"cropBottom"		: 0, | ||||
| 		"redSignalThreshold"	: 5, | ||||
| 		"greenSignalThreshold"	: 5, | ||||
| 		"blueSignalThreshold"	: 5, | ||||
| 		"signalDetection"	: false, | ||||
| 		"sDVOffsetMin"		: 0.25, | ||||
| 		"sDHOffsetMin"		: 0.25, | ||||
| 		"sDVOffsetMax"		: 0.75, | ||||
| 		"sDHOffsetMax"		: 0.75 | ||||
| 	}, | ||||
|  | ||||
| 	"framegrabber" : | ||||
|   | ||||
| @@ -15,13 +15,23 @@ | ||||
| #include <grabber/VideoStandard.h> | ||||
| #include <utils/Components.h> | ||||
|  | ||||
| #ifdef HAVE_JPEG | ||||
| // general JPEG decoder includes | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 	#include <QImage> | ||||
| 	#include <QColor> | ||||
| #endif | ||||
|  | ||||
| // System JPEG decoder | ||||
| #ifdef HAVE_JPEG | ||||
| 	#include <jpeglib.h> | ||||
| 	#include <csetjmp> | ||||
| #endif | ||||
|  | ||||
| // TurboJPEG decoder | ||||
| #ifdef HAVE_TURBO_JPEG | ||||
| 	#include <turbojpeg.h> | ||||
| #endif | ||||
|  | ||||
| /// Capture class for V4L2 devices | ||||
| /// | ||||
| /// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html | ||||
| @@ -31,6 +41,9 @@ class V4L2Grabber : public Grabber | ||||
|  | ||||
| public: | ||||
| 	V4L2Grabber(const QString & device, | ||||
| 			const unsigned width, | ||||
| 			const unsigned height, | ||||
| 			const unsigned fps, | ||||
| 			VideoStandard videoStandard, | ||||
| 			PixelFormat pixelFormat, | ||||
| 			int pixelDecimation | ||||
| @@ -46,11 +59,6 @@ public: | ||||
|  | ||||
| 	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 | ||||
| 	/// @param  pixelDecimation  The new pixelDecimation value | ||||
| @@ -84,6 +92,16 @@ public: | ||||
| 	///  | ||||
| 	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: | ||||
|  | ||||
| 	bool start(); | ||||
| @@ -173,6 +191,11 @@ private: | ||||
| 	errorManager* _error; | ||||
| #endif | ||||
|  | ||||
| #ifdef HAVE_TURBO_JPEG | ||||
| 	tjhandle _decompress = nullptr; | ||||
| 	int _subsamp; | ||||
| #endif | ||||
|  | ||||
| private: | ||||
| 	QString _deviceName; | ||||
| 	std::map<QString,QString> _v4lDevices; | ||||
|   | ||||
| @@ -9,6 +9,9 @@ class V4L2Wrapper : public GrabberWrapper | ||||
|  | ||||
| public: | ||||
| 	V4L2Wrapper(const QString & device, | ||||
| 			const unsigned grabWidth, | ||||
| 			const unsigned grabHeight, | ||||
| 			const unsigned fps, | ||||
| 			VideoStandard videoStandard, | ||||
| 			PixelFormat pixelFormat, | ||||
| 			int pixelDecimation ); | ||||
|   | ||||
| @@ -40,6 +40,12 @@ public: | ||||
| 	/// | ||||
| 	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) | ||||
| 	/// | ||||
| @@ -111,6 +117,8 @@ protected: | ||||
| 	/// Height of the captured snapshot [pixels] | ||||
| 	int _height; | ||||
|  | ||||
| 	int _fps; | ||||
|  | ||||
| 	// number of pixels to crop after capturing | ||||
| 	int _cropLeft, _cropRight, _cropTop, _cropBottom; | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ enum PixelFormat { | ||||
| 	PIXELFORMAT_BGR24, | ||||
| 	PIXELFORMAT_RGB32, | ||||
| 	PIXELFORMAT_BGR32, | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 	PIXELFORMAT_MJPEG, | ||||
| #endif | ||||
| 	PIXELFORMAT_NO_CHANGE | ||||
| @@ -47,7 +47,7 @@ inline PixelFormat parsePixelFormat(QString pixelFormat) | ||||
| 	{ | ||||
| 		return PIXELFORMAT_BGR32; | ||||
| 	} | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 	else if (pixelFormat == "mjpeg") | ||||
| 	{ | ||||
| 		return PIXELFORMAT_MJPEG; | ||||
|   | ||||
| @@ -187,6 +187,14 @@ private: | ||||
| 	/// | ||||
| 	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: | ||||
| 	/// The schema of the entire json-configuration | ||||
| 	QJsonObject _qSchema; | ||||
|   | ||||
| @@ -41,6 +41,37 @@ public: | ||||
| 		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: | ||||
|  | ||||
| 	static QJsonValue createValue(QJsonValue schema, bool ignoreRequired) | ||||
|   | ||||
| @@ -11,6 +11,8 @@ target_link_libraries(v4l2-grabber | ||||
| 	${QT_LIBRARIES} | ||||
| ) | ||||
|  | ||||
| if (JPEG_FOUND) | ||||
| 	target_link_libraries(v4l2-grabber ${JPEG_LIBRARY}) | ||||
| endif() | ||||
| if(TURBOJPEG_FOUND) | ||||
| 	target_link_libraries(v4l2-grabber ${TurboJPEG_LIBRARY}) | ||||
| elseif (JPEG_FOUND) | ||||
| 		target_link_libraries(v4l2-grabber ${JPEG_LIBRARY}) | ||||
| endif(TURBOJPEG_FOUND) | ||||
|   | ||||
| @@ -27,6 +27,9 @@ | ||||
| #define CLEAR(x) memset(&(x), 0, sizeof(x)) | ||||
|  | ||||
| V4L2Grabber::V4L2Grabber(const QString & device | ||||
| 		, const unsigned width | ||||
| 		, const unsigned height | ||||
| 		, const unsigned fps | ||||
| 		, VideoStandard videoStandard | ||||
| 		, PixelFormat pixelFormat | ||||
| 		, int pixelDecimation | ||||
| @@ -59,6 +62,8 @@ V4L2Grabber::V4L2Grabber(const QString & device | ||||
| 	getV4Ldevices(); | ||||
|  | ||||
| 	// init | ||||
| 	setWidthHeight(width, height); | ||||
| 	setFramerate(fps); | ||||
| 	setDeviceVideoStandard(device, videoStandard); | ||||
| } | ||||
|  | ||||
| @@ -561,7 +566,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) | ||||
| 			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; | ||||
| 		break; | ||||
|  | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 		case PIXELFORMAT_MJPEG: | ||||
| 		{ | ||||
| 			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; | ||||
| @@ -576,53 +581,41 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	// get maximum video devices resolution | ||||
| 	__u32 max_width = 0, max_height = 0; | ||||
| 	struct v4l2_fmtdesc fmtdesc; | ||||
| 	CLEAR(fmtdesc); | ||||
| 	fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||||
| 	fmtdesc.index = 0; | ||||
| 	while (xioctl(VIDIOC_ENUM_FMT, &fmtdesc) >= 0) | ||||
| 	// collect available device resolutions | ||||
| 	QString v4lDevice_res; | ||||
| 	v4l2_frmsizeenum frmsizeenum; | ||||
| 	CLEAR(frmsizeenum); | ||||
| 	frmsizeenum.index = 0; | ||||
| 	frmsizeenum.pixel_format = fmt.fmt.pix.pixelformat; | ||||
| 	while (xioctl(VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0) | ||||
| 	{ | ||||
| 		v4l2_frmsizeenum frmsizeenum; | ||||
| 		CLEAR(frmsizeenum); | ||||
| 		frmsizeenum.pixel_format = fmtdesc.pixelformat; | ||||
| 		frmsizeenum.index = 0; | ||||
| 		while (xioctl(VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0) | ||||
| 		switch (frmsizeenum.type) | ||||
| 		{ | ||||
| 			switch (frmsizeenum.type) | ||||
| 			case V4L2_FRMSIZE_TYPE_DISCRETE: | ||||
| 				v4lDevice_res += "\t"+ QString::number(frmsizeenum.discrete.width) + "x" + QString::number(frmsizeenum.discrete.height) + "\n"; | ||||
| 			break; | ||||
| 			case V4L2_FRMSIZE_TYPE_CONTINUOUS: | ||||
| 			case V4L2_FRMSIZE_TYPE_STEPWISE: | ||||
| 			{ | ||||
| 				case V4L2_FRMSIZE_TYPE_DISCRETE: | ||||
| 				for(unsigned int y = frmsizeenum.stepwise.min_height; y <= frmsizeenum.stepwise.max_height; y += frmsizeenum.stepwise.step_height) | ||||
| 				{ | ||||
| 					max_width = std::max(max_width, frmsizeenum.discrete.width); | ||||
| 					max_height = std::max(max_height, frmsizeenum.discrete.height); | ||||
| 				} | ||||
| 				break; | ||||
| 				case V4L2_FRMSIZE_TYPE_CONTINUOUS: | ||||
| 				case V4L2_FRMSIZE_TYPE_STEPWISE: | ||||
| 				{ | ||||
| 					max_width = std::max(max_width, frmsizeenum.stepwise.max_width); | ||||
| 					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++; | ||||
| 		} | ||||
|  | ||||
| 		fmtdesc.index++; | ||||
| 		frmsizeenum.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 | ||||
| 	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.height = _height; | ||||
| 	} | ||||
| 	fmt.fmt.pix.width = _width; | ||||
| 	fmt.fmt.pix.height = _height; | ||||
|  | ||||
| 	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) | ||||
| 		{ | ||||
| 			// 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.denominator = 30; | ||||
| 			streamparms.parm.capture.timeperframe.denominator = _fps; | ||||
| 			if(-1 == xioctl(VIDIOC_S_PARM, &streamparms)) | ||||
| 			{ | ||||
| 				throw_errno_exception("VIDIOC_S_PARM"); | ||||
| 				// 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; | ||||
|  | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 		case V4L2_PIX_FMT_MJPEG: | ||||
| 		{ | ||||
| 			_pixelFormat = PIXELFORMAT_MJPEG; | ||||
| @@ -703,7 +700,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) | ||||
| #endif | ||||
|  | ||||
| 		default: | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 			throw_exception("Only pixel formats UYVY, YUYV, RGB32 and MJPEG are supported"); | ||||
| #else | ||||
| 			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) | ||||
| { | ||||
| 	// We do want a new frame... | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 	if (size != _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG) | ||||
| #else | ||||
| 	if (size != _frameByteSize) | ||||
| @@ -976,9 +973,15 @@ void V4L2Grabber::process_image(const uint8_t * data, int size) | ||||
| { | ||||
| 	Image<ColorRgb> image(_width, _height); | ||||
|  | ||||
| #ifdef HAVE_JPEG | ||||
| /* ---------------------------------------------------------- | ||||
|  * ----------- BEGIN of JPEG decoder related code ----------- | ||||
|  * --------------------------------------------------------*/ | ||||
|  | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 	if (_pixelFormat == PIXELFORMAT_MJPEG) | ||||
| 	{ | ||||
| #endif | ||||
| #ifdef HAVE_JPEG | ||||
| 		_decompress = new jpeg_decompress_struct; | ||||
| 		_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) | ||||
| 			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); | ||||
| 		imageFrame = imageFrame.copy(rect); | ||||
| 		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 | ||||
| #endif | ||||
|  | ||||
| /* ---------------------------------------------------------- | ||||
|  * ------------ END of JPEG decoder related code ------------ | ||||
|  * --------------------------------------------------------*/ | ||||
|  | ||||
| 		_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image); | ||||
|  | ||||
| 	if (_signalDetectionEnabled) | ||||
| @@ -1171,3 +1203,27 @@ void V4L2Grabber::setDeviceVideoStandard(QString device, VideoStandard videoStan | ||||
| 		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> | ||||
|  | ||||
| V4L2Wrapper::V4L2Wrapper(const QString &device, | ||||
| 		const unsigned grabWidth, | ||||
| 		const unsigned grabHeight, | ||||
| 		const unsigned fps, | ||||
| 		VideoStandard videoStandard, | ||||
| 		PixelFormat pixelFormat, | ||||
| 		int pixelDecimation ) | ||||
| 	: GrabberWrapper("V4L2:"+device, &_grabber, 0, 0, 10) | ||||
| 	: GrabberWrapper("V4L2:"+device, &_grabber, grabWidth, grabHeight, 10) | ||||
| 	, _grabber(device, | ||||
| 			grabWidth, | ||||
| 			grabHeight, | ||||
| 			fps, | ||||
| 			videoStandard, | ||||
| 			pixelFormat, | ||||
| 			pixelDecimation) | ||||
|   | ||||
| @@ -7,6 +7,7 @@ Grabber::Grabber(QString grabberName, int width, int height, int cropLeft, int c | ||||
| 	, _videoMode(VIDEO_2D) | ||||
| 	, _width(width) | ||||
| 	, _height(height) | ||||
| 	, _fps(15) | ||||
| 	, _cropLeft(0) | ||||
| 	, _cropRight(0) | ||||
| 	, _cropTop(0) | ||||
| @@ -86,3 +87,11 @@ bool Grabber::setWidthHeight(int width, int height) | ||||
| 	} | ||||
| 	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["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->setSignalDetectionOffset( | ||||
| 				obj["sDHOffsetMin"].toDouble(0.25), | ||||
| @@ -170,7 +176,6 @@ void GrabberWrapper::handleSettingsUpdate(const settings::type& type, const QJso | ||||
| 			_ggrabber->setDeviceVideoStandard( | ||||
| 				obj["device"].toString("auto"), | ||||
| 				parseVideoStandard(obj["standard"].toString("no-change"))); | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -30,7 +30,8 @@ | ||||
| 			"items" : { | ||||
| 				"type" : "integer", | ||||
| 				"minimum" : 0, | ||||
| 				"maximum" : 255 | ||||
| 				"maximum" : 255, | ||||
| 				"default" : 0 | ||||
| 			}, | ||||
| 			"minItems" : 3, | ||||
| 			"maxItems" : 3, | ||||
|   | ||||
| @@ -30,7 +30,8 @@ | ||||
| 			"items" : { | ||||
| 				"type" : "integer", | ||||
| 				"minimum" : 0, | ||||
| 				"maximum" : 255 | ||||
| 				"maximum" : 255, | ||||
| 				"default" : 0 | ||||
| 			}, | ||||
| 			"minItems" : 3, | ||||
| 			"maxItems" : 3, | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| 			"type" : "string", | ||||
| 			"title" : "edt_conf_v4l2_device_title", | ||||
| 			"default" : "auto", | ||||
| 			"minLength" : 4, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 1 | ||||
| 		}, | ||||
| @@ -17,14 +16,44 @@ | ||||
| 		{ | ||||
| 			"type" : "string", | ||||
| 			"title" : "edt_conf_v4l2_standard_title", | ||||
| 			"enum" : ["PAL","NTSC","SECAM","NO_CHANGE"], | ||||
| 			"enum" : ["NO_CHANGE", "PAL","NTSC","SECAM"], | ||||
| 			"default" : "NO_CHANGE", | ||||
| 			"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, | ||||
| 			"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" : | ||||
| 		{ | ||||
| 			"type" : "integer", | ||||
| @@ -33,7 +62,7 @@ | ||||
| 			"maximum" : 30, | ||||
| 			"default" : 6, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 3 | ||||
| 			"propertyOrder" : 6 | ||||
| 		}, | ||||
| 		"cropLeft" : | ||||
| 		{ | ||||
| @@ -43,7 +72,7 @@ | ||||
| 			"default" : 0, | ||||
| 			"append" : "edt_append_pixel", | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 4 | ||||
| 			"propertyOrder" : 7 | ||||
| 		}, | ||||
| 		"cropRight" : | ||||
| 		{ | ||||
| @@ -53,7 +82,7 @@ | ||||
| 			"default" : 0, | ||||
| 			"append" : "edt_append_pixel", | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 5 | ||||
| 			"propertyOrder" : 8 | ||||
| 		}, | ||||
| 		"cropTop" : | ||||
| 		{ | ||||
| @@ -63,7 +92,7 @@ | ||||
| 			"default" : 0, | ||||
| 			"append" : "edt_append_pixel", | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 6 | ||||
| 			"propertyOrder" : 9 | ||||
| 		}, | ||||
| 		"cropBottom" : | ||||
| 		{ | ||||
| @@ -73,7 +102,7 @@ | ||||
| 			"default" : 0, | ||||
| 			"append" : "edt_append_pixel", | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 7 | ||||
| 			"propertyOrder" : 10 | ||||
| 		}, | ||||
| 		"signalDetection" : | ||||
| 		{ | ||||
| @@ -81,7 +110,7 @@ | ||||
| 			"title" : "edt_conf_v4l2_signalDetection_title", | ||||
| 			"default" : false, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 8 | ||||
| 			"propertyOrder" : 11 | ||||
| 		}, | ||||
| 		"redSignalThreshold" : | ||||
| 		{ | ||||
| @@ -97,7 +126,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 9 | ||||
| 			"propertyOrder" : 12 | ||||
| 		}, | ||||
| 		"greenSignalThreshold" : | ||||
| 		{ | ||||
| @@ -113,7 +142,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 10 | ||||
| 			"propertyOrder" : 13 | ||||
| 		}, | ||||
| 		"blueSignalThreshold" : | ||||
| 		{ | ||||
| @@ -129,7 +158,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 11 | ||||
| 			"propertyOrder" : 14 | ||||
| 		}, | ||||
| 		"sDVOffsetMin" : | ||||
| 		{ | ||||
| @@ -145,7 +174,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 12 | ||||
| 			"propertyOrder" : 15 | ||||
| 		}, | ||||
| 		"sDVOffsetMax" : | ||||
| 		{ | ||||
| @@ -161,7 +190,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 13 | ||||
| 			"propertyOrder" : 16 | ||||
| 		}, | ||||
| 		"sDHOffsetMin" : | ||||
| 		{ | ||||
| @@ -177,7 +206,7 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 14 | ||||
| 			"propertyOrder" : 17 | ||||
| 		}, | ||||
| 		"sDHOffsetMax" : | ||||
| 		{ | ||||
| @@ -193,8 +222,8 @@ | ||||
| 				} | ||||
| 			}, | ||||
| 			"required" : true, | ||||
| 			"propertyOrder" : 15 | ||||
| 			"propertyOrder" : 18 | ||||
| 		} | ||||
| 	}, | ||||
| 	"additionalProperties" : false | ||||
| 	"additionalProperties" : true | ||||
| } | ||||
|   | ||||
| @@ -45,7 +45,8 @@ | ||||
| 			"required" : true, | ||||
| 			"items" : { | ||||
| 				"type": "string", | ||||
| 				"title" : "edt_conf_net_ip_itemtitle" | ||||
| 				"title" : "edt_conf_net_ip_itemtitle", | ||||
| 				"allowEmptyArray" : true | ||||
| 			}, | ||||
| 			"options": { | ||||
| 				"dependencies": { | ||||
|   | ||||
| @@ -121,7 +121,7 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i | ||||
| 					rgb.red   = data[index+2]; | ||||
| 				} | ||||
| 				break; | ||||
| #ifdef HAVE_JPEG | ||||
| #ifdef HAVE_JPEG_DECODER | ||||
| 				case PIXELFORMAT_MJPEG: | ||||
| 					break; | ||||
| #endif | ||||
|   | ||||
| @@ -73,7 +73,7 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s | ||||
| 		QJsonObject::const_iterator defaultValue = schema.find("default"); | ||||
|  | ||||
| 		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") | ||||
| 		{ | ||||
| 			if (value.isObject()) | ||||
| @@ -106,13 +106,13 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s | ||||
| 			} | ||||
| 		} | ||||
| 		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") | ||||
| 			checkMaximum(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null)); | ||||
| 			checkMaximum(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null)); | ||||
| 		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") | ||||
| 			checkMaxLength(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null)); | ||||
| 			checkMaxLength(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null)); | ||||
| 		else if (attribute == "items") | ||||
| 		{ | ||||
| 			if (value.isArray()) | ||||
| @@ -125,19 +125,20 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s | ||||
| 			} | ||||
| 		} | ||||
| 		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") | ||||
| 			checkMaxItems(value, attributeValue, (defaultValue != schema.end() ? defaultValue.value() : QJsonValue::Null)); | ||||
| 			checkMaxItems(value, attributeValue, (defaultValue != schema.end() ? *defaultValue : QJsonValue::Null)); | ||||
| 		else if (attribute == "uniqueItems") | ||||
| 			checkUniqueItems(value, attributeValue); | ||||
| 		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") | ||||
|  			; // nothing to do. value is present so always oke | ||||
|  		else if (attribute == "id") | ||||
|  			; // references have already been collected | ||||
|  		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. | ||||
| 		else | ||||
| 		{ | ||||
| @@ -225,7 +226,7 @@ void QJsonSchemaChecker::checkProperties(const QJsonObject & value, const QJsonO | ||||
| 			if (_correct == "create") | ||||
| 			{ | ||||
| 				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 == "") | ||||
| @@ -391,7 +392,7 @@ void QJsonSchemaChecker::checkItems(const QJsonValue & value, const QJsonObject | ||||
| 	QJsonArray jArray = value.toArray(); | ||||
|  | ||||
| 	if (_correct == "remove") | ||||
| 		if (jArray.isEmpty()) | ||||
| 		if (jArray.isEmpty() && !schema.contains("allowEmptyArray")) | ||||
| 		{ | ||||
| 			QJsonUtils::modify(_autoCorrected, _currentPath); | ||||
| 			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"); | ||||
| 		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"); | ||||
| 		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          & 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)"); | ||||
| @@ -105,6 +108,9 @@ int main(int argc, char** argv) | ||||
| 		// initialize the grabber | ||||
| 		V4L2Grabber grabber( | ||||
| 					argDevice.value(parser), | ||||
| 					argWidth.getInt(parser), | ||||
| 					argHeight.getInt(parser), | ||||
| 					1000 / argFps.getInt(parser), | ||||
| 					argVideoStandard.switchValue(parser), | ||||
| 					argPixelFormat.switchValue(parser), | ||||
| 					std::max(1, argSizeDecimation.getInt(parser))); | ||||
|   | ||||
| @@ -443,9 +443,12 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& settingsType, co | ||||
|  | ||||
| 			_v4l2Grabber = new V4L2Wrapper( | ||||
| 				grabberConfig["device"].toString("auto"), | ||||
| 				grabberConfig["width"].toInt(0), | ||||
| 				grabberConfig["height"].toInt(0), | ||||
| 				grabberConfig["fps"].toInt(15), | ||||
| 				parseVideoStandard(grabberConfig["standard"].toString("no-change")), | ||||
| 				parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change")), | ||||
| 				grabberConfig["sizeDecimation"].toInt(8) ); | ||||
| 				grabberConfig["sizeDecimation"].toInt(8)); | ||||
| 			_v4l2Grabber->setSignalThreshold( | ||||
| 				grabberConfig["redSignalThreshold"].toDouble(0.0)/100.0, | ||||
| 				grabberConfig["greenSignalThreshold"].toDouble(0.0)/100.0, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user