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:
@@ -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)
|
||||
|
Reference in New Issue
Block a user