Merge remote-tracking branch 'origin/grabberDiscovery' into mediafoundation

This commit is contained in:
Paulchen Panther
2021-04-04 12:43:29 +02:00
committed by LordGrey
187 changed files with 3716 additions and 15430 deletions

View File

@@ -21,6 +21,9 @@ class Effect : public QThread
Q_OBJECT
public:
static const int ENDLESS;
friend class EffectModule;
Effect(Hyperion *hyperion
@@ -44,10 +47,21 @@ public:
void requestInterruption() { _interupt = true; }
///
/// @brief Check if the interruption flag has been set
/// @brief Check an interruption was requested.
/// This can come from requestInterruption()
/// or the effect's timeout expiring.
///
/// @return The flag state
///
bool isInterruptionRequested() { return _interupt; }
bool isInterruptionRequested();
///
/// @brief Get the remaining timeout, or indication it is endless
///
/// @return The flag state
///
int getRemaining() const;
QString getScript() const { return _script; }
QString getName() const { return _name; }
@@ -76,7 +90,7 @@ private:
const QJsonObject _args;
const QString _imageData;
int64_t _endTime;
qint64 _endTime;
/// Buffer for colorData
QVector<ColorRgb> _colors;

View File

@@ -13,6 +13,7 @@
// Effect engine includes
#include <effectengine/EffectDefinition.h>
#include <effectengine/Effect.h>
#include <effectengine/ActiveEffectDefinition.h>
#include <effectengine/EffectSchema.h>
#include <utils/Logger.h>
@@ -69,13 +70,13 @@ signals:
public slots:
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
int runEffect(const QString &effectName, int priority, int timeout = Effect::ENDLESS, const QString &origin="System");
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const QString &effectName
, const QJsonObject &args
, int priority
, int timeout = -1
, int timeout = Effect::ENDLESS
, const QString &pythonScript = ""
, const QString &origin = "System"
, unsigned smoothCfg=0
@@ -102,7 +103,7 @@ private:
,const QString &name
, const QJsonObject &args
, int priority
, int timeout = -1
, int timeout = Effect::ENDLESS
, const QString &origin="System"
, unsigned smoothCfg=0
, const QString &imageData = ""

View File

@@ -64,12 +64,12 @@ private:
///
/// @brief Load the effect definition, called by updateEffects()
///
bool loadEffectDefinition(const QString & path, const QString & effectConfigFile, EffectDefinition &effectDefinition);
bool loadEffectDefinition(const QString& path, const QString& effectConfigFile, EffectDefinition& effectDefinition);
///
/// @brief load effect schemas, called by updateEffects()
///
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
bool loadEffectSchema(const QString& path, const QString& effectSchemaFile, EffectSchema& effectSchema);
private:
QJsonObject _effectConfig;

View File

@@ -54,6 +54,11 @@ public:
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
///
/// @brief Apply display index
///
void setDisplayIndex(int index) override;
private:
///
/// @brief Setup a new capture display, will free the previous one
@@ -68,6 +73,7 @@ private:
private:
int _pixelDecimation;
unsigned _display;
unsigned _displayWidth;
unsigned _displayHeight;
RECT* _srcRect;

View File

@@ -11,6 +11,9 @@
#include <QRectF>
#include <QMap>
#include <QMultiMap>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
// utils includes
#include <utils/PixelFormat.h>
@@ -38,7 +41,6 @@ class MFGrabber : public Grabber
{
Q_OBJECT
friend class SourceReaderCB;
public:
struct DeviceProperties
{
@@ -52,79 +54,72 @@ public:
GUID guid = GUID_NULL;
};
MFGrabber(const QString & device, const unsigned width, const unsigned height, const unsigned fps, int pixelDecimation, QString flipMode);
MFGrabber();
~MFGrabber() override;
void receive_image(const void *frameImageBuffer, int size);
QRectF getSignalDetectionOffset() const { return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); }
bool getSignalDetectionEnabled() const { return _signalDetectionEnabled; }
bool getCecDetectionEnabled() const { return _cecDetectionEnabled; }
QStringList getDevices() const override;
QString getDeviceName(const QString& devicePath) const override { return devicePath; }
QMultiMap<QString, int> getDeviceInputs(const QString& devicePath) const override { return { {devicePath, 0} }; }
QStringList getAvailableEncodingFormats(const QString& devicePath, const int& /*deviceInput*/) const override;
QMultiMap<int, int> getAvailableDeviceResolutions(const QString& devicePath, const int& /*deviceInput*/, const PixelFormat& encFormat) const override;
QIntList getAvailableDeviceFramerates(const QString& devicePath, const int& /*deviceInput*/, const PixelFormat& encFormat, const unsigned width, const unsigned height) const override;
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold) override;
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax) override;
void setSignalDetectionEnable(bool enable) override;
void setPixelDecimation(int pixelDecimation) override;
void setCecDetectionEnable(bool enable) override;
bool setDevice(QString device) override;
void setDevice(const QString& device);
bool setInput(int input) override;
bool setWidthHeight(int width, int height) override;
bool setFramerate(int fps) override;
void setFpsSoftwareDecimation(int decimation);
bool setEncoding(QString enc);
void setFlipMode(QString flipMode);
bool setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
void setEncoding(QString enc);
void setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold);
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
bool reload(bool force = false);
void reloadGrabber();
///
/// @brief Discover available Media Foundation USB devices (for configuration).
/// @param[in] params Parameters used to overwrite discovery default behaviour
/// @return A JSON structure holding a list of USB devices found
///
QJsonArray discover(const QJsonObject& params);
public slots:
bool prepare();
bool start();
void stop();
void newThreadFrame(unsigned int _workerIndex, const Image<ColorRgb>& image,unsigned int sourceCount);
void newThreadFrame(Image<ColorRgb> image);
signals:
void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
private:
bool init();
void uninit();
HRESULT init_device(QString device, DeviceProperties props);
void uninit_device();
void enumVideoCaptureDevices();
void start_capturing();
void process_image(const void *frameImageBuffer, int size);
void checkSignalDetectionEnabled(Image<ColorRgb> image);
QString _currentDeviceName, _newDeviceName;
QString _currentDeviceName,
_newDeviceName;
QMap<QString, QList<DeviceProperties>> _deviceProperties;
HRESULT _hr;
IMFSourceReader* _sourceReader;
SourceReaderCB* _sourceReaderCB;
PixelFormat _pixelFormat, _pixelFormatConfig;
int _pixelDecimation,
_lineLength,
MFThreadManager* _threadManager;
PixelFormat _pixelFormat,
_pixelFormatConfig;
int _lineLength,
_frameByteSize,
_noSignalCounterThreshold,
_noSignalCounter,
_fpsSoftwareDecimation,
_brightness,
_contrast,
_saturation,
_hue;
volatile unsigned int _currentFrame;
QAtomicInt _currentFrame;
ColorRgb _noSignalThresholdColor;
bool _signalDetectionEnabled,
_cecDetectionEnabled,
_noSignalDetected,
_initialized;
_initialized,
_reload;
double _x_frac_min,
_y_frac_min,
_x_frac_max,
_y_frac_max;
MFThreadManager _threadManager;
IMFSourceReader* _sourceReader;
#ifdef HAVE_TURBO_JPEG
int _subsamp;

