From 3fd20ec5fa2b425e75f1c9abc825b18ba4df4f16 Mon Sep 17 00:00:00 2001 From: Gamadril Date: Sat, 24 Jan 2015 23:42:22 +0100 Subject: [PATCH] - refactored framebuffer grabber to use ImageResampler - added OsxGrabber for OSX - added binary for imx6 (cubox-i) and updated install script Former-commit-id: 2c55e292c842c67e54ce36bd91e4f6303b98687a --- CMakeLists.txt | 15 +++ CompileHowto.txt | 4 + HyperionConfig.h.in | 3 + bin/install_hyperion.sh | 14 +- deploy/hyperion_imx6.tar.gz.REMOVED.git-id | 1 + include/grabber/FramebufferWrapper.h | 3 +- include/grabber/OsxWrapper.h | 95 ++++++++++++++ include/utils/PixelFormat.h | 10 ++ libsrc/grabber/CMakeLists.txt | 4 + .../framebuffer/FramebufferFrameGrabber.cpp | 121 ++++++++---------- .../framebuffer/FramebufferFrameGrabber.h | 12 +- libsrc/grabber/osx/CMakeLists.txt | 30 +++++ libsrc/grabber/osx/OsxFrameGrabber.cpp | 82 ++++++++++++ libsrc/grabber/osx/OsxFrameGrabber.h | 59 +++++++++ libsrc/grabber/osx/OsxWrapper.cpp | 79 ++++++++++++ libsrc/leddevice/LedDeviceTpm2.cpp | 4 - libsrc/leddevice/LedRs232Device.cpp | 1 - libsrc/utils/ImageResampler.cpp | 16 +++ src/hyperiond/CMakeLists.txt | 4 + src/hyperiond/hyperiond.cpp | 46 ++++++- 20 files changed, 514 insertions(+), 89 deletions(-) create mode 100644 deploy/hyperion_imx6.tar.gz.REMOVED.git-id create mode 100644 include/grabber/OsxWrapper.h create mode 100644 libsrc/grabber/osx/CMakeLists.txt create mode 100755 libsrc/grabber/osx/OsxFrameGrabber.cpp create mode 100644 libsrc/grabber/osx/OsxFrameGrabber.h create mode 100644 libsrc/grabber/osx/OsxWrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e500bc6..5a1eb223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,10 +35,21 @@ endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) option(ENABLE_FB "Enable the framebuffer grabber" OFF) message(STATUS "ENABLE_FB = " ${ENABLE_FB}) +option(ENABLE_OSX "Enable the osx grabber" OFF) +message(STATUS "ENABLE_OSX = " ${ENABLE_OSX}) + if(ENABLE_FB AND ENABLE_DISPMANX) message(FATAL_ERROR "dispmanx grabber and framebuffer grabber cannot be used at the same time") endif(ENABLE_FB AND ENABLE_DISPMANX) +if(ENABLE_FB AND ENABLE_OSX) + message(FATAL_ERROR "osx grabber and framebuffer grabber cannot be used at the same time") +endif(ENABLE_FB AND ENABLE_OSX) + +if(ENABLE_OSX AND ENABLE_DISPMANX) + message(FATAL_ERROR "dispmanx grabber and osx grabber cannot be used at the same time") +endif(ENABLE_OSX AND ENABLE_DISPMANX) + # Createt the configuration file # configure a header file to pass some of the CMake settings # to the source code @@ -89,6 +100,10 @@ if(NOT APPLE) link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) endif() +if(ENABLE_OSX) + set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics") +endif() + configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY) configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY) configure_file(config/hyperion_x86.config.json ${LIBRARY_OUTPUT_PATH} @ONLY) diff --git a/CompileHowto.txt b/CompileHowto.txt index 2ca29f71..df85dc5f 100644 --- a/CompileHowto.txt +++ b/CompileHowto.txt @@ -28,6 +28,10 @@ cmake .. cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_X11=ON .. # as an alternative for the dispmanx grabber on non-rpi devices (e.g. cubox-i) you could try the framebuffer grabber cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_FB=ON .. +# for OSX build you need XCode, qt4 libraries and cmake. You can use macport (homebrew might work too) to install them +sudo port install qt4-mac +sudo port install cmake +cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_V4L2=OFF -DENABLE_OSX=ON . # run make to build Hyperion make diff --git a/HyperionConfig.h.in b/HyperionConfig.h.in index ed1e6660..7644e7d6 100644 --- a/HyperionConfig.h.in +++ b/HyperionConfig.h.in @@ -21,3 +21,6 @@ // Define to enable the framebuffer grabber #cmakedefine ENABLE_FB +// Define to enable the osx grabber +#cmakedefine ENABLE_OSX + diff --git a/bin/install_hyperion.sh b/bin/install_hyperion.sh index f697c2f2..4d3e9a2c 100755 --- a/bin/install_hyperion.sh +++ b/bin/install_hyperion.sh @@ -10,6 +10,9 @@ IS_XBIAN=`cat /etc/issue | grep XBian | wc -l` IS_RASPBMC=`cat /etc/issue | grep Raspbmc | wc -l` IS_OPENELEC=`cat /etc/issue | grep -m 1 OpenELEC | wc -l` +# Find out if its an imx6 device +IS_IMX6=`cat /proc/cpuinfo | grep i.MX6 | wc -l` + # check which init script we should use USE_INITCTL=`which /sbin/initctl | wc -l` USE_SERVICE=`which /usr/sbin/service | wc -l` @@ -34,14 +37,21 @@ fi echo 'Downloading hyperion' if [ $IS_OPENELEC -eq 1 ]; then # OpenELEC has a readonly file system. Use alternative location +if [ $IS_IMX6 -eq 1 ]; then + curl -L --get https://raw.githubusercontent.com/tvdzwan/hyperion/master/deploy/hyperion_imx6.tar.gz | tar -C /storage -xz +else curl -L --get https://raw.githubusercontent.com/tvdzwan/hyperion/master/deploy/hyperion.tar.gz | tar -C /storage -xz +fi curl -L --get https://raw.githubusercontent.com/tvdzwan/hyperion/master/deploy/hyperion.deps.openelec-rpi.tar.gz | tar -C /storage/hyperion/bin -xz - # modify the default config to have a correct effect path sed -i 's:/opt:/storage:g' /storage/hyperion/config/hyperion.config.json +else +if [ $IS_IMX6 -eq 1 ]; then + wget https://raw.githubusercontent.com/tvdzwan/hyperion/master/deploy/hyperion_imx6.tar.gz -O - | tar -C /opt -xz else wget https://raw.githubusercontent.com/tvdzwan/hyperion/master/deploy/hyperion.tar.gz -O - | tar -C /opt -xz fi +fi # create links to the binaries if [ $IS_OPENELEC -ne 1 ]; then @@ -51,7 +61,7 @@ if [ $IS_OPENELEC -ne 1 ]; then fi # create link to the gpio changer (gpio->spi) -if [ $IS_RASPBMC -eq 1 ]; then +if [ $IS_RASPBMC -eq 1 ] && [ $IS_IMX6 -ne 1 ]; then ln -fs /opt/hyperion/bin/gpio2spi /usr/bin/gpio2spi fi diff --git a/deploy/hyperion_imx6.tar.gz.REMOVED.git-id b/deploy/hyperion_imx6.tar.gz.REMOVED.git-id new file mode 100644 index 00000000..e3383379 --- /dev/null +++ b/deploy/hyperion_imx6.tar.gz.REMOVED.git-id @@ -0,0 +1 @@ +12dce43d5b0f92cd013594f1b3d5045d5578de98 \ No newline at end of file diff --git a/include/grabber/FramebufferWrapper.h b/include/grabber/FramebufferWrapper.h index 26312c92..f633ae55 100644 --- a/include/grabber/FramebufferWrapper.h +++ b/include/grabber/FramebufferWrapper.h @@ -7,7 +7,6 @@ // Utils includes #include #include -#include #include #include @@ -81,7 +80,7 @@ private: QTimer _timer; /// The image used for grabbing frames - Image _image; + Image _image; /// The actual grabber FramebufferFrameGrabber * _frameGrabber; /// The processor for transforming images to led colors diff --git a/include/grabber/OsxWrapper.h b/include/grabber/OsxWrapper.h new file mode 100644 index 00000000..39ac1a7e --- /dev/null +++ b/include/grabber/OsxWrapper.h @@ -0,0 +1,95 @@ +#pragma once + +// QT includes +#include +#include + +// Utils includes +#include +#include +#include +#include +#include + +// Forward class declaration +class OsxFrameGrabber; +class Hyperion; +class ImageProcessor; + +/// +/// 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. +/// +class OsxWrapper: public QObject +{ + Q_OBJECT +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] hyperion The instance of Hyperion used to write the led values + /// + OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion); + + /// + /// Destructor of this osx frame grabber. Releases any claimed resources. + /// + virtual ~OsxWrapper(); + +public slots: + /// + /// Starts the grabber wich produces led values with the specified update rate + /// + void start(); + + /// + /// Performs a single frame grab and computes the led-colors + /// + void action(); + + /// + /// Stops the grabber + /// + void stop(); + + /// + /// Set the grabbing mode + /// @param[in] mode The new grabbing mode + /// + void setGrabbingMode(const GrabbingMode mode); + + /// + /// Set the video mode (2D/3D) + /// @param[in] mode The new video mode + /// + void setVideoMode(const VideoMode videoMode); + +private: + /// The update rate [Hz] + const int _updateInterval_ms; + /// The timeout of the led colors [ms] + const int _timeout_ms; + /// The priority of the led colors + const int _priority; + + /// The timer for generating events with the specified update rate + QTimer _timer; + + /// The image used for grabbing frames + Image _image; + /// The actual grabber + OsxFrameGrabber * _frameGrabber; + /// The processor for transforming images to led colors + ImageProcessor * _processor; + + /// The list with computed led colors + std::vector _ledColors; + + /// Pointer to Hyperion for writing led values + Hyperion * _hyperion; +}; diff --git a/include/utils/PixelFormat.h b/include/utils/PixelFormat.h index b269dfcb..3b56bdad 100644 --- a/include/utils/PixelFormat.h +++ b/include/utils/PixelFormat.h @@ -9,6 +9,8 @@ enum PixelFormat { PIXELFORMAT_YUYV, PIXELFORMAT_UYVY, + PIXELFORMAT_BGR16, + PIXELFORMAT_BGR24, PIXELFORMAT_RGB32, PIXELFORMAT_BGR32, PIXELFORMAT_NO_CHANGE @@ -27,6 +29,14 @@ inline PixelFormat parsePixelFormat(std::string pixelFormat) { return PIXELFORMAT_UYVY; } + else if (pixelFormat == "bgr16") + { + return PIXELFORMAT_BGR16; + } + else if (pixelFormat == "bgr24") + { + return PIXELFORMAT_BGR24; + } else if (pixelFormat == "rgb32") { return PIXELFORMAT_RGB32; diff --git a/libsrc/grabber/CMakeLists.txt b/libsrc/grabber/CMakeLists.txt index e86bee2b..fee4235f 100644 --- a/libsrc/grabber/CMakeLists.txt +++ b/libsrc/grabber/CMakeLists.txt @@ -13,3 +13,7 @@ endif (ENABLE_V4L2) if (ENABLE_X11) add_subdirectory(x11) endif() + +if (ENABLE_OSX) + add_subdirectory(osx) +endif() diff --git a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp index 3ab79ce1..98baf977 100755 --- a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp +++ b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp @@ -5,10 +5,8 @@ #include #include #include -#include // STL includes -#include #include // Local includes @@ -20,59 +18,48 @@ FramebufferFrameGrabber::FramebufferFrameGrabber(const std::string & device, con _fbDevice(device), _width(width), _height(height), - _xScale(1), - _yScale(1) + _imgResampler(new ImageResampler()) { int result; struct fb_var_screeninfo vinfo; // Check if the framebuffer device can be opened and display the current resolution _fbfd = open(_fbDevice.c_str(), O_RDONLY); - assert(_fbfd > 0); - - // get variable screen information - result = ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo); - assert(result == 0); - - std::cout << "Framebuffer opened with resolution: " << vinfo.xres << "x" << vinfo.yres << "@" << vinfo.bits_per_pixel << "bit" << std::endl; - - close(_fbfd); + if (_fbfd == 0) + { + std::cerr << "Error openning " << _fbDevice << std::endl; + } + else + { + // get variable screen information + result = ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo); + if (result != 0) + { + std::cerr << "Could not get screen information" << std::endl; + } + else + { + std::cout << "Framebuffer opened with resolution: " << vinfo.xres << "x" << vinfo.yres << "@" << vinfo.bits_per_pixel << "bit" << std::endl; + } + close(_fbfd); + } } FramebufferFrameGrabber::~FramebufferFrameGrabber() { + delete _imgResampler; } void FramebufferFrameGrabber::setVideoMode(const VideoMode videoMode) { - switch (videoMode) { - case VIDEO_3DSBS: - _xScale = 2; - _yScale = 1; - break; - case VIDEO_3DTAB: - _xScale = 1; - _yScale = 2; - break; - case VIDEO_2D: - default: - _xScale = 1; - _yScale = 1; - break; - } + _imgResampler->set3D(videoMode); } -void FramebufferFrameGrabber::grabFrame(Image & image) +void FramebufferFrameGrabber::grabFrame(Image & image) { struct fb_var_screeninfo vinfo; - unsigned capSize, px, py, index, bytesPerPixel; - float x_scale, y_scale; - - /* resize the given image if needed */ - if (image.width() != _width || image.height() != _height) - { - image.resize(_width, _height); - } + unsigned capSize, bytesPerPixel; + PixelFormat pixelFormat; /* Open the framebuffer device */ _fbfd = open(_fbDevice.c_str(), O_RDONLY); @@ -82,41 +69,37 @@ void FramebufferFrameGrabber::grabFrame(Image & image) bytesPerPixel = vinfo.bits_per_pixel / 8; capSize = vinfo.xres * vinfo.yres * bytesPerPixel; - + + if (vinfo.bits_per_pixel == 16) + { + pixelFormat = PIXELFORMAT_BGR16; + } + else if (vinfo.bits_per_pixel == 24) + { + pixelFormat = PIXELFORMAT_BGR24; + } + else if (vinfo.bits_per_pixel == 32) + { + pixelFormat = PIXELFORMAT_BGR32; + } + else + { + std::cerr << "Unknown pixel format: " << vinfo.bits_per_pixel << " bits per pixel" << std::endl; + close(_fbfd); + return; + } + /* map the device to memory */ _fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, _fbfd, 0); - /* nearest neighbor downscaling */ - x_scale = (vinfo.xres / float(_xScale)) / float(_width); - y_scale = (vinfo.yres / float(_yScale)) / float(_height); - - ColorRgba *pPixel = image.memptr(); - for (unsigned i=0; i < _height; i++) { - for (unsigned j=0; j < _width; j++) { - px = floor(j * x_scale); - py = floor(i * y_scale); - index = (py * vinfo.xres + px) * bytesPerPixel; - - if (vinfo.bits_per_pixel == 16) { - pPixel->blue = (_fbp[index] & 0x1f) << 3; - pPixel->green = (((_fbp[index + 1] & 0x7) << 3) | (_fbp[index] & 0xE0) >> 5) << 2; - pPixel->red = (_fbp[index + 1] & 0xF8); - pPixel->alpha = 255; - } else if(vinfo.bits_per_pixel == 24) { - pPixel->blue = _fbp[index]; - pPixel->green = _fbp[index + 1]; - pPixel->red = _fbp[index + 2]; - pPixel->alpha = 255; - } else if(vinfo.bits_per_pixel == 32) { - pPixel->blue = _fbp[index]; - pPixel->green = _fbp[index + 1]; - pPixel->red = _fbp[index + 2]; - pPixel->alpha = _fbp[index + 3]; - } - - pPixel++; - } - } + _imgResampler->setHorizontalPixelDecimation(vinfo.xres/_width); + _imgResampler->setVerticalPixelDecimation(vinfo.yres/_height); + _imgResampler->processImage(_fbp, + vinfo.xres, + vinfo.yres, + vinfo.xres * bytesPerPixel, + pixelFormat, + image); munmap(_fbp, capSize); close(_fbfd); diff --git a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.h b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.h index d6fe62e4..55cc3fe9 100644 --- a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.h +++ b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.h @@ -2,8 +2,9 @@ // Utils includes #include -#include +#include #include +#include /// /// The FramebufferFrameGrabber is used for creating snapshots of the display (screenshots) @@ -35,7 +36,7 @@ public: /// @param[out] image The snapped screenshot (should be initialized with correct width and /// height) /// - void grabFrame(Image & image); + void grabFrame(Image & image); private: /// Framebuffer file descriptor @@ -53,9 +54,6 @@ private: /// Height of the captured snapshot [pixels] const unsigned _height; - /// width scale factor for 3D image processing - float _xScale; - - /// height scale factor for 3D image processing - float _yScale; + /// Image resampler for downscaling the image + ImageResampler * _imgResampler; }; diff --git a/libsrc/grabber/osx/CMakeLists.txt b/libsrc/grabber/osx/CMakeLists.txt new file mode 100644 index 00000000..05c67b3b --- /dev/null +++ b/libsrc/grabber/osx/CMakeLists.txt @@ -0,0 +1,30 @@ +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/osx) + +# Group the headers that go through the MOC compiler +SET(OsxGrabberQT_HEADERS + ${CURRENT_HEADER_DIR}/OsxWrapper.h +) + +SET(OsxGrabberHEADERS + ${CURRENT_SOURCE_DIR}/OsxFrameGrabber.h +) + +SET(OsxGrabberSOURCES + ${CURRENT_SOURCE_DIR}/OsxWrapper.cpp + ${CURRENT_SOURCE_DIR}/OsxFrameGrabber.cpp +) + +QT4_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS}) + +add_library(osx-grabber + ${OsxGrabberHEADERS} + ${OsxGrabberQT_HEADERS} + ${OsxGrabberHEADERS_MOC} + ${OsxGrabberSOURCES} +) + +target_link_libraries(osx-grabber + hyperion + ${QT_LIBRARIES}) diff --git a/libsrc/grabber/osx/OsxFrameGrabber.cpp b/libsrc/grabber/osx/OsxFrameGrabber.cpp new file mode 100755 index 00000000..b6c7a2c9 --- /dev/null +++ b/libsrc/grabber/osx/OsxFrameGrabber.cpp @@ -0,0 +1,82 @@ +// STL includes +#include +#include + +// Local includes +#include "OsxFrameGrabber.h" + +OsxFrameGrabber::OsxFrameGrabber(const unsigned display, const unsigned width, const unsigned height) : + _screenIndex(display), + _width(width), + _height(height), + _imgResampler(new ImageResampler()) +{ + CGImageRef image; + CGDisplayCount displayCount; + CGDirectDisplayID displays[8]; + + // get list of displays + CGGetActiveDisplayList(8, displays, &displayCount); + if (_screenIndex + 1 > displayCount) + { + std::cerr << "OSX display with index " << _screenIndex << " is not available. Using main display" << std::endl; + _display = kCGDirectMainDisplay; + } else { + _display = displays[_screenIndex]; + } + + image = CGDisplayCreateImage(_display); + assert(image != NULL); + + std::cout << "OSX display opened with resolution: " << CGImageGetWidth(image) << "x" << CGImageGetHeight(image) << "@" << CGImageGetBitsPerPixel(image) << "bit" << std::endl; + + CGImageRelease(image); +} + +OsxFrameGrabber::~OsxFrameGrabber() +{ + delete _imgResampler; +} + +void OsxFrameGrabber::setVideoMode(const VideoMode videoMode) +{ + _imgResampler->set3D(videoMode); +} + +void OsxFrameGrabber::grabFrame(Image & image) +{ + CGImageRef dispImage; + CFDataRef imgData; + unsigned char * pImgData; + unsigned dspWidth, dspHeight; + + dispImage = CGDisplayCreateImage(_display); + + // dsiplay lost, use main + if (dispImage == NULL && _display) + { + dispImage = CGDisplayCreateImage(kCGDirectMainDisplay); + // no displays connected, return + if (dispImage == NULL) + { + std::cerr << "OSX no display connected..." << std::endl; + return; + } + } + imgData = CGDataProviderCopyData(CGImageGetDataProvider(dispImage)); + pImgData = (unsigned char*) CFDataGetBytePtr(imgData); + dspWidth = CGImageGetWidth(dispImage); + dspHeight = CGImageGetHeight(dispImage); + + _imgResampler->setHorizontalPixelDecimation(dspWidth/_width); + _imgResampler->setVerticalPixelDecimation(dspHeight/_height); + _imgResampler->processImage( pImgData, + dspWidth, + dspHeight, + CGImageGetBytesPerRow(dispImage), + PIXELFORMAT_BGR32, + image); + + CFRelease(imgData); + CGImageRelease(dispImage); +} diff --git a/libsrc/grabber/osx/OsxFrameGrabber.h b/libsrc/grabber/osx/OsxFrameGrabber.h new file mode 100644 index 00000000..f0815584 --- /dev/null +++ b/libsrc/grabber/osx/OsxFrameGrabber.h @@ -0,0 +1,59 @@ +#pragma once + +// OSX includes +#include + +// Utils includes +#include +#include +#include +#include + +/// +/// The OsxFrameGrabber is used for creating snapshots of the display (screenshots) +/// +class OsxFrameGrabber +{ +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(const unsigned display, const unsigned width, const unsigned height); + ~OsxFrameGrabber(); + + /// + /// Set the video mode (2D/3D) + /// @param[in] mode The new video mode + /// + void setVideoMode(const VideoMode videoMode); + + /// + /// 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) + /// + /// @param[out] image The snapped screenshot (should be initialized with correct width and + /// height) + /// + void grabFrame(Image & image); + +private: + /// display + const unsigned _screenIndex; + + /// With of the captured snapshot [pixels] + const unsigned _width; + + /// Height of the captured snapshot [pixels] + const unsigned _height; + + /// Reference to the captured diaplay + CGDirectDisplayID _display; + + /// Image resampler for downscaling the image + ImageResampler * _imgResampler; +}; diff --git a/libsrc/grabber/osx/OsxWrapper.cpp b/libsrc/grabber/osx/OsxWrapper.cpp new file mode 100644 index 00000000..6d6f9a00 --- /dev/null +++ b/libsrc/grabber/osx/OsxWrapper.cpp @@ -0,0 +1,79 @@ +// Hyperion includes +#include +#include +#include + +// Osx grabber includes +#include +#include "OsxFrameGrabber.h" + +OsxWrapper::OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) : + _updateInterval_ms(1000/updateRate_Hz), + _timeout_ms(2 * _updateInterval_ms), + _priority(1000), + _timer(), + _image(grabWidth, grabHeight), + _frameGrabber(new OsxFrameGrabber(display, grabWidth, grabHeight)), + _processor(ImageProcessorFactory::getInstance().newImageProcessor()), + _ledColors(hyperion->getLedCount(), ColorRgb{0,0,0}), + _hyperion(hyperion) +{ + // Configure the timer to generate events every n milliseconds + _timer.setInterval(_updateInterval_ms); + _timer.setSingleShot(false); + + _processor->setSize(grabWidth, grabHeight); + + // Connect the QTimer to this + QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(action())); +} + +OsxWrapper::~OsxWrapper() +{ + // Cleanup used resources (ImageProcessor and FrameGrabber) + delete _processor; + delete _frameGrabber; +} + +void OsxWrapper::start() +{ + // Start the timer with the pre configured interval + _timer.start(); +} + +void OsxWrapper::action() +{ + // Grab frame into the allocated image + _frameGrabber->grabFrame(_image); + + _processor->process(_image, _ledColors); + + _hyperion->setColors(_priority, _ledColors, _timeout_ms); +} +void OsxWrapper::stop() +{ + // Stop the timer, effectivly stopping the process + _timer.stop(); +} + +void OsxWrapper::setGrabbingMode(const GrabbingMode mode) +{ + switch (mode) + { + case GRABBINGMODE_VIDEO: + case GRABBINGMODE_AUDIO: + case GRABBINGMODE_PHOTO: + case GRABBINGMODE_MENU: + case GRABBINGMODE_INVALID: + start(); + break; + case GRABBINGMODE_OFF: + stop(); + break; + } +} + +void OsxWrapper::setVideoMode(const VideoMode mode) +{ + _frameGrabber->setVideoMode(mode); +} diff --git a/libsrc/leddevice/LedDeviceTpm2.cpp b/libsrc/leddevice/LedDeviceTpm2.cpp index a0fcf869..c865ef96 100644 --- a/libsrc/leddevice/LedDeviceTpm2.cpp +++ b/libsrc/leddevice/LedDeviceTpm2.cpp @@ -4,10 +4,6 @@ #include #include -// Linux includes -#include -#include - // hyperion local includes #include "LedDeviceTpm2.h" diff --git a/libsrc/leddevice/LedRs232Device.cpp b/libsrc/leddevice/LedRs232Device.cpp index a4b058d2..3a88bb76 100644 --- a/libsrc/leddevice/LedRs232Device.cpp +++ b/libsrc/leddevice/LedRs232Device.cpp @@ -1,7 +1,6 @@ // STL includes #include -#include #include // Qt includes diff --git a/libsrc/utils/ImageResampler.cpp b/libsrc/utils/ImageResampler.cpp index d66ca742..bf4984dc 100644 --- a/libsrc/utils/ImageResampler.cpp +++ b/libsrc/utils/ImageResampler.cpp @@ -91,6 +91,22 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue); } break; + case PIXELFORMAT_BGR16: + { + int index = lineLength * ySource + xSource * 2; + rgb.blue = (data[index] & 0x1f) << 3; + rgb.green = (((data[index+1] & 0x7) << 3) | (data[index] & 0xE0) >> 5) << 2; + rgb.red = (data[index+1] & 0xF8); + } + break; + case PIXELFORMAT_BGR24: + { + int index = lineLength * ySource + xSource * 3; + rgb.blue = data[index ]; + rgb.green = data[index+1]; + rgb.red = data[index+2]; + } + break; case PIXELFORMAT_RGB32: { int index = lineLength * ySource + xSource * 4; diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index d3c859fb..9f4f1188 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -18,6 +18,10 @@ if (ENABLE_FB) target_link_libraries(hyperiond framebuffer-grabber) endif (ENABLE_FB) +if (ENABLE_OSX) + target_link_libraries(hyperiond osx-grabber) +endif (ENABLE_OSX) + if (ENABLE_V4L2) target_link_libraries(hyperiond v4l2-grabber) endif (ENABLE_V4L2) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index cf65db9a..7c89c94e 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -31,6 +31,11 @@ #include #endif +#ifdef ENABLE_OSX +// OSX grabber includes +#include +#endif + // XBMC Video checker includes #include @@ -187,7 +192,7 @@ int main(int argc, char** argv) std::cout << "Frame grabber created and started" << std::endl; } #else -#ifndef ENABLE_FB +#if !defined(ENABLE_OSX) && !defined(ENABLE_FB) if (config.isMember("framegrabber")) { std::cerr << "The dispmanx framegrabber can not be instantiated, becuse it has been left out from the build" << std::endl; @@ -238,7 +243,6 @@ int main(int argc, char** argv) if (config.isMember("framegrabber")) { const Json::Value & grabberConfig = config["framegrabber"]; - // TODO get device from config fbGrabber = new FramebufferWrapper( grabberConfig.get("device", "/dev/fb0").asString(), grabberConfig["width"].asUInt(), @@ -256,13 +260,44 @@ int main(int argc, char** argv) std::cout << "Framebuffer grabber created and started" << std::endl; } #else -#ifndef ENABLE_DISPMANX +#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) if (config.isMember("framegrabber")) { std::cerr << "The framebuffer grabber can not be instantiated, becuse it has been left out from the build" << std::endl; } #endif -#endif +#endif + +#ifdef ENABLE_OSX + // Construct and start the osx grabber if the configuration is present + OsxWrapper * osxGrabber = nullptr; + if (config.isMember("framegrabber")) + { + const Json::Value & grabberConfig = config["framegrabber"]; + osxGrabber = new OsxWrapper( + grabberConfig.get("display", 0).asUInt(), + grabberConfig["width"].asUInt(), + grabberConfig["height"].asUInt(), + grabberConfig["frequency_Hz"].asUInt(), + &hyperion); + + if (xbmcVideoChecker != nullptr) + { + QObject::connect(xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), osxGrabber, SLOT(setGrabbingMode(GrabbingMode))); + QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), osxGrabber, SLOT(setVideoMode(VideoMode))); + } + + osxGrabber->start(); + std::cout << "OSX grabber created and started" << std::endl; + } +#else +#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_FB) + if (config.isMember("framegrabber")) + { + std::cerr << "The osx grabber can not be instantiated, becuse it has been left out from the build" << std::endl; + } +#endif +#endif // Create Json server if configuration is present JsonServer * jsonServer = nullptr; @@ -304,6 +339,9 @@ int main(int argc, char** argv) #ifdef ENABLE_FB delete fbGrabber; #endif +#ifdef ENABLE_OSX + delete osxGrabber; +#endif #ifdef ENABLE_V4L2 delete v4l2Grabber; #endif