From b49ada956b4eb8711ae5580dc306c85e3c4a3502 Mon Sep 17 00:00:00 2001 From: redPanther Date: Thu, 14 Jul 2016 23:40:10 +0200 Subject: [PATCH] hyperion won't fail, if v4l2 has invalid device + auto device (#118) * hyperion won't fail, if v4l2 has invalid device * add v4l auto select. use "auto" as device name --- include/grabber/V4L2Grabber.h | 16 ++- include/grabber/V4L2Wrapper.h | 2 +- libsrc/grabber/v4l2/V4L2Grabber.cpp | 189 ++++++++++++++++++---------- libsrc/grabber/v4l2/V4L2Wrapper.cpp | 8 +- src/hyperion-v4l2/hyperion-v4l2.cpp | 4 +- src/hyperiond/hyperiond.cpp | 11 +- 6 files changed, 152 insertions(+), 78 deletions(-) diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/V4L2Grabber.h index a3c1f2b0..4c08c357 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/V4L2Grabber.h @@ -3,6 +3,7 @@ // stl includes #include #include +#include // Qt includes #include @@ -50,7 +51,7 @@ public slots: double blueSignalThreshold, int noSignalCounterThreshold); - void start(); + bool start(); void stop(); @@ -61,6 +62,11 @@ private slots: int read_frame(); private: + void getV4Ldevices(); + + bool init(); + void uninit(); + void open_device(); void close_device(); @@ -102,8 +108,11 @@ private: }; private: - const std::string _deviceName; - const io_method _ioMethod; + std::string _deviceName; + std::map _v4lDevices; + int _input; + VideoStandard _videoStandard; + io_method _ioMethod; int _fileDescriptor; std::vector _buffers; @@ -125,4 +134,5 @@ private: ImageResampler _imageResampler; Logger * _log; + bool _initialized; }; diff --git a/include/grabber/V4L2Wrapper.h b/include/grabber/V4L2Wrapper.h index 63fce069..9911ceab 100644 --- a/include/grabber/V4L2Wrapper.h +++ b/include/grabber/V4L2Wrapper.h @@ -30,7 +30,7 @@ public: virtual ~V4L2Wrapper(); public slots: - void start(); + bool start(); void stop(); diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index fe6de6ba..b933b19a 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -7,12 +7,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include "grabber/V4L2Grabber.h" @@ -26,38 +29,113 @@ V4L2Grabber::V4L2Grabber(const std::string & device, int height, int frameDecimation, int horizontalPixelDecimation, - int verticalPixelDecimation) : - _deviceName(device), - _ioMethod(IO_METHOD_MMAP), - _fileDescriptor(-1), - _buffers(), - _pixelFormat(pixelFormat), - _width(width), - _height(height), - _lineLength(-1), - _frameByteSize(-1), - _frameDecimation(std::max(1, frameDecimation)), - _noSignalCounterThreshold(50), - _noSignalThresholdColor(ColorRgb{0,0,0}), - _currentFrame(0), - _noSignalCounter(0), - _streamNotifier(nullptr), - _imageResampler(), - _log(Logger::getInstance("V4L2GRABBER")) + int verticalPixelDecimation) + : _deviceName(device) + , _input(input) + , _videoStandard(videoStandard) + , _ioMethod(IO_METHOD_MMAP) + , _fileDescriptor(-1) + , _buffers() + , _pixelFormat(pixelFormat) + , _width(width) + , _height(height) + , _lineLength(-1) + , _frameByteSize(-1) + , _frameDecimation(std::max(1, frameDecimation)) + , _noSignalCounterThreshold(50) + , _noSignalThresholdColor(ColorRgb{0,0,0}) + , _currentFrame(0) + , _noSignalCounter(0) + , _streamNotifier(nullptr) + , _imageResampler() + , _log(Logger::getInstance("V4L2GRABBER")) + ,_initialized(false) { _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); - open_device(); - init_device(videoStandard, input); + getV4Ldevices(); } V4L2Grabber::~V4L2Grabber() +{ + uninit(); +} + +void V4L2Grabber::uninit() { // stop if the grabber was not stopped - stop(); - uninit_device(); - close_device(); + if (_initialized) + { + stop(); + uninit_device(); + close_device(); + _initialized = false; + } +} + + +bool V4L2Grabber::init() +{ + if ( _deviceName == "auto" ) + { + for (auto& dev: _v4lDevices) + { + Debug(_log, "check v4l2 device: %s (%s)",dev.first.c_str(), dev.second.c_str()); + _deviceName = dev.first; + if ( init() ) + { + Info(_log, "found usable v4l2 device: %s (%s)",dev.first.c_str(), dev.second.c_str()); + break; + } + } + } + + if (! _initialized) + { + bool opened = false; + try + { + open_device(); + opened = true; + init_device(_videoStandard, _input); + _initialized = true; + } + catch(std::exception& e) + { + if (opened) + { + uninit_device(); + close_device(); + } + Error( _log, "V4l2 init failed (%s)", e.what()); + } + } + + return _initialized; +} + +void V4L2Grabber::getV4Ldevices() +{ + QDirIterator it("/sys/class/video4linux/", QDirIterator::NoIteratorFlags); + while(it.hasNext()) + { + //_v4lDevices + QString dev = it.next(); + if (it.fileName().startsWith("video")) + { + QFile devNameFile(dev+"/name"); + QString devName; + if ( devNameFile.exists()) + { + devNameFile.open(QFile::ReadOnly); + devName = devNameFile.readLine(); + devName = devName.trimmed(); + devNameFile.close(); + } + _v4lDevices.emplace("/dev/"+it.fileName().toStdString(), devName.toStdString()); + } + } } void V4L2Grabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) @@ -77,17 +155,22 @@ void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSign _noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold); _noSignalCounterThreshold = std::max(1, noSignalCounterThreshold); - Info(_log, "Signal threshold set to: %d", _noSignalThresholdColor); + std::stringstream ss; + ss << _noSignalThresholdColor; + Info(_log, "Signal threshold set to: %s", ss.str().c_str() ); } -void V4L2Grabber::start() +bool V4L2Grabber::start() { - if (_streamNotifier != nullptr && !_streamNotifier->isEnabled()) + if (init() && _streamNotifier != nullptr && !_streamNotifier->isEnabled()) { _streamNotifier->setEnabled(true); start_capturing(); Info(_log, "Started"); + return true; } + + return false; } void V4L2Grabber::stop() @@ -106,25 +189,19 @@ void V4L2Grabber::open_device() if (-1 == stat(_deviceName.c_str(), &st)) { - std::ostringstream oss; - oss << "V4L2GRABBER ERROR: Cannot identify '" << _deviceName << "'"; - throw_errno_exception(oss.str()); + throw_errno_exception("Cannot identify '" + _deviceName + "'"); } if (!S_ISCHR(st.st_mode)) { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no device"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' is no device"); } _fileDescriptor = open(_deviceName.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0); if (-1 == _fileDescriptor) { - std::ostringstream oss; - oss << "V4L2GRABBER ERROR: Cannot open '" << _deviceName << "'"; - throw_errno_exception(oss.str()); + throw_errno_exception("Cannot open '" + _deviceName + "'"); } // create the notifier for when a new frame is available @@ -155,7 +232,7 @@ void V4L2Grabber::init_read(unsigned int buffer_size) _buffers[0].start = malloc(buffer_size); if (!_buffers[0].start) { - throw_exception("V4L2GRABBER ERROR: Out of memory"); + throw_exception("Out of memory"); } } @@ -171,18 +248,14 @@ void V4L2Grabber::init_mmap() if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support memory mapping"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' does not support memory mapping"); } else { throw_errno_exception("VIDIOC_REQBUFS"); } } if (req.count < 2) { - std::ostringstream oss; - oss << "Insufficient buffer memory on " << _deviceName; - throw_exception(oss.str()); + throw_exception("Insufficient buffer memory on " + _deviceName); } _buffers.resize(req.count); @@ -225,9 +298,7 @@ void V4L2Grabber::init_userp(unsigned int buffer_size) if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support user pointer"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' does not support user pointer"); } else { throw_errno_exception("VIDIOC_REQBUFS"); } @@ -240,7 +311,7 @@ void V4L2Grabber::init_userp(unsigned int buffer_size) _buffers[n_buffers].start = malloc(buffer_size); if (!_buffers[n_buffers].start) { - throw_exception("V4L2GRABBER ERROR: Out of memory"); + throw_exception("Out of memory"); } } } @@ -251,9 +322,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) if (-1 == xioctl(VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no V4L2 device"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' is no V4L2 device"); } else { throw_errno_exception("VIDIOC_QUERYCAP"); } @@ -261,18 +330,14 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no video capture device"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' is no video capture device"); } switch (_ioMethod) { case IO_METHOD_READ: if (!(cap.capabilities & V4L2_CAP_READWRITE)) { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support read i/o"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' does not support read i/o"); } break; @@ -280,9 +345,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) case IO_METHOD_USERPTR: if (!(cap.capabilities & V4L2_CAP_STREAMING)) { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support streaming i/o"; - throw_exception(oss.str()); + throw_exception("'" + _deviceName + "' does not support streaming i/o"); } break; } @@ -413,7 +476,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) _height = fmt.fmt.pix.height; // display the used width and height - Info(Logger::getInstance("V4l2GRABBER"), "width=%d height=%d", _width, _height ); + Info(_log, "width=%d height=%d", _width, _height ); // check pixel format and frame size @@ -435,7 +498,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input) Debug(_log, "Pixel format=RGB32"); break; default: - throw_exception("V4L2GRABBER ERROR: Only pixel formats UYVY, YUYV, and RGB32 are supported"); + throw_exception("Only pixel formats UYVY, YUYV, and RGB32 are supported"); } switch (_ioMethod) { @@ -727,14 +790,12 @@ int V4L2Grabber::xioctl(int request, void *arg) void V4L2Grabber::throw_exception(const std::string & error) { - std::ostringstream oss; - oss << error << " ERROR"; - throw std::runtime_error(oss.str()); + throw std::runtime_error(error); } void V4L2Grabber::throw_errno_exception(const std::string & error) { std::ostringstream oss; - oss << error << " ERROR " << errno << ", " << strerror(errno); + oss << error << " error code " << errno << ", " << strerror(errno); throw std::runtime_error(oss.str()); } diff --git a/libsrc/grabber/v4l2/V4L2Wrapper.cpp b/libsrc/grabber/v4l2/V4L2Wrapper.cpp index 276da94f..ca18df6f 100644 --- a/libsrc/grabber/v4l2/V4L2Wrapper.cpp +++ b/libsrc/grabber/v4l2/V4L2Wrapper.cpp @@ -68,9 +68,13 @@ V4L2Wrapper::~V4L2Wrapper() delete _processor; } -void V4L2Wrapper::start() +bool V4L2Wrapper::start() { - _grabber.start(); + bool grabber_started = _grabber.start(); + if ( ! grabber_started ) + _timer.stop(); + + return grabber_started; } void V4L2Wrapper::stop() diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index 59cf69ad..fdde0c49 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -164,8 +164,8 @@ int main(int argc, char** argv) { ProtoConnectionWrapper handler(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet()); QObject::connect(&grabber, SIGNAL(newFrame(Image)), &handler, SLOT(receiveImage(Image))); - grabber.start(); - QCoreApplication::exec(); + if (grabber.start()) + QCoreApplication::exec(); grabber.stop(); } } diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 82e2fb67..2af566bb 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -360,8 +360,6 @@ void HyperionDaemon::createGrabberV4L2() if (_config.isMember("grabber-v4l2")) { const Json::Value & grabberConfig = _config["grabber-v4l2"]; - if (grabberConfig.get("enable", true).asBool()) - { _v4l2Grabber = new V4L2Wrapper( grabberConfig.get("device", "/dev/video0").asString(), grabberConfig.get("input", 0).asInt(), @@ -381,11 +379,12 @@ void HyperionDaemon::createGrabberV4L2() grabberConfig.get("cropRight", 0).asInt(), grabberConfig.get("cropTop", 0).asInt(), grabberConfig.get("cropBottom", 0).asInt()); + Debug(_log, "V4L2 grabber created"); - QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, const Image&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - - _v4l2Grabber->start(); - Info(_log, "V4L2 grabber created and started"); + QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, const Image&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); + if (grabberConfig.get("enable", true).asBool() && _v4l2Grabber->start()) + { + Info(_log, "V4L2 grabber started"); } } #else