View File

@@ -2,7 +2,6 @@
// Qt includes
#include <QThread>
#include <QSemaphore>
// util includes
#include <utils/PixelFormat.h>
@@ -15,31 +14,27 @@
#include <turbojpeg.h>
#endif
// Forward class declaration
class MFThreadManager;
/// Encoder thread for USB devices
class MFThread : public QThread
class MFThread : public QObject
{
Q_OBJECT
friend class MFThreadManager;
public:
MFThread();
explicit MFThread();
~MFThread();
void setup(
unsigned int threadIndex, PixelFormat pixelFormat, uint8_t* sharedData,
PixelFormat pixelFormat, uint8_t* sharedData,
int size, int width, int height, int lineLength,
int subsamp, unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
VideoMode videoMode, FlipMode flipMode, int currentFrame, int pixelDecimation);
void run();
VideoMode videoMode, FlipMode flipMode, int pixelDecimation);
bool isBusy();
void noBusy();
void process();
bool isBusy() { return _busy; }
QAtomicInt _busy = false;
signals:
void newFrame(unsigned int threadIndex, const Image<ColorRgb>& data, unsigned int sourceCount);
void newFrame(const Image<ColorRgb>& data);
private:
void processImageMjpeg();
@@ -51,73 +46,132 @@ private:
tjtransform* _xform;
#endif
static volatile bool _isActive;
volatile bool _isBusy;
QSemaphore _semaphore;
unsigned int _threadIndex;
PixelFormat _pixelFormat;
uint8_t* _localData, *_flipBuffer;
int _scalingFactorsCount, _width, _height, _lineLength, _subsamp, _currentFrame, _pixelDecimation;
unsigned long _size;
unsigned _cropLeft, _cropTop, _cropBottom, _cropRight;
FlipMode _flipMode;
ImageResampler _imageResampler;
PixelFormat _pixelFormat;
uint8_t* _localData,
*_flipBuffer;
int _scalingFactorsCount,
_width,
_height,
_lineLength,
_subsamp,
_currentFrame,
_pixelDecimation;
unsigned long _size;
unsigned _cropLeft,
_cropTop,
_cropBottom,
_cropRight;
FlipMode _flipMode;
ImageResampler _imageResampler;
};
template <typename TThread> class Thread : public QThread
{
public:
TThread *_thread;
explicit Thread(TThread *thread, QObject *parent = nullptr)
: QThread(parent)
, _thread(thread)
{
_thread->moveToThread(this);
start();
}
~Thread()
{
quit();
wait();
}
MFThread* thread() const { return qobject_cast<MFThread*>(_thread); }
void setup(
PixelFormat pixelFormat, uint8_t* sharedData,
int size, int width, int height, int lineLength,
int subsamp, unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
VideoMode videoMode, FlipMode flipMode, int pixelDecimation)
{
auto mfthread = qobject_cast<MFThread*>(_thread);
if (mfthread != nullptr)
mfthread->setup(pixelFormat, sharedData,
size, width, height, lineLength,
subsamp, cropLeft, cropTop, cropBottom, cropRight,
videoMode, flipMode, pixelDecimation);
}
bool isBusy()
{
auto mfthread = qobject_cast<MFThread*>(_thread);
if (mfthread != nullptr)
return mfthread->isBusy();
return true;
}
void process()
{
auto mfthread = qobject_cast<MFThread*>(_thread);
if (mfthread != nullptr)
mfthread->process();
}
protected:
void run() override
{
QThread::run();
delete _thread;
}
};
class MFThreadManager : public QObject
{
Q_OBJECT
Q_OBJECT
public:
MFThreadManager() : _threads(nullptr)
explicit MFThreadManager(QObject *parent = nullptr)
: QObject(parent)
, _threadCount(qMax(QThread::idealThreadCount(), 1))
, _threads(nullptr)
{
_maxThreads = qBound(1, (QThread::idealThreadCount() > 4 ? (QThread::idealThreadCount() - 1) : QThread::idealThreadCount()), 8);
_threads = new Thread<MFThread>*[_threadCount];
for (int i = 0; i < _threadCount; i++)
{
_threads[i] = new Thread<MFThread>(new MFThread, this);
_threads[i]->setObjectName("MFThread " + i);
}
}
~MFThreadManager()
{
if (_threads != nullptr)
{
for(unsigned i=0; i < _maxThreads; i++)
if (_threads[i] != nullptr)
{
_threads[i]->deleteLater();
_threads[i] = nullptr;
}
for(int i = 0; i < _threadCount; i++)
{
_threads[i]->deleteLater();
_threads[i] = nullptr;
}
delete[] _threads;
_threads = nullptr;
}
}
void initThreads()
void start()
{
if (_maxThreads >= 1)
{
_threads = new MFThread*[_maxThreads];
for (unsigned i=0; i < _maxThreads; i++)
_threads[i] = new MFThread();
}
if (_threads != nullptr)
for (int i = 0; i < _threadCount; i++)
connect(_threads[i]->thread(), &MFThread::newFrame, this, &MFThreadManager::newFrame);
}
void start() { MFThread::_isActive = true; }
bool isActive() { return MFThread::_isActive; }
void stop()
{
MFThread::_isActive = false;
if (_threads != nullptr)
{
for(unsigned i = 0; i < _maxThreads; i++)
if (_threads[i] != nullptr)
{
_threads[i]->quit();
_threads[i]->wait();
}
}
for(int i = 0; i < _threadCount; i++)
disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr);
}
unsigned int _maxThreads;
MFThread** _threads;
int _threadCount;
Thread<MFThread>** _threads;
signals:
void newFrame(const Image<ColorRgb>& data);
};

