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
This commit is contained in:
redPanther 2016-08-12 09:39:41 +02:00 committed by GitHub
parent f1cc82b8c7
commit 050ab11c8e
7 changed files with 82 additions and 57 deletions

View File

@ -62,8 +62,6 @@ private:
const int _updateInterval_ms; const int _updateInterval_ms;
/// The timeout of the led colors [ms] /// The timeout of the led colors [ms]
const int _timeout_ms; const int _timeout_ms;
/// The priority of the led colors
const int _priority;
/// The image used for grabbing frames /// The image used for grabbing frames
Image<ColorRgba> _image; Image<ColorRgba> _image;

View File

@ -57,6 +57,7 @@ public slots:
signals: signals:
void newFrame(const Image<ColorRgb> & image); void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
private slots: private slots:
int read_frame(); int read_frame();
@ -135,4 +136,5 @@ private:
Logger * _log; Logger * _log;
bool _initialized; bool _initialized;
bool _deviceAutoDiscoverEnabled;
}; };

View File

@ -44,6 +44,7 @@ public slots:
private slots: private slots:
void newFrame(const Image<ColorRgb> & image); void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
virtual void action(); virtual void action();
void checkSources(); void checkSources();

View File

@ -50,8 +50,9 @@ V4L2Grabber::V4L2Grabber(const std::string & device,
, _noSignalCounter(0) , _noSignalCounter(0)
, _streamNotifier(nullptr) , _streamNotifier(nullptr)
, _imageResampler() , _imageResampler()
, _log(Logger::getInstance("V4L2GRABBER")) , _log(Logger::getInstance("V4L2"))
,_initialized(false) , _initialized(false)
, _deviceAutoDiscoverEnabled(false)
{ {
_imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation));
_imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation));
@ -96,16 +97,20 @@ bool V4L2Grabber::init()
if ( _deviceName == "auto" ) if ( _deviceName == "auto" )
{ {
_deviceAutoDiscoverEnabled = true;
_deviceName = "unknown"; _deviceName = "unknown";
Info( _log, "search for usable video devices" );
for (auto& dev: _v4lDevices) for (auto& dev: _v4lDevices)
{ {
_deviceName = dev.first; _deviceName = dev.first;
if ( init() ) if ( init() )
{ {
Info(_log, "found usable v4l2 device: %s (%s)",dev.first.c_str(), dev.second.c_str()); Info(_log, "found usable v4l2 device: %s (%s)",dev.first.c_str(), dev.second.c_str());
_deviceAutoDiscoverEnabled = false;
return _initialized; return _initialized;
} }
} }
Info( _log, "no usable device found" );
} }
else if ( ! QString(_deviceName.c_str()).startsWith("/dev/") ) else if ( ! QString(_deviceName.c_str()).startsWith("/dev/") )
{ {
@ -121,7 +126,7 @@ bool V4L2Grabber::init()
} }
else 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; bool opened = false;
@ -139,7 +144,7 @@ bool V4L2Grabber::init()
uninit_device(); uninit_device();
close_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() bool V4L2Grabber::start()
{ {
if (init() && _streamNotifier != nullptr && !_streamNotifier->isEnabled()) try
{ {
_streamNotifier->setEnabled(true); if (init() && _streamNotifier != nullptr && !_streamNotifier->isEnabled())
start_capturing(); {
Info(_log, "Started"); _streamNotifier->setEnabled(true);
return true; start_capturing();
Info(_log, "Started");
return true;
}
}
catch(std::exception& e)
{
Error(_log, "start failed (%s)", e.what());
} }
return false; return false;
@ -507,7 +519,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
_height = fmt.fmt.pix.height; _height = fmt.fmt.pix.height;
// display the used width and 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 // check pixel format and frame size
@ -629,8 +641,7 @@ void V4L2Grabber::stop_capturing()
case IO_METHOD_MMAP: case IO_METHOD_MMAP:
case IO_METHOD_USERPTR: case IO_METHOD_USERPTR:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE; type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(VIDIOC_STREAMOFF, &type)) ErrorIf((xioctl(VIDIOC_STREAMOFF, &type) == -1), _log, "VIDIOC_STREAMOFF error code %d, %s", errno, strerror(errno));
throw_errno_exception("VIDIOC_STREAMOFF");
break; break;
} }
} }
@ -639,6 +650,8 @@ int V4L2Grabber::read_frame()
{ {
bool rc = false; bool rc = false;
try
{
struct v4l2_buffer buf; struct v4l2_buffer buf;
switch (_ioMethod) { switch (_ioMethod) {
@ -737,7 +750,13 @@ int V4L2Grabber::read_frame()
} }
break; break;
} }
}
catch (std::exception& e)
{
emit readError(e.what());
rc = false;
}
return rc ? 1 : 0; return rc ? 1 : 0;
} }
@ -746,7 +765,6 @@ bool V4L2Grabber::process_image(const void *p, int size)
if (++_currentFrame >= _frameDecimation) if (++_currentFrame >= _frameDecimation)
{ {
// We do want a new frame... // We do want a new frame...
if (size != _frameByteSize) if (size != _frameByteSize)
{ {
Error(_log, "Frame too small: %d != %d", size, _frameByteSize); Error(_log, "Frame too small: %d != %d", size, _frameByteSize);

View File

@ -37,10 +37,9 @@ V4L2Wrapper::V4L2Wrapper(const std::string &device,
qRegisterMetaType<std::vector<ColorRgb>>("std::vector<ColorRgb>"); qRegisterMetaType<std::vector<ColorRgb>>("std::vector<ColorRgb>");
// Handle the image in the captured thread using a direct connection // Handle the image in the captured thread using a direct connection
QObject::connect( QObject::connect(&_grabber, SIGNAL(newFrame(Image<ColorRgb>)), this, SLOT(newFrame(Image<ColorRgb>)), Qt::DirectConnection);
&_grabber, SIGNAL(newFrame(Image<ColorRgb>)),
this, SLOT(newFrame(Image<ColorRgb>)), QObject::connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection);
Qt::DirectConnection);
// send color data to Hyperion using a queued connection to handle the data over to the main event loop // send color data to Hyperion using a queued connection to handle the data over to the main event loop
// QObject::connect( // QObject::connect(
@ -92,6 +91,12 @@ void V4L2Wrapper::newFrame(const Image<ColorRgb> &image)
_hyperion->setColors(_priority, _ledColors, _timeout_ms); _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() void V4L2Wrapper::checkSources()
{ {
QList<int> activePriorities = _hyperion->getActivePriorities(); QList<int> activePriorities = _hyperion->getActivePriorities();

View File

@ -51,7 +51,14 @@ void GrabberWrapper::componentStateChanged(const hyperion::Components component,
_forward = _hyperion->getForwarder()->protoForwardingEnabled(); _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) if (component == hyperion::COMP_BLACKBORDER && _processor->blackBorderDetectorEnabled() != enable)

View File

@ -535,42 +535,36 @@ void HyperionDaemon::createGrabberOsx(const QJsonObject & grabberConfig)
void HyperionDaemon::createGrabberV4L2() void HyperionDaemon::createGrabberV4L2()
{ {
// construct and start the v4l2 grabber if the configuration is present // construct and start the v4l2 grabber if the configuration is present
if (_qconfig.contains("grabber-v4l2")) bool v4lConfigured = _qconfig.contains("grabber-v4l2");
{ const QJsonObject & grabberConfig = _qconfig["grabber-v4l2"].toObject();
const QJsonObject & grabberConfig = _qconfig["grabber-v4l2"].toObject(); bool enableV4l = v4lConfigured && grabberConfig["enable"].toBool(true);
#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");
QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, #ifdef ENABLE_V4L2
const Image<ColorRgb>&, const int)), _protoServer, _v4l2Grabber = new V4L2Wrapper(
SLOT(sendImageToProtoSlaves(int, grabberConfig["device"].toString("auto").toStdString(),
const Image<ColorRgb>&, const int))); grabberConfig["input"].toInt(0),
if (grabberConfig["enable"].toBool(true) && _v4l2Grabber->start()) { parseVideoStandard(grabberConfig["standard"].toString("no-change").toStdString()),
Info(_log, "V4L2 grabber started"); parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change").toStdString()),
} grabberConfig["width"].toInt(-1),
#else grabberConfig["height"].toInt(-1),
if (grabberConfig["enable"].toBool(true)) { grabberConfig["frameDecimation"].toInt(2),
Error(_log, "The v4l2 grabber can not be instantiated, because it has been left out from the build"); 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<ColorRgb>&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)));
InfoIf( enableV4l && _v4l2Grabber->start(), _log, "V4L2 grabber started");
#endif #endif
}
ErrorIf(enableV4l && _v4l2Grabber==nullptr, _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build");
} }