diff --git a/effects/police-lights-single.json b/effects/police-lights-single.json new file mode 100644 index 00000000..9f171139 --- /dev/null +++ b/effects/police-lights-single.json @@ -0,0 +1,12 @@ +{ + "name" : "Police Lights Single", + "script" : "police.py", + "args" : + { + "rotation-time" : 1.5, + "color_one" : [ 255, 0, 0 ], + "color_two" : [ 0, 0, 255 ], + "colors_count" : 10, + "reverse" : false + } +} diff --git a/effects/police-lights-solid.json b/effects/police-lights-solid.json new file mode 100644 index 00000000..5eee1f58 --- /dev/null +++ b/effects/police-lights-solid.json @@ -0,0 +1,11 @@ +{ + "name" : "Police Lights Solid", + "script" : "police.py", + "args" : + { + "rotation-time" : 1.0, + "color_one" : [ 255, 0, 0 ], + "color_two" : [ 0, 0, 255 ], + "reverse" : false + } +} diff --git a/effects/police.py b/effects/police.py new file mode 100644 index 00000000..2f4133d2 --- /dev/null +++ b/effects/police.py @@ -0,0 +1,46 @@ +import hyperion +import time +import colorsys + +# Get the parameters +rotationTime = float(hyperion.args.get('rotation-time', 2.0)) +colorOne = hyperion.args.get('color_one', (255,0,0)) +colorTwo = hyperion.args.get('color_two', (0,0,255)) +colorsCount = hyperion.args.get('colors_count', hyperion.ledCount/2) +reverse = bool(hyperion.args.get('reverse', False)) + +# Check parameters +rotationTime = max(0.1, rotationTime) +colorsCount = min(hyperion.ledCount/2, colorsCount) + +# Initialize the led data +hsv1 = colorsys.rgb_to_hsv(colorOne[0]/255.0, colorOne[1]/255.0, colorOne[2]/255.0) +hsv2 = colorsys.rgb_to_hsv(colorTwo[0]/255.0, colorTwo[1]/255.0, colorTwo[2]/255.0) +colorBlack = (0,0,0) +ledData = bytearray() +for i in range(hyperion.ledCount): + if i <= colorsCount: + rgb = colorsys.hsv_to_rgb(hsv1[0], hsv1[1], hsv1[2]) + elif (i >= hyperion.ledCount/2-1) & (i < (hyperion.ledCount/2) + colorsCount): + rgb = colorsys.hsv_to_rgb(hsv2[0], hsv2[1], hsv2[2]) + else: + rgb = colorBlack + ledData += bytearray((int(255*rgb[0]), int(255*rgb[1]), int(255*rgb[2]))) + +# Calculate the sleep time and rotation increment +increment = 3 +sleepTime = rotationTime / hyperion.ledCount +while sleepTime < 0.05: + increment *= 2 + sleepTime *= 2 +increment %= hyperion.ledCount + +# Switch direction if needed +if reverse: + increment = -increment + +# Start the write data loop +while not hyperion.abort(): + hyperion.setColor(ledData) + ledData = ledData[-increment:] + ledData[:-increment] + time.sleep(sleepTime) diff --git a/include/grabber/X11Grabber.h b/include/grabber/X11Grabber.h index ee857b01..b35031cf 100644 --- a/include/grabber/X11Grabber.h +++ b/include/grabber/X11Grabber.h @@ -7,6 +7,11 @@ // X11 includes #include +#include +#include +#include +#include + class X11Grabber { public: @@ -16,6 +21,8 @@ public: virtual ~X11Grabber(); int open(); + + bool Setup(); Image & grab(); @@ -26,14 +33,24 @@ private: int _cropRight; int _cropTop; int _cropBottom; + + XImage* _xImage; + XShmSegmentInfo _shminfo; /// Reference to the X11 display (nullptr if not opened) - Display * _x11Display; + Display* _x11Display; + Window _window; + XWindowAttributes _windowAttr; unsigned _screenWidth; unsigned _screenHeight; + unsigned _croppedWidth; + unsigned _croppedHeight; Image _image; - + + void freeResources(); + void setupResources(); + int updateScreenDimensions(); }; diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index 0787e056..b051fe82 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -17,82 +17,116 @@ X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, _x11Display(nullptr), _screenWidth(0), _screenHeight(0), + _croppedWidth(0), + _croppedHeight(0), _image(0,0) { _imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation); _imageResampler.setVerticalPixelDecimation(verticalPixelDecimation); - _imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XGetImage + _imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage } X11Grabber::~X11Grabber() { if (_x11Display != nullptr) { + freeResources(); XCloseDisplay(_x11Display); } } -int X11Grabber::open() +void X11Grabber::freeResources() { - const char * display_name = nullptr; - _x11Display = XOpenDisplay(display_name); + // Cleanup allocated resources of the X11 grab + XShmDetach(_x11Display, &_shminfo); + XDestroyImage(_xImage); + shmdt(_shminfo.shmaddr); + shmctl(_shminfo.shmid, IPC_RMID, 0); +} +void X11Grabber::setupResources() +{ + _xImage = XShmCreateImage(_x11Display, _windowAttr.visual, + _windowAttr.depth, ZPixmap, NULL, &_shminfo, + _croppedWidth, _croppedHeight); + + _shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777); + _shminfo.shmaddr = _xImage->data = (char*)shmat(_shminfo.shmid,0,0); + _shminfo.readOnly = False; + + XShmAttach(_x11Display, &_shminfo); +} + +bool X11Grabber::Setup() +{ + _x11Display = XOpenDisplay(NULL); if (_x11Display == nullptr) { - std::cerr << "Failed to open the default X11-display" << std::endl; - return -1; - } + std::cerr << "Unable to open display"; + if (getenv("DISPLAY")) + std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl; + else + std::cerr << ". DISPLAY environment variable not set" << std::endl; + return false; + } + + _window = DefaultRootWindow(_x11Display); - return 0; -} + return true; + } Image & X11Grabber::grab() { - if (_x11Display == nullptr) - { - open(); - } - updateScreenDimensions(); - - const unsigned croppedWidth = _screenWidth - _cropLeft - _cropRight; - const unsigned croppedHeight = _screenHeight - _cropTop - _cropBottom; - - // Capture the current screen - XImage * xImage = XGetImage(_x11Display, DefaultRootWindow(_x11Display), _cropLeft, _cropTop, croppedWidth, croppedHeight, AllPlanes, ZPixmap); - if (xImage == nullptr) + + XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, 0x00FFFFFF); + if (_xImage == nullptr) { std::cerr << "Grab failed" << std::endl; return _image; } - _imageResampler.processImage(reinterpret_cast(xImage->data), xImage->width, xImage->height, xImage->bytes_per_line, PIXELFORMAT_BGR32, _image); - - // Cleanup allocated resources of the X11 grab - XDestroyImage(xImage); + _imageResampler.processImage(reinterpret_cast(_xImage->data), _xImage->width, _xImage->height, _xImage->bytes_per_line, PIXELFORMAT_BGR32, _image); return _image; } int X11Grabber::updateScreenDimensions() { - XWindowAttributes window_attributes_return; - const Status status = XGetWindowAttributes(_x11Display, DefaultRootWindow(_x11Display), &window_attributes_return); + const Status status = XGetWindowAttributes(_x11Display, _window, &_windowAttr); if (status == 0) { std::cerr << "Failed to obtain window attributes" << std::endl; return -1; } - if (_screenWidth == unsigned(window_attributes_return.width) && _screenHeight == unsigned(window_attributes_return.height)) + if (_screenWidth == unsigned(_windowAttr.width) && _screenHeight == unsigned(_windowAttr.height)) { // No update required return 0; } + std::cout << "Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => "; - _screenWidth = window_attributes_return.width; - _screenHeight = window_attributes_return.height; + + if (_screenWidth || _screenHeight) + freeResources(); + + _screenWidth = _windowAttr.width; + _screenHeight = _windowAttr.height; + std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl; + + if (_screenWidth > unsigned(_cropLeft + _cropRight)) + _croppedWidth = _screenWidth - _cropLeft - _cropRight; + else + _croppedWidth = _screenWidth; + + if (_screenHeight > unsigned(_cropTop + _cropBottom)) + _croppedHeight = _screenHeight - _cropTop - _cropBottom; + else + _croppedHeight = _screenHeight; + + setupResources(); return 0; } diff --git a/src/hyperion-x11/X11Wrapper.cpp b/src/hyperion-x11/X11Wrapper.cpp index 6f33cc61..a0489fdf 100644 --- a/src/hyperion-x11/X11Wrapper.cpp +++ b/src/hyperion-x11/X11Wrapper.cpp @@ -29,6 +29,11 @@ void X11Wrapper::stop() _timer.stop(); } +bool X11Wrapper::displayInit() +{ + return _grabber.Setup(); +} + void X11Wrapper::capture() { const Image & screenshot = _grabber.grab(); diff --git a/src/hyperion-x11/X11Wrapper.h b/src/hyperion-x11/X11Wrapper.h index 211dfe18..18fab407 100644 --- a/src/hyperion-x11/X11Wrapper.h +++ b/src/hyperion-x11/X11Wrapper.h @@ -19,6 +19,8 @@ public: void start(); void stop(); + + bool displayInit(); signals: void sig_screenshot(const Image & screenshot); diff --git a/src/hyperion-x11/hyperion-x11.cpp b/src/hyperion-x11/hyperion-x11.cpp index 449f3990..7815aa34 100644 --- a/src/hyperion-x11/hyperion-x11.cpp +++ b/src/hyperion-x11/hyperion-x11.cpp @@ -77,6 +77,9 @@ int main(int argc, char ** argv) argCropBottom.getValue(), argSizeDecimation.getValue(), // horizontal decimation argSizeDecimation.getValue()); // vertical decimation + + if (!x11Wrapper.displayInit()) + return -1; if (argScreenshot.isSet()) {