View File

@@ -1,40 +0,0 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/MFGrabber.h>
class MFWrapper : public GrabberWrapper
{
Q_OBJECT
public:
MFWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned fps, int pixelDecimation, QString flipMode);
~MFWrapper() override;
bool getSignalDetectionEnable() const;
bool getCecDetectionEnable() const;
public slots:
bool start() override;
void stop() override;
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold);
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
void setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
void setCecDetectionEnable(bool enable);
bool setDevice(const QString& device);
void setFpsSoftwareDecimation(int decimation);
bool setEncoding(QString enc);
bool setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
private slots:
void newFrame(const Image<ColorRgb> & image);
void action() override;
private:
/// The Media Foundation grabber
MFGrabber _grabber;
};

View File

@@ -15,7 +15,7 @@ class QtGrabber : public Grabber
{
public:
QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
QtGrabber(int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0, int pixelDecimation=8, int display=0);
~QtGrabber() override;
@@ -39,11 +39,6 @@ public:
///
bool setWidthHeight(int width, int height) override { return true; }
///
/// @brief Apply new pixelDecimation
///
void setPixelDecimation(int pixelDecimation) override;
///
/// Set the crop values
/// @param cropLeft Left pixel crop
@@ -58,6 +53,28 @@ public:
///
void setDisplayIndex(int index) override;
///
/// @brief Discover QT screens available (for configuration).
///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found
///
QJsonObject discover(const QJsonObject& params);
///
/// @brief Setup a new capture display, will free the previous one
/// @return True on success, false if no display is found
///
bool setupDisplay();
///
/// @brief Opens the input device.
///
/// @return Zero, on success (i.e. device is ready), else negative
///
bool open();
private slots:
///
/// @brief is called whenever the current _screen changes it's geometry
@@ -66,11 +83,7 @@ private slots:
void geometryChanged(const QRect &geo);
private:
///
/// @brief Setup a new capture display, will free the previous one
/// @return True on success, false if no display is found
///
bool setupDisplay();
///
/// @brief Is called whenever we need new screen dimension calculations based on window geometry
@@ -84,13 +97,20 @@ private:
private:
unsigned _display;
int _display;
int _numberOfSDisplays;
int _pixelDecimation;
unsigned _calculatedWidth;
unsigned _calculatedHeight;
unsigned _src_x;
unsigned _src_y;
unsigned _src_x_max;
unsigned _src_y_max;
int _calculatedWidth;
int _calculatedHeight;
int _src_x;
int _src_y;
int _src_x_max;
int _src_y_max;
bool _isWayland;
QScreen* _screen;
bool _isVirtual;
Logger * _logger;
};

