diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a1eb223..5b89af70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,37 +7,40 @@ cmake_minimum_required(VERSION 2.8) #set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake) # set the build options +option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" OFF) +message(STATUS "ENABLE_AMLOGIC = " ${ENABLE_AMLOGIC}) + option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ON) message(STATUS "ENABLE_DISPMANX = " ${ENABLE_DISPMANX}) -option(ENABLE_SPIDEV "Enable the SPIDEV device" ON) -message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV}) - -option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" OFF) -message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM}) - -option(ENABLE_V4L2 "Enable the V4L2 grabber" ON) -message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2}) - -option(ENABLE_X11 "Enable the X11 grabber" OFF) -message(STATUS "ENABLE_X11 = " ${ENABLE_X11}) - -option(ENABLE_TINKERFORGE "Enable the TINKERFORGE device" ON) -message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE}) - -option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON) -message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF}) - -if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) - message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF") -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}) +option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON) +message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF}) + +option(ENABLE_SPIDEV "Enable the SPIDEV device" ON) +message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV}) + +option(ENABLE_TINKERFORGE "Enable the TINKERFORGE device" ON) +message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE}) + +option(ENABLE_V4L2 "Enable the V4L2 grabber" ON) +message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2}) + +option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" OFF) +message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM}) + +option(ENABLE_X11 "Enable the X11 grabber" OFF) +message(STATUS "ENABLE_X11 = " ${ENABLE_X11}) + +if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) + message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF") +endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) + 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) @@ -89,10 +92,6 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED QUIET) find_package(libusb-1.0 REQUIRED) find_package(Threads REQUIRED) -if (ENABLE_TINKERFORGE) - #find_package(libtinkerforge-1.0 REQUIRED) -endif (ENABLE_TINKERFORGE) - include(${QT_USE_FILE}) add_definitions(${QT_DEFINITIONS}) # TODO[TvdZ]: This linking directory should only be added if we are cross compiling diff --git a/HyperionConfig.h.in b/HyperionConfig.h.in index 7644e7d6..f5bd3ce1 100644 --- a/HyperionConfig.h.in +++ b/HyperionConfig.h.in @@ -21,6 +21,9 @@ // Define to enable the framebuffer grabber #cmakedefine ENABLE_FB +// Define to enable the amlogic grabber +#cmakedefine ENABLE_AMLOGIC + // Define to enable the osx grabber #cmakedefine ENABLE_OSX diff --git a/include/grabber/AmlogicWrapper.h b/include/grabber/AmlogicWrapper.h new file mode 100644 index 00000000..0ce70b80 --- /dev/null +++ b/include/grabber/AmlogicWrapper.h @@ -0,0 +1,94 @@ +#pragma once + +// QT includes +#include +#include + +// Utils includes +#include +#include +#include +#include +#include + +// Forward class declaration +class AmlogicGrabber; +class Hyperion; +class ImageProcessor; + +/// +/// 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 +/// attached Hyperion. +/// +class AmlogicWrapper : public QObject +{ + Q_OBJECT +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] updateRate_Hz The image grab rate [Hz] + /// @param[in] hyperion The instance of Hyperion used to write the led values + /// + AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion); + + /// + /// Destructor of this dispmanx frame grabber. Releases any claimed resources. + /// + virtual ~AmlogicWrapper(); + +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 + AmlogicGrabber * _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/ColorBgr.h b/include/utils/ColorBgr.h new file mode 100644 index 00000000..a92e1270 --- /dev/null +++ b/include/utils/ColorBgr.h @@ -0,0 +1,63 @@ +#pragma once + +// STL includes +#include +#include + +struct ColorBgr; + +/// +/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the +/// structure is exactly 3-bytes for easy writing to led-device +/// +struct ColorBgr +{ + /// The blue color channel + uint8_t blue; + /// The green color channel + uint8_t green; + /// The red color channel + uint8_t red; + + /// 'Black' RgbColor (0, 0, 0) + static ColorBgr BLACK; + /// 'Red' RgbColor (255, 0, 0) + static ColorBgr RED; + /// 'Green' RgbColor (0, 255, 0) + static ColorBgr GREEN; + /// 'Blue' RgbColor (0, 0, 255) + static ColorBgr BLUE; + /// 'Yellow' RgbColor (255, 255, 0) + static ColorBgr YELLOW; + /// 'White' RgbColor (255, 255, 255) + static ColorBgr WHITE; +}; + +/// Assert to ensure that the size of the structure is 'only' 3 bytes +static_assert(sizeof(ColorBgr) == 3, "Incorrect size of ColorRgb"); + +/// +/// Stream operator to write ColorRgb to an outputstream (format "'{'[red]','[green]','[blue]'}'") +/// +/// @param os The output stream +/// @param color The color to write +/// @return The output stream (with the color written to it) +/// +inline std::ostream& operator<<(std::ostream& os, const ColorBgr& color) +{ + os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}"; + return os; +} + + +/// Compare operator to check if a color is 'smaller' than another color +inline bool operator<(const ColorBgr & lhs, const ColorBgr & rhs) +{ + return (lhs.red < rhs.red) && (lhs.green < rhs.green) && (lhs.blue < rhs.blue); +} + +/// Compare operator to check if a color is 'smaller' than or 'equal' to another color +inline bool operator<=(const ColorBgr & lhs, const ColorBgr & rhs) +{ + return (lhs.red <= rhs.red) && (lhs.green <= rhs.green) && (lhs.blue <= rhs.blue); +} diff --git a/libsrc/grabber/CMakeLists.txt b/libsrc/grabber/CMakeLists.txt index fee4235f..bb35f046 100644 --- a/libsrc/grabber/CMakeLists.txt +++ b/libsrc/grabber/CMakeLists.txt @@ -1,3 +1,7 @@ +if (ENABLE_AMLOGIC) + add_subdirectory(amlogic) +endif (ENABLE_AMLOGIC) + if (ENABLE_DISPMANX) add_subdirectory(dispmanx) endif (ENABLE_DISPMANX) @@ -6,6 +10,10 @@ if (ENABLE_FB) add_subdirectory(framebuffer) endif (ENABLE_FB) +if (ENABLE_OSX) + add_subdirectory(osx) +endif() + if (ENABLE_V4L2) add_subdirectory(v4l2) endif (ENABLE_V4L2) @@ -13,7 +21,3 @@ endif (ENABLE_V4L2) if (ENABLE_X11) add_subdirectory(x11) endif() - -if (ENABLE_OSX) - add_subdirectory(osx) -endif() diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.cpp b/libsrc/grabber/amlogic/AmlogicGrabber.cpp new file mode 100644 index 00000000..dd727217 --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicGrabber.cpp @@ -0,0 +1,150 @@ + +// STL includes +#include +#include +#include + +// Linux includes +#include +#include +#include +#include +#include +#include + +// Local includes +#include "AmlogicGrabber.h" + +// Flags copied from 'include/linux/amlogic/amports/amvideocap.h' at https://github.com/codesnake/linux-amlogic +#define AMVIDEOCAP_IOC_MAGIC 'V' +#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int) +#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int) + +// Flags copied from 'include/linux/amlogic/amports/amvstream.h' at https://github.com/codesnake/linux-amlogic +#define AMSTREAM_IOC_MAGIC 'S' +#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR(AMSTREAM_IOC_MAGIC, 0x48, unsigned long) + +AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height) : + // Minimum required width or height is 160 + _width(std::max(160u, width)), + _height(std::max(160u, height)), + _amlogicCaptureDev(-1) +{ + std::cout << "[" << __PRETTY_FUNCTION__ << "] constructed(" << _width << "x" << _height << ")" << std::endl; +} + +AmlogicGrabber::~AmlogicGrabber() +{ + if (_amlogicCaptureDev != -1) + { + if (close(_amlogicCaptureDev) == -1) + { + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Failed to close AMLOGIC device (" << errno << ")" << std::endl; + } + _amlogicCaptureDev = -1; + } +} + +void AmlogicGrabber::setVideoMode(const VideoMode videoMode) +{ + switch (videoMode) { + case VIDEO_3DSBS: + //vc_dispmanx_rect_set(&_rectangle, 0, 0, _width/2, _height); + break; + case VIDEO_3DTAB: + //vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height/2); + break; + case VIDEO_2D: + default: + //vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height); + break; + } +} + +bool AmlogicGrabber::isVideoPlaying() +{ + const std::string videoDevice = "/dev/amvideo"; + + // Open the video device + int video_fd = open(videoDevice.c_str(), O_RDONLY); + if (video_fd < 0) + { + std::cerr << "Failed to open video device(" << videoDevice << "): " << strerror(errno) << std::endl; + return false; + } + + // Check the video disabled flag + int videoDisabled; + if (ioctl(video_fd, AMSTREAM_IOC_GET_VIDEO_DISABLE, &videoDisabled) == -1) + { + std::cerr << "Failed to retrieve video state from device: " << strerror(errno) << std::endl; + close(video_fd); + return false; + } + + // Make sure to close the device after use + close(video_fd); + + return videoDisabled == 0; +} + +int AmlogicGrabber::grabFrame(Image & image) +{ + // resize the given image if needed + if (image.width() != _width || image.height() != _height) + { + image.resize(_width, _height); + } + + // Make sure video is playing, else there is nothing to grab + if (!isVideoPlaying()) + { + return -1; + } + + + // If the device is not open, attempt to open it + if (_amlogicCaptureDev == -1) + { + _amlogicCaptureDev = open("/dev/amvideocap0", O_RDONLY, 0); + + // If the device is still not open, there is something wrong + if (_amlogicCaptureDev == -1) + { + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Failed to open the AMLOGIC device (" << errno << "): " << strerror(errno) << std::endl; + return -1; + } + } + + + if (ioctl(_amlogicCaptureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, _width) == -1 || + ioctl(_amlogicCaptureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, _height) == -1) + { + // Failed to configure frame width + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Failed to configure capture size (" << errno << "): " << strerror(errno) << std::endl; + return -1; + } + + // Read the snapshot into the memory + void * image_ptr = image.memptr(); + const ssize_t bytesToRead = _width * _height * sizeof(ColorBgr); + + const ssize_t bytesRead = pread(_amlogicCaptureDev, image_ptr, bytesToRead, 0); + if (bytesRead == -1) + { + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Read of device failed (erno=" << errno << "): " << strerror(errno) << std::endl; + return -1; + } + else if (bytesToRead != bytesRead) + { + // Read of snapshot failed + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Capture failed to grab entire image [bytesToRead(" << bytesToRead << ") != bytesRead(" << bytesRead << ")]" << std::endl; + return -1; + } + + // For now we always close the device again + close(_amlogicCaptureDev); + _amlogicCaptureDev = -1; + + return 0; +} diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.h b/libsrc/grabber/amlogic/AmlogicGrabber.h new file mode 100644 index 00000000..05694853 --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicGrabber.h @@ -0,0 +1,58 @@ +#pragma once + +// STL includes +#include + +// Utils includes +#include +#include +#include + +/// +/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a +/// downsized and scaled resolution. +/// +class AmlogicGrabber +{ +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(const unsigned width, const unsigned height); + ~AmlogicGrabber(); + + /// + /// 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) + /// @return Zero on success else negative + /// + int grabFrame(Image & image); + + /** + * Returns true if video is playing over the amlogic chip + * @return True if video is playing else false + */ + bool isVideoPlaying(); +private: + + /// With of the captured snapshot [pixels] + const unsigned _width; + /// Height of the captured snapshot [pixels] + const unsigned _height; + + /** The snapshot/capture device of the amlogic video chip */ + int _amlogicCaptureDev; +}; diff --git a/libsrc/grabber/amlogic/AmlogicWrapper.cpp b/libsrc/grabber/amlogic/AmlogicWrapper.cpp new file mode 100644 index 00000000..1dca6764 --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicWrapper.cpp @@ -0,0 +1,93 @@ +// QT includes +#include +#include + +// Hyperion includes +#include +#include +#include + +// Amlogic grabber includes +#include +#include "AmlogicGrabber.h" + + +AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) : + _updateInterval_ms(1000/updateRate_Hz), + _timeout_ms(2 * _updateInterval_ms), + _priority(999), + _timer(), + _image(grabWidth, grabHeight), + _frameGrabber(new AmlogicGrabber(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())); +} + +AmlogicWrapper::~AmlogicWrapper() +{ + // Cleanup used resources (ImageProcessor and FrameGrabber) + delete _processor; + delete _frameGrabber; +} + +void AmlogicWrapper::start() +{ + // Start the timer with the pre configured interval + _timer.start(); +} + +void AmlogicWrapper::action() +{ + // Grab frame into the allocated image + if (_frameGrabber->grabFrame(_image) < 0) + { + // Frame grab failed, maybe nothing playing or .... + return; + } + + _processor->process(_image, _ledColors); + + _hyperion->setColors(_priority, _ledColors, _timeout_ms); +} + +void AmlogicWrapper::stop() +{ + // Stop the timer, effectivly stopping the process + _timer.stop(); +} + +void AmlogicWrapper::setGrabbingMode(const GrabbingMode mode) +{ + switch (mode) + { + case GRABBINGMODE_VIDEO: +// _frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL); + start(); + break; + case GRABBINGMODE_AUDIO: + case GRABBINGMODE_PHOTO: + case GRABBINGMODE_MENU: + case GRABBINGMODE_INVALID: +// _frameGrabber->setFlags(0); + start(); + break; + case GRABBINGMODE_OFF: + stop(); + break; + } +} + +void AmlogicWrapper::setVideoMode(const VideoMode mode) +{ + _frameGrabber->setVideoMode(mode); +} diff --git a/libsrc/grabber/amlogic/CMakeLists.txt b/libsrc/grabber/amlogic/CMakeLists.txt new file mode 100644 index 00000000..447a873d --- /dev/null +++ b/libsrc/grabber/amlogic/CMakeLists.txt @@ -0,0 +1,29 @@ + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic) + +# Group the headers that go through the MOC compiler +SET(AmlogicQT_HEADERS ${CURRENT_HEADER_DIR}/AmlogicWrapper.h) + +SET(AmlogicHEADERS + ${CURRENT_SOURCE_DIR}/AmlogicGrabber.h +) + +SET(AmlogicSOURCES + ${CURRENT_SOURCE_DIR}/AmlogicWrapper.cpp + ${CURRENT_SOURCE_DIR}/AmlogicGrabber.cpp +) + +QT4_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS}) + +add_library(amlogic-grabber + ${AmlogicHEADERS} + ${AmlogicQT_HEADERS} + ${AmlogicHEADERS_MOC} + ${AmlogicSOURCES} +) + +target_link_libraries(amlogic-grabber + hyperion + ${QT_LIBRARIES}) diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 5549ce74..1aad10cb 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -6,6 +6,8 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils) add_library(hyperion-utils ${CURRENT_HEADER_DIR}/ColorArgb.h ${CURRENT_SOURCE_DIR}/ColorArgb.cpp + ${CURRENT_HEADER_DIR}/ColorBgr.h + ${CURRENT_SOURCE_DIR}/ColorBgr.cpp ${CURRENT_HEADER_DIR}/ColorRgb.h ${CURRENT_SOURCE_DIR}/ColorRgb.cpp ${CURRENT_HEADER_DIR}/ColorRgba.h diff --git a/libsrc/utils/ColorBgr.cpp b/libsrc/utils/ColorBgr.cpp new file mode 100644 index 00000000..3167925e --- /dev/null +++ b/libsrc/utils/ColorBgr.cpp @@ -0,0 +1,11 @@ + +// Local includes +#include + +ColorBgr ColorBgr::BLACK = { 0, 0, 0 }; +ColorBgr ColorBgr::RED = { 0, 0, 255 }; +ColorBgr ColorBgr::GREEN = { 0, 255, 0 }; +ColorBgr ColorBgr::BLUE = { 255, 0, 0 }; +ColorBgr ColorBgr::YELLOW= { 0, 255, 255 }; +ColorBgr ColorBgr::WHITE = { 255, 255, 255 }; + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 098a08d3..2a291850 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,13 +3,16 @@ add_subdirectory(hyperion-remote) # The following clients depend on the protobuf library if(ENABLE_PROTOBUF) - # Add the 'Video 4 Linux' grabber if it is enabled - if(ENABLE_V4L2) - add_subdirectory(hyperion-v4l2) - endif() + if (ENABLE_AMLOGIC) + add_subdirectory(hyperion-aml) + endif() + # Add the 'Video 4 Linux' grabber if it is enabled + if(ENABLE_V4L2) + add_subdirectory(hyperion-v4l2) + endif() - # Add the X11 grabber if it is enabled - if(ENABLE_X11) - add_subdirectory(hyperion-x11) - endif() + # Add the X11 grabber if it is enabled + if(ENABLE_X11) + add_subdirectory(hyperion-x11) + endif() endif() diff --git a/src/hyperion-aml/CMakeLists.txt b/src/hyperion-aml/CMakeLists.txt new file mode 100644 index 00000000..d6f88a90 --- /dev/null +++ b/src/hyperion-aml/CMakeLists.txt @@ -0,0 +1,46 @@ +# Configure minimum CMAKE version +cmake_minimum_required(VERSION 2.8) + +# Set the project name +project(hyperion-aml) + +# find Qt4 +find_package(Qt4 REQUIRED QtCore QtGui QtNetwork) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/protoserver + ${QT_INCLUDES} + ${PROTOBUF_INCLUDE_DIRS} +) + +set(Hyperion_AML_QT_HEADERS +) + +set(Hyperion_AML_HEADERS +) + +set(Hyperion_AML_SOURCES + hyperion-aml.cpp +) + +QT4_WRAP_CPP(Hyperion_AML_HEADERS_MOC ${Hyperion_AML_QT_HEADERS}) + +add_executable(hyperion-amlogic + ${Hyperion_AML_HEADERS} + ${Hyperion_AML_SOURCES} + ${Hyperion_AML_HEADERS_MOC} +) + +target_link_libraries(hyperion-amlogic + getoptPlusPlus + blackborder + hyperion-utils + protoserver + amlogic-grabber + pthread +) + +qt4_use_modules(hyperion-amlogic + Core + Gui + Network) diff --git a/src/hyperion-aml/hyperion-aml.cpp b/src/hyperion-aml/hyperion-aml.cpp new file mode 100644 index 00000000..13da6686 --- /dev/null +++ b/src/hyperion-aml/hyperion-aml.cpp @@ -0,0 +1,91 @@ + + +// QT includes +#include +#include + +// getoptPlusPLus includes +#include + +#include "../../libsrc/grabber/amlogic/AmlogicGrabber.h" + +using namespace vlofgren; + +// save the image as screenshot +void saveScreenshot(const char * filename, const Image & image) +{ + // store as PNG + QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); + pngImage = pngImage.rgbSwapped(); + pngImage.save(filename); +} + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + try + { + // create the option parser and initialize all parameters + OptionsParser optionParser("X11 capture application for Hyperion"); + ParameterSet & parameters = optionParser.getParameters(); + + //IntParameter & argFps = parameters.add ('f', "framerate", "Capture frame rate [default=10]"); + IntParameter & argWidth = parameters.add (0x0, "width", "Width of the captured image [default=128]"); + IntParameter & argHeight = parameters.add (0x0, "height", "Height of the captured image [default=128]"); + SwitchParameter<> & argScreenshot = parameters.add> (0x0, "screenshot", "Take a single screenshot, save it to file and quit"); + StringParameter & argAddress = parameters.add ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]"); + IntParameter & argPriority = parameters.add ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]"); + //SwitchParameter<> & argSkipReply = parameters.add> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); + SwitchParameter<> & argHelp = parameters.add> ('h', "help", "Show this help message and exit"); + + // set defaults + argWidth.setDefault(160); + argHeight.setDefault(160); + argAddress.setDefault("127.0.0.1:19445"); + argPriority.setDefault(800); + + // parse all options + optionParser.parse(argc, const_cast(argv)); + + // check if we need to display the usage. exit if we do. + if (argHelp.isSet()) + { + optionParser.usage(); + return 0; + } + + int width = argWidth.getValue(); + int height = argHeight.getValue(); + if (width < 160 || height < 60) + { + std::cout << "Minimum width and height is 160" << std::endl; + width = std::max(160, width); + height = std::max(160, height); + } + if (argScreenshot.isSet()) + { + + // Create the grabber + AmlogicGrabber amlGrabber(width, height); + + // Capture a single screenshot and finish + Image screenshot; + amlGrabber.grabFrame(screenshot); + saveScreenshot("screenshot.png", screenshot); + } + else + { + // TODO[TvdZ]: Implement the proto-client mechanisme + std::cerr << "The PROTO-interface has not been implemented yet" << std::endl; + } + + } + catch (const std::runtime_error & e) + { + // An error occured. Display error and quit + std::cerr << e.what() << std::endl; + return -1; + } + return 0; +} diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index 9f4f1188..70c2381b 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -26,6 +26,10 @@ if (ENABLE_V4L2) target_link_libraries(hyperiond v4l2-grabber) endif (ENABLE_V4L2) +if (ENABLE_AMLOGIC) + target_link_libraries(hyperiond amlogic-grabber) +endif (ENABLE_AMLOGIC) + if (ENABLE_PROTOBUF) target_link_libraries(hyperiond protoserver) endif (ENABLE_PROTOBUF) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 7c89c94e..ead62d80 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -31,6 +31,10 @@ #include #endif +#ifdef ENABLE_AMLOGIC +#include +#endif + #ifdef ENABLE_OSX // OSX grabber includes #include @@ -123,7 +127,7 @@ int main(int argc, char** argv) const std::string effectName = effectConfig["effect"].asString(); const unsigned duration_ms = effectConfig["duration_ms"].asUInt(); const int priority = 0; - + hyperion.setColor(priority+1, ColorRgb::BLACK, duration_ms, false); if (effectConfig.isMember("args")) @@ -236,7 +240,37 @@ int main(int argc, char** argv) std::cerr << "The v4l2 grabber can not be instantiated, becuse it has been left out from the build" << std::endl; } #endif - + +#ifdef ENABLE_AMLOGIC + // Construct and start the framebuffer grabber if the configuration is present + AmlogicWrapper * amlGrabber = nullptr; + if (config.isMember("amlgrabber")) + { + const Json::Value & grabberConfig = config["amlgrabber"]; + amlGrabber = new AmlogicWrapper( + grabberConfig["width"].asUInt(), + grabberConfig["height"].asUInt(), + grabberConfig["frequency_Hz"].asUInt(), + &hyperion); + + if (xbmcVideoChecker != nullptr) + { + QObject::connect(xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), amlGrabber, SLOT(setGrabbingMode(GrabbingMode))); + QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), amlGrabber, SLOT(setVideoMode(VideoMode))); + } + + amlGrabber->start(); + std::cout << "AMLOGIC grabber created and started" << std::endl; + } +#else +#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 + #ifdef ENABLE_FB // Construct and start the framebuffer grabber if the configuration is present FramebufferWrapper * fbGrabber = nullptr; @@ -260,42 +294,40 @@ int main(int argc, char** argv) std::cout << "Framebuffer grabber created and started" << std::endl; } #else -#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) - if (config.isMember("framegrabber")) + if (config.isMember("amlgrabber")) { - std::cerr << "The framebuffer grabber can not be instantiated, becuse it has been left out from the build" << std::endl; + std::cerr << "The AMLOGIC grabber can not be instantiated, because it has been left out from the build" << std::endl; } #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; - } + // 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; - } + 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 @@ -340,7 +372,7 @@ int main(int argc, char** argv) delete fbGrabber; #endif #ifdef ENABLE_OSX - delete osxGrabber; + delete osxGrabber; #endif #ifdef ENABLE_V4L2 delete v4l2Grabber;