multiple v4l devices. (#210)

* implement use of multiple v4l devices.
Not all v4l devices are compat with that or must be attaches to different usb controllers

* fix typo in config
spilt grabber components in "GRABBER" and "V4L"
This commit is contained in:
redPanther 2016-08-31 10:13:43 +02:00 committed by GitHub
commit 742ad9df08
12 changed files with 184 additions and 155 deletions

View File

@ -168,25 +168,27 @@
/// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0] /// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0]
/// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0] /// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0]
"grabber-v4l2" : "grabber-v4l2" :
{ [
"enable" : false, {
"device" : "/dev/video0", "enable" : false,
"input" : 0, "device" : "auto",
"standard" : "no-change", "input" : 0,
"width" : -1, "standard" : "PAL",
"height" : -1, "width" : -1,
"frameDecimation" : 2, "height" : -1,
"sizeDecimation" : 8, "frameDecimation" : 2,
"priority" : 890, "sizeDecimation" : 8,
"mode" : "2D", "priority" : 890,
"cropLeft" : 0, "mode" : "2D",
"cropRight" : 0, "cropLeft" : 0,
"cropTop" : 0, "cropRight" : 0,
"cropBottom" : 0, "cropTop" : 0,
"redSignalThreshold" : 0.0, "cropBottom" : 0,
"greenSignalThreshold" : 0.0, "redSignalThreshold" : 0.0,
"blueSignalThreshold" : 0.0 "greenSignalThreshold" : 0.0,
}, "blueSignalThreshold" : 0.0
}
],
/// The configuration for the frame-grabber, contains the following items: /// The configuration for the frame-grabber, contains the following items:
/// * enable : true if the framegrabber (platform grabber) should be activated /// * enable : true if the framegrabber (platform grabber) should be activated

View File

@ -97,25 +97,27 @@
}, },
"grabber-v4l2" : "grabber-v4l2" :
{ [
"enable" : false, {
"device" : "auto", "enable" : false,
"input" : 0, "device" : "auto",
"standard" : "PAL", "input" : 0,
"width" : -1, "standard" : "PAL",
"height" : -1, "width" : -1,
"frameDecimation" : 2, "height" : -1,
"sizeDecimation" : 8, "frameDecimation" : 2,
"priority" : 890, "sizeDecimation" : 8,
"mode" : "2D", "priority" : 890,
"cropLeft" : 0, "mode" : "2D",
"cropRight" : 0, "cropLeft" : 0,
"cropTop" : 0, "cropRight" : 0,
"cropBottom" : 0, "cropTop" : 0,
"redSignalThreshold" : 0.0, "cropBottom" : 0,
"greenSignalThreshold" : 0.0, "redSignalThreshold" : 0.0,
"blueSignalThreshold" : 0.0 "greenSignalThreshold" : 0.0,
}, "blueSignalThreshold" : 0.0
}
],
"framegrabber" : "framegrabber" :
{ {

View File

@ -15,7 +15,7 @@ class GrabberWrapper : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
GrabberWrapper(std::string grabberName, const int priority); GrabberWrapper(std::string grabberName, const int priority, hyperion::Components grabberComponentId=hyperion::COMP_GRABBER);
virtual ~GrabberWrapper(); virtual ~GrabberWrapper();
@ -72,4 +72,5 @@ protected:
/// The processor for transforming images to led colors /// The processor for transforming images to led colors
ImageProcessor * _processor; ImageProcessor * _processor;
hyperion::Components _grabberComponentId;
}; };

View File