View File

@@ -21,6 +21,11 @@ public:
///
QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, unsigned updateRate_Hz);
///
/// Starts the grabber which produces led values with the specified update rate
///
bool open() override;
public slots:
///
/// Performs a single frame grab and computes the led-colors

View File

@@ -16,7 +16,12 @@
#include <hyperion/Grabber.h>
#include <utils/VideoStandard.h>
#include <utils/Components.h>
#include <cec/CECEvent.h>
#include <HyperionConfig.h> // Required to determine the cmake options
#if defined(ENABLE_CEC)
#include <cec/CECEvent.h>
#endif
// general JPEG decoder includes
#ifdef HAVE_JPEG_DECODER
@@ -53,8 +58,8 @@ public:
QList<VideoStandard> standards = QList<VideoStandard>();
struct EncodingProperties
{
unsigned int width = 0;
unsigned int height = 0;
int width = 0;
int height = 0;
QList<int> framerates = QList<int>();
};
QMultiMap<PixelFormat, EncodingProperties> encodingFormats = QMultiMap<PixelFormat, EncodingProperties>();
@@ -62,115 +67,40 @@ public:
QMap<int, InputProperties> inputs = QMap<int, InputProperties>();
};
V4L2Grabber(const QString & device, const unsigned width, const unsigned height, const unsigned fps, const unsigned input, VideoStandard videoStandard, PixelFormat pixelFormat, int pixelDecimation);
V4L2Grabber();
~V4L2Grabber() override;
QRectF getSignalDetectionOffset() const
{
return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max);
}
bool getSignalDetectionEnabled() const { return _signalDetectionEnabled; }
bool getCecDetectionEnabled() const { return _cecDetectionEnabled; }
int grabFrame(Image<ColorRgb> &);
///
/// @brief set new PixelDecimation value to ImageResampler
/// @param pixelDecimation The new pixelDecimation value
///
void setPixelDecimation(int pixelDecimation) override;
///
/// @brief overwrite Grabber.h implementation
///
void setSignalThreshold(
double redSignalThreshold,
double greenSignalThreshold,
double blueSignalThreshold,
int noSignalCounterThreshold = 50) override;
///
/// @brief overwrite Grabber.h implementation
///
void setSignalDetectionOffset(
double verticalMin,
double horizontalMin,
double verticalMax,
double horizontalMax) override;
///
/// @brief overwrite Grabber.h implementation
///
void setSignalDetectionEnable(bool enable) override;
///
/// @brief overwrite Grabber.h implementation
///
void setCecDetectionEnable(bool enable) override;
///
/// @brief overwrite Grabber.h implementation
///
void setDeviceVideoStandard(QString device, VideoStandard videoStandard) override;
///
/// @brief overwrite Grabber.h implementation
///
void setDevice(const QString& device);
bool setInput(int input) override;
///
/// @brief overwrite Grabber.h implementation
///
bool setWidthHeight(int width, int height) override;
void setEncoding(QString enc);
void setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold = 50);
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
void setCecDetectionEnable(bool enable);
bool reload(bool force = false);
QRectF getSignalDetectionOffset() const { return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); } //used from hyperion-v4l2
///
/// @brief overwrite Grabber.h implementation
/// @brief Discover available V4L2 USB devices (for configuration).
/// @param[in] params Parameters used to overwrite discovery default behaviour
/// @return A JSON structure holding a list of USB devices found
///
bool setFramerate(int fps) override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getDevices() const override;
///
/// @brief overwrite Grabber.h implementation
///
QString getDeviceName(const QString& devicePath) const override;
///
/// @brief overwrite Grabber.h implementation
///
QMultiMap<QString, int> getDeviceInputs(const QString& devicePath) const override;
///
/// @brief overwrite Grabber.h implementation
///
QList<VideoStandard> getAvailableDeviceStandards(const QString& devicePath, const int& deviceInput) const override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getAvailableEncodingFormats(const QString& devicePath, const int& deviceInput) const override;
///
/// @brief overwrite Grabber.h implementation
///
QMultiMap<int, int> getAvailableDeviceResolutions(const QString& devicePath, const int& deviceInput, const PixelFormat& encFormat) const override;
///
/// @brief overwrite Grabber.h implementation
///
QIntList getAvailableDeviceFramerates(const QString& devicePath, const int& deviceInput, const PixelFormat& encFormat, const unsigned width, const unsigned height) const override;
QJsonArray discover(const QJsonObject& params);
public slots:
bool prepare() { return true; }
bool start();
void stop();
#if defined(ENABLE_CEC)
void handleCecEvent(CECEvent event);
#endif
signals:
void newFrame(const Image<ColorRgb> & image);
@@ -180,36 +110,21 @@ private slots:
int read_frame();
private:
void getV4Ldevices();
void enumVideoCaptureDevices();
bool init();
void uninit();
bool open_device();
void close_device();
void init_read(unsigned int buffer_size);
void init_mmap();
void init_userp(unsigned int buffer_size);
void init_device(VideoStandard videoStandard);
void uninit_device();
void start_capturing();
void stop_capturing();
bool process_image(const void *p, int size);
void process_image(const uint8_t *p, int size);
int xioctl(int request, void *arg);
int xioctl(int fileDescriptor, int request, void *arg);
void throw_exception(const QString & error)
@@ -264,16 +179,14 @@ private:
#endif
private:
QString _deviceName;
std::map<QString, QString> _v4lDevices;
QString _currentDeviceName, _newDeviceName;
QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
VideoStandard _videoStandard;
io_method _ioMethod;
int _fileDescriptor;
std::vector<buffer> _buffers;
PixelFormat _pixelFormat;
PixelFormat _pixelFormat, _pixelFormatConfig;
int _pixelDecimation;
int _lineLength;
int _frameByteSize;
@@ -281,10 +194,7 @@ private:
// signal detection
int _noSignalCounterThreshold;
ColorRgb _noSignalThresholdColor;
bool _signalDetectionEnabled;
bool _cecDetectionEnabled;
bool _cecStandbyActivated;
bool _noSignalDetected;
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected;
int _noSignalCounter;
double _x_frac_min;
double _y_frac_min;
@@ -293,8 +203,7 @@ private:
QSocketNotifier *_streamNotifier;
bool _initialized;
bool _deviceAutoDiscoverEnabled;
bool _initialized, _reload;
protected:
void enumFrameIntervals(QList<int> &framerates, int fileDescriptor, int pixelformat, int width, int height);

