From 050ab11c8e033b82770fc9847f71ba00ec8ed55b Mon Sep 17 00:00:00 2001 From: redPanther Date: Fri, 12 Aug 2016 09:39:41 +0200 Subject: [PATCH] v4l grabber wont crash hyperiond anymore (#168) * v4l errors won't lead to crash hyperiond (exceptions are catched) v4l auto device mode with better log messages createV4l in hyperiond.cpp refactored, now v4l is always available as long as it is compiled in * change back, code accidently altered * fix compile of dispmanx grabber --- include/grabber/DispmanxWrapper.h | 2 - include/grabber/V4L2Grabber.h | 2 + include/grabber/V4L2Wrapper.h | 1 + libsrc/grabber/v4l2/V4L2Grabber.cpp | 46 ++++++++++++++------ libsrc/grabber/v4l2/V4L2Wrapper.cpp | 13 ++++-- libsrc/hyperion/GrabberWrapper.cpp | 9 +++- src/hyperiond/hyperiond.cpp | 66 +++++++++++++---------------- 7 files changed, 82 insertions(+), 57 deletions(-) diff --git a/include/grabber/DispmanxWrapper.h b/include/grabber/DispmanxWrapper.h index 329f35b6..ab47b1a0 100644 --- a/include/grabber/DispmanxWrapper.h +++ b/include/grabber/DispmanxWrapper.h @@ -62,8 +62,6 @@ private: const int _updateInterval_ms; /// The timeout of the led colors [ms] const int _timeout_ms; - /// The priority of the led colors - const int _priority; /// The image used for grabbing frames Image _image; diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/V4L2Grabber.h index 4c08c357..ab779ce7 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/V4L2Grabber.h @@ -57,6 +57,7 @@ public slots: signals: void newFrame(const Image & image); + void readError(const char* err); private slots: int read_frame(); @@ -135,4 +136,5 @@ private: Logger * _log; bool _initialized; + bool _deviceAutoDiscoverEnabled; }; diff --git a/include/grabber/V4L2Wrapper.h b/include/grabber/V4L2Wrapper.h index dde90edd..41daf033 100644 --- a/include/grabber/V4L2Wrapper.h +++ b/include/grabber/V4L2Wrapper.h @@ -44,6 +44,7 @@ public slots: private slots: void newFrame(const Image & image); + void readError(const char* err); virtual void action(); void checkSources(); diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index 5f73ccfc..7e2a2ec2 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -50,8 +50,9 @@ V4L2Grabber::V4L2Grabber(const std::string & device, , _noSignalCounter(0) , _streamNotifier(nullptr) , _imageResampler() - , _log(Logger::getInstance("V4L2GRABBER")) - ,_initialized(false) + , _log(Logger::getInstance("V4L2")) + , _initialized(false) + , _deviceAutoDiscoverEnabled(false) { _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); @@ -96,16 +97,20 @@ bool V4L2Grabber::init() if ( _deviceName == "auto" ) { + _deviceAutoDiscoverEnabled = true; _deviceName = "unknown"; + Info( _log, "search for usable video devices" ); for (auto& dev: _v4lDevices) { _deviceName = dev.first; if ( init() ) { Info(_log, "found usable v4l2 device: %s (%s)",dev.first.c_str(), dev.second.c_str()); + _deviceAutoDiscoverEnabled = false; return _initialized; } } + Info( _log, "no usable device found" ); } else if ( ! QString(_deviceName.c_str()).startsWith("/dev/") ) { @@ -121,7 +126,7 @@ bool V4L2Grabber::init() } else { - Info(_log, "configured v4l device: %s", _deviceName.c_str()); + Info(_log, "%s v4l device: %s", (_deviceAutoDiscoverEnabled? "test" : "configured"),_deviceName.c_str()); } bool opened = false; @@ -139,7 +144,7 @@ bool V4L2Grabber::init() uninit_device(); close_device(); } - Error( _log, "V4l2 init failed (%s)", e.what()); + ErrorIf( !_deviceAutoDiscoverEnabled, _log, "V4l2 init failed (%s)", e.what()); } } @@ -193,12 +198,19 @@ void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSign bool V4L2Grabber::start() { - if (init() && _streamNotifier != nullptr && !_streamNotifier->isEnabled()) + try { - _streamNotifier->setEnabled(true); - start_capturing(); - Info(_log, "Started"); - return true; + if (init() && _streamNotifier != nullptr && !_streamNotifier->isEnabled()) + { + _streamNotifier->setEnabled(true); + start_capturing(); + Info(_log, "Started"); + return true; + } + } + catch(std::exception& e) + { + Error(_log, "start failed (%s)", e.what()); } return false; @@ -507,7 +519,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) _height = fmt.fmt.pix.height; // display the used width and height - Info(_log, "width=%d height=%d", _width, _height ); + Debug(_log, "width=%d height=%d", _width, _height ); // check pixel format and frame size @@ -629,8 +641,7 @@ void V4L2Grabber::stop_capturing() case IO_METHOD_MMAP: case IO_METHOD_USERPTR: type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(VIDIOC_STREAMOFF, &type)) - throw_errno_exception("VIDIOC_STREAMOFF"); + ErrorIf((xioctl(VIDIOC_STREAMOFF, &type) == -1), _log, "VIDIOC_STREAMOFF error code %d, %s", errno, strerror(errno)); break; } } @@ -639,6 +650,8 @@ int V4L2Grabber::read_frame() { bool rc = false; + try + { struct v4l2_buffer buf; switch (_ioMethod) { @@ -737,7 +750,13 @@ int V4L2Grabber::read_frame() } break; } - + } + catch (std::exception& e) + { + emit readError(e.what()); + rc = false; + } + return rc ? 1 : 0; } @@ -746,7 +765,6 @@ bool V4L2Grabber::process_image(const void *p, int size) if (++_currentFrame >= _frameDecimation) { // We do want a new frame... - if (size != _frameByteSize) { Error(_log, "Frame too small: %d != %d", size, _frameByteSize); diff --git a/libsrc/grabber/v4l2/V4L2Wrapper.cpp b/libsrc/grabber/v4l2/V4L2Wrapper.cpp index e67847ac..7b233148 100644 --- a/libsrc/grabber/v4l2/V4L2Wrapper.cpp +++ b/libsrc/grabber/v4l2/V4L2Wrapper.cpp @@ -37,10 +37,9 @@ V4L2Wrapper::V4L2Wrapper(const std::string &device, qRegisterMetaType>("std::vector"); // Handle the image in the captured thread using a direct connection - QObject::connect( - &_grabber, SIGNAL(newFrame(Image)), - this, SLOT(newFrame(Image)), - Qt::DirectConnection); + QObject::connect(&_grabber, SIGNAL(newFrame(Image)), this, SLOT(newFrame(Image)), Qt::DirectConnection); + + QObject::connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection); // send color data to Hyperion using a queued connection to handle the data over to the main event loop // QObject::connect( @@ -92,6 +91,12 @@ void V4L2Wrapper::newFrame(const Image &image) _hyperion->setColors(_priority, _ledColors, _timeout_ms); } +void V4L2Wrapper::readError(const char* err) +{ + Error(_log, "stop grabber, because reading device failed. (%s)", err); + stop(); +} + void V4L2Wrapper::checkSources() { QList activePriorities = _hyperion->getActivePriorities(); diff --git a/libsrc/hyperion/GrabberWrapper.cpp b/libsrc/hyperion/GrabberWrapper.cpp index 753c70ac..8e3eb455 100644 --- a/libsrc/hyperion/GrabberWrapper.cpp +++ b/libsrc/hyperion/GrabberWrapper.cpp @@ -51,7 +51,14 @@ void GrabberWrapper::componentStateChanged(const hyperion::Components component, _forward = _hyperion->getForwarder()->protoForwardingEnabled(); - Info(_log, "grabber change state to %s", (enable ? "enabled" : "disabled") ); + if ( enable == _timer.isActive() ) + { + Info(_log, "grabber change state to %s", (_timer.isActive() ? "enabled" : "disabled") ); + } + else + { + WarningIf( enable, _log, "enable grabber failed"); + } } if (component == hyperion::COMP_BLACKBORDER && _processor->blackBorderDetectorEnabled() != enable) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 0abf8f3e..ddd2d73c 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -535,42 +535,36 @@ void HyperionDaemon::createGrabberOsx(const QJsonObject & grabberConfig) void HyperionDaemon::createGrabberV4L2() { // construct and start the v4l2 grabber if the configuration is present - if (_qconfig.contains("grabber-v4l2")) - { - const QJsonObject & grabberConfig = _qconfig["grabber-v4l2"].toObject(); -#ifdef ENABLE_V4L2 - _v4l2Grabber = new V4L2Wrapper( - grabberConfig["device"].toString("/dev/video0").toStdString(), - grabberConfig["input"].toInt(0), - parseVideoStandard(grabberConfig["standard"].toString("no-change").toStdString()), - parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change").toStdString()), - grabberConfig["width"].toInt(-1), - grabberConfig["height"].toInt(-1), - grabberConfig["frameDecimation"].toInt(2), - grabberConfig["sizeDecimation"].toInt(8), - grabberConfig["redSignalThreshold"].toDouble(0.0), - grabberConfig["greenSignalThreshold"].toDouble(0.0), - grabberConfig["blueSignalThreshold"].toDouble(0.0), - grabberConfig["priority"].toInt(890)); - _v4l2Grabber->set3D(parse3DMode(grabberConfig["mode"].toString("2D").toStdString())); - _v4l2Grabber->setCropping( - grabberConfig["cropLeft"].toInt(0), - grabberConfig["cropRight"].toInt(0), - grabberConfig["cropTop"].toInt(0), - grabberConfig["cropBottom"].toInt(0)); - Debug(_log, "V4L2 grabber created"); + bool v4lConfigured = _qconfig.contains("grabber-v4l2"); + const QJsonObject & grabberConfig = _qconfig["grabber-v4l2"].toObject(); + bool enableV4l = v4lConfigured && grabberConfig["enable"].toBool(true); - QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, - const Image&, const int)), _protoServer, - SLOT(sendImageToProtoSlaves(int, - const Image&, const int))); - if (grabberConfig["enable"].toBool(true) && _v4l2Grabber->start()) { - Info(_log, "V4L2 grabber started"); - } -#else - if (grabberConfig["enable"].toBool(true)) { - Error(_log, "The v4l2 grabber can not be instantiated, because it has been left out from the build"); - } +#ifdef ENABLE_V4L2 + _v4l2Grabber = new V4L2Wrapper( + grabberConfig["device"].toString("auto").toStdString(), + grabberConfig["input"].toInt(0), + parseVideoStandard(grabberConfig["standard"].toString("no-change").toStdString()), + parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change").toStdString()), + grabberConfig["width"].toInt(-1), + grabberConfig["height"].toInt(-1), + grabberConfig["frameDecimation"].toInt(2), + grabberConfig["sizeDecimation"].toInt(8), + grabberConfig["redSignalThreshold"].toDouble(0.0), + grabberConfig["greenSignalThreshold"].toDouble(0.0), + grabberConfig["blueSignalThreshold"].toDouble(0.0), + grabberConfig["priority"].toInt(890)); + _v4l2Grabber->set3D(parse3DMode(grabberConfig["mode"].toString("2D").toStdString())); + _v4l2Grabber->setCropping( + grabberConfig["cropLeft"].toInt(0), + grabberConfig["cropRight"].toInt(0), + grabberConfig["cropTop"].toInt(0), + grabberConfig["cropBottom"].toInt(0)); + Debug(_log, "V4L2 grabber created"); + + QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, const Image&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int))); + InfoIf( enableV4l && _v4l2Grabber->start(), _log, "V4L2 grabber started"); #endif - } + + ErrorIf(enableV4l && _v4l2Grabber==nullptr, _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build"); + }