@ -15,7 +15,8 @@ enum Components
COMP_FORWARDER, COMP_FORWARDER,
COMP_UDPLISTENER, COMP_UDPLISTENER,
COMP_BOBLIGHTSERVER, COMP_BOBLIGHTSERVER,
COMP_GRABBER COMP_GRABBER,
COMP_V4L
}; };
inline const char* componentToString(Components c) inline const char* componentToString(Components c)
@ -29,6 +30,7 @@ inline const char* componentToString(Components c)
case COMP_UDPLISTENER: return "UDP listener"; case COMP_UDPLISTENER: return "UDP listener";
case COMP_BOBLIGHTSERVER:return "Boblight server"; case COMP_BOBLIGHTSERVER:return "Boblight server";
case COMP_GRABBER: return "Framegrabber"; case COMP_GRABBER: return "Framegrabber";
case COMP_V4L: return "V4l Capture device";
default: return ""; default: return "";
} }
} }
@ -43,6 +45,7 @@ inline Components stringToComponent(QString component)
if (component == "UDPLISTENER") return COMP_UDPLISTENER; if (component == "UDPLISTENER") return COMP_UDPLISTENER;
if (component == "BOBLIGHTSERVER")return COMP_BOBLIGHTSERVER; if (component == "BOBLIGHTSERVER")return COMP_BOBLIGHTSERVER;
if (component == "GRABBER") return COMP_GRABBER; if (component == "GRABBER") return COMP_GRABBER;
if (component == "V4L") return COMP_V4L;
return COMP_INVALID; return COMP_INVALID;
} }

View File