View File

@@ -1,46 +0,0 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/V4L2Grabber.h>
class V4L2Wrapper : public GrabberWrapper
{
Q_OBJECT
public:
V4L2Wrapper(const QString & device,
const unsigned grabWidth,
const unsigned grabHeight,
const unsigned fps,
const unsigned input,
VideoStandard videoStandard,
PixelFormat pixelFormat,
int pixelDecimation);
~V4L2Wrapper() override;
bool getSignalDetectionEnable() const;
bool getCecDetectionEnable() const;
public slots:
bool start() override;
void stop() override;
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold);
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
void setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
void setCecDetectionEnable(bool enable);
void setDeviceVideoStandard(const QString& device, VideoStandard videoStandard);
void handleCecEvent(CECEvent event);
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
private slots:
void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
void action() override;
private:
/// The V4L2 grabber
V4L2Grabber _grabber;
};

View File

@@ -0,0 +1,47 @@
#pragma once
#include <HyperionConfig.h> // Required to determine the cmake options
#include <hyperion/GrabberWrapper.h>
#if defined(ENABLE_MF)
#include <grabber/MFGrabber.h>
#elif defined(ENABLE_V4L2)
#include <grabber/V4L2Grabber.h>
#endif
#if defined(ENABLE_CEC)
#include <cec/CECEvent.h>
#endif
class VideoWrapper : public GrabberWrapper
{
Q_OBJECT
public:
VideoWrapper();
~VideoWrapper() override;
public slots:
bool start() override;
void stop() override;
#if defined(ENABLE_CEC)
void handleCecEvent(CECEvent event);
#endif
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
private slots:
void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
void action() override;
private:
/// The Media Foundation or V4L2 grabber
#if defined(ENABLE_MF)
MFGrabber _grabber;
#elif defined(ENABLE_V4L2)
V4L2Grabber _grabber;
#endif
};

View File

