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
This commit is contained in:
redPanther 2016-07-14 23:40:10 +02:00 committed by brindosch
parent 9f1bc6d9e8
commit b49ada956b
6 changed files with 152 additions and 78 deletions

View File

@ -3,6 +3,7 @@
// stl includes
#include <string>
#include <vector>
#include <map>
// Qt includes
#include <QObject>
@ -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<std::string,std::string> _v4lDevices;
int _input;
VideoStandard _videoStandard;
io_method _ioMethod;
int _fileDescriptor;
std::vector<buffer> _buffers;
@ -125,4 +134,5 @@ private:
ImageResampler _imageResampler;
Logger * _log;
bool _initialized;
};

View File

@ -30,7 +30,7 @@ public:
virtual ~V4L2Wrapper();
public slots:
void start();
bool start();
void stop();

View File

@ -7,12 +7,15 @@
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <QDirIterator>
#include <QFileInfo>
#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());
}

View File

@ -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()

View File

@ -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<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
grabber.start();
QCoreApplication::exec();
if (grabber.start())
QCoreApplication::exec();
grabber.stop();
}
}

View File

@ -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<ColorRgb>&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
_v4l2Grabber->start();
Info(_log, "V4L2 grabber created and started");
QObject::connect(_v4l2Grabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
if (grabberConfig.get("enable", true).asBool() && _v4l2Grabber->start())
{
Info(_log, "V4L2 grabber started");
}
}
#else