@ -50,7 +50,7 @@ V4L2Grabber::V4L2Grabber(const std::string & device,
, _noSignalCounter(0) , _noSignalCounter(0)
, _streamNotifier(nullptr) , _streamNotifier(nullptr)
, _imageResampler() , _imageResampler()
, _log(Logger::getInstance("V4L2")) , _log(Logger::getInstance("V4L2:"+device))
, _initialized(false) , _initialized(false)
, _deviceAutoDiscoverEnabled(false) , _deviceAutoDiscoverEnabled(false)
{ {

View File

@ -16,7 +16,7 @@ V4L2Wrapper::V4L2Wrapper(const std::string &device,
double greenSignalThreshold, double greenSignalThreshold,
double blueSignalThreshold, double blueSignalThreshold,
const int priority) const int priority)
: GrabberWrapper("V4L2", priority) : GrabberWrapper("V4L2:"+device, priority, hyperion::COMP_V4L)
, _timeout_ms(1000) , _timeout_ms(1000)
, _grabber(device, , _grabber(device,
input, input,

View File

@ -4,7 +4,7 @@
#include <hyperion/GrabberWrapper.h> #include <hyperion/GrabberWrapper.h>
GrabberWrapper::GrabberWrapper(std::string grabberName, const int priority) GrabberWrapper::GrabberWrapper(std::string grabberName, const int priority, hyperion::Components grabberComponentId)
: _grabberName(grabberName) : _grabberName(grabberName)
, _hyperion(Hyperion::getInstance()) , _hyperion(Hyperion::getInstance())
, _priority(priority) , _priority(priority)
@ -12,6 +12,7 @@ GrabberWrapper::GrabberWrapper(std::string grabberName, const int priority)
, _log(Logger::getInstance(grabberName.c_str())) , _log(Logger::getInstance(grabberName.c_str()))
, _forward(true) , _forward(true)
, _processor(ImageProcessorFactory::getInstance().newImageProcessor()) , _processor(ImageProcessorFactory::getInstance().newImageProcessor())
, _grabberComponentId(grabberComponentId)
{ {
_timer.setSingleShot(false); _timer.setSingleShot(false);
@ -44,7 +45,7 @@ void GrabberWrapper::stop()
void GrabberWrapper::componentStateChanged(const hyperion::Components component, bool enable) void GrabberWrapper::componentStateChanged(const hyperion::Components component, bool enable)
{ {
if (component == hyperion::COMP_GRABBER && _timer.isActive() != enable) if (component == _grabberComponentId && _timer.isActive() != enable)
{ {
if (enable) start(); if (enable) start();
else stop(); else stop();

View File

@ -399,83 +399,87 @@
}, },
"grabber-v4l2" : "grabber-v4l2" :
{ {
"type" : "object", "type":"array",
"properties" : "items":
{ {
"enable" : "type" : "object",
"properties" :
{ {
"type" : "boolean" "enable" :
{
"type" : "boolean"
},
"device" :
{
"type" : "string"
},
"input" :
{
"type" : "integer"
},
"standard" :
{
"type" : "string"
},
"width" :
{
"type" : "integer"
},
"height" :
{
"type" : "integer"
},
"frameDecimation" :
{
"type" : "integer"
},
"sizeDecimation" :
{
"type" : "integer"
},
"priority" :
{
"type" : "integer"
},
"mode" :
{
"type" : "string"
},
"useKodiChecker" :
{
"type" : "boolean"
},
"cropLeft" :
{
"type" : "integer"
},
"cropRight" :
{
"type" : "integer"
},
"cropTop" :
{
"type" : "integer"
},
"cropBottom" :
{
"type" : "integer"
},
"redSignalThreshold" :
{
"type" : "number"
},
"greenSignalThreshold" :
{
"type" : "number"
},
"blueSignalThreshold" :
{
"type" : "number"
}
}, },
"device" :
{
"type" : "string"
},
"input" :
{
"type" : "integer"
},
"standard" :
{
"type" : "string"
},
"width" :
{
"type" : "integer"
},
"height" :
{
"type" : "integer"
},
"frameDecimation" :
{
"type" : "integer"
},
"sizeDecimation" :
{
"type" : "integer"
},
"priority" :
{
"type" : "integer"
},
"mode" :
{
"type" : "string"
},
"useKodiChecker" :
{
"type" : "boolean"
},
"cropLeft" :
{
"type" : "integer"
},
"cropRight" :
{
"type" : "integer"
},
"cropTop" :
{
"type" : "integer"
},
"cropBottom" :
{
"type" : "integer"
},
"redSignalThreshold" :
{
"type" : "number"
},
"greenSignalThreshold" :
{
"type" : "number"
},
"blueSignalThreshold" :
{
"type" : "number"
}
},
"additionalProperties" : false "additionalProperties" : false
}
}, },
"framegrabber" : "framegrabber" :
{ {

View File

@ -21,7 +21,7 @@
"component": "component":
{ {
"type" : "string", "type" : "string",
"enum" : ["SMOOTHING", "BLACKBORDER", "KODICHECKER", "FORWARDER", "UDPLISTENER", "BOBLIGHTSERVER", "GRABBER"], "enum" : ["SMOOTHING", "BLACKBORDER", "KODICHECKER", "FORWARDER", "UDPLISTENER", "BOBLIGHTSERVER", "GRABBER", "V4L"],
"required": true "required": true
}, },
"state": "state":

View File

@ -65,8 +65,8 @@ int main(int argc, char * argv[])
BooleanOption & argServerInfo = parser.add<BooleanOption> ('l', "list" , "List server info and active effects with priority and duration"); BooleanOption & argServerInfo = parser.add<BooleanOption> ('l', "list" , "List server info and active effects with priority and duration");
BooleanOption & argClear = parser.add<BooleanOption> ('x', "clear" , "Clear data for the priority channel provided by the -p option"); BooleanOption & argClear = parser.add<BooleanOption> ('x', "clear" , "Clear data for the priority channel provided by the -p option");
BooleanOption & argClearAll = parser.add<BooleanOption> (0x0, "clearall" , "Clear data for all active priority channels"); BooleanOption & argClearAll = parser.add<BooleanOption> (0x0, "clearall" , "Clear data for all active priority channels");
Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER]"); Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER, V4L]");
Option & argDisableComponent = parser.add<Option> ('D', "disable" , "Disable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER]"); Option & argDisableComponent = parser.add<Option> ('D', "disable" , "Disable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER, V4L]");
Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the transform to set"); Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the transform to set");
DoubleOption & argSaturation = parser.add<DoubleOption> ('s', "saturation", "!DEPRECATED! Will be removed soon! Set the HSV saturation gain of the leds"); DoubleOption & argSaturation = parser.add<DoubleOption> ('s', "saturation", "!DEPRECATED! Will be removed soon! Set the HSV saturation gain of the leds");
DoubleOption & argValue = parser.add<DoubleOption> ('v', "getColors" , "!DEPRECATED! Will be removed soon! Set the HSV getColors gain of the leds"); DoubleOption & argValue = parser.add<DoubleOption> ('v', "getColors" , "!DEPRECATED! Will be removed soon! Set the HSV getColors gain of the leds");

View File

@ -41,7 +41,7 @@ HyperionDaemon::HyperionDaemon(QString configFile, QObject *parent)
, _protoServer(nullptr) , _protoServer(nullptr)
, _boblightServer(nullptr) , _boblightServer(nullptr)
, _udpListener(nullptr) , _udpListener(nullptr)
, _v4l2Grabber(nullptr) , _v4l2Grabbers()
, _dispmanx(nullptr) , _dispmanx(nullptr)
#ifdef ENABLE_X11 #ifdef ENABLE_X11
, _x11Grabber(nullptr) , _x11Grabber(nullptr)
@ -83,7 +83,10 @@ HyperionDaemon::~HyperionDaemon()
delete _dispmanx; delete _dispmanx;
delete _fbGrabber; delete _fbGrabber;
delete _osxGrabber; delete _osxGrabber;
delete _v4l2Grabber; for(V4L2Wrapper* grabber : _v4l2Grabbers)
{
delete grabber;
}
delete _kodiVideoChecker; delete _kodiVideoChecker;
delete _jsonServer; delete _jsonServer;
delete _protoServer; delete _protoServer;
@ -538,39 +541,52 @@ 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
bool v4lConfigured = _qconfig.contains("grabber-v4l2"); bool v4lConfigured = _qconfig.contains("grabber-v4l2");
const QJsonObject & grabberConfig = _qconfig["grabber-v4l2"].toObject(); unsigned v4lEnableCount = 0;
bool enableV4l = v4lConfigured && grabberConfig["enable"].toBool(true);
if (_qconfig["grabber-v4l2"].isArray())
#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<ColorRgb>&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)));
if (grabberConfig["useKodiChecker"].toBool(false))
{ {
QObject::connect(_kodiVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), _v4l2Grabber, SLOT(setGrabbingMode(GrabbingMode))); const QJsonArray & v4lArray = _qconfig["grabber-v4l2"].toArray();
} for ( signed idx=0; idx<v4lArray.size(); idx++)
InfoIf( enableV4l && _v4l2Grabber->start(), _log, "V4L2 grabber started"); {
#endif const QJsonObject & grabberConfig = v4lArray.at(idx).toObject();
bool enableV4l = v4lConfigured && grabberConfig["enable"].toBool(true);
if (enableV4l)
{
v4lEnableCount++;
}
#ifdef ENABLE_V4L2
V4L2Wrapper* grabber = 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));
grabber->set3D(parse3DMode(grabberConfig["mode"].toString("2D").toStdString()));
grabber->setCropping(
grabberConfig["cropLeft"].toInt(0),
grabberConfig["cropRight"].toInt(0),
grabberConfig["cropTop"].toInt(0),
grabberConfig["cropBottom"].toInt(0));
Debug(_log, "V4L2 grabber created");
ErrorIf(enableV4l && _v4l2Grabber==nullptr, _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build"); QObject::connect(grabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), _protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)));
if (grabberConfig["useKodiChecker"].toBool(false))
{
QObject::connect(_kodiVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), grabber, SLOT(setGrabbingMode(GrabbingMode)));
}
InfoIf( enableV4l && grabber->start(), _log, "V4L2 grabber started");
_v4l2Grabbers.push_back(grabber);
#endif
}
}
ErrorIf( (v4lEnableCount>0 && _v4l2Grabbers.size()==0), _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build");
} }

View File

@ -79,7 +79,7 @@ private:
ProtoServer* _protoServer; ProtoServer* _protoServer;
BoblightServer* _boblightServer; BoblightServer* _boblightServer;
UDPListener* _udpListener; UDPListener* _udpListener;
V4L2Wrapper* _v4l2Grabber; std::vector<V4L2Wrapper*> _v4l2Grabbers;
DispmanxWrapper* _dispmanx; DispmanxWrapper* _dispmanx;
#ifdef ENABLE_X11 #ifdef ENABLE_X11
X11Wrapper* _x11Grabber; X11Wrapper* _x11Grabber;