@@ -2,7 +2,13 @@
#include <QAbstractEventDispatcher>
#include <QAbstractNativeEventFilter>
#include <QCoreApplication>
// QT includes
#include <QObject>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
// Hyperion-utils includes
#include <utils/ColorRgb.h>
@@ -20,11 +26,13 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter
{
public:
X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
X11Grabber(int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0, int pixelDecimation=8);
~X11Grabber() override;
bool Setup();
bool open();
bool setupDisplay();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
@@ -50,7 +58,7 @@ public:
///
/// @brief Apply new pixelDecimation
///
void setPixelDecimation(int pixelDecimation) override;
bool setPixelDecimation(int pixelDecimation) override;
///
/// Set the crop values
@@ -61,20 +69,31 @@ public:
///
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
///
/// @brief Discover X11 screens available (for configuration).
///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found
///
QJsonObject discover(const QJsonObject& params);
protected:
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
private:
bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable, _XRandRAvailable;
XImage* _xImage;
XShmSegmentInfo _shminfo;
void freeResources();
void setupResources();
/// Reference to the X11 display (nullptr if not opened)
Display* _x11Display;
Window _window;
XWindowAttributes _windowAttr;
XImage* _xImage;
XShmSegmentInfo _shminfo;
Pixmap _pixmap;
XRenderPictFormat* _srcFormat;
XRenderPictFormat* _dstFormat;
@@ -92,8 +111,13 @@ private:
unsigned _src_x;
unsigned _src_y;
Image<ColorRgb> _image;
bool _XShmAvailable;
bool _XShmPixmapAvailable;
bool _XRenderAvailable;
bool _XRandRAvailable;
bool _isWayland;
void freeResources();
void setupResources();
Logger * _logger;
Image<ColorRgb> _image;
};

View File

@@ -1,7 +1,11 @@
#pragma once
#include <QAbstractNativeEventFilter>
// QT includes
#include <QObject>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <utils/ColorRgb.h>
#include <hyperion/Grabber.h>
@@ -21,17 +25,29 @@ class XcbGrabber : public Grabber, public QAbstractNativeEventFilter
Q_OBJECT
public:
XcbGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
XcbGrabber(int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0, int pixelDecimation=8);
~XcbGrabber() override;
bool Setup();
bool open();
bool setupDisplay();
int grabFrame(Image<ColorRgb> & image, bool forceUpdate = false);
int updateScreenDimensions(bool force = false);
void setVideoMode(VideoMode mode) override;
bool setWidthHeight(int width, int height) override { return true; }
void setPixelDecimation(int pixelDecimation) override;
bool setPixelDecimation(int pixelDecimation) override;
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
///
/// @brief Discover XCB screens available (for configuration).
///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found
///
QJsonObject discover(const QJsonObject& params);
private:
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
void freeResources();
@@ -54,6 +70,7 @@ private:
int _pixelDecimation;
int _screen_num;
unsigned _screenWidth;
unsigned _screenHeight;
unsigned _src_x;
@@ -63,6 +80,8 @@ private:
bool _XcbRandRAvailable;
bool _XcbShmAvailable;
bool _XcbShmPixmapAvailable;
bool _isWayland;
Logger * _logger;
uint8_t * _shmData;

View File

@@ -3,6 +3,7 @@
#include <utils/Logger.h>
#include <hyperion/Hyperion.h>
#include <utils/settings.h>
#include <effectengine/Effect.h>
///
/// @brief Handle the background Effect settings, reacts on runtime to settings changes
@@ -37,7 +38,7 @@ private slots:
#define BGCONFIG_ARRAY bgColorConfig.toArray()
// clear background priority
_hyperion->clear(254);
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
// initial background effect/color
if (BGEffectConfig["enable"].toBool(true))
{
@@ -53,12 +54,12 @@ private slots:
static_cast<uint8_t>(BGCONFIG_ARRAY.at(2).toInt(0))
}
};
_hyperion->setColor(254, bg_color);
_hyperion->setColor(PriorityMuxer::BG_PRIORITY, bg_color);
Info(Logger::getInstance("HYPERION"),"Initial background color set (%d %d %d)",bg_color.at(0).red, bg_color.at(0).green, bg_color.at(0).blue);
}
else
{
int result = _hyperion->setEffect(bgEffectConfig, 254);
int result = _hyperion->setEffect(bgEffectConfig, PriorityMuxer::BG_PRIORITY, Effect::ENDLESS);
Info(Logger::getInstance("HYPERION"),"Initial background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed"));
}
}

View File

@@ -41,7 +41,7 @@ public:
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
///
/// @brief Apply new video input (used from v4l)
/// @brief Apply new video input (used from v4l2/MediaFoundation)
/// @param input device input
///
virtual bool setInput(int input);
@@ -53,52 +53,26 @@ public:
virtual bool setWidthHeight(int width, int height);
///
/// @brief Apply new framerate (used from v4l)
/// @brief Apply new framerate (used from v4l2/MediaFoundation)
/// @param fps framesPerSecond
///
virtual bool setFramerate(int fps);
///
/// @brief Apply new pixelDecimation (used from x11, xcb and qt)
/// @brief Apply new framerate software decimation (used from v4l2/MediaFoundation)
/// @param decimation how many frames per second to omit
///
virtual void setPixelDecimation(int pixelDecimation) {}
virtual void setFpsSoftwareDecimation(int decimation);
///
/// @brief Apply new signalThreshold (used from v4l)
/// @brief Apply videoStandard (used from v4l2)
///
virtual void setSignalThreshold(
double redSignalThreshold,
double greenSignalThreshold,
double blueSignalThreshold,
int noSignalCounterThreshold = 50) {}
///
/// @brief Apply new SignalDetectionOffset (used from v4l)
///
virtual void setSignalDetectionOffset(
double verticalMin,
double horizontalMin,
double verticalMax,
double horizontalMax) {}
virtual void setVideoStandard(VideoStandard videoStandard);
///
/// @brief Apply SignalDetectionEnable (used from v4l)
/// @brief Apply new pixelDecimation (used from v4l2, MediaFoundation, x11, xcb and qt)
///
virtual void setSignalDetectionEnable(bool enable) {}
///
/// @brief Apply CecDetectionEnable (used from v4l)
///
virtual void setCecDetectionEnable(bool enable) {}
///
/// @brief Apply device and videoStandard (used from v4l)
///
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {}
///
/// @brief Apply device (used from MediaFoundation)
///
virtual bool setDevice(QString device) { return false; }
virtual bool setPixelDecimation(int pixelDecimation);
///
/// @brief Apply display index (used from qt)
@@ -125,71 +99,26 @@ public:
///
void setEnabled(bool enable);
///
/// @brief Get a list of all available devices
/// @return List of all available devices on success else empty List
///
virtual QStringList getDevices() const { return QStringList(); }
///
/// @brief Get the device name by path
/// @param devicePath The device path
/// @return The name of the device on success else empty String
///
virtual QString getDeviceName(const QString& /*devicePath*/) const { return QString(); }
///
/// @brief Get a name/index pair of supported device inputs
/// @param devicePath The device path
/// @return multi pair of name/index on success else empty pair
///
virtual QMultiMap<QString, int> getDeviceInputs(const QString& /*devicePath*/) const { return QMultiMap<QString, int>(); }
///
/// @brief Get a list of available device video standards depends on device input
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @return List of video standards on success else empty List
///
virtual QList<VideoStandard> getAvailableDeviceStandards(const QString& /*devicePath*/, const int& /*deviceInput*/) const { return QList<VideoStandard>(); }
///
/// @brief Get a list of all available device encoding formats depends on device input
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @return List of device encoding formats on success else empty List
///
virtual QStringList getAvailableEncodingFormats(const QString& /*devicePath*/, const int& /*deviceInput*/) const { return QStringList(); }
///
/// @brief Get a map of available device resolutions (width/heigth) depends on device input and encoding format
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @param encFormat The device encoding format
/// @return Map of resolutions (width/heigth) on success else empty List
///
virtual QMultiMap<int, int> getAvailableDeviceResolutions(const QString& /*devicePath*/, const int& /*deviceInput*/, const PixelFormat& /*encFormat*/) const { return QMultiMap<int, int>(); }
///
/// @brief Get a list of available device framerates depends on device input, encoding format and resolution
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @param encFormat The device encoding format
/// @param width The device width
/// @param heigth The device heigth
/// @return List of framerates on success else empty List
///
virtual QIntList getAvailableDeviceFramerates(const QString& /*devicePath*/, const int& /*deviceInput*/, const PixelFormat& /*encFormat*/, const unsigned /*width*/, const unsigned /*height*/) const { return QIntList(); }
QString getGrabberName() const { return _grabberName; }
protected:
QString _grabberName;
ImageResampler _imageResampler;
bool _useImageResampler;
/// The selected VideoMode
/// the selected VideoMode
VideoMode _videoMode;
/// The used Flip Mode
/// the used video standard
VideoStandard _videoStandard;
/// Image size decimation
int _pixelDecimation;
/// the used Flip Mode
FlipMode _flipMode;
/// With of the captured snapshot [pixels]
@@ -201,6 +130,9 @@ protected:
/// frame per second
int _fps;
/// fps software decimation
int _fpsSoftwareDecimation;
/// device input
int _input;

View File

@@ -58,62 +58,6 @@ public:
///
virtual bool isActive() const;
///
/// @brief Get a list of all available devices
/// @return List of all available devices on success else empty List
///
virtual QStringList getDevices() const;
///
/// @brief Get the device name by path
/// @param devicePath The device path
/// @return The name of the device on success else empty String
///
virtual QString getDeviceName(const QString& devicePath) const;
///
/// @brief Get a map of name/index pair of supported device inputs
/// @param devicePath The device path
/// @return multi pair of name/index on success else empty pair
///
virtual QMultiMap<QString, int> getDeviceInputs(const QString& devicePath) const;
///
/// @brief Get a list of available device video standards depends on device input
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @return List of video standards on success else empty List
///
virtual QList<VideoStandard> getAvailableDeviceStandards(const QString& devicePath, const int& deviceInput) const;
///
/// @brief Get a list of all available device encoding formats depends on device input
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @return List of device encoding formats on success else empty List
///
virtual QStringList getAvailableEncodingFormats(const QString& devicePath, const int& deviceInput) const;
///
/// @brief Get a map of available device resolutions (width/heigth) depends on device input and encoding format
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @param encFormat The device encoding format
/// @return Map of resolutions (width/heigth) on success else empty List
///
virtual QMultiMap<int, int> getAvailableDeviceResolutions(const QString& devicePath, const int& deviceInput, const PixelFormat& encFormat) const;
///
/// @brief Get a list of available device framerates depends on device input, encoding format and resolution
/// @param devicePath The device path
/// @param inputIndex The device input index
/// @param encFormat The device encoding format
/// @param width The device width
/// @param heigth The device heigth
/// @return List of framerates on success else empty List
///
virtual QIntList getAvailableDeviceFramerates(const QString& devicePath, const int& deviceInput, const PixelFormat& encFormat, const unsigned width, const unsigned height) const;
///
/// @brief Get active grabber name
/// @param hyperionInd The instance index
@@ -155,6 +99,12 @@ public slots:
///
virtual void setVideoMode(VideoMode videoMode);
///
/// Set the Flip mode
/// @param flipMode The new flip mode
///
virtual void setFlipMode(QString flipMode);
///
/// Set the crop values
/// @param cropLeft Left pixel crop
@@ -166,7 +116,7 @@ public slots:
///
/// @brief Handle settings update from HyperionDaemon Settingsmanager emit
/// @param type settingyType from enum
/// @param type settingsType from enum
/// @param config configuration object
///
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
@@ -189,6 +139,22 @@ private slots:
void updateTimer(int interval);
protected:
///
/// @brief Opens the input device.
///
/// @return True, on success (i.e. device is ready)
///
virtual bool open() { return true; }
///
/// @brief Closes the input device.
///
/// @return True on success (i.e. device is closed)
///
virtual bool close() { return true; }
QString _grabberName;
/// The timer for generating events with the specified update rate

View File

@@ -26,6 +26,7 @@
// Effect engine includes
#include <effectengine/EffectDefinition.h>
#include <effectengine/Effect.h>
#include <effectengine/ActiveEffectDefinition.h>
#include <effectengine/EffectSchema.h>
@@ -217,7 +218,7 @@ public slots:
/// @param effectName Name of the effec to run
/// @param priority The priority channel of the effect
/// @param timeout The timeout of the effect (after the timout, the effect will be cleared)
int setEffect(const QString & effectName, int priority, int timeout = -1, const QString & origin="System");
int setEffect(const QString & effectName, int priority, int timeout = Effect::ENDLESS, const QString & origin="System");
/// Run the specified effect on the given priority channel and optionally specify a timeout
/// @param effectName Name of the effec to run
@@ -227,7 +228,7 @@ public slots:
int setEffect(const QString &effectName
, const QJsonObject &args
, int priority
, int timeout = -1
, int timeout = Effect::ENDLESS
, const QString &pythonScript = ""
, const QString &origin="System"
, const QString &imageData = ""

View File

@@ -54,6 +54,9 @@ public:
QString owner;
};
//Foreground and Background priorities
const static int FG_PRIORITY;
const static int BG_PRIORITY;
/// The lowest possible priority, which is used when no priority channels are active
const static int LOWEST_PRIORITY;

27
include/utils/WaitTime.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef WAITTIME_H
#define WAITTIME_H
#include <QEventLoop>
#include <QTimer>
#include <chrono>
inline void wait(std::chrono::milliseconds millisecondsWait)
{
QEventLoop loop;
QTimer t;
t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
t.start(millisecondsWait.count());
loop.exec();
}
inline void wait(int millisecondsWait)
{
QEventLoop loop;
QTimer t;
t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
t.start(millisecondsWait);
loop.exec();
}
#endif // WAITTIME_H

View File

@@ -7,6 +7,7 @@
#include <hyperion/LedString.h>
// fg effect
#include <hyperion/Hyperion.h>
#include <hyperion/PriorityMuxer.h>
///
/// @brief Provide utility methods for Hyperion class
@@ -16,7 +17,6 @@ namespace hyperion {
void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
{
#define FGCONFIG_ARRAY fgColorConfig.toArray()
const int FG_PRIORITY = 0;
const int DURATION_INFINITY = 0;
// initial foreground effect/color
@@ -41,12 +41,12 @@ namespace hyperion {
static_cast<uint8_t>(FGCONFIG_ARRAY.at(2).toInt(0))
}
};
hyperion->setColor(FG_PRIORITY, fg_color, fg_duration_ms);
hyperion->setColor(PriorityMuxer::FG_PRIORITY, fg_color, fg_duration_ms);
Info(Logger::getInstance("HYPERION"),"Initial foreground color set (%d %d %d)",fg_color.at(0).red,fg_color.at(0).green,fg_color.at(0).blue);
}
else
{
int result = hyperion->setEffect(fgEffectConfig, FG_PRIORITY, fg_duration_ms);
int result = hyperion->setEffect(fgEffectConfig, PriorityMuxer::FG_PRIORITY, fg_duration_ms);
Info(Logger::getInstance("HYPERION"),"Initial foreground effect '%s' %s", QSTRING_CSTR(fgEffectConfig), ((result == 0) ? "started" : "failed"));
}
}