Merge branch 'master' into Razer_Chroma_Support

# Conflicts:
#	assets/webconfig/i18n/en.json
#	assets/webconfig/js/content_leds.js
#	libsrc/leddevice/dev_net/ProviderRestApi.cpp
#	libsrc/leddevice/dev_net/ProviderRestApi.h
This commit is contained in:
LordGrey
2021-11-01 15:40:37 +01:00
474 changed files with 24405 additions and 24526 deletions

View File

@@ -278,6 +278,12 @@ private:
///
void handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan);
/// Handle an incoming JSON message regarding Input Sources (Grabbers)
///
/// @param message the incoming message
///
void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
///
/// Handle an incoming JSON message of unknown type
///

View File

@@ -21,6 +21,9 @@ class Effect : public QThread
Q_OBJECT
public:
static const int ENDLESS;
friend class EffectModule;
Effect(Hyperion *hyperion
@@ -44,15 +47,27 @@ 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; }
int getTimeout() const {return _timeout; }
bool isEndless() const { return _isEndless; }
QJsonObject getArgs() const { return _args; }
@@ -69,6 +84,7 @@ private:
const int _priority;
const int _timeout;
bool _isEndless;
const QString _script;
const QString _name;
@@ -76,7 +92,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

@@ -8,8 +8,10 @@
class Effect;
class EffectModule
class EffectModule: public QObject
{
Q_OBJECT
public:
// Python 3 module def
static struct PyModuleDef moduleDef;

View File

@@ -14,12 +14,16 @@ public:
///
/// Construct a AmlogicGrabber that will capture snapshots with specified dimensions.
///
/// @param[in] width The width of the captured screenshot
/// @param[in] height The heigth of the captured screenshot
///
AmlogicGrabber(unsigned width, unsigned height);
AmlogicGrabber();
~AmlogicGrabber() override;
///
/// @brief Setup a new capture screen, will free the previous one
/// @return True on success, false if no screen is found
///
bool setupScreen();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
@@ -31,14 +35,51 @@ public:
///
int grabFrame(Image<ColorRgb> & image);
///
/// @brief Discover AmLogic 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);
///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
void setVideoMode(VideoMode mode) override;
///
/// @brief Apply new crop values, on errors reject the values
///
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
///
/// @brief Apply new width/height values, on errors (collide with cropping) reject the values
/// @return True on success else false
///
bool setWidthHeight(int width, int height) override;
///
/// @brief Apply new framerate
/// @param fps framesPerSecond
///
bool setFramerate(int fps) override;
///
/// @brief Apply new pixelDecimation
///
bool setPixelDecimation(int pixelDecimation) override;
private:
/**
* Returns true if video is playing over the amlogic chip
* @return True if video is playing else false
*/
bool isVideoPlaying();
void closeDev(int &fd);
bool openDev(int &fd, const char* dev);
void closeDevice(int &fd);
bool openDevice(int &fd, const char* dev);
int grabFrame_amvideocap(Image<ColorRgb> & image);

View File

@@ -4,8 +4,8 @@
#include <grabber/AmlogicGrabber.h>
///
/// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
/// The Amlogic uses an instance of the AmlogicGrabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and committed to the
/// attached Hyperion.
///
class AmlogicWrapper : public GrabberWrapper
@@ -13,12 +13,14 @@ class AmlogicWrapper : public GrabberWrapper
Q_OBJECT
public:
///
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
/// Constructs the Amlogic frame grabber
///
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
///
AmlogicWrapper(unsigned grabWidth, unsigned grabHeight);
AmlogicWrapper(int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ);
public slots:
///

View File

@@ -8,8 +8,14 @@
// Hyperion-utils includes
#include <utils/ColorRgb.h>
#include <hyperion/GrabberWrapper.h>
#include <hyperion/Grabber.h>
// qt includes
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
///
/// @brief The DirectX9 capture implementation
///
@@ -17,33 +23,32 @@ class DirectXGrabber : public Grabber
{
public:
DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
DirectXGrabber(int display=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
virtual ~DirectXGrabber();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
/// _height)
/// provided image should have the same dimensions as the configured values (_width and _height)
///
/// @param[out] image The snapped screenshot
///
virtual int grabFrame(Image<ColorRgb> & image);
int grabFrame(Image<ColorRgb> & image);
///
/// @brief Set a new video mode
///
virtual void setVideoMode(VideoMode mode);
void setVideoMode(VideoMode mode) override;
///
/// @brief Apply new width/height values, overwrite Grabber.h implementation
///
virtual bool setWidthHeight(int width, int height) { return true; };
bool setWidthHeight(int /* width */, int /*height*/) override { return true; }
///
/// @brief Apply new pixelDecimation
///
virtual void setPixelDecimation(int pixelDecimation);
bool setPixelDecimation(int pixelDecimation) override;
///
/// Set the crop values
@@ -52,7 +57,20 @@ public:
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
///
/// @brief Apply display index
///
bool 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);
private:
///
@@ -67,7 +85,7 @@ private:
void freeResources();
private:
int _pixelDecimation;
unsigned _display;
unsigned _displayWidth;
unsigned _displayHeight;
RECT* _srcRect;

View File

@@ -9,15 +9,21 @@ public:
///
/// Constructs the DirectX grabber with a specified grab size and update rate.
///
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] display Display to be grabbed
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] cropLeft Remove from left [pixels]
/// @param[in] cropRight Remove from right [pixels]
/// @param[in] cropTop Remove from top [pixels]
/// @param[in] cropBottom Remove from bottom [pixels]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] display The display used[index]
/// @param[in] updateRate_Hz The image grab rate [Hz]
///
DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz);
DirectXWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int display=0,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
///
/// Destructor of this DirectX grabber. Releases any claimed resources.

View File

@@ -14,8 +14,7 @@
#include <hyperion/Grabber.h>
///
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a
/// downsized and scaled resolution.
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a downsized and scaled resolution.
///
class DispmanxFrameGrabber : public Grabber
{
@@ -23,12 +22,16 @@ public:
///
/// Construct a DispmanxFrameGrabber that will capture snapshots with specified dimensions.
///
/// @param[in] width The width of the captured screenshot
/// @param[in] height The heigth of the captured screenshot
///
DispmanxFrameGrabber(unsigned width, unsigned height);
DispmanxFrameGrabber();
~DispmanxFrameGrabber() override;
bool open();
///
/// @brief Setup a new capture screen, will free the previous one
/// @return True on success, false if no screen is found
///
bool setupScreen();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
@@ -44,13 +47,24 @@ public:
///@brief Set new width and height for dispmanx, overwrite Grabber.h impl
bool setWidthHeight(int width, int height) override;
QSize getScreenSize(int display=0) const;
///
/// @brief Discover DispmanX 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:
///
/// Updates the frame-grab flags as used by the VC library for frame grabbing
///
/// @param vc_flags The snapshot grabbing mask
///
void setFlags(int vc_flags);
void setFlags(DISPMANX_TRANSFORM_T vc_flags);
///
/// @brief free _vc_resource and captureBuffer
@@ -63,11 +77,11 @@ private:
/// Handle to the resource for storing the captured snapshot
DISPMANX_RESOURCE_HANDLE_T _vc_resource;
/// Rectangle of the captured resource that is transfered to user space
/// Rectangle of the captured resource that is transferred to user space
VC_RECT_T _rectangle;
/// Flags (transforms) for creating snapshots
int _vc_flags;
DISPMANX_TRANSFORM_T _vc_flags;
// temp buffer when capturing with unsupported pitch size or
// when we need to crop the image
@@ -78,5 +92,4 @@ private:
// rgba output buffer
Image<ColorRgba> _image_rgba;
};

View File

@@ -16,6 +16,7 @@ typedef int DISPMANX_TRANSFORM_T;
struct DISPMANX_MODEINFO_T {
int width;
int height;
uint32_t display_num;
};
struct VC_RECT_T {
@@ -34,6 +35,6 @@ DISPMANX_RESOURCE_HANDLE_T vc_dispmanx_resource_create(int,int width,int height,
void vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T resource);
int vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T vc_resource, VC_RECT_T *rectangle, void* capturePtr, unsigned capturePitch);
void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, int height);
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags);
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, DISPMANX_TRANSFORM_T vc_flags);
#endif

View File

@@ -16,11 +16,14 @@ public:
///
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
///
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
///
DispmanxWrapper(unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
DispmanxWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
bool screenInit();
public slots:
///

View File

@@ -0,0 +1,176 @@
#pragma once
// Qt includes
#include <QThread>
// util includes
#include <utils/PixelFormat.h>
#include <utils/ImageResampler.h>
// Determine the cmake options
#include <HyperionConfig.h>
// Turbo JPEG decoder
#ifdef HAVE_TURBO_JPEG
#include <turbojpeg.h>
#endif
/// Encoder thread for USB devices
class EncoderThread : public QObject
{
Q_OBJECT
public:
explicit EncoderThread();
~EncoderThread();
void setup(
PixelFormat pixelFormat, uint8_t* sharedData,
int size, int width, int height, int lineLength,
unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
VideoMode videoMode, FlipMode flipMode, int pixelDecimation);
void process();
bool isBusy() { return _busy; }
QAtomicInt _busy = false;
signals:
void newFrame(const Image<ColorRgb>& data);
private:
PixelFormat _pixelFormat;
uint8_t* _localData,
*_flipBuffer;
int _scalingFactorsCount,
_width,
_height,
_lineLength,
_currentFrame,
_pixelDecimation;
unsigned long _size;
unsigned _cropLeft,
_cropTop,
_cropBottom,
_cropRight;
FlipMode _flipMode;
ImageResampler _imageResampler;
#ifdef HAVE_TURBO_JPEG
tjhandle _transform, _decompress;
tjscalingfactor* _scalingFactors;
tjtransform* _xform;
void processImageMjpeg();
#endif
};
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();
}
EncoderThread* thread() const { return qobject_cast<EncoderThread*>(_thread); }
void setup(
PixelFormat pixelFormat, uint8_t* sharedData,
int size, int width, int height, int lineLength,
unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
VideoMode videoMode, FlipMode flipMode, int pixelDecimation)
{
auto encThread = qobject_cast<EncoderThread*>(_thread);
if (encThread != nullptr)
encThread->setup(pixelFormat, sharedData,
size, width, height, lineLength,
cropLeft, cropTop, cropBottom, cropRight,
videoMode, flipMode, pixelDecimation);
}
bool isBusy()
{
auto encThread = qobject_cast<EncoderThread*>(_thread);
if (encThread != nullptr)
return encThread->isBusy();
return true;
}
void process()
{
auto encThread = qobject_cast<EncoderThread*>(_thread);
if (encThread != nullptr)
encThread->process();
}
protected:
void run() override
{
QThread::run();
delete _thread;
}
};
class EncoderThreadManager : public QObject
{
Q_OBJECT
public:
explicit EncoderThreadManager(QObject *parent = nullptr)
: QObject(parent)
, _threadCount(qMax(QThread::idealThreadCount(), 1))
, _threads(nullptr)
{
_threads = new Thread<EncoderThread>*[_threadCount];
for (int i = 0; i < _threadCount; i++)
{
_threads[i] = new Thread<EncoderThread>(new EncoderThread, this);
_threads[i]->setObjectName("Encoder " + i);
}
}
~EncoderThreadManager()
{
if (_threads != nullptr)
{
for(int i = 0; i < _threadCount; i++)
{
_threads[i]->deleteLater();
_threads[i] = nullptr;
}
delete[] _threads;
_threads = nullptr;
}
}
void start()
{
if (_threads != nullptr)
for (int i = 0; i < _threadCount; i++)
connect(_threads[i]->thread(), &EncoderThread::newFrame, this, &EncoderThreadManager::newFrame);
}
void stop()
{
if (_threads != nullptr)
for(int i = 0; i < _threadCount; i++)
disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr);
}
int _threadCount;
Thread<EncoderThread>** _threads;
signals:
void newFrame(const Image<ColorRgb>& data);
};

View File

@@ -1,5 +1,7 @@
#pragma once
#include <linux/fb.h>
// Utils includes
#include <utils/ColorRgb.h>
#include <hyperion/Grabber.h>
@@ -14,10 +16,10 @@ public:
/// Construct a FramebufferFrameGrabber that will capture snapshots with specified dimensions.
///
/// @param[in] device The framebuffer device name/path
/// @param[in] width The width of the captured screenshot
/// @param[in] height The heigth of the captured screenshot
///
FramebufferFrameGrabber(const QString & device, unsigned width, unsigned height);
FramebufferFrameGrabber(const QString & device="/dev/fb0");
~FramebufferFrameGrabber() override;
///
/// Captures a single snapshot of the display and writes the data to the given image. The
@@ -30,11 +32,42 @@ public:
int grabFrame(Image<ColorRgb> & image);
///
/// @brief Overwrite Grabber.h implememtation
/// @brief Setup a new capture screen, will free the previous one
/// @return True on success, false if no screen is found
///
void setDevicePath(const QString& path) override;
bool setupScreen();
QSize getScreenSize() const;
QSize getScreenSize(const QString& device) const;
///
///@brief Set new width and height for framegrabber, overwrite Grabber.h implementation
bool setWidthHeight(int width, int height) override;
QString getPath() const {return _fbDevice;}
///
/// @brief Discover Framebuffer 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 openDevice();
bool closeDevice();
bool getScreenInfo();
/// Framebuffer device e.g. /dev/fb0
QString _fbDevice;
int _fbfd;
struct fb_var_screeninfo _varInfo;
struct fb_fix_screeninfo _fixInfo;
PixelFormat _pixelFormat;
};

View File

@@ -5,7 +5,7 @@
///
/// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and committed to the
/// attached Hyperion.
///
class FramebufferWrapper: public GrabberWrapper
@@ -15,12 +15,14 @@ public:
///
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
///
/// @param[in] device Framebuffer device name/path
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] device Framebuffer device name/path
/// @param[in] pixelDecimation Decimation factor for image [pixels]
///
FramebufferWrapper(const QString & device, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
FramebufferWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
const QString & device = "/dev/fb0",
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
public slots:
///

129
include/grabber/MFGrabber.h Normal file
View File

@@ -0,0 +1,129 @@
#pragma once
// Windows include
#include <Windows.h>
// COM includes
#include <Guiddef.h>
// Qt includes
#include <QObject>
#include <QRectF>
#include <QMap>
#include <QMultiMap>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
// utils includes
#include <utils/PixelFormat.h>
#include <utils/Components.h>
#include <hyperion/Grabber.h>
// decoder thread includes
#include <grabber/EncoderThread.h>
/// Forward class declaration
class SourceReaderCB;
/// Forward struct declaration
struct IMFSourceReader;
///
/// Media Foundation capture class
///
class MFGrabber : public Grabber
{
Q_OBJECT
friend class SourceReaderCB;
public:
struct DeviceProperties
{
QString symlink = QString();
int width = 0;
int height = 0;
int fps = 0;
int numerator = 0;
int denominator = 0;
PixelFormat pf = PixelFormat::NO_CHANGE;
GUID guid = GUID_NULL;
};
struct DeviceControls
{
QString property = QString();
int minValue = 0;
int maxValue = 0;
int step = 0;
int default = 0;
int currentValue = 0;
};
MFGrabber();
~MFGrabber() override;
void receive_image(const void *frameImageBuffer, int size);
void setDevice(const QString& device);
bool setInput(int input) override;
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);
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
bool reload(bool force = false);
///
/// @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(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 enumVideoCaptureDevices();
void start_capturing();
void process_image(const void *frameImageBuffer, int size);
QString _currentDeviceName,
_newDeviceName;
QMap<QString, QList<DeviceProperties>> _deviceProperties;
QMap<QString, QList<DeviceControls>> _deviceControls;
HRESULT _hr;
IMFSourceReader* _sourceReader;
SourceReaderCB* _sourceReaderCB;
EncoderThreadManager* _threadManager;
PixelFormat _pixelFormat,
_pixelFormatConfig;
int _lineLength,
_frameByteSize,
_noSignalCounterThreshold,
_noSignalCounter,
_brightness,
_contrast,
_saturation,
_hue;
QAtomicInt _currentFrame;
ColorRgb _noSignalThresholdColor;
bool _signalDetectionEnabled,
_noSignalDetected,
_initialized,
_reload;
double _x_frac_min,
_y_frac_min,
_x_frac_max,
_y_frac_max;
};

View File

@@ -21,12 +21,17 @@ public:
/// Construct a OsxFrameGrabber that will capture snapshots with specified dimensions.
///
/// @param[in] display The index of the display to capture
/// @param[in] width The width of the captured screenshot
/// @param[in] height The heigth of the captured screenshot
///
OsxFrameGrabber(unsigned display, unsigned width, unsigned height);
OsxFrameGrabber(int display=kCGDirectMainDisplay);
~OsxFrameGrabber() override;
///
/// @brief Setup a new capture screen, will free the previous one
/// @return True on success, false if no screen is found
///
bool setupDisplay();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
@@ -40,12 +45,21 @@ public:
///
/// @brief Overwrite Grabber.h implementation
///
void setDisplayIndex(int index) override;
bool setDisplayIndex(int index) override;
///
/// @brief Discover OSX 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:
/// display
unsigned _screenIndex;
int _screenIndex;
/// Reference to the captured diaplay
/// Reference to the captured display
CGDirectDisplayID _display;
};

View File

@@ -4,31 +4,90 @@
/*
* this is a mock up for compiling and testing osx wrapper on no osx platform.
* this will show a test image and rotate the colors.
*
* see https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.8.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers
*
*/
#include <utils/Image.h>
#include <utils/ColorRgb.h>
typedef int CGDirectDisplayID;
enum _CGError {
kCGErrorSuccess = 0,
kCGErrorFailure = 1000,
kCGErrorIllegalArgument = 1001,
kCGErrorInvalidConnection = 1002,
kCGErrorInvalidContext = 1003,
kCGErrorCannotComplete = 1004,
kCGErrorNotImplemented = 1006,
kCGErrorRangeCheck = 1007,
kCGErrorTypeCheck = 1008,
kCGErrorInvalidOperation = 1010,
kCGErrorNoneAvailable = 1011,
/* Obsolete errors. */
kCGErrorNameTooLong = 1005,
kCGErrorNoCurrentPoint = 1009,
kCGErrorApplicationRequiresNewerSystem = 1015,
kCGErrorApplicationNotPermittedToExecute = 1016,
kCGErrorApplicationIncorrectExecutableFormatFound = 1023,
kCGErrorApplicationIsLaunching = 1024,
kCGErrorApplicationAlreadyRunning = 1025,
kCGErrorApplicationCanOnlyBeRunInOneSessionAtATime = 1026,
kCGErrorClassicApplicationsMustBeLaunchedByClassic = 1027,
kCGErrorForkFailed = 1028,
kCGErrorRetryRegistration = 1029,
kCGErrorFirst = 1000,
kCGErrorLast = 1029
};
typedef int32_t CGError;
typedef double CGFloat;
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
struct CGPoint {
float x;
float y;
};
typedef struct CGPoint CGPoint;
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;
typedef CGError CGDisplayErr;
typedef uint32_t CGDirectDisplayID;
typedef uint32_t CGDisplayCount;;
typedef struct CGDisplayMode *CGDisplayModeRef;
typedef Image<ColorRgb> CGImage;
typedef CGImage* CGImageRef;
typedef unsigned char CFData;
typedef CFData* CFDataRef;
typedef unsigned CGDisplayCount;
const int kCGDirectMainDisplay = 0;
void CGGetActiveDisplayList(int max, CGDirectDisplayID *displays, CGDisplayCount *displayCount);
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display);
void CGImageRelease(CGImageRef image);
CGImageRef CGImageGetDataProvider(CGImageRef image);
CFDataRef CGDataProviderCopyData(CGImageRef image);
unsigned char* CFDataGetBytePtr(CFDataRef imgData);
unsigned CGImageGetWidth(CGImageRef image);
unsigned CGImageGetHeight(CGImageRef image);
unsigned CGImageGetBitsPerPixel(CGImageRef image);
unsigned CGImageGetBytesPerRow(CGImageRef image);
void CFRelease(CFDataRef imgData);
CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount);
CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display);
CGRect CGDisplayBounds(CGDirectDisplayID display);
void CGDisplayModeRelease(CGDisplayModeRef mode);
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display);
void CGImageRelease(CGImageRef image);
CGImageRef CGImageGetDataProvider(CGImageRef image);
CFDataRef CGDataProviderCopyData(CGImageRef image);
unsigned char* CFDataGetBytePtr(CFDataRef imgData);
unsigned CGImageGetWidth(CGImageRef image);
unsigned CGImageGetHeight(CGImageRef image);
unsigned CGImageGetBitsPerPixel(CGImageRef image);
unsigned CGImageGetBytesPerRow(CGImageRef image);
void CFRelease(CFDataRef imgData);
#endif

View File

@@ -4,9 +4,8 @@
#include <grabber/OsxFrameGrabber.h>
///
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
/// attached Hyperion.
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the displayed content.
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
///
class OsxWrapper: public GrabberWrapper
{
@@ -15,12 +14,14 @@ public:
///
/// Constructs the osx frame grabber with a specified grab size and update rate.
///
/// @param[in] display Index of the display to grab
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] display Index of the display to grab
/// @param[in] pixelDecimation Decimation factor for image [pixels]
///
OsxWrapper(unsigned display, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
OsxWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int display = kCGDirectMainDisplay,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
public slots:
///

View File

@@ -15,14 +15,13 @@ class QtGrabber : public Grabber
{
public:
QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
QtGrabber(int display=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
~QtGrabber() override;
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
/// _height)
/// provided image should have the same dimensions as the configured values (_width and _height)
///
/// @param[out] image The snapped screenshot (should be initialized with correct width and
/// height)
@@ -37,12 +36,12 @@ public:
///
/// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions
///
bool setWidthHeight(int width, int height) override { return true; }
bool setWidthHeight(int /*width*/, int /*height*/) override { return true; }
///
/// @brief Apply new pixelDecimation
///
void setPixelDecimation(int pixelDecimation) override;
bool setPixelDecimation(int pixelDecimation) override;
///
/// Set the crop values
@@ -51,14 +50,46 @@ public:
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
///
/// @brief Apply display index
///
void setDisplayIndex(int index) override;
bool 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();
#ifdef _WIN32
///
/// @brief Replacement for the virtual QWindowsScreen Function grabWindow (only on Windows).
///
/// @return QPixmap
///
QPixmap grabWindow(quintptr window, int xIn, int yIn, int width, int height) const;
#endif
private slots:
///
/// @brief is called whenever the current _screen changes it's geometry
/// @param geo The new geometry
@@ -66,11 +97,6 @@ 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 +110,19 @@ private:
private:
unsigned _display;
int _pixelDecimation;
unsigned _screenWidth;
unsigned _screenHeight;
unsigned _src_x;
unsigned _src_y;
unsigned _src_x_max;
unsigned _src_y_max;
int _display;
int _numberOfSDisplays;
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

@@ -10,16 +10,28 @@ class QtWrapper: public GrabberWrapper
{
public:
///
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
/// Constructs the QT frame grabber with a specified grab size and update rate.
///
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] display Display to be grabbed
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] cropLeft Remove from left [pixels]
/// @param[in] cropRight Remove from right [pixels]
/// @param[in] cropTop Remove from top [pixels]
/// @param[in] cropBottom Remove from bottom [pixels]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
///
QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, unsigned updateRate_Hz);
QtWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int display=0,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
///
/// Starts the grabber which produces led values with the specified update rate
///
bool open() override;
public slots:
///

View File

@@ -14,30 +14,24 @@
// util includes
#include <utils/PixelFormat.h>
#include <hyperion/Grabber.h>
#include <grabber/VideoStandard.h>
#include <hyperion/GrabberWrapper.h>
#include <utils/VideoStandard.h>
#include <utils/Components.h>
#include <cec/CECEvent.h>
// general JPEG decoder includes
#ifdef HAVE_JPEG_DECODER
#include <QImage>
#include <QColor>
#endif
// System JPEG decoder
#ifdef HAVE_JPEG
#include <jpeglib.h>
#include <csetjmp>
#endif
// TurboJPEG decoder
#ifdef HAVE_TURBO_JPEG
#include <turbojpeg.h>
// decoder thread includes
#include <grabber/EncoderThread.h>
// Determine the cmake options
#include <HyperionConfig.h>
#if defined(ENABLE_CEC)
#include <cec/CECEvent.h>
#endif
///
/// Capture class for V4L2 devices
///
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
class V4L2Grabber : public Grabber
{
Q_OBJECT
@@ -45,118 +39,67 @@ class V4L2Grabber : public Grabber
public:
struct DeviceProperties
{
QString name = QString();
QMultiMap<QString, int> inputs = QMultiMap<QString, int>();
QStringList resolutions = QStringList();
QStringList framerates = QStringList();
QString name = QString();
struct InputProperties
{
QString inputName = QString();
QList<VideoStandard> standards = QList<VideoStandard>();
struct EncodingProperties
{
int width = 0;
int height = 0;
QList<int> framerates = QList<int>();
};
QMultiMap<PixelFormat, EncodingProperties> encodingFormats = QMultiMap<PixelFormat, EncodingProperties>();
};
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
);
struct DeviceControls
{
QString property = QString();
int minValue = 0;
int maxValue = 0;
int step = 0;
int defaultValue = 0;
int currentValue = 0;
};
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& devicePath, const QString& deviceName);
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 getV4L2devices() const override;
///
/// @brief overwrite Grabber.h implementation
///
QString getV4L2deviceName(const QString& devicePath) const override;
///
/// @brief overwrite Grabber.h implementation
///
QMultiMap<QString, int> getV4L2deviceInputs(const QString& devicePath) const override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getResolutions(const QString& devicePath) const override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getFramerates(const QString& devicePath) const override;
QJsonArray discover(const QJsonObject& params);
public slots:
bool prepare();
bool start();
void stop();
void newThreadFrame(Image<ColorRgb> image);
#if defined(ENABLE_CEC)
void handleCecEvent(CECEvent event);
#endif
signals:
void newFrame(const Image<ColorRgb> & image);
@@ -166,36 +109,19 @@ private slots:
int read_frame();
private:
void getV4Ldevices();
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)
@@ -222,56 +148,28 @@ private:
size_t length;
};
#ifdef HAVE_JPEG
struct errorManager
{
jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
static void errorHandler(j_common_ptr cInfo)
{
errorManager* mgr = reinterpret_cast<errorManager*>(cInfo->err);
longjmp(mgr->setjmp_buffer, 1);
}
static void outputHandler(j_common_ptr cInfo)
{
// Suppress fprintf warnings.
}
jpeg_decompress_struct* _decompress;
errorManager* _error;
#endif
#ifdef HAVE_TURBO_JPEG
tjhandle _decompress = nullptr;
int _subsamp;
#endif
private:
QString _deviceName;
std::map<QString, QString> _v4lDevices;
QString _currentDevicePath, _currentDeviceName;
EncoderThreadManager* _threadManager;
QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
QMap<QString, QList<DeviceControls>> _deviceControls;
VideoStandard _videoStandard;
io_method _ioMethod;
int _fileDescriptor;
std::vector<buffer> _buffers;
PixelFormat _pixelFormat;
int _pixelDecimation;
PixelFormat _pixelFormat, _pixelFormatConfig;
int _lineLength;
int _frameByteSize;
QAtomicInt _currentFrame;
// signal detection
int _noSignalCounterThreshold;
ColorRgb _noSignalThresholdColor;
bool _signalDetectionEnabled;
bool _cecDetectionEnabled;
bool _cecStandbyActivated;
bool _noSignalDetected;
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected;
int _noSignalCounter;
int _brightness, _contrast, _saturation, _hue;
double _x_frac_min;
double _y_frac_min;
double _x_frac_max;
@@ -279,9 +177,9 @@ private:
QSocketNotifier *_streamNotifier;
bool _initialized;
bool _deviceAutoDiscoverEnabled;
bool _initialized, _reload;
protected:
void enumFrameIntervals(QStringList &framerates, int fileDescriptor, int pixelformat, int width, int height);
void enumVideoCaptureDevices();
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);
~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
@@ -59,22 +67,33 @@ public:
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
void setCropping(int cropLeft, int cropRight, int cropTop, int 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;
@@ -85,15 +104,19 @@ private:
int _XRandREventBase;
XTransform _transform;
int _pixelDecimation;
unsigned _screenWidth;
unsigned _screenHeight;
unsigned _calculatedWidth;
unsigned _calculatedHeight;
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

@@ -9,25 +9,26 @@
///
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
/// attached Hyperion.
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the displayed content.
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
///
class X11Wrapper: public GrabberWrapper
{
public:
///
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
/// Constructs the X11 frame grabber with a specified grab size and update rate.
///
/// @param[in] device X11 device name/path
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
///
X11Wrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, unsigned updateRate_Hz);
X11Wrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
///
/// Destructor of this framebuffer frame grabber. Releases any claimed resources.
/// Destructor of this frame grabber. Releases any claimed resources.
///
~X11Wrapper() override;

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,16 +25,28 @@ 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);
~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;
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
bool setPixelDecimation(int pixelDecimation) override;
void setCropping(int cropLeft, int cropRight, int cropTop, int 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;
@@ -52,8 +68,7 @@ private:
xcb_render_transform_t _transform;
xcb_shm_seg_t _shminfo;
int _pixelDecimation;
int _screen_num;
unsigned _screenWidth;
unsigned _screenHeight;
unsigned _src_x;
@@ -63,6 +78,8 @@ private:
bool _XcbRandRAvailable;
bool _XcbShmAvailable;
bool _XcbShmPixmapAvailable;
bool _isWayland;
Logger * _logger;
uint8_t * _shmData;

View File

@@ -11,7 +11,12 @@
class XcbWrapper: public GrabberWrapper
{
public:
XcbWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz);
XcbWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
~XcbWrapper() override;
public slots:

View File

@@ -3,6 +3,8 @@
#include <utils/Logger.h>
#include <hyperion/Hyperion.h>
#include <utils/settings.h>
#include <effectengine/Effect.h>
#include <hyperion/PriorityMuxer.h>
///
/// @brief Handle the background Effect settings, reacts on runtime to settings changes
@@ -13,11 +15,19 @@ class BGEffectHandler : public QObject
public:
BGEffectHandler(Hyperion* hyperion)
: QObject(hyperion)
, _hyperion(hyperion)
: QObject(hyperion)
, _hyperion(hyperion)
, _prioMuxer(_hyperion->getMuxerInstance())
, _isBgEffectConfigured(false)
{
// listen for config changes
connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
connect(_hyperion, &Hyperion::settingsChanged,
[=](settings::type type, const QJsonDocument& config) { this->handleSettingsUpdate(type, config); }
);
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged,
[=]() { this->handlePriorityUpdate(); }
);
// initialization
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
@@ -33,14 +43,18 @@ private slots:
{
if(type == settings::BGEFFECT)
{
const QJsonObject& BGEffectConfig = config.object();
_isBgEffectConfigured = false;
_bgEffectConfig = config;
const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
#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))
{
_isBgEffectConfigured = true;
const QString bgTypeConfig = BGEffectConfig["type"].toString("effect");
const QString bgEffectConfig = BGEffectConfig["effect"].toString("Warm mood blobs");
const QJsonValue bgColorConfig = BGEffectConfig["color"];
@@ -53,21 +67,42 @@ 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"));
}
}
#undef BGCONFIG_ARRAY
}
}
///
/// @brief Handle priority updates.
/// In case the background effect is not current priority, stop BG-effect to save resources; otherwise start effect again.
///
void handlePriorityUpdate()
{
if (_prioMuxer->getCurrentPriority() != PriorityMuxer::BG_PRIORITY && _prioMuxer->hasPriority(PriorityMuxer::BG_PRIORITY))
{
Debug(Logger::getInstance("HYPERION"),"Stop background (color-) effect as it moved out of scope");
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
}
else if (_prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectConfigured)
{
emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
}
}
private:
/// Hyperion instance pointer
Hyperion* _hyperion;
/// priority muxer instance
PriorityMuxer* _prioMuxer;
QJsonDocument _bgEffectConfig;
bool _isBgEffectConfigured;
};

View File

@@ -6,23 +6,21 @@
#include <utils/ColorRgb.h>
#include <utils/Image.h>
#include <utils/VideoMode.h>
#include <grabber/VideoStandard.h>
#include <utils/VideoStandard.h>
#include <utils/ImageResampler.h>
#include <utils/Logger.h>
#include <utils/Components.h>
#include <QMultiMap>
///
/// @brief The Grabber class is responsible to apply image resizes (with or without ImageResampler)
/// Overwrite the videoMode with setVideoMode()
/// Overwrite setCropping()
class Grabber : public QObject
{
Q_OBJECT
public:
Grabber(const QString& grabberName = "", int width=0, int height=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
Grabber(const QString& grabberName = "", int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
///
/// Set the video mode (2D/3D)
@@ -31,12 +29,18 @@ public:
virtual void setVideoMode(VideoMode mode);
///
/// @brief Apply new crop values, on errors reject the values
/// Apply new flip mode (vertical/horizontal/both)
/// @param[in] mode The new flip mode
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
virtual void setFlipMode(FlipMode mode);
///
/// @brief Apply new video input (used from v4l)
/// @brief Apply new crop values, on errors reject the values
///
virtual void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
///
/// @brief Apply new video input (used from v4l2/MediaFoundation)
/// @param input device input
///
virtual bool setInput(int input);
@@ -48,114 +52,95 @@ public:
virtual bool setWidthHeight(int width, int height);
///
/// @brief Apply new framerate (used from v4l)
/// @brief Apply new capture framerate in Hz
/// @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
///
virtual void setSignalDetectionEnable(bool enable) {}
///
/// @brief Apply CecDetectionEnable (used from v4l)
///
virtual void setCecDetectionEnable(bool enable) {}
///
/// @brief Apply device and videoStanded (used from v4l)
///
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {}
virtual bool setPixelDecimation(int pixelDecimation);
///
/// @brief Apply display index (used from qt)
///
virtual void setDisplayIndex(int index) {}
///
/// @brief Apply path for device (used from framebuffer)
///
virtual void setDevicePath(const QString& path) {}
///
/// @brief get current resulting height of image (after crop)
///
virtual int getImageWidth() { return _width; }
///
/// @brief get current resulting width of image (after crop)
///
virtual int getImageHeight() { return _height; }
virtual bool setDisplayIndex(int /*index*/) { return true; }
///
/// @brief Prevent the real capture implementation from capturing if disabled
///
void setEnabled(bool enable);
virtual void setEnabled(bool enable);
///
/// @brief Get a list of all available V4L devices
/// @return List of all available V4L devices on success else empty List
/// @brief get current resulting height of image (after crop)
///
virtual QStringList getV4L2devices() const { return QStringList(); }
int getImageWidth() const { return _width; }
///
/// @brief Get the V4L device name
/// @param devicePath The device path
/// @return The name of the V4L device on success else empty String
/// @brief get current resulting width of image (after crop)
///
virtual QString getV4L2deviceName(const QString& /*devicePath*/) const { return QString(); }
int getImageHeight() const { return _height; }
///
/// @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
/// @brief Get current capture framerate in Hz
/// @param fps framesPerSecond
///
virtual QMultiMap<QString, int> getV4L2deviceInputs(const QString& /*devicePath*/) const { return QMultiMap<QString, int>(); }
int getFramerate() const { return _fps; }
///
/// @brief Get a list of supported device resolutions
/// @param devicePath The device path
/// @return List of resolutions on success else empty List
/// @brief Get capture interval in ms
///
virtual QStringList getResolutions(const QString& /*devicePath*/) const { return QStringList(); }
int getUpdateInterval() const { return 1000/_fps; }
///
/// @brief Get a list of supported device framerates
/// @param devicePath The device path
/// @return List of framerates on success else empty List
/// @brief Get pixelDecimation
///
virtual QStringList getFramerates(const QString& devicePath) const { return QStringList(); }
int getPixelDecimation() const { return _pixelDecimation; }
QString getGrabberName() const { return _grabberName; }
protected slots:
///
/// @brief Set device in error state
///
/// @param[in] errorMsg The error message to be logged
///
virtual void setInError( const QString& errorMsg);
protected:
QString _grabberName;
/// logger instance
Logger * _log;
ImageResampler _imageResampler;
bool _useImageResampler;
/// the selected VideoMode
VideoMode _videoMode;
VideoMode _videoMode;
/// the used video standard
VideoStandard _videoStandard;
/// Image size decimation
int _pixelDecimation;
/// the used Flip Mode
FlipMode _flipMode;
/// With of the captured snapshot [pixels]
int _width;
@@ -166,15 +151,21 @@ protected:
/// frame per second
int _fps;
/// fps software decimation
int _fpsSoftwareDecimation;
/// device input
int _input;
/// number of pixels to crop after capturing
int _cropLeft, _cropRight, _cropTop, _cropBottom;
bool _enabled;
// Device states
/// logger instance
Logger * _log;
/// Is the device enabled?
bool _isEnabled;
/// Is the device in error state and stopped?
bool _isDeviceInError;
};

View File

@@ -12,30 +12,38 @@
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/VideoMode.h>
#include <utils/PixelFormat.h>
#include <utils/settings.h>
#include <utils/VideoStandard.h>
class Grabber;
class GlobalSignals;
class QTimer;
/// List of Hyperion instances that requested screen capt
static QList<int> GRABBER_SYS_CLIENTS;
static QList<int> GRABBER_V4L_CLIENTS;
///
/// This class will be inherted by FramebufferWrapper and others which contains the real capture interface
/// This class will be inherited by GrabberWrappers which contains the real capture interface
///
class GrabberWrapper : public QObject
{
Q_OBJECT
public:
GrabberWrapper(const QString& grabberName, Grabber * ggrabber, unsigned width, unsigned height, unsigned updateRate_Hz = 0);
GrabberWrapper(const QString& grabberName, Grabber * ggrabber,int updateRate_Hz = DEFAULT_RATE_HZ);
~GrabberWrapper() override;
static GrabberWrapper* instance;
static GrabberWrapper* getInstance(){ return instance; }
static const int DEFAULT_RATE_HZ;
static const int DEFAULT_MIN_GRAB_RATE_HZ;
static const int DEFAULT_MAX_GRAB_RATE_HZ;
static const int DEFAULT_PIXELDECIMATION;
static QMap<int, QString> GRABBER_SYS_CLIENTS;
static QMap<int, QString> GRABBER_V4L_CLIENTS;
static bool GLOBAL_GRABBER_SYS_ENABLE;
static bool GLOBAL_GRABBER_V4L_ENABLE;
///
/// Starts the grabber which produces led values with the specified update rate
///
@@ -56,45 +64,17 @@ public:
///
virtual bool isActive() const;
///
/// @brief Get a list of all available V4L devices
/// @return List of all available V4L devices on success else empty List
///
virtual QStringList getV4L2devices() const;
///
/// @brief Get the V4L device name
/// @param devicePath The device path
/// @return The name of the V4L device on success else empty String
///
virtual QString getV4L2deviceName(const QString& devicePath) const;
///
/// @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> getV4L2deviceInputs(const QString& devicePath) const;
///
/// @brief Get a list of supported device resolutions
/// @param devicePath The device path
/// @return List of resolutions on success else empty List
///
virtual QStringList getResolutions(const QString& devicePath) const;
///
/// @brief Get a list of supported device framerates
/// @param devicePath The device path
/// @return List of framerates on success else empty List
///
virtual QStringList getFramerates(const QString& devicePath) const;
///
/// @brief Get active grabber name
/// @return Active grabber name
/// @param hyperionInd The instance index
/// @return Active grabbers
///
virtual QString getActive() const;
virtual QStringList getActive(int inst) const;
bool getSysGrabberState() const { return GLOBAL_GRABBER_SYS_ENABLE; }
void setSysGrabberState(bool sysGrabberState){ GLOBAL_GRABBER_SYS_ENABLE = sysGrabberState; }
bool getV4lGrabberState() const { return GLOBAL_GRABBER_V4L_ENABLE; }
void setV4lGrabberState(bool v4lGrabberState){ GLOBAL_GRABBER_V4L_ENABLE = v4lGrabberState; }
static QStringList availableGrabbers();
@@ -130,6 +110,12 @@ public slots:
///
virtual void setVideoMode(VideoMode videoMode);
///
/// Set the Flip mode
/// @param flipMode The new flip mode
///
virtual void setFlipMode(const QString &flipMode);
///
/// Set the crop values
/// @param cropLeft Left pixel crop
@@ -137,11 +123,11 @@ public slots:
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
virtual void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
///
/// @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);
@@ -159,22 +145,38 @@ private slots:
///
/// @brief Update Update capture rate
/// @param type interval between frames in millisecons
/// @param type interval between frames in milliseconds
///
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 Logger instance
Logger * _log;
/// The timer for generating events with the specified update rate
QTimer* _timer;
/// The calced update rate [ms]
/// The calculated update rate [ms]
int _updateInterval_ms;
/// The Logger instance
Logger * _log;
Grabber *_ggrabber;
/// The image used for grabbing frames

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>
@@ -45,7 +46,9 @@ class ColorAdjustment;
class SettingsManager;
class BGEffectHandler;
class CaptureCont;
#if defined(ENABLE_BOBLIGHT)
class BoblightServer;
#endif
class LedDeviceWrapper;
class Logger;
@@ -98,7 +101,7 @@ public:
///
QString getActiveDeviceType() const;
bool getReadOnlyMode() {return _readOnlyMode; };
bool getReadOnlyMode() {return _readOnlyMode; }
public slots:
@@ -192,7 +195,7 @@ public slots:
bool clear(int priority, bool forceClearAll=false);
/// #############
// EFFECTENGINE
/// EFFECTENGINE
///
/// @brief Get a pointer to the effect engine
/// @return EffectEngine instance pointer
@@ -217,7 +220,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 +230,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 = ""
@@ -475,8 +478,11 @@ private slots:
///
void handleNewVideoMode(VideoMode mode) { _currVideoMode = mode; }
void handlePriorityChangedLedDevice(const quint8& priority);
///
/// @brief Handle the scenario when no/an input source is available
/// @param priority Current priority
///
void handleSourceAvailability(const quint8& priority);
private:
friend class HyperionDaemon;
@@ -541,8 +547,10 @@ private:
VideoMode _currVideoMode = VideoMode::VIDEO_2D;
#if defined(ENABLE_BOBLIGHT)
/// Boblight instance
BoblightServer* _boblightServer;
#endif
bool _readOnlyMode;
};

View File

@@ -102,6 +102,8 @@ public slots:
///
bool saveName(quint8 inst, const QString& name);
QString getRootPath() const { return _rootPath; }
signals:
///
/// @brief Emits whenever the state of a instance changes according to enum instanceState

View File

@@ -154,7 +154,7 @@ namespace hyperion
const unsigned _verticalBorder;
/// The absolute indices into the image for each led
std::vector<std::vector<unsigned>> _colorsMap;
std::vector<std::vector<int32_t>> _colorsMap;
///
/// Calculates the 'mean color' of the given list. This is the mean over each color-channel
@@ -166,7 +166,7 @@ namespace hyperion
/// @return The mean of the given list of colors (or black when empty)
///
template <typename Pixel_T>
ColorRgb calcMeanColor(const Image<Pixel_T> & image, const std::vector<unsigned> & colors) const
ColorRgb calcMeanColor(const Image<Pixel_T> & image, const std::vector<int32_t> & colors) const
{
const auto colorVecSize = colors.size();

View File

@@ -54,8 +54,14 @@ public:
QString owner;
};
//Foreground and Background priorities
const static int FG_PRIORITY;
const static int BG_PRIORITY;
const static int MANUAL_SELECTED_PRIORITY;
/// The lowest possible priority, which is used when no priority channels are active
const static int LOWEST_PRIORITY;
/// Timeout used to identify a non active priority
const static int TIMEOUT_NOT_ACTIVE_PRIO;
///
/// Constructs the PriorityMuxer for the given number of LEDs (used to switch to black when
@@ -81,7 +87,7 @@ public:
/// @param update True to update _currentPriority - INTERNAL usage.
/// @return True if changed has been applied, false if the state is unchanged
///
bool setSourceAutoSelectEnabled(bool enabel, bool update = true);
bool setSourceAutoSelectEnabled(bool enable, bool update = true);
///
/// @brief Get the state of source auto selection

View File

@@ -3,9 +3,14 @@
#include <utils/Logger.h>
#include <utils/settings.h>
#include <utils/version.hpp>
using namespace semver;
// qt includes
#include <QJsonObject>
const int GLOABL_INSTANCE_ID = 255;
class Hyperion;
class SettingsTable;
@@ -42,7 +47,7 @@ public:
/// @brief get the full settings object of this instance (with global settings)
/// @return The requested json
///
const QJsonObject & getSettings() const { return _qconfig; }
QJsonObject getSettings() const;
signals:
///
@@ -61,12 +66,17 @@ private:
bool handleConfigUpgrade(QJsonObject& config);
/// Hyperion instance
Hyperion* _hyperion;
bool resolveConfigVersion(QJsonObject& config);
/// Logger instance
Logger* _log;
/// Hyperion instance
Hyperion* _hyperion;
/// Instance number
quint8 _instance;
/// instance of database table interface
SettingsTable* _sTable;
@@ -76,5 +86,8 @@ private:
/// the current configuration of this instance
QJsonObject _qconfig;
semver::version _configVersion;
semver::version _previousVersion;
bool _readonlyMode;
};

View File

@@ -300,10 +300,21 @@ protected:
/// even if the device is not in enabled state (allowing to have a defined state during device power-off).
/// @note: latch-time is considered between each write
///
/// @param[in] numberOfWrites Write Black given number of times
/// @param[in] numberOfWrites Write Black a given number of times
/// @return Zero on success else negative
///
virtual int writeBlack(int numberOfBlack=1);
virtual int writeBlack(int numberOfWrites = 1);
///
/// @brief Writes a color to the output stream,
/// even if the device is not in enabled state (allowing to have a defined state during device power-off).
/// @note: latch-time is considered between each write
///
/// @param[in] color to be written
/// @param[in] numberOfWrites Write the color a given number of times
/// @return Zero on success else negative
///
virtual int writeColor(const ColorRgb& color, int numberOfWrites = 1);
///
/// @brief Power-/turn on the LED-device.

View File

@@ -1,6 +1,8 @@
#pragma once
#include <QString>
#include "HyperionConfig.h"
namespace hyperion
{
@@ -14,7 +16,9 @@ enum Components
COMP_SMOOTHING,
COMP_BLACKBORDER,
COMP_FORWARDER,
#if defined(ENABLE_BOBLIGHT)
COMP_BOBLIGHTSERVER,
#endif
COMP_GRABBER,
COMP_V4L,
COMP_COLOR,
@@ -33,7 +37,9 @@ inline const char* componentToString(Components c)
case COMP_SMOOTHING: return "Smoothing";
case COMP_BLACKBORDER: return "Blackborder detector";
case COMP_FORWARDER: return "Json/Proto forwarder";
#if defined(ENABLE_BOBLIGHT)
case COMP_BOBLIGHTSERVER:return "Boblight server";
#endif
case COMP_GRABBER: return "Framegrabber";
case COMP_V4L: return "V4L capture device";
case COMP_COLOR: return "Solid color";
@@ -54,7 +60,9 @@ inline const char* componentToIdString(Components c)
case COMP_SMOOTHING: return "SMOOTHING";
case COMP_BLACKBORDER: return "BLACKBORDER";
case COMP_FORWARDER: return "FORWARDER";
#if defined(ENABLE_BOBLIGHT)
case COMP_BOBLIGHTSERVER:return "BOBLIGHTSERVER";
#endif
case COMP_GRABBER: return "GRABBER";
case COMP_V4L: return "V4L";
case COMP_COLOR: return "COLOR";
@@ -74,7 +82,9 @@ inline Components stringToComponent(const QString& component)
if (cmp == "SMOOTHING") return COMP_SMOOTHING;
if (cmp == "BLACKBORDER") return COMP_BLACKBORDER;
if (cmp == "FORWARDER") return COMP_FORWARDER;
#if defined(ENABLE_BOBLIGHT)
if (cmp == "BOBLIGHTSERVER")return COMP_BOBLIGHTSERVER;
#endif
if (cmp == "GRABBER") return COMP_GRABBER;
if (cmp == "V4L") return COMP_V4L;
if (cmp == "COLOR") return COMP_COLOR;

View File

@@ -9,12 +9,13 @@ class ImageResampler
{
public:
ImageResampler();
~ImageResampler();
~ImageResampler() {}
void setHorizontalPixelDecimation(int decimator);
void setVerticalPixelDecimation(int decimator);
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
void setVideoMode(VideoMode mode);
void setVideoMode(VideoMode mode) { _videoMode = mode; }
void setFlipMode(FlipMode mode) { _flipMode = mode; }
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
private:
@@ -25,5 +26,6 @@ private:
int _cropTop;
int _cropBottom;
VideoMode _videoMode;
FlipMode _flipMode;
};

View File

@@ -12,7 +12,9 @@ enum class PixelFormat {
BGR24,
RGB32,
BGR32,
#ifdef HAVE_JPEG_DECODER
NV12,
I420,
#ifdef HAVE_TURBO_JPEG
MJPEG,
#endif
NO_CHANGE
@@ -23,32 +25,40 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
// convert to lower case
QString format = pixelFormat.toLower();
if (format.compare("yuyv") )
if (format.compare("yuyv") == 0)
{
return PixelFormat::YUYV;
}
else if (format.compare("uyvy") )
else if (format.compare("uyvy") == 0)
{
return PixelFormat::UYVY;
}
else if (format.compare("bgr16") )
else if (format.compare("bgr16") == 0)
{
return PixelFormat::BGR16;
}
else if (format.compare("bgr24") )
else if (format.compare("bgr24") == 0)
{
return PixelFormat::BGR24;
}
else if (format.compare("rgb32") )
else if (format.compare("rgb32") == 0)
{
return PixelFormat::RGB32;
}
else if (format.compare("bgr32") )
else if (format.compare("bgr32") == 0)
{
return PixelFormat::BGR32;
}
#ifdef HAVE_JPEG_DECODER
else if (format.compare("mjpeg") )
else if (format.compare("i420") == 0)
{
return PixelFormat::I420;
}
else if (format.compare("nv12") == 0)
{
return PixelFormat::NV12;
}
#ifdef HAVE_TURBO_JPEG
else if (format.compare("mjpeg") == 0)
{
return PixelFormat::MJPEG;
}
@@ -57,3 +67,102 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
// return the default NO_CHANGE
return PixelFormat::NO_CHANGE;
}
inline QString pixelFormatToString(const PixelFormat& pixelFormat)
{
if ( pixelFormat == PixelFormat::YUYV)
{
return "YUYV";
}
else if (pixelFormat == PixelFormat::UYVY)
{
return "UYVY";
}
else if (pixelFormat == PixelFormat::BGR16)
{
return "BGR16";
}
else if (pixelFormat == PixelFormat::BGR24)
{
return "BGR24";
}
else if (pixelFormat == PixelFormat::RGB32)
{
return "RGB32";
}
else if (pixelFormat == PixelFormat::BGR32)
{
return "BGR32";
}
else if (pixelFormat == PixelFormat::I420)
{
return "I420";
}
else if (pixelFormat == PixelFormat::NV12)
{
return "NV12";
}
#ifdef HAVE_TURBO_JPEG
else if (pixelFormat == PixelFormat::MJPEG)
{
return "MJPEG";
}
#endif
// return the default NO_CHANGE
return "NO_CHANGE";
}
/**
* Enumeration of the possible flip modes
*/
enum class FlipMode
{
HORIZONTAL,
VERTICAL,
BOTH,
NO_CHANGE
};
inline FlipMode parseFlipMode(const QString& flipMode)
{
// convert to lower case
QString mode = flipMode.toLower();
if (mode.compare("horizontal") == 0)
{
return FlipMode::HORIZONTAL;
}
else if (mode.compare("vertical") == 0)
{
return FlipMode::VERTICAL;
}
else if (mode.compare("both") == 0)
{
return FlipMode::BOTH;
}
// return the default NO_CHANGE
return FlipMode::NO_CHANGE;
}
inline QString flipModeToString(const FlipMode& flipMode)
{
if ( flipMode == FlipMode::HORIZONTAL)
{
return "horizontal";
}
else if (flipMode == FlipMode::VERTICAL)
{
return "vertical";
}
else if (flipMode == FlipMode::BOTH)
{
return "both";
}
// return the default NO_CHANGE
return "NO_CHANGE";
}

View File

@@ -21,12 +21,16 @@ public:
QString prettyName;
QString hostName;
QString domainName;
bool isUserAdmin;
QString qtVersion;
QString pyVersion;
};
static HyperionSysInfo get();
static bool isUserAdmin();
static QString userName();
private:
SysInfo();
void getCPUInfo();

View File

@@ -1,5 +1,7 @@
#pragma once
#include <QString>
/**
* Enumeration of the possible video standards the grabber can be set to
*/
@@ -13,17 +15,17 @@ enum class VideoStandard {
inline VideoStandard parseVideoStandard(const QString& videoStandard)
{
// convert to lower case
QString standard = videoStandard.toLower();
QString standard = videoStandard.toUpper();
if (standard == "pal")
if (standard == "PAL")
{
return VideoStandard::PAL;
}
else if (standard == "ntsc")
else if (standard == "NTSC")
{
return VideoStandard::NTSC;
}
else if (standard == "secam")
else if (standard == "SECAM")
{
return VideoStandard::SECAM;
}
@@ -31,3 +33,14 @@ inline VideoStandard parseVideoStandard(const QString& videoStandard)
// return the default NO_CHANGE
return VideoStandard::NO_CHANGE;
}
inline QString VideoStandard2String(VideoStandard videoStandard)
{
switch (videoStandard)
{
case VideoStandard::PAL: return "PAL";
case VideoStandard::NTSC: return "NTSC";
case VideoStandard::SECAM: return "SECAM";
default: return "NO_CHANGE";
}
}

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

@@ -1,4 +1,6 @@
#pragma once
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
typedef QList< int > QIntList;

View File

@@ -7,6 +7,8 @@
#include <hyperion/LedString.h>
// fg effect
#include <hyperion/Hyperion.h>
#include <hyperion/PriorityMuxer.h>
#include <effectengine/Effect.h>
///
/// @brief Provide utility methods for Hyperion class
@@ -16,8 +18,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
if (FGEffectConfig["enable"].toBool(true))
@@ -27,7 +27,7 @@ namespace hyperion {
const QJsonValue fgColorConfig = FGEffectConfig["color"];
int default_fg_duration_ms = 3000;
int fg_duration_ms = FGEffectConfig["duration_ms"].toInt(default_fg_duration_ms);
if (fg_duration_ms == DURATION_INFINITY)
if (fg_duration_ms <= Effect::ENDLESS)
{
fg_duration_ms = default_fg_duration_ms;
Warning(Logger::getInstance("HYPERION"), "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
@@ -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"));
}
}

550
include/utils/version.hpp Normal file
View File

@@ -0,0 +1,550 @@
#ifndef VERSION_H
#define VERSION_H
/**
* Semver - The Semantic Versioning, https://github.com/euskadi31/semver-cpp
*
* Copyright (c) 2013 Axel Etcheverry, 2021 enhancements & fixes Lord-Grey
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
namespace semver {
enum PRE_RELEASE {
PRE_RELEASE_ALPHA,
PRE_RELEASE_BETA,
PRE_RELEASE_RC,
PRE_RELEASE_NONE
};
typedef enum PRE_RELEASE pre_release_t;
class version
{
private:
std::string m_version;
int m_major;
int m_minor;
int m_patch;
pre_release_t m_pre_release_type;
std::string m_pre_release_id;
std::string m_pre_release;
std::string m_build;
bool m_is_valid;
bool m_is_stable;
enum m_type {
TYPE_MAJOR,
TYPE_MINOR,
TYPE_PATCH,
TYPE_PRE_RELEASE,
TYPE_PRE_RELEASE_ID,
TYPE_BUILD
};
void parse()
{
int type = TYPE_MAJOR;
std::string major, minor, patch;
for (std::size_t i = 0; i < m_version.length(); i++)
{
char chr = m_version[i];
int chr_dec = chr;
switch (type)
{
case TYPE_MAJOR:
if (chr == '.')
{
type = TYPE_MINOR;
continue;
}
if (chr_dec < 48 || chr_dec > 57)
{
m_is_valid = false;
}
// major
major += chr;
break;
case TYPE_MINOR:
if (chr == '.')
{
type = TYPE_PATCH;
continue;
}
if (chr_dec < 48 || chr_dec > 57)
{
m_is_valid = false;
}
minor += chr;
break;
case TYPE_PATCH:
if (chr == '-')
{
type = TYPE_PRE_RELEASE;
continue;
}
if (chr == '+')
{
type = TYPE_BUILD;
continue;
}
if (chr_dec < 48 || chr_dec > 57)
{
m_is_valid = false;
}
patch += chr;
break;
case TYPE_PRE_RELEASE:
if (chr == '.')
{
type = TYPE_PRE_RELEASE_ID;
m_pre_release += chr;
continue;
}
if (chr == '+')
{
type = TYPE_BUILD;
continue;
}
if (
(chr_dec < 48 || chr_dec > 57) && // 0-9
(chr_dec < 65 || chr_dec > 90) && // A-Z
(chr_dec < 97 || chr_dec > 122) && // a-z
(chr_dec != 45) && // -
(chr_dec != 46) // .
)
{
m_is_valid = false;
}
m_pre_release += chr;
break;
case TYPE_PRE_RELEASE_ID:
if (chr == '+')
{
type = TYPE_BUILD;
continue;
}
if (
(chr_dec < 48 || chr_dec > 57) && // 0-9
(chr_dec < 65 || chr_dec > 90) && // A-Z
(chr_dec < 97 || chr_dec > 122) && // a-z
(chr_dec != 45) // -
)
{
m_is_valid = false;
}
m_pre_release += chr;
m_pre_release_id += chr;
break;
case TYPE_BUILD:
if (
(chr_dec < 48 || chr_dec > 57) && // 0-9
(chr_dec < 65 || chr_dec > 90) && // A-Z
(chr_dec < 97 || chr_dec > 122) && // a-z
(chr_dec != 45) // -
)
{
m_is_valid = false;
}
m_build += chr;
break;
}
}
if (m_is_valid)
{
std::istringstream(major) >> m_major;
std::istringstream(minor) >> m_minor;
std::istringstream(patch) >> m_patch;
if (m_pre_release.empty())
{
m_pre_release_type = PRE_RELEASE_NONE;
}
else if (m_pre_release.find("alpha") != std::string::npos)
{
m_pre_release_type = PRE_RELEASE_ALPHA;
}
else if (m_pre_release.find("beta") != std::string::npos)
{
m_pre_release_type = PRE_RELEASE_BETA;
}
else if (m_pre_release.find("rc") != std::string::npos)
{
m_pre_release_type = PRE_RELEASE_RC;
}
if (m_major == 0 && m_minor == 0 && m_patch == 0)
{
m_is_valid = false;
}
if (!m_pre_release_id.empty() && m_pre_release_id[0] == '0')
{
m_is_valid = false;
}
if (m_major == 0)
{
m_is_stable = false;
}
if (m_pre_release_type != PRE_RELEASE_NONE)
{
m_is_stable = false;
}
}
}
public:
/**
* Parse the version string
*/
version(const std::string& version)
{
setVersion(version);
}
version(const version&) = default;
~version() = default;
/**
* Set version
*/
bool setVersion(const std::string& version)
{
m_version = version;
m_major = 0;
m_minor = 0;
m_patch = 0;
m_build = "";
m_pre_release = "";
m_pre_release_id = "";
m_is_stable = true;
if (version.empty())
{
m_is_valid = false;
}
else
{
m_is_valid = true;
parse();
}
return m_is_valid;
}
/**
* Get full version
*/
const std::string& getVersion() const
{
return m_version;
}
/**
* Get the major of the version
*/
const int& getMajor() const
{
return m_major;
}
/**
* Get the minor of the version
*/
const int& getMinor() const
{
return m_minor;
}
/**
* Get the patch of the version
*/
const int& getPatch() const
{
return m_patch;
}
/**
* Get the build of the version
*/
const std::string& getBuild() const
{
return m_build;
}
/**
* Get the release type of the version
*/
const pre_release_t& getPreReleaseType() const
{
return m_pre_release_type;
}
/**
* Get the release identifier of the version
*/
const std::string& getPreReleaseId() const
{
return m_pre_release_id;
}
/**
* Get the release of the version
*/
const std::string& getPreRelease() const
{
return m_pre_release;
}
/**
* Check if the version is stable
*/
const bool& isStable() const
{
return m_is_stable;
}
/**
* Check if the version is valid
*/
const bool& isValid() const
{
return m_is_valid;
}
int compare(version& rgt)
{
if ((*this) == rgt)
{
return 0;
}
if ((*this) > rgt)
{
return 1;
}
return -1;
}
version& operator= (version& rgt)
{
if ((*this) != rgt)
{
this->m_version = rgt.getVersion();
this->m_major = rgt.getMajor();
this->m_minor = rgt.getMinor();
this->m_patch = rgt.getPatch();
this->m_pre_release_type = rgt.getPreReleaseType();
this->m_pre_release_id = rgt.getPreReleaseId();
this->m_pre_release = rgt.getPreRelease();
this->m_build = rgt.getBuild();
this->m_is_valid = rgt.isValid();
this->m_is_stable = rgt.isStable();
}
return *this;
}
friend bool operator== (version &lft, version &rgt)
{
return !(lft != rgt);
}
friend bool operator!= (version &lft, version &rgt)
{
return (lft > rgt) || (lft < rgt);
}
friend bool operator> (version &lft, version &rgt)
{
// Major
if (lft.getMajor() < 0 && rgt.getMajor() >= 0)
{
return false;
}
if (lft.getMajor() >= 0 && rgt.getMajor() < 0)
{
return true;
}
if (lft.getMajor() > rgt.getMajor())
{
return true;
}
if (lft.getMajor() < rgt.getMajor())
{
return false;
}
// Minor
if (lft.getMinor() < 0 && rgt.getMinor() >= 0)
{
return false;
}
if (lft.getMinor() >= 0 && rgt.getMinor() < 0)
{
return true;
}
if (lft.getMinor() > rgt.getMinor())
{
return true;
}
if (lft.getMinor() < rgt.getMinor())
{
return false;
}
// Patch
if (lft.getPatch() < 0 && rgt.getPatch() >= 0)
{
return false;
}
if (lft.getPatch() >= 0 && rgt.getPatch() < 0)
{
return true;
}
if (lft.getPatch() > rgt.getPatch())
{
return true;
}
if (lft.getPatch() < rgt.getPatch())
{
return false;
}
// Pre release
if (
(lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
(lft.getPreReleaseId() == rgt.getPreReleaseId())
)
{
return false;
}
if (
(lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
(lft.getPreReleaseId().find_first_not_of("0123456789") == std::string::npos) &&
(rgt.getPreReleaseId().find_first_not_of("0123456789") == std::string::npos)
)
{
if (atoi(lft.getPreReleaseId().c_str()) > atoi(rgt.getPreReleaseId().c_str()))
{
return true;
}
else
{
return false;
}
}
if (
(lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
(lft.getPreReleaseId().compare(rgt.getPreReleaseId()) > 0)
)
{
return true;
}
if (lft.getPreReleaseType() > rgt.getPreReleaseType())
{
return true;
}
return false;
}
friend bool operator>= (version &lft, version &rgt)
{
return (lft > rgt) || (lft == rgt);
}
friend bool operator< (version &lft, version &rgt)
{
return (rgt > lft);
}
friend bool operator<= (version &lft, version &rgt)
{
return (lft < rgt) || (lft == rgt);
}
friend std::ostream& operator<< (std::ostream& out, const version& value)
{
out << value.getVersion();
return out;
}
};
} // end semver namespace
#endif // VERSION_H