mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
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:
parent
9f1bc6d9e8
commit
b49ada956b
@ -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;
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
virtual ~V4L2Wrapper();
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
bool start();
|
||||
|
||||
void stop();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user