From 2de173722de0a78ba3bdb19a9a76d800a6f6c77b Mon Sep 17 00:00:00 2001 From: "T.van der Zwan" Date: Fri, 7 Aug 2015 14:37:41 +0200 Subject: [PATCH] Added code for amlogic grabber. Former-commit-id: fdb9c1c5d8ce02d531d2008057e22f1ae8f7d04e --- CMakeLists.txt | 51 ++++++------ include/grabber/AmlogicWrapper.h | 94 +++++++++++++++++++++++ libsrc/grabber/CMakeLists.txt | 12 ++- libsrc/grabber/amlogic/AmlogicGrabber.cpp | 87 +++++++++++++++++++++ libsrc/grabber/amlogic/AmlogicGrabber.h | 52 +++++++++++++ libsrc/grabber/amlogic/AmlogicWrapper.cpp | 88 +++++++++++++++++++++ libsrc/grabber/amlogic/CMakeLists.txt | 29 +++++++ 7 files changed, 383 insertions(+), 30 deletions(-) create mode 100644 include/grabber/AmlogicWrapper.h create mode 100644 libsrc/grabber/amlogic/AmlogicGrabber.cpp create mode 100644 libsrc/grabber/amlogic/AmlogicGrabber.h create mode 100644 libsrc/grabber/amlogic/AmlogicWrapper.cpp create mode 100644 libsrc/grabber/amlogic/CMakeLists.txt 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/include/grabber/AmlogicWrapper.h b/include/grabber/AmlogicWrapper.h new file mode 100644 index 00000000..8147a8d6 --- /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/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..895818be --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicGrabber.cpp @@ -0,0 +1,87 @@ + +// STL includes +#include +#include + +// Linux includes +#include +#include +#include +#include +#include +#include + +// Local includes +#include "AmlogicGrabber.h" + +// Flags copied from '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) + +AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height) : + _width(width), + _height(height), + _amlogicCaptureDev(-1) +{ + _amlogicCaptureDev = open("/dev/amvideocap0", O_RDONLY, 0); + if (_amlogicCaptureDev == -1) + { + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Failed to open the AMLOGIC device (" << errno << ")" << std::endl; + return; + } + + 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 << ")" << 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; + } +} + +void AmlogicGrabber::grabFrame(Image & image) +{ + // resize the given image if needed + if (image.width() != unsigned(_rectangle.width) || image.height() != unsigned(_rectangle.height)) + { + image.resize(_rectangle.width, _rectangle.height); + } + + // Read the snapshot into the memory + void * image_ptr = image.memptr(); + const size_t bytesToRead = _width * _height * sizeof(ColorRgb); + const size_t bytesRead = pread(amlogicCaptureDev, image_ptr, bytesToRead, 0) + if (bytesToRead != bytesRead) + { + // Read of snapshot failed + std::cerr << "[" << __PRETTY_FUNCTION__ << "] Capture failed to grab entire image [bytesToRead(" << bytesToRead << ") != bytesRead(" << bytesRead << ")]" << std::endl; + } +} diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.h b/libsrc/grabber/amlogic/AmlogicGrabber.h new file mode 100644 index 00000000..d9b884ed --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicGrabber.h @@ -0,0 +1,52 @@ +#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) + /// + void grabFrame(Image & image); + +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..202989f8 --- /dev/null +++ b/libsrc/grabber/amlogic/AmlogicWrapper.cpp @@ -0,0 +1,88 @@ +// 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(1000), + _timer(), + _image(grabWidth, grabHeight), + _frameGrabber(new DispmanxFrameGrabber(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 + _frameGrabber->grabFrame(_image); + + _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..77f7eb58 --- /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}/AmlogicFrameGrabber.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})