mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Merge pull request #4 from tvdzwan/master
Updating Former-commit-id: f2babbeab3f8dd80e92b37be5fd0c25c1b45a76b
This commit is contained in:
commit
9d01c84494
@ -91,9 +91,6 @@ include_directories(${CMAKE_SOURCE_DIR}/include)
|
|||||||
# Prefer static linking over dynamic
|
# Prefer static linking over dynamic
|
||||||
#set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
|
#set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
|
||||||
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
|
||||||
#set(CMAKE_BUILD_TYPE "Release")
|
|
||||||
|
|
||||||
# enable C++11
|
# enable C++11
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++11 -Wall")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++11 -Wall")
|
||||||
|
@ -24,11 +24,11 @@ mkdir "$HYPERION_DIR/build"
|
|||||||
cd "$HYPERION_DIR/build"
|
cd "$HYPERION_DIR/build"
|
||||||
|
|
||||||
# run cmake to generate make files on the raspberry pi
|
# run cmake to generate make files on the raspberry pi
|
||||||
cmake ..
|
cmake -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
|
||||||
# or if you are not compiling on the raspberry pi and need to disable the Dispmanx grabber and support for spi devices
|
# or if you are not compiling on the raspberry pi and need to disable the Dispmanx grabber and support for spi devices
|
||||||
cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_X11=ON ..
|
cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_X11=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
|
||||||
# as an alternative for the dispmanx grabber on non-rpi devices (e.g. cubox-i) you could try the framebuffer grabber
|
# 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 ..
|
cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_FB=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
|
||||||
# for OSX build you need XCode, qt4 libraries and cmake. You can use macport (homebrew might work too) to install them
|
# 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 qt4-mac
|
||||||
sudo port install cmake
|
sudo port install cmake
|
||||||
@ -36,6 +36,12 @@ cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_V4L2=OFF -DENABLE_OSX=O
|
|||||||
|
|
||||||
# run make to build Hyperion
|
# run make to build Hyperion
|
||||||
make
|
make
|
||||||
|
# or if you have a system with more then 1 cpu core
|
||||||
|
make -j 4
|
||||||
|
# "4" is the number of cpu cores (e.g. 4 on RPi2), this makes compile faster
|
||||||
|
|
||||||
|
#after compile, to remove any stuff not needed for a release version.
|
||||||
|
strip bin/*
|
||||||
|
|
||||||
# The binaries are build in "$HYPERION_DIR/build/bin". You could copy those to /usr/bin
|
# The binaries are build in "$HYPERION_DIR/build/bin". You could copy those to /usr/bin
|
||||||
sudo cp ./bin/hyperion-remote /usr/bin/
|
sudo cp ./bin/hyperion-remote /usr/bin/
|
||||||
|
@ -24,6 +24,8 @@ tar --create --verbose --gzip --absolute-names --show-transformed-names --ignore
|
|||||||
--transform "s:$repodir/effects/:hyperion/effects/:" \
|
--transform "s:$repodir/effects/:hyperion/effects/:" \
|
||||||
--transform "s:$repodir/config/:hyperion/config/:" \
|
--transform "s:$repodir/config/:hyperion/config/:" \
|
||||||
--transform "s:$repodir/bin/hyperion.init.sh:hyperion/init.d/hyperion.init.sh:" \
|
--transform "s:$repodir/bin/hyperion.init.sh:hyperion/init.d/hyperion.init.sh:" \
|
||||||
|
--transform "s:$repodir/bin/hyperion.systemd.sh:hyperion/init.d/hyperion.systemd.sh:" \
|
||||||
|
--transform "s:$repodir/bin/hyperion.initctl.sh:hyperion/init.d/hyperion.initctl.sh:" \
|
||||||
--transform "s://:/:g" \
|
--transform "s://:/:g" \
|
||||||
"$builddir/bin/hyperiond" \
|
"$builddir/bin/hyperiond" \
|
||||||
"$builddir/bin/hyperion-remote" \
|
"$builddir/bin/hyperion-remote" \
|
||||||
@ -32,5 +34,7 @@ tar --create --verbose --gzip --absolute-names --show-transformed-names --ignore
|
|||||||
"$builddir/bin/dispmanx2png" \
|
"$builddir/bin/dispmanx2png" \
|
||||||
"$repodir/effects/"* \
|
"$repodir/effects/"* \
|
||||||
"$repodir/bin/hyperion.init.sh" \
|
"$repodir/bin/hyperion.init.sh" \
|
||||||
|
"$repodir/bin/hyperion.systemd.sh" \
|
||||||
|
"$repodir/bin/hyperion.initctl.sh" \
|
||||||
"$repodir/config/hyperion.config.json"
|
"$repodir/config/hyperion.config.json"
|
||||||
|
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Hyperion daemon
|
# Hyperion daemon service
|
||||||
# description: Hyperion daemon
|
# description: Hyperion daemon
|
||||||
# processname: hyperiond
|
# processname: hyperiond
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: Hyperion
|
||||||
|
# Required-Start: $remote_fs $syslog
|
||||||
|
# Required-Stop: $remote_fs $syslog
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Hyperion Ambilight init.d Service.
|
||||||
|
# Description: Hyperion Ambilight init.d Service.
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
DAEMON=hyperiond
|
DAEMON=hyperiond
|
||||||
DAEMONOPTS="/etc/hyperion.config.json"
|
DAEMONOPTS="/etc/hyperion.config.json"
|
||||||
|
17
bin/hyperion.initctl.sh
Normal file
17
bin/hyperion.initctl.sh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
## Hyperion daemon initctl script
|
||||||
|
|
||||||
|
description "hyperion"
|
||||||
|
author "poljvd & tvdzwan"
|
||||||
|
|
||||||
|
start on (runlevel [2345])
|
||||||
|
stop on (runlevel [!2345])
|
||||||
|
|
||||||
|
respawn
|
||||||
|
|
||||||
|
pre-start script
|
||||||
|
#comment out the following 2 lines for x32/64
|
||||||
|
modprobe spidev
|
||||||
|
/usr/bin/gpio2spi
|
||||||
|
end script
|
||||||
|
|
||||||
|
exec /usr/bin/hyperiond /etc/hyperion.config.json
|
15
bin/hyperion.systemd.sh
Normal file
15
bin/hyperion.systemd.sh
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Hyperion Systemd service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
UMask=007
|
||||||
|
ExecStart=/opt/hyperion/bin/hyperiond /etc/hyperion.config.json
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
105
bin/remove_hyperion.sh
Normal file
105
bin/remove_hyperion.sh
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Script to remove Hyperion and all services
|
||||||
|
|
||||||
|
# Make sure /sbin is on the path (for service to find sub scripts)
|
||||||
|
PATH="/sbin:$PATH"
|
||||||
|
|
||||||
|
#Check if HyperCon is logged in as root
|
||||||
|
if [ $(id -u) != 0 ] && [ "$1" = "HyperConRemove" ]; then
|
||||||
|
echo '---> Critical Error: Please connect as user "root" through HyperCon'
|
||||||
|
echo '---> We need admin privileges to remove your Hyperion! -> abort'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Check, if script is running as root
|
||||||
|
if [ $(id -u) != 0 ]; then
|
||||||
|
echo '---> Critical Error: Please run the script as root (sudo sh ./remove_hyperion.sh)'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Welcome message
|
||||||
|
echo '*******************************************************************************'
|
||||||
|
echo 'This script will remove Hyperion and it´s services'
|
||||||
|
echo '-----> Please BACKUP your hyperion.config.json if necessary <-----'
|
||||||
|
echo '*******************************************************************************'
|
||||||
|
|
||||||
|
#Skip the prompt if HyperCon Remove
|
||||||
|
if [ "$1" = "" ]; then
|
||||||
|
#Prompt for confirmation to proceed
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
echo -n "---> Do you really want to remove Hyperion and it´s services? (y or n) :"
|
||||||
|
read CONFIRM
|
||||||
|
case $CONFIRM in
|
||||||
|
y|Y|YES|yes|Yes) break ;;
|
||||||
|
n|N|no|NO|No)
|
||||||
|
echo "---> Aborting - you entered \"$CONFIRM\""
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
*) echo "-> Please enter only y or n"
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo "---> You entered \"$CONFIRM\". Remove Hyperion!"
|
||||||
|
fi
|
||||||
|
# Find out if we are on OpenElec
|
||||||
|
OS_OPENELEC=`grep -m1 -c OpenELEC /etc/issue`
|
||||||
|
|
||||||
|
# check which init script we should use
|
||||||
|
USE_SYSTEMD=`grep -m1 -c systemd /proc/1/comm`
|
||||||
|
USE_INITCTL=`which /sbin/initctl | wc -l`
|
||||||
|
USE_SERVICE=`which /usr/sbin/service | wc -l`
|
||||||
|
|
||||||
|
# Stop hyperion daemon if it is running
|
||||||
|
echo '---> Stop Hyperion, if necessary'
|
||||||
|
if [ $OS_OPENELEC -eq 1 ]; then
|
||||||
|
killall hyperiond 2>/dev/null
|
||||||
|
elif [ $USE_INITCTL -eq 1 ]; then
|
||||||
|
/sbin/initctl stop hyperion 2>/dev/null
|
||||||
|
elif [ $USE_SERVICE -eq 1 ]; then
|
||||||
|
/usr/sbin/service hyperion stop 2>/dev/null
|
||||||
|
elif [ $USE_SYSTEMD -eq 1 ]; then
|
||||||
|
service hyperion stop 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Disabling and delete service files
|
||||||
|
if [ $USE_INITCTL -eq 1 ]; then
|
||||||
|
echo '---> Delete and disable Hyperion initctl script'
|
||||||
|
rm -v /etc/init/hyperion 2>/dev/null
|
||||||
|
initctl reload-configuration
|
||||||
|
elif [ $OS_OPENELEC -eq 1 ]; then
|
||||||
|
# Remove Hyperion from OpenELEC autostart.sh
|
||||||
|
echo "---> Remove Hyperion from OpenELEC autostart.sh"
|
||||||
|
sed -i "/hyperiond/d" /storage/.config/autostart.sh 2>/dev/null
|
||||||
|
elif [ $USE_SYSTEMD -eq 1 ]; then
|
||||||
|
# Delete and disable Hyperion systemd script
|
||||||
|
echo '---> Delete and disable Hyperion systemd script'
|
||||||
|
systemctl disable hyperion.service
|
||||||
|
rm -v /etc/systemd/system/hyperion.service 2>/dev/null
|
||||||
|
elif [ $USE_SERVICE -eq 1 ]; then
|
||||||
|
# Delete and disable Hyperion init.d script
|
||||||
|
echo '---> Delete and disable Hyperion init.d script'
|
||||||
|
update-rc.d -f hyperion remove
|
||||||
|
rm /etc/init.d/hyperion 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Delete Hyperion binaries
|
||||||
|
if [ $OS_OPENELEC -eq 1 ]; then
|
||||||
|
# Remove OpenELEC Hyperion binaries and configs
|
||||||
|
echo '---> Remove the OpenELEC Hyperion binaries and hyperion.config.json'
|
||||||
|
rm -rv /storage/hyperion 2>/dev/null
|
||||||
|
rm -v /storage/.config/hyperion.config.json 2>/dev/null
|
||||||
|
else
|
||||||
|
#Remove binaries on all distributions/systems (not OpenELEC)
|
||||||
|
echo "---> Remove links to the binaries"
|
||||||
|
rm -v /usr/bin/hyperiond 2>/dev/null
|
||||||
|
rm -v /usr/bin/hyperion-remote 2>/dev/null
|
||||||
|
rm -v /usr/bin/hyperion-v4l2 2>/dev/null
|
||||||
|
rm -v /etc/hyperion.config.json 2>/dev/null
|
||||||
|
echo "---> Remove binaries"
|
||||||
|
rm -rv /opt/hyperion 2>/dev/null
|
||||||
|
fi
|
||||||
|
echo '*******************************************************************************'
|
||||||
|
echo 'Hyperion successful removed!'
|
||||||
|
echo '*******************************************************************************'
|
||||||
|
exit 0
|
||||||
|
|
@ -4,22 +4,16 @@
|
|||||||
{
|
{
|
||||||
/// Device configuration contains the following fields:
|
/// Device configuration contains the following fields:
|
||||||
/// * 'name' : The user friendly name of the device (only used for display purposes)
|
/// * 'name' : The user friendly name of the device (only used for display purposes)
|
||||||
/// * 'type' : The type of the device or leds (known types for now are 'ws2801', 'ldp8806',
|
/// * 'type' : The type of the device or leds (known types for now are
|
||||||
/// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'philipshue', 'test' and 'none')
|
/// APA102, Adalight, AmbiLed, Atmo, Hyperion-USBASP-WS2801, Hyperion-USBASP-WS2812, Lightberry, Lightpack, LPD6803, LPD8806, Multi-Lightpack, P9813, Paintpack, PhilipsHUE, PiBlaster, SEDU, Test, ThinkerForge, TPM2, WS2801, WS2812b, None)
|
||||||
/// * 'output' : The output specification depends on selected device. This can for example be the
|
/// * [device type specific configuration]
|
||||||
/// device specifier, device serial number, or the output file name
|
|
||||||
/// * 'rate' : The baudrate of the output to the device
|
|
||||||
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
|
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
|
||||||
/// Specific of Philips Hue:
|
|
||||||
/// * 'username' : The name of user registred on the Philips Hue Bridge
|
|
||||||
/// * 'switchOffOnBlack' : Define if Hue light switch off when black is detected
|
|
||||||
/// * 'transitiontime' : Set the time of transition between color of Hue light
|
|
||||||
"device" :
|
"device" :
|
||||||
{
|
{
|
||||||
"name" : "MyPi",
|
"name" : "MyPi",
|
||||||
"type" : "ws2801",
|
"type" : "ws2801",
|
||||||
"output" : "/dev/spidev0.0",
|
"output" : "/dev/spidev0.0",
|
||||||
"rate" : 250000,
|
"rate" : 1000000,
|
||||||
"colorOrder" : "rgb"
|
"colorOrder" : "rgb"
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -45,6 +39,7 @@
|
|||||||
/// - 'type' The type of smoothing algorithm ('linear' or 'none')
|
/// - 'type' The type of smoothing algorithm ('linear' or 'none')
|
||||||
/// - 'time_ms' The time constant for smoothing algorithm in milliseconds
|
/// - 'time_ms' The time constant for smoothing algorithm in milliseconds
|
||||||
/// - 'updateFrequency' The update frequency of the leds in Hz
|
/// - 'updateFrequency' The update frequency of the leds in Hz
|
||||||
|
/// - 'updateDelay' The delay of the output to leds (in periods of smoothing)
|
||||||
"color" :
|
"color" :
|
||||||
{
|
{
|
||||||
"transform" :
|
"transform" :
|
||||||
@ -82,13 +77,156 @@
|
|||||||
],
|
],
|
||||||
"smoothing" :
|
"smoothing" :
|
||||||
{
|
{
|
||||||
"type" : "none",
|
"type" : "linear",
|
||||||
"time_ms" : 200,
|
"time_ms" : 200,
|
||||||
"updateFrequency" : 20.0000,
|
"updateFrequency" : 20.0000,
|
||||||
"updateDelay" : 0
|
"updateDelay" : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// The black border configuration, contains the following items:
|
||||||
|
/// * enable : true if the detector should be activated
|
||||||
|
/// * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
|
||||||
|
/// * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600)
|
||||||
|
/// * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50)
|
||||||
|
/// * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency
|
||||||
|
/// * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1)
|
||||||
|
/// * mode : Border detection mode (values=default,classic,osd)
|
||||||
|
"blackborderdetector" :
|
||||||
|
{
|
||||||
|
"enable" : true,
|
||||||
|
"threshold" : 0.0,
|
||||||
|
"unknownFrameCnt" : 600,
|
||||||
|
"borderFrameCnt" : 50,
|
||||||
|
"maxInconsistentCnt" : 10,
|
||||||
|
"blurRemoveCnt" : 1,
|
||||||
|
"mode" : "default"
|
||||||
|
},
|
||||||
|
|
||||||
|
/// The configuration of the effect engine, contains the following items:
|
||||||
|
/// * paths : An array with absolute location(s) of directories with effects
|
||||||
|
/// * color : Set static color after boot -> set effect to "" (empty) and input the values [R,G,B] and set duration_ms NOT to 0 (use 1) instead
|
||||||
|
/// * effect : The effect selected as 'boot sequence'
|
||||||
|
/// * duration_ms : The duration of the selected effect (0=endless)
|
||||||
|
/// * priority : The priority of the selected effect/static color (default=0)
|
||||||
|
"effects" :
|
||||||
|
{
|
||||||
|
"paths" :
|
||||||
|
[
|
||||||
|
"/opt/hyperion/effects"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"bootsequence" :
|
||||||
|
{
|
||||||
|
"color" : [0,0,0],
|
||||||
|
"effect" : "Rainbow swirl fast",
|
||||||
|
"duration_ms" : 3000,
|
||||||
|
"priority" : 990
|
||||||
|
},
|
||||||
|
|
||||||
|
/// The configuration of the Json/Proto forwarder. Forward messages to multiple instances of Hyperion on same and/or other hosts
|
||||||
|
/// 'proto' is mostly used for video streams and 'json' for effects
|
||||||
|
/// * proto : Proto server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19447"] or more instances to forward ["127.0.0.1:19447","192.168.0.24:19449"]
|
||||||
|
/// * json : Json server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19446"] or more instances to forward ["127.0.0.1:19446","192.168.0.24:19448"]
|
||||||
|
/// HINT: If you redirect to "127.0.0.1" (localhost) you could start a second hyperion with another device/led config!
|
||||||
|
/// Be sure your client(s) is/are listening on the configured ports. The second Hyperion (if used) also needs to be configured! (HyperCon -> External -> Json Server/Proto Server)
|
||||||
|
// "forwarder" :
|
||||||
|
// {
|
||||||
|
// "proto" : ["127.0.0.1:19447"],
|
||||||
|
// "json" : ["127.0.0.1:19446"]
|
||||||
|
// },
|
||||||
|
|
||||||
|
/// The configuration for the frame-grabber, contains the following items:
|
||||||
|
/// * width : The width of the grabbed frames [pixels]
|
||||||
|
/// * height : The height of the grabbed frames [pixels]
|
||||||
|
/// * frequency_Hz : The frequency of the frame grab [Hz]
|
||||||
|
"framegrabber" :
|
||||||
|
{
|
||||||
|
"width" : 80,
|
||||||
|
"height" : 45,
|
||||||
|
"frequency_Hz" : 10.0
|
||||||
|
},
|
||||||
|
|
||||||
|
/// The configuration of the Kodi connection used to enable and disable the frame-grabber. Contains the following fields:
|
||||||
|
/// * xbmcAddress : The IP address of the Kodi-host
|
||||||
|
/// * xbmcTcpPort : The TCP-port of the Kodi-server
|
||||||
|
/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback
|
||||||
|
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
|
||||||
|
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
|
||||||
|
/// * grabMenu : Flag indicating that the frame-grabber is on(true) at the Kodi menu
|
||||||
|
/// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when Kodi is on screensaver
|
||||||
|
/// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing
|
||||||
|
// "xbmcVideoChecker" :
|
||||||
|
// {
|
||||||
|
// "xbmcAddress" : "127.0.0.1",
|
||||||
|
// "xbmcTcpPort" : 9090,
|
||||||
|
// "grabVideo" : true,
|
||||||
|
// "grabPictures" : true,
|
||||||
|
// "grabAudio" : true,
|
||||||
|
// "grabMenu" : false,
|
||||||
|
// "grabScreensaver" : true,
|
||||||
|
// "enable3DDetection" : true
|
||||||
|
// },
|
||||||
|
|
||||||
|
/// The configuration of the Json server which enables the json remote interface
|
||||||
|
/// * port : Port at which the json server is started
|
||||||
|
"jsonServer" :
|
||||||
|
{
|
||||||
|
"port" : 19444
|
||||||
|
},
|
||||||
|
|
||||||
|
/// The configuration of the Proto server which enables the protobuffer remote interface
|
||||||
|
/// * port : Port at which the protobuffer server is started
|
||||||
|
"protoServer" :
|
||||||
|
{
|
||||||
|
"port" : 19445
|
||||||
|
},
|
||||||
|
|
||||||
|
/// The configuration of the boblight server which enables the boblight remote interface
|
||||||
|
/// * port : Port at which the boblight server is started
|
||||||
|
// "boblightServer" :
|
||||||
|
// {
|
||||||
|
// "port" : 19333
|
||||||
|
// },
|
||||||
|
|
||||||
|
/// Configuration for the embedded V4L2 grabber
|
||||||
|
/// * device : V4L2 Device to use [default="/dev/video0"]
|
||||||
|
/// * input : V4L2 input to use [default=0]
|
||||||
|
/// * standard : Video standard (no-change/PAL/NTSC) [default="no-change"]
|
||||||
|
/// * width : V4L2 width to set [default=-1]
|
||||||
|
/// * height : V4L2 height to set [default=-1]
|
||||||
|
/// * frameDecimation : Frame decimation factor [default=2]
|
||||||
|
/// * sizeDecimation : Size decimation factor [default=8]
|
||||||
|
/// * priority : Hyperion priority channel [default=800]
|
||||||
|
/// * mode : 3D mode to use 2D/3DSBS/3DTAB (note: no autodetection) [default="2D"]
|
||||||
|
/// * cropLeft : Cropping from the left [default=0]
|
||||||
|
/// * cropRight : Cropping from the right [default=0]
|
||||||
|
/// * cropTop : Cropping from the top [default=0]
|
||||||
|
/// * cropBottom : Cropping from the bottom [default=0]
|
||||||
|
/// * redSignalThreshold : Signal threshold for the red channel between 0.0 and 1.0 [default=0.0]
|
||||||
|
/// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0]
|
||||||
|
/// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0]
|
||||||
|
// "grabber-v4l2" :
|
||||||
|
// {
|
||||||
|
// "device" : "/dev/video0",
|
||||||
|
// "input" : 0,
|
||||||
|
// "standard" : "no-change",
|
||||||
|
// "width" : -1,
|
||||||
|
// "height" : -1,
|
||||||
|
// "frameDecimation" : 2,
|
||||||
|
// "sizeDecimation" : 8,
|
||||||
|
// "priority" : 800,
|
||||||
|
// "mode" : "2D",
|
||||||
|
// "cropLeft" : 0,
|
||||||
|
// "cropRight" : 0,
|
||||||
|
// "cropTop" : 0,
|
||||||
|
// "cropBottom" : 0,
|
||||||
|
// "redSignalThreshold" : 0.0,
|
||||||
|
// "greenSignalThreshold" : 0.0,
|
||||||
|
// "blueSignalThreshold" : 0.0
|
||||||
|
// },
|
||||||
|
|
||||||
/// The configuration for each individual led. This contains the specification of the area
|
/// The configuration for each individual led. This contains the specification of the area
|
||||||
/// averaged of an input image for each led to determine its color. Each item in the list
|
/// averaged of an input image for each led to determine its color. Each item in the list
|
||||||
/// contains the following fields:
|
/// contains the following fields:
|
||||||
@ -102,47 +240,47 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"index" : 0,
|
"index" : 0,
|
||||||
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
|
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 1,
|
"index" : 1,
|
||||||
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
|
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 2,
|
"index" : 2,
|
||||||
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
|
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 3,
|
"index" : 3,
|
||||||
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
|
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 4,
|
"index" : 4,
|
||||||
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
|
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 5,
|
"index" : 5,
|
||||||
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
|
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 6,
|
"index" : 6,
|
||||||
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
|
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 7,
|
"index" : 7,
|
||||||
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
|
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 8,
|
"index" : 8,
|
||||||
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
|
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -182,271 +320,155 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 16,
|
"index" : 16,
|
||||||
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
|
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index" : 17,
|
|
||||||
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
|
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 18,
|
"index" : 17,
|
||||||
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
|
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 19,
|
"index" : 18,
|
||||||
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
|
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 20,
|
"index" : 19,
|
||||||
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
|
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 21,
|
"index" : 20,
|
||||||
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
|
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 22,
|
"index" : 21,
|
||||||
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
|
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 23,
|
"index" : 22,
|
||||||
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
|
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 24,
|
"index" : 23,
|
||||||
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
|
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 25,
|
"index" : 24,
|
||||||
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
|
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"index" : 25,
|
||||||
|
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
|
||||||
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"index" : 26,
|
"index" : 26,
|
||||||
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
|
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 27,
|
"index" : 27,
|
||||||
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
|
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 28,
|
"index" : 28,
|
||||||
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
|
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 29,
|
"index" : 29,
|
||||||
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
|
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 30,
|
"index" : 30,
|
||||||
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
|
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 31,
|
"index" : 31,
|
||||||
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
|
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 32,
|
"index" : 32,
|
||||||
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
|
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index" : 33,
|
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index" : 34,
|
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 }
|
"vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 35,
|
"index" : 33,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 }
|
"vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 36,
|
"index" : 34,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 }
|
"vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 37,
|
"index" : 35,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 }
|
"vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 38,
|
"index" : 36,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 }
|
"vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 39,
|
"index" : 37,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 }
|
"vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 40,
|
"index" : 38,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 41,
|
"index" : 39,
|
||||||
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
|
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index" : 42,
|
|
||||||
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
|
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 43,
|
"index" : 40,
|
||||||
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
|
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 44,
|
"index" : 41,
|
||||||
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
|
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 45,
|
"index" : 42,
|
||||||
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
|
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 46,
|
"index" : 43,
|
||||||
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
|
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 47,
|
"index" : 44,
|
||||||
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
|
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index" : 48,
|
"index" : 45,
|
||||||
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
|
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
||||||
},
|
|
||||||
{
|
|
||||||
"index" : 49,
|
|
||||||
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
|
|
||||||
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
/// The black border configuration, contains the following items:
|
|
||||||
/// * enable : true if the detector should be activated
|
|
||||||
/// * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
|
|
||||||
/// * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600) - optional
|
|
||||||
/// * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50) - optional
|
|
||||||
/// * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency - optional
|
|
||||||
/// * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1) - optional
|
|
||||||
/// * mode : Border detection mode (values "default","classic","osd") - optional
|
|
||||||
|
|
||||||
"blackborderdetector" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"threshold" : 0.01,
|
|
||||||
"unknownFrameCnt": 600,
|
|
||||||
"borderFrameCnt" : 50,
|
|
||||||
"maxInconsistentCnt" : 10,
|
|
||||||
"blurRemoveCnt": 1,
|
|
||||||
"mode" : "default"
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the effect engine, contains the following items:
|
|
||||||
/// * paths : An array with absolute location(s) of directories with effects
|
|
||||||
/// * bootsequence : The effect selected as 'boot sequence'
|
|
||||||
/// * effect : name of the effect you want to start. Set to empty if no effect wanted
|
|
||||||
/// * color : switch to static color after effect is done
|
|
||||||
/// * duration_ms : duration of boot effect in ms. 0 means effect stays forever
|
|
||||||
/// * priority : priority of boot effect and static color
|
|
||||||
"effects" :
|
|
||||||
{
|
|
||||||
"paths" :
|
|
||||||
[
|
|
||||||
"/opt/hyperion/effects"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"bootsequence" :
|
|
||||||
{
|
|
||||||
"color" : [0,0,0],
|
|
||||||
"effect" : "Rainbow swirl fast",
|
|
||||||
"duration_ms" : 3000,
|
|
||||||
"priority" : 0
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration for the frame-grabber, contains the following items:
|
|
||||||
/// * width : The width of the grabbed frames [pixels]
|
|
||||||
/// * height : The height of the grabbed frames [pixels]
|
|
||||||
/// * frequency_Hz : The frequency of the frame grab [Hz]
|
|
||||||
"framegrabber" :
|
|
||||||
{
|
|
||||||
"width" : 64,
|
|
||||||
"height" : 64,
|
|
||||||
"frequency_Hz" : 10.0
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields:
|
|
||||||
/// * xbmcAddress : The IP address of the XBMC-host
|
|
||||||
/// * xbmcTcpPort : The TCP-port of the XBMC-server
|
|
||||||
/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback
|
|
||||||
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
|
|
||||||
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
|
|
||||||
/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu
|
|
||||||
/// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when XBMC is on screensaver
|
|
||||||
/// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing
|
|
||||||
"xbmcVideoChecker" :
|
|
||||||
{
|
|
||||||
"xbmcAddress" : "127.0.0.1",
|
|
||||||
"xbmcTcpPort" : 9090,
|
|
||||||
"grabVideo" : true,
|
|
||||||
"grabPictures" : true,
|
|
||||||
"grabAudio" : true,
|
|
||||||
"grabMenu" : false,
|
|
||||||
"grabScreensaver" : true,
|
|
||||||
"enable3DDetection" : true
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Json server which enables the json remote interface
|
|
||||||
/// * port : Port at which the json server is started
|
|
||||||
"jsonServer" :
|
|
||||||
{
|
|
||||||
"port" : 19444
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Proto server which enables the protobuffer remote interface
|
|
||||||
/// * port : Port at which the protobuffer server is started
|
|
||||||
"protoServer" :
|
|
||||||
{
|
|
||||||
"port" : 19445
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the boblight server which enables the boblight remote interface
|
|
||||||
/// * port : Port at which the boblight server is started
|
|
||||||
// "boblightServer" :
|
|
||||||
// {
|
|
||||||
// "port" : 19333
|
|
||||||
// },
|
|
||||||
|
|
||||||
"endOfJson" : "endOfJson"
|
"endOfJson" : "endOfJson"
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,21 @@
|
|||||||
"colorOrder" : "rgb"
|
"colorOrder" : "rgb"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Configuration for message forwarding to other hyperions
|
||||||
|
/// protobuffer and json remote interface are forwarded to configured hosts
|
||||||
|
/// 'proto' is mostly used for video streams and 'json' for effects
|
||||||
|
///
|
||||||
|
/// ** pay attention which port you use. use correct ports for protols **
|
||||||
|
///
|
||||||
|
/// * 'proto' : list of host in form of <ip>:<port>
|
||||||
|
/// * 'json' : list of host in form of <ip>:<port>
|
||||||
|
/// "forwarder" :
|
||||||
|
/// {
|
||||||
|
/// "proto" : [ "127.0.0.1:19445","192.168.178.88:19445" ],
|
||||||
|
/// "json" : [ "127.0.0.1:19444","192.168.178.88:19444" ]
|
||||||
|
/// },
|
||||||
|
|
||||||
|
|
||||||
/// Color manipulation configuration used to tune the output colors to specific surroundings.
|
/// Color manipulation configuration used to tune the output colors to specific surroundings.
|
||||||
/// The configuration contains a list of color-transforms. Each transform contains the
|
/// The configuration contains a list of color-transforms. Each transform contains the
|
||||||
/// following fields:
|
/// following fields:
|
||||||
|
10
effects/cinema-fade-in.json
Normal file
10
effects/cinema-fade-in.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name" : "Cinema brighten lights",
|
||||||
|
"script" : "fade.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"fade-time" : 5.0,
|
||||||
|
"color-start" : [ 136, 97, 7 ],
|
||||||
|
"color-end" : [ 238, 173, 47 ]
|
||||||
|
}
|
||||||
|
}
|
10
effects/cinema-fade-off.json
Normal file
10
effects/cinema-fade-off.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name" : "Cinema dim lights",
|
||||||
|
"script" : "fade.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"fade-time" : 5.0,
|
||||||
|
"color-start" : [ 238, 173, 47 ],
|
||||||
|
"color-end" : [ 136, 97, 7 ]
|
||||||
|
}
|
||||||
|
}
|
27
effects/fade.py
Normal file
27
effects/fade.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import hyperion, time
|
||||||
|
|
||||||
|
# Get the parameters
|
||||||
|
fadeTime = float(hyperion.args.get('fade-time', 5.0))
|
||||||
|
colorStart = hyperion.args.get('color-start', (255,174,11))
|
||||||
|
colorEnd = hyperion.args.get('color-end', (100,100,100))
|
||||||
|
|
||||||
|
color_step = (
|
||||||
|
(colorEnd[0] - colorStart[0]) / 256.0,
|
||||||
|
(colorEnd[1] - colorStart[1]) / 256.0,
|
||||||
|
(colorEnd[2] - colorStart[2]) / 256.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# fade color
|
||||||
|
calcChannel = lambda i: min(max(int(colorStart[i] + color_step[i]*step),0),255)
|
||||||
|
for step in range(256):
|
||||||
|
if hyperion.abort():
|
||||||
|
break
|
||||||
|
|
||||||
|
hyperion.setColor( calcChannel(0),calcChannel(1),calcChannel(2) )
|
||||||
|
time.sleep( fadeTime / 256 )
|
||||||
|
|
||||||
|
# maintain color until effect end
|
||||||
|
hyperion.setColor(colorEnd[0],colorEnd[1],colorEnd[2])
|
||||||
|
while not hyperion.abort():
|
||||||
|
time.sleep(1)
|
||||||
|
|
9
effects/random.json
Normal file
9
effects/random.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name" : "Random",
|
||||||
|
"script" : "random.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"speed" : 1.0,
|
||||||
|
"saturation" : 1.0
|
||||||
|
}
|
||||||
|
}
|
21
effects/random.py
Normal file
21
effects/random.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import hyperion, time, colorsys, random
|
||||||
|
|
||||||
|
# get args
|
||||||
|
sleepTime = float(hyperion.args.get('speed', 1.0))
|
||||||
|
saturation = float(hyperion.args.get('saturation', 1.0))
|
||||||
|
ledData = bytearray()
|
||||||
|
|
||||||
|
# Initialize the led data
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
ledData += bytearray((0,0,0))
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
while not hyperion.abort():
|
||||||
|
hyperion.setColor(ledData)
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
if random.randrange(10) == 1:
|
||||||
|
rgb = colorsys.hsv_to_rgb(random.random(), saturation, random.random())
|
||||||
|
ledData[i*3 ] = int(255*rgb[0])
|
||||||
|
ledData[i*3+1] = int(255*rgb[1])
|
||||||
|
ledData[i*3+2] = int(255*rgb[2])
|
||||||
|
time.sleep(sleepTime)
|
10
effects/running_dots.json
Normal file
10
effects/running_dots.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name" : "Running dots",
|
||||||
|
"script" : "running_dots.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"speed" : 1.5,
|
||||||
|
"whiteLevel" : 100,
|
||||||
|
"colorLevel" : 230
|
||||||
|
}
|
||||||
|
}
|
43
effects/running_dots.py
Normal file
43
effects/running_dots.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import hyperion, time, colorsys, random
|
||||||
|
|
||||||
|
# get options from args
|
||||||
|
sleepTime = float(hyperion.args.get('speed', 1.5)) * 0.005
|
||||||
|
whiteLevel = int(hyperion.args.get('whiteLevel', 0))
|
||||||
|
lvl = int(hyperion.args.get('colorLevel', 220))
|
||||||
|
|
||||||
|
# check value
|
||||||
|
whiteLevel = min( whiteLevel, 254 )
|
||||||
|
lvl = min( lvl, 255 )
|
||||||
|
|
||||||
|
if whiteLevel >= lvl:
|
||||||
|
lvl = 255
|
||||||
|
|
||||||
|
# Initialize the led data
|
||||||
|
ledData = bytearray()
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
ledData += bytearray((0,0,0))
|
||||||
|
|
||||||
|
runners = [
|
||||||
|
{ "pos":0, "step": 4, "lvl":lvl},
|
||||||
|
{ "pos":1, "step": 5, "lvl":lvl},
|
||||||
|
{ "pos":2, "step": 6, "lvl":lvl},
|
||||||
|
{ "pos":0, "step": 7, "lvl":lvl},
|
||||||
|
{ "pos":1, "step": 8, "lvl":lvl},
|
||||||
|
{ "pos":2, "step": 9, "lvl":lvl},
|
||||||
|
#{ "pos":0, "step":10, "lvl":lvl},
|
||||||
|
#{ "pos":1, "step":11, "lvl":lvl},
|
||||||
|
#{ "pos":2, "step":12, "lvl":lvl},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
counter = 0
|
||||||
|
while not hyperion.abort():
|
||||||
|
counter += 1
|
||||||
|
for r in runners:
|
||||||
|
if counter % r["step"] == 0:
|
||||||
|
ledData[r["pos"]] = whiteLevel
|
||||||
|
r["pos"] = (r["pos"]+3) % (hyperion.ledCount*3)
|
||||||
|
ledData[r["pos"]] = r["lvl"]
|
||||||
|
|
||||||
|
hyperion.setColor(ledData)
|
||||||
|
time.sleep(sleepTime)
|
11
effects/shutdown.json
Normal file
11
effects/shutdown.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name" : "System Shutdown",
|
||||||
|
"script" : "shutdown.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"speed" : 1.2,
|
||||||
|
"alarm-color" : [255,0,0],
|
||||||
|
"post-color" : [255,174,11],
|
||||||
|
"shutdown-enabled" : false
|
||||||
|
}
|
||||||
|
}
|
49
effects/shutdown.py
Normal file
49
effects/shutdown.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import hyperion, time, subprocess
|
||||||
|
|
||||||
|
def setPixel(x,y,rgb):
|
||||||
|
global imageData, width
|
||||||
|
offset = y*width*3 + x*3
|
||||||
|
if offset+2 < len(imageData):
|
||||||
|
imageData[offset] = rgb[0]
|
||||||
|
imageData[offset+1] = rgb[1]
|
||||||
|
imageData[offset+2] = rgb[2]
|
||||||
|
|
||||||
|
# Initialize the led data and args
|
||||||
|
sleepTime = float(hyperion.args.get('speed', 1.0))*0.5
|
||||||
|
alarmColor = hyperion.args.get('alarm-color', (255,0,0))
|
||||||
|
postColor = hyperion.args.get('post-color', (255,174,11))
|
||||||
|
off = bool(hyperion.args.get('shutdown-enabled', False))
|
||||||
|
width = 12
|
||||||
|
height = 10
|
||||||
|
|
||||||
|
imageData = bytearray(height * width * (0,0,0))
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
for i in range(6):
|
||||||
|
if hyperion.abort():
|
||||||
|
off = False
|
||||||
|
break
|
||||||
|
if i % 2:
|
||||||
|
hyperion.setColor(alarmColor[0], alarmColor[1], alarmColor[2])
|
||||||
|
else:
|
||||||
|
hyperion.setColor(0, 0, 0)
|
||||||
|
time.sleep(sleepTime)
|
||||||
|
|
||||||
|
for y in range(height,0,-1):
|
||||||
|
if hyperion.abort():
|
||||||
|
off = False
|
||||||
|
break
|
||||||
|
for x in range(width):
|
||||||
|
setPixel(x, y-1, alarmColor)
|
||||||
|
hyperion.setImage(width, height, imageData)
|
||||||
|
time.sleep(sleepTime)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
for y in range(height):
|
||||||
|
for x in range(width):
|
||||||
|
setPixel(x, y, postColor)
|
||||||
|
hyperion.setImage(width, height, imageData)
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
if off and not hyperion.abort():
|
||||||
|
subprocess.call("halt")
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name" : "Snake",
|
"name" : "Snake",
|
||||||
"script" : "snake.py",
|
"script" : "snake.py",
|
||||||
"args" :
|
"args" :
|
||||||
{
|
{
|
||||||
"rotation-time" : 10.0,
|
"rotation-time" : 12.0,
|
||||||
"color" : [255, 0, 0],
|
"color" : [255, 0, 0],
|
||||||
"percentage" : 25
|
"percentage" : 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ for i in range(hyperion.ledCount-snakeLeds):
|
|||||||
ledData += bytearray((0, 0, 0))
|
ledData += bytearray((0, 0, 0))
|
||||||
|
|
||||||
for i in range(1,snakeLeds+1):
|
for i in range(1,snakeLeds+1):
|
||||||
rgb = colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2]/i)
|
rgb = colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2]*(snakeLeds-i)/snakeLeds)
|
||||||
ledData += bytearray((int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255)))
|
ledData += bytearray((int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255)))
|
||||||
|
|
||||||
# Calculate the sleep time and rotation increment
|
# Calculate the sleep time and rotation increment
|
||||||
|
14
effects/sparks-color.json
Normal file
14
effects/sparks-color.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name" : "Sparks Color",
|
||||||
|
"script" : "sparks.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"rotation-time" : 3.0,
|
||||||
|
"sleep-time" : 0.05,
|
||||||
|
"brightness" : 1.0,
|
||||||
|
"saturation" : 1.0,
|
||||||
|
"reverse" : false,
|
||||||
|
"color" : [255,255,255],
|
||||||
|
"random-color" : true
|
||||||
|
}
|
||||||
|
}
|
14
effects/sparks.json
Normal file
14
effects/sparks.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name" : "Sparks",
|
||||||
|
"script" : "sparks.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"rotation-time" : 3.0,
|
||||||
|
"sleep-time" : 0.05,
|
||||||
|
"brightness" : 1.0,
|
||||||
|
"saturation" : 1.0,
|
||||||
|
"reverse" : false,
|
||||||
|
"color" : [255,255,255],
|
||||||
|
"random-color" : false
|
||||||
|
}
|
||||||
|
}
|
37
effects/sparks.py
Normal file
37
effects/sparks.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import hyperion, time, colorsys, random
|
||||||
|
|
||||||
|
# Get the parameters
|
||||||
|
rotationTime = float(hyperion.args.get('rotation-time', 3.0))
|
||||||
|
sleepTime = float(hyperion.args.get('sleep-time', 0.05))
|
||||||
|
brightness = float(hyperion.args.get('brightness', 1.0))
|
||||||
|
saturation = float(hyperion.args.get('saturation', 1.0))
|
||||||
|
reverse = bool(hyperion.args.get('reverse', False))
|
||||||
|
color = list(hyperion.args.get('color', (255,255,255)))
|
||||||
|
randomColor = bool(hyperion.args.get('random-color', False))
|
||||||
|
|
||||||
|
# Check parameters
|
||||||
|
rotationTime = max(0.1, rotationTime)
|
||||||
|
brightness = max(0.0, min(brightness, 1.0))
|
||||||
|
saturation = max(0.0, min(saturation, 1.0))
|
||||||
|
|
||||||
|
# Initialize the led data
|
||||||
|
ledData = bytearray()
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
ledData += bytearray((0, 0, 0))
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
while not hyperion.abort():
|
||||||
|
ledData[:] = bytearray(3*hyperion.ledCount)
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
if random.random() < 0.005:
|
||||||
|
|
||||||
|
if randomColor:
|
||||||
|
rgb = colorsys.hsv_to_rgb(random.random(), 1, 1)
|
||||||
|
for n in range(3):
|
||||||
|
color[n] = int(rgb[n]*255)
|
||||||
|
|
||||||
|
for n in range(3):
|
||||||
|
ledData[i*3+n] = color[n]
|
||||||
|
|
||||||
|
hyperion.setColor(ledData)
|
||||||
|
time.sleep(sleepTime)
|
@ -1,6 +1,4 @@
|
|||||||
import hyperion
|
import hyperion, time
|
||||||
import time
|
|
||||||
import colorsys
|
|
||||||
|
|
||||||
# Get the rotation time
|
# Get the rotation time
|
||||||
color = hyperion.args.get('color', (255,255,255))
|
color = hyperion.args.get('color', (255,255,255))
|
||||||
@ -12,13 +10,9 @@ frequency = min(100.0, frequency)
|
|||||||
# Compute the strobe interval
|
# Compute the strobe interval
|
||||||
sleepTime = 1.0 / frequency
|
sleepTime = 1.0 / frequency
|
||||||
|
|
||||||
# Initialize the led data
|
|
||||||
blackLedsData = bytearray(hyperion.ledCount * ( 0, 0, 0))
|
|
||||||
whiteLedsData = bytearray(hyperion.ledCount * color)
|
|
||||||
|
|
||||||
# Start the write data loop
|
# Start the write data loop
|
||||||
while not hyperion.abort():
|
while not hyperion.abort():
|
||||||
hyperion.setColor(blackLedsData)
|
hyperion.setColor(0, 0, 0)
|
||||||
time.sleep(sleepTime)
|
time.sleep(sleepTime)
|
||||||
hyperion.setColor(whiteLedsData)
|
hyperion.setColor(color[0], color[1], color[2])
|
||||||
time.sleep(sleepTime)
|
time.sleep(sleepTime)
|
||||||
|
8
effects/traces.json
Normal file
8
effects/traces.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name" : "Color traces",
|
||||||
|
"script" : "traces.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"speed" : 1.0
|
||||||
|
}
|
||||||
|
}
|
34
effects/traces.py
Normal file
34
effects/traces.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import hyperion
|
||||||
|
import time
|
||||||
|
import colorsys
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Initialize the led data
|
||||||
|
ledData = bytearray()
|
||||||
|
for i in range(hyperion.ledCount):
|
||||||
|
ledData += bytearray((0,0,0))
|
||||||
|
|
||||||
|
sleepTime = float(hyperion.args.get('speed', 1.0)) * 0.004
|
||||||
|
|
||||||
|
runners = [
|
||||||
|
{ "i":0, "pos":0, "c":0, "step":9 , "lvl":255},
|
||||||
|
{ "i":1, "pos":0, "c":0, "step":8 , "lvl":255},
|
||||||
|
{ "i":2, "pos":0, "c":0, "step":7 , "lvl":255},
|
||||||
|
{ "i":0, "pos":0, "c":0, "step":6 , "lvl":100},
|
||||||
|
{ "i":1, "pos":0, "c":0, "step":5 , "lvl":100},
|
||||||
|
{ "i":2, "pos":0, "c":0, "step":4, "lvl":100},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
while not hyperion.abort():
|
||||||
|
for r in runners:
|
||||||
|
if r["c"] == 0:
|
||||||
|
#ledData[r["pos"]*3+r["i"]] = 0
|
||||||
|
r["c"] = r["step"]
|
||||||
|
r["pos"] = (r["pos"]+1)%hyperion.ledCount
|
||||||
|
ledData[r["pos"]*3+r["i"]] = int(r["lvl"]*(0.2+0.8*random.random()))
|
||||||
|
else:
|
||||||
|
r["c"] -= 1
|
||||||
|
|
||||||
|
hyperion.setColor(ledData)
|
||||||
|
time.sleep(sleepTime)
|
@ -68,6 +68,9 @@ public slots:
|
|||||||
///
|
///
|
||||||
void setVideoMode(const VideoMode videoMode);
|
void setVideoMode(const VideoMode videoMode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The update rate [Hz]
|
/// The update rate [Hz]
|
||||||
const int _updateInterval_ms;
|
const int _updateInterval_ms;
|
||||||
@ -91,4 +94,7 @@ private:
|
|||||||
|
|
||||||
/// Pointer to Hyperion for writing led values
|
/// Pointer to Hyperion for writing led values
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
|
|
||||||
|
// forwarding enabled
|
||||||
|
bool _forward;
|
||||||
};
|
};
|
||||||
|
@ -68,6 +68,9 @@ public slots:
|
|||||||
///
|
///
|
||||||
void setVideoMode(const VideoMode videoMode);
|
void setVideoMode(const VideoMode videoMode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The update rate [Hz]
|
/// The update rate [Hz]
|
||||||
const int _updateInterval_ms;
|
const int _updateInterval_ms;
|
||||||
@ -91,4 +94,7 @@ private:
|
|||||||
|
|
||||||
/// Pointer to Hyperion for writing led values
|
/// Pointer to Hyperion for writing led values
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
|
|
||||||
|
// forwarding enabled
|
||||||
|
bool _forward;
|
||||||
};
|
};
|
||||||
|
@ -68,6 +68,9 @@ public slots:
|
|||||||
///
|
///
|
||||||
void setVideoMode(const VideoMode videoMode);
|
void setVideoMode(const VideoMode videoMode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The update rate [Hz]
|
/// The update rate [Hz]
|
||||||
const int _updateInterval_ms;
|
const int _updateInterval_ms;
|
||||||
|
@ -69,6 +69,9 @@ public slots:
|
|||||||
///
|
///
|
||||||
void setVideoMode(const VideoMode videoMode);
|
void setVideoMode(const VideoMode videoMode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The update rate [Hz]
|
/// The update rate [Hz]
|
||||||
const int _updateInterval_ms;
|
const int _updateInterval_ms;
|
||||||
|
@ -44,6 +44,7 @@ public slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void emitColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
|
void emitColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
|
||||||
|
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void newFrame(const Image<ColorRgb> & image);
|
void newFrame(const Image<ColorRgb> & image);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// Hyperion includes
|
// Hyperion includes
|
||||||
#include <hyperion/LedString.h>
|
#include <hyperion/LedString.h>
|
||||||
#include <hyperion/PriorityMuxer.h>
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
#include <hyperion/MessageForwarder.h>
|
||||||
|
|
||||||
// Effect engine includes
|
// Effect engine includes
|
||||||
#include <effectengine/EffectDefinition.h>
|
#include <effectengine/EffectDefinition.h>
|
||||||
@ -125,6 +126,10 @@ public slots:
|
|||||||
/// Tell Hyperion that the transforms have changed and the leds need to be updated
|
/// Tell Hyperion that the transforms have changed and the leds need to be updated
|
||||||
void transformsUpdated();
|
void transformsUpdated();
|
||||||
|
|
||||||
|
/// Returns MessageForwarder Object
|
||||||
|
/// @return instance of message forwarder object
|
||||||
|
MessageForwarder * getForwarder();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Clears the given priority channel. This will switch the led-colors to the colors of the next
|
/// Clears the given priority channel. This will switch the led-colors to the colors of the next
|
||||||
/// lower priority channel (or off if no more channels are set)
|
/// lower priority channel (or off if no more channels are set)
|
||||||
@ -168,6 +173,7 @@ public:
|
|||||||
static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig);
|
static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig);
|
||||||
|
|
||||||
static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice);
|
static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice);
|
||||||
|
static MessageForwarder * createMessageForwarder(const Json::Value & forwarderConfig);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// Signal which is emitted when a priority channel is actively cleared
|
/// Signal which is emitted when a priority channel is actively cleared
|
||||||
@ -201,6 +207,9 @@ private:
|
|||||||
/// Effect engine
|
/// Effect engine
|
||||||
EffectEngine * _effectEngine;
|
EffectEngine * _effectEngine;
|
||||||
|
|
||||||
|
// proto and json Message forwarder
|
||||||
|
MessageForwarder * _messageForwarder;
|
||||||
|
|
||||||
/// The timer for handling priority channel timeouts
|
/// The timer for handling priority channel timeouts
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
};
|
};
|
||||||
|
38
include/hyperion/MessageForwarder.h
Normal file
38
include/hyperion/MessageForwarder.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QHostAddress>
|
||||||
|
|
||||||
|
// Utils includes
|
||||||
|
#include <utils/ColorRgb.h>
|
||||||
|
class MessageForwarder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct JsonSlaveAddress {
|
||||||
|
QHostAddress addr;
|
||||||
|
quint16 port;
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageForwarder();
|
||||||
|
~MessageForwarder();
|
||||||
|
|
||||||
|
void addJsonSlave(std::string slave);
|
||||||
|
void addProtoSlave(std::string slave);
|
||||||
|
|
||||||
|
bool protoForwardingEnabled();
|
||||||
|
QStringList getProtoSlaves();
|
||||||
|
QList<MessageForwarder::JsonSlaveAddress> getJsonSlaves();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList _protoSlaves;
|
||||||
|
QList<MessageForwarder::JsonSlaveAddress> _jsonSlaves;
|
||||||
|
};
|
@ -7,6 +7,7 @@
|
|||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
#include <QTimer>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
||||||
// hyperion util
|
// hyperion util
|
||||||
@ -19,8 +20,11 @@
|
|||||||
///
|
///
|
||||||
/// Connection class to setup an connection to the hyperion server and execute commands
|
/// Connection class to setup an connection to the hyperion server and execute commands
|
||||||
///
|
///
|
||||||
class ProtoConnection
|
class ProtoConnection : public QObject
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// Constructor
|
/// Constructor
|
||||||
@ -67,10 +71,6 @@ public:
|
|||||||
///
|
///
|
||||||
void clearAll();
|
void clearAll();
|
||||||
|
|
||||||
private:
|
|
||||||
/// Try to connect to the Hyperion host
|
|
||||||
void connectToHost();
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Send a command message and receive its reply
|
/// Send a command message and receive its reply
|
||||||
///
|
///
|
||||||
@ -78,6 +78,13 @@ private:
|
|||||||
///
|
///
|
||||||
void sendMessage(const proto::HyperionRequest & message);
|
void sendMessage(const proto::HyperionRequest & message);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/// Try to connect to the Hyperion host
|
||||||
|
void connectToHost();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Parse a reply message
|
/// Parse a reply message
|
||||||
///
|
///
|
||||||
@ -99,4 +106,7 @@ private:
|
|||||||
|
|
||||||
/// Skip receiving reply messages from Hyperion if set
|
/// Skip receiving reply messages from Hyperion if set
|
||||||
bool _skipReply;
|
bool _skipReply;
|
||||||
|
|
||||||
|
QTimer _timer;
|
||||||
|
QAbstractSocket::SocketState _prevSocketState;
|
||||||
};
|
};
|
||||||
|
@ -6,11 +6,23 @@
|
|||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
// Hyperion includes
|
// Hyperion includes
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
|
// hyperion includes
|
||||||
|
#include <utils/Image.h>
|
||||||
|
#include <utils/ColorRgb.h>
|
||||||
|
|
||||||
|
// forward decl
|
||||||
class ProtoClientConnection;
|
class ProtoClientConnection;
|
||||||
|
class ProtoConnection;
|
||||||
|
|
||||||
|
namespace proto {
|
||||||
|
class HyperionRequest;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// This class creates a TCP server which accepts connections wich can then send
|
/// This class creates a TCP server which accepts connections wich can then send
|
||||||
@ -35,6 +47,9 @@ public:
|
|||||||
///
|
///
|
||||||
uint16_t getPort() const;
|
uint16_t getPort() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void sendImageToProtoSlaves(int priority, const Image<ColorRgb> & image, int duration_ms);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
/// Slot which is called when a client tries to create a new connection
|
/// Slot which is called when a client tries to create a new connection
|
||||||
@ -47,6 +62,8 @@ private slots:
|
|||||||
///
|
///
|
||||||
void closedConnection(ProtoClientConnection * connection);
|
void closedConnection(ProtoClientConnection * connection);
|
||||||
|
|
||||||
|
void newMessage(const proto::HyperionRequest * message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
@ -56,4 +73,9 @@ private:
|
|||||||
|
|
||||||
/// List with open connections
|
/// List with open connections
|
||||||
QSet<ProtoClientConnection *> _openConnections;
|
QSet<ProtoClientConnection *> _openConnections;
|
||||||
|
QStringList _forwardClients;
|
||||||
|
|
||||||
|
/// Hyperion proto connection object for forwarding
|
||||||
|
QList<ProtoConnection*> _proxy_connections;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utils/ColorRgb.h>
|
||||||
|
|
||||||
|
|
||||||
template <typename Pixel_T>
|
template <typename Pixel_T>
|
||||||
class Image
|
class Image
|
||||||
@ -183,6 +185,25 @@ public:
|
|||||||
{
|
{
|
||||||
return _pixels;
|
return _pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Convert image of any color order to a RGB image.
|
||||||
|
///
|
||||||
|
/// @param[out] image The image that buffers the output
|
||||||
|
///
|
||||||
|
void toRgb(Image<ColorRgb>& image)
|
||||||
|
{
|
||||||
|
image.resize(_width, _height);
|
||||||
|
const unsigned imageSize = _width * _height;
|
||||||
|
|
||||||
|
for (unsigned idx=0; idx<imageSize; idx++)
|
||||||
|
{
|
||||||
|
const Pixel_T color = memptr()[idx];
|
||||||
|
image.memptr()[idx] = ColorRgb{color.red, color.green, color.blue};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
find_package(PythonLibs REQUIRED)
|
find_package(PythonLibs REQUIRED)
|
||||||
|
#OpenElec uses 2.7, if you want to compile for OpenElec require 2.7
|
||||||
|
#find_package(PythonLibs 2.7 REQUIRED)
|
||||||
|
|
||||||
# Include the python directory. Also include the parent (which is for example /usr/include)
|
# Include the python directory. Also include the parent (which is for example /usr/include)
|
||||||
# which may be required when it is not includes by the (cross-) compiler by default.
|
# which may be required when it is not includes by the (cross-) compiler by default.
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include "AmlogicGrabber.h"
|
#include <grabber/AmlogicGrabber.h>
|
||||||
|
|
||||||
// Flags copied from 'include/linux/amlogic/amports/amvideocap.h' at https://github.com/codesnake/linux-amlogic
|
// Flags copied from 'include/linux/amlogic/amports/amvideocap.h' at https://github.com/codesnake/linux-amlogic
|
||||||
#define AMVIDEOCAP_IOC_MAGIC 'V'
|
#define AMVIDEOCAP_IOC_MAGIC 'V'
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Amlogic grabber includes
|
// Amlogic grabber includes
|
||||||
#include <grabber/AmlogicWrapper.h>
|
#include <grabber/AmlogicWrapper.h>
|
||||||
#include "AmlogicGrabber.h"
|
#include <grabber/AmlogicGrabber.h>
|
||||||
|
|
||||||
|
|
||||||
AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
||||||
@ -26,6 +26,7 @@ AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeig
|
|||||||
// Configure the timer to generate events every n milliseconds
|
// Configure the timer to generate events every n milliseconds
|
||||||
_timer.setInterval(_updateInterval_ms);
|
_timer.setInterval(_updateInterval_ms);
|
||||||
_timer.setSingleShot(false);
|
_timer.setSingleShot(false);
|
||||||
|
_forward = _hyperion->getForwarder()->protoForwardingEnabled();
|
||||||
|
|
||||||
_processor->setSize(grabWidth, grabHeight);
|
_processor->setSize(grabWidth, grabHeight);
|
||||||
|
|
||||||
@ -55,8 +56,14 @@ void AmlogicWrapper::action()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_processor->process(_image, _ledColors);
|
if ( _forward )
|
||||||
|
{
|
||||||
|
Image<ColorRgb> image_rgb;
|
||||||
|
_image.toRgb(image_rgb);
|
||||||
|
emit emitImage(_priority, image_rgb, _timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor->process(_image, _ledColors);
|
||||||
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic)
|
|||||||
SET(AmlogicQT_HEADERS ${CURRENT_HEADER_DIR}/AmlogicWrapper.h)
|
SET(AmlogicQT_HEADERS ${CURRENT_HEADER_DIR}/AmlogicWrapper.h)
|
||||||
|
|
||||||
SET(AmlogicHEADERS
|
SET(AmlogicHEADERS
|
||||||
${CURRENT_SOURCE_DIR}/AmlogicGrabber.h
|
${CURRENT_HEADER_DIR}/AmlogicGrabber.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(AmlogicSOURCES
|
SET(AmlogicSOURCES
|
||||||
|
@ -9,32 +9,33 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx)
|
|||||||
|
|
||||||
# Group the headers that go through the MOC compiler
|
# Group the headers that go through the MOC compiler
|
||||||
SET(DispmanxGrabberQT_HEADERS
|
SET(DispmanxGrabberQT_HEADERS
|
||||||
${CURRENT_HEADER_DIR}/DispmanxWrapper.h
|
${CURRENT_HEADER_DIR}/DispmanxWrapper.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(DispmanxGrabberHEADERS
|
SET(DispmanxGrabberHEADERS
|
||||||
${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.h
|
${CURRENT_HEADER_DIR}/DispmanxFrameGrabber.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(DispmanxGrabberSOURCES
|
SET(DispmanxGrabberSOURCES
|
||||||
${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp
|
${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp
|
||||||
${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp
|
${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_QT5)
|
if(ENABLE_QT5)
|
||||||
QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
|
QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
|
||||||
else(ENABLE_QT5)
|
else(ENABLE_QT5)
|
||||||
QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
|
QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
|
||||||
endif(ENABLE_QT5)
|
endif(ENABLE_QT5)
|
||||||
|
|
||||||
add_library(dispmanx-grabber
|
add_library(dispmanx-grabber
|
||||||
${DispmanxGrabberHEADERS}
|
${DispmanxGrabberHEADERS}
|
||||||
${DispmanxGrabberQT_HEADERS}
|
${DispmanxGrabberQT_HEADERS}
|
||||||
${DispmanxGrabberHEADERS_MOC}
|
${DispmanxGrabberHEADERS_MOC}
|
||||||
${DispmanxGrabberSOURCES}
|
${DispmanxGrabberSOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(dispmanx-grabber
|
target_link_libraries(dispmanx-grabber
|
||||||
hyperion
|
hyperion
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
${BCM_LIBRARIES})
|
${BCM_LIBRARIES}
|
||||||
|
)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include "DispmanxFrameGrabber.h"
|
#include "grabber/DispmanxFrameGrabber.h"
|
||||||
|
|
||||||
DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned height) :
|
DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned height) :
|
||||||
_vc_display(0),
|
_vc_display(0),
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Dispmanx grabber includes
|
// Dispmanx grabber includes
|
||||||
#include <grabber/DispmanxWrapper.h>
|
#include <grabber/DispmanxWrapper.h>
|
||||||
#include "DispmanxFrameGrabber.h"
|
#include <grabber/DispmanxFrameGrabber.h>
|
||||||
|
|
||||||
|
|
||||||
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
||||||
@ -28,6 +28,7 @@ DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHe
|
|||||||
_timer.setSingleShot(false);
|
_timer.setSingleShot(false);
|
||||||
|
|
||||||
_processor->setSize(grabWidth, grabHeight);
|
_processor->setSize(grabWidth, grabHeight);
|
||||||
|
_forward = _hyperion->getForwarder()->protoForwardingEnabled();
|
||||||
|
|
||||||
// Connect the QTimer to this
|
// Connect the QTimer to this
|
||||||
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(action()));
|
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(action()));
|
||||||
@ -51,10 +52,17 @@ void DispmanxWrapper::action()
|
|||||||
// Grab frame into the allocated image
|
// Grab frame into the allocated image
|
||||||
_frameGrabber->grabFrame(_image);
|
_frameGrabber->grabFrame(_image);
|
||||||
|
|
||||||
_processor->process(_image, _ledColors);
|
if ( _forward )
|
||||||
|
{
|
||||||
|
Image<ColorRgb> image_rgb;
|
||||||
|
_image.toRgb(image_rgb);
|
||||||
|
emit emitImage(_priority, image_rgb, _timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
_processor->process(_image, _ledColors);
|
||||||
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispmanxWrapper::stop()
|
void DispmanxWrapper::stop()
|
||||||
{
|
{
|
||||||
// Stop the timer, effectivly stopping the process
|
// Stop the timer, effectivly stopping the process
|
||||||
|
@ -46,8 +46,9 @@ void FramebufferWrapper::action()
|
|||||||
// Grab frame into the allocated image
|
// Grab frame into the allocated image
|
||||||
_frameGrabber->grabFrame(_image);
|
_frameGrabber->grabFrame(_image);
|
||||||
|
|
||||||
_processor->process(_image, _ledColors);
|
emit emitImage(_priority, _image, _timeout_ms);
|
||||||
|
|
||||||
|
_processor->process(_image, _ledColors);
|
||||||
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
||||||
}
|
}
|
||||||
void FramebufferWrapper::stop()
|
void FramebufferWrapper::stop()
|
||||||
|
@ -46,8 +46,9 @@ void OsxWrapper::action()
|
|||||||
// Grab frame into the allocated image
|
// Grab frame into the allocated image
|
||||||
_frameGrabber->grabFrame(_image);
|
_frameGrabber->grabFrame(_image);
|
||||||
|
|
||||||
_processor->process(_image, _ledColors);
|
emit emitImage(_priority, _image, _timeout_ms);
|
||||||
|
|
||||||
|
_processor->process(_image, _ledColors);
|
||||||
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
||||||
}
|
}
|
||||||
void OsxWrapper::stop()
|
void OsxWrapper::stop()
|
||||||
|
@ -94,6 +94,9 @@ void V4L2Wrapper::newFrame(const Image<ColorRgb> &image)
|
|||||||
// process the new image
|
// process the new image
|
||||||
_processor->process(image, _ledColors);
|
_processor->process(image, _ledColors);
|
||||||
|
|
||||||
|
// forward to other hyperions
|
||||||
|
emit emitImage(_priority, image, _timeout_ms);
|
||||||
|
|
||||||
// send colors to Hyperion
|
// send colors to Hyperion
|
||||||
emit emitColors(_priority, _ledColors, _timeout_ms);
|
emit emitColors(_priority, _ledColors, _timeout_ms);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ SET(Hyperion_HEADERS
|
|||||||
${CURRENT_HEADER_DIR}/PriorityMuxer.h
|
${CURRENT_HEADER_DIR}/PriorityMuxer.h
|
||||||
|
|
||||||
${CURRENT_SOURCE_DIR}/MultiColorTransform.h
|
${CURRENT_SOURCE_DIR}/MultiColorTransform.h
|
||||||
|
${CURRENT_HEADER_DIR}/MessageForwarder.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(Hyperion_SOURCES
|
SET(Hyperion_SOURCES
|
||||||
@ -30,6 +31,7 @@ SET(Hyperion_SOURCES
|
|||||||
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
||||||
${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp
|
${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp
|
||||||
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp
|
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/MessageForwarder.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(Hyperion_RESOURCES
|
set(Hyperion_RESOURCES
|
||||||
|
@ -267,12 +267,45 @@ LedDevice * Hyperion::createColorSmoothing(const Json::Value & smoothingConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MessageForwarder * Hyperion::createMessageForwarder(const Json::Value & forwarderConfig)
|
||||||
|
{
|
||||||
|
MessageForwarder * forwarder = new MessageForwarder();
|
||||||
|
if ( ! forwarderConfig.isNull() )
|
||||||
|
{
|
||||||
|
if ( ! forwarderConfig["json"].isNull() && forwarderConfig["json"].isArray() )
|
||||||
|
{
|
||||||
|
for (const Json::Value& addr : forwarderConfig["json"])
|
||||||
|
{
|
||||||
|
std::cout << "Json forward to " << addr.asString() << std::endl;
|
||||||
|
forwarder->addJsonSlave(addr.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! forwarderConfig["proto"].isNull() && forwarderConfig["proto"].isArray() )
|
||||||
|
{
|
||||||
|
for (const Json::Value& addr : forwarderConfig["proto"])
|
||||||
|
{
|
||||||
|
std::cout << "Proto forward to " << addr.asString() << std::endl;
|
||||||
|
forwarder->addProtoSlave(addr.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return forwarder;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageForwarder * Hyperion::getForwarder()
|
||||||
|
{
|
||||||
|
return _messageForwarder;
|
||||||
|
}
|
||||||
|
|
||||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||||
_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))),
|
_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))),
|
||||||
_muxer(_ledString.leds().size()),
|
_muxer(_ledString.leds().size()),
|
||||||
_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])),
|
_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])),
|
||||||
_device(LedDeviceFactory::construct(jsonConfig["device"])),
|
_device(LedDeviceFactory::construct(jsonConfig["device"])),
|
||||||
_effectEngine(nullptr),
|
_effectEngine(nullptr),
|
||||||
|
_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])),
|
||||||
_timer()
|
_timer()
|
||||||
{
|
{
|
||||||
if (!_raw2ledTransform->verifyTransforms())
|
if (!_raw2ledTransform->verifyTransforms())
|
||||||
@ -314,6 +347,9 @@ Hyperion::~Hyperion()
|
|||||||
|
|
||||||
// delete the color transform
|
// delete the color transform
|
||||||
delete _raw2ledTransform;
|
delete _raw2ledTransform;
|
||||||
|
|
||||||
|
// delete the message forwarder
|
||||||
|
delete _messageForwarder;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Hyperion::getLedCount() const
|
unsigned Hyperion::getLedCount() const
|
||||||
|
51
libsrc/hyperion/MessageForwarder.cpp
Normal file
51
libsrc/hyperion/MessageForwarder.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// STL includes
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <hyperion/MessageForwarder.h>
|
||||||
|
|
||||||
|
|
||||||
|
MessageForwarder::MessageForwarder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageForwarder::~MessageForwarder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MessageForwarder::addJsonSlave(std::string slave)
|
||||||
|
{
|
||||||
|
QStringList parts = QString(slave.c_str()).split(":");
|
||||||
|
if (parts.size() != 2)
|
||||||
|
throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(slave.c_str()).toStdString());
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
quint16 port = parts[1].toUShort(&ok);
|
||||||
|
if (!ok)
|
||||||
|
throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString());
|
||||||
|
|
||||||
|
JsonSlaveAddress c;
|
||||||
|
c.addr = QHostAddress(parts[0]);
|
||||||
|
c.port = port;
|
||||||
|
_jsonSlaves << c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageForwarder::addProtoSlave(std::string slave)
|
||||||
|
{
|
||||||
|
_protoSlaves << QString(slave.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList MessageForwarder::getProtoSlaves()
|
||||||
|
{
|
||||||
|
return _protoSlaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<MessageForwarder::JsonSlaveAddress> MessageForwarder::getJsonSlaves()
|
||||||
|
{
|
||||||
|
return _jsonSlaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageForwarder::protoForwardingEnabled()
|
||||||
|
{
|
||||||
|
return ! _protoSlaves.empty();
|
||||||
|
}
|
@ -16,6 +16,7 @@
|
|||||||
// hyperion util includes
|
// hyperion util includes
|
||||||
#include <hyperion/ImageProcessorFactory.h>
|
#include <hyperion/ImageProcessorFactory.h>
|
||||||
#include <hyperion/ImageProcessor.h>
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
#include <hyperion/MessageForwarder.h>
|
||||||
#include <hyperion/ColorTransform.h>
|
#include <hyperion/ColorTransform.h>
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
|
|
||||||
@ -250,8 +251,27 @@ void JsonClientConnection::handleMessage(const std::string &messageString)
|
|||||||
handleNotImplemented();
|
handleNotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JsonClientConnection::forwardJsonMessage(const Json::Value & message)
|
||||||
|
{
|
||||||
|
QTcpSocket client;
|
||||||
|
QList<MessageForwarder::JsonSlaveAddress> list = _hyperion->getForwarder()->getJsonSlaves();
|
||||||
|
|
||||||
|
for ( int i=0; i<list.size(); i++ )
|
||||||
|
{
|
||||||
|
client.connectToHost(list.at(i).addr, list.at(i).port);
|
||||||
|
if ( client.waitForConnected(500) )
|
||||||
|
{
|
||||||
|
sendMessage(message,&client);
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JsonClientConnection::handleColorCommand(const Json::Value &message)
|
void JsonClientConnection::handleColorCommand(const Json::Value &message)
|
||||||
{
|
{
|
||||||
|
forwardJsonMessage(message);
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
int priority = message["priority"].asInt();
|
int priority = message["priority"].asInt();
|
||||||
int duration = message.get("duration", -1).asInt();
|
int duration = message.get("duration", -1).asInt();
|
||||||
@ -289,6 +309,8 @@ void JsonClientConnection::handleColorCommand(const Json::Value &message)
|
|||||||
|
|
||||||
void JsonClientConnection::handleImageCommand(const Json::Value &message)
|
void JsonClientConnection::handleImageCommand(const Json::Value &message)
|
||||||
{
|
{
|
||||||
|
forwardJsonMessage(message);
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
int priority = message["priority"].asInt();
|
int priority = message["priority"].asInt();
|
||||||
int duration = message.get("duration", -1).asInt();
|
int duration = message.get("duration", -1).asInt();
|
||||||
@ -320,6 +342,8 @@ void JsonClientConnection::handleImageCommand(const Json::Value &message)
|
|||||||
|
|
||||||
void JsonClientConnection::handleEffectCommand(const Json::Value &message)
|
void JsonClientConnection::handleEffectCommand(const Json::Value &message)
|
||||||
{
|
{
|
||||||
|
forwardJsonMessage(message);
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
int priority = message["priority"].asInt();
|
int priority = message["priority"].asInt();
|
||||||
int duration = message.get("duration", -1).asInt();
|
int duration = message.get("duration", -1).asInt();
|
||||||
@ -418,6 +442,8 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
|
|||||||
|
|
||||||
void JsonClientConnection::handleClearCommand(const Json::Value &message)
|
void JsonClientConnection::handleClearCommand(const Json::Value &message)
|
||||||
{
|
{
|
||||||
|
forwardJsonMessage(message);
|
||||||
|
|
||||||
// extract parameters
|
// extract parameters
|
||||||
int priority = message["priority"].asInt();
|
int priority = message["priority"].asInt();
|
||||||
|
|
||||||
@ -428,8 +454,10 @@ void JsonClientConnection::handleClearCommand(const Json::Value &message)
|
|||||||
sendSuccessReply();
|
sendSuccessReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonClientConnection::handleClearallCommand(const Json::Value &)
|
void JsonClientConnection::handleClearallCommand(const Json::Value & message)
|
||||||
{
|
{
|
||||||
|
forwardJsonMessage(message);
|
||||||
|
|
||||||
// clear priority
|
// clear priority
|
||||||
_hyperion->clearall();
|
_hyperion->clearall();
|
||||||
|
|
||||||
@ -534,6 +562,47 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JsonClientConnection::sendMessage(const Json::Value & message, QTcpSocket * socket)
|
||||||
|
{
|
||||||
|
// serialize message (FastWriter already appends a newline)
|
||||||
|
std::string serializedMessage = Json::FastWriter().write(message);
|
||||||
|
|
||||||
|
// write message
|
||||||
|
socket->write(serializedMessage.c_str());
|
||||||
|
if (!socket->waitForBytesWritten())
|
||||||
|
{
|
||||||
|
//std::cout << "Error while writing data to host" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read reply data
|
||||||
|
QByteArray serializedReply;
|
||||||
|
while (!serializedReply.contains('\n'))
|
||||||
|
{
|
||||||
|
// receive reply
|
||||||
|
if (!socket->waitForReadyRead())
|
||||||
|
{
|
||||||
|
//std::cout << "Error while reading data from host" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedReply += socket->readAll();
|
||||||
|
}
|
||||||
|
int bytes = serializedReply.indexOf('\n') + 1; // Find the end of message
|
||||||
|
|
||||||
|
// parse reply data
|
||||||
|
Json::Reader jsonReader;
|
||||||
|
Json::Value reply;
|
||||||
|
if (!jsonReader.parse(serializedReply.constData(), serializedReply.constData() + bytes, reply))
|
||||||
|
{
|
||||||
|
//std::cout << "Error while parsing reply: invalid json" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void JsonClientConnection::sendSuccessReply()
|
void JsonClientConnection::sendSuccessReply()
|
||||||
{
|
{
|
||||||
// create reply
|
// create reply
|
||||||
|
@ -124,6 +124,7 @@ private:
|
|||||||
/// @param message The JSON message to send
|
/// @param message The JSON message to send
|
||||||
///
|
///
|
||||||
void sendMessage(const Json::Value & message);
|
void sendMessage(const Json::Value & message);
|
||||||
|
void sendMessage(const Json::Value & message, QTcpSocket * socket);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Send a standard reply indicating success
|
/// Send a standard reply indicating success
|
||||||
@ -147,6 +148,11 @@ private:
|
|||||||
///
|
///
|
||||||
void handleWebSocketFrame();
|
void handleWebSocketFrame();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// forward json message
|
||||||
|
///
|
||||||
|
void forwardJsonMessage(const Json::Value & message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
/// Check if a JSON messag is valid according to a given JSON schema
|
/// Check if a JSON messag is valid according to a given JSON schema
|
||||||
|
@ -16,6 +16,14 @@ JsonServer::JsonServer(Hyperion *hyperion, uint16_t port) :
|
|||||||
throw std::runtime_error("Json server could not bind to port");
|
throw std::runtime_error("Json server could not bind to port");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<MessageForwarder::JsonSlaveAddress> list = _hyperion->getForwarder()->getJsonSlaves();
|
||||||
|
for ( int i=0; i<list.size(); i++ )
|
||||||
|
{
|
||||||
|
if ( list.at(i).addr == QHostAddress::LocalHost && list.at(i).port == port ) {
|
||||||
|
throw std::runtime_error("Loop between proto server and forwarder detected. Fix your config!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set trigger for incoming connections
|
// Set trigger for incoming connections
|
||||||
connect(&_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
|
connect(&_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "LedDeviceFadeCandy.h"
|
#include "LedDeviceFadeCandy.h"
|
||||||
|
|
||||||
static const ssize_t MAX_NUM_LEDS = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
|
static const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
|
||||||
static const ssize_t OPC_SET_PIXELS = 0; // OPC command codes
|
static const unsigned OPC_SET_PIXELS = 0; // OPC command codes
|
||||||
static const ssize_t OPC_HEADER_SIZE = 4; // OPC header size
|
static const unsigned OPC_HEADER_SIZE = 4; // OPC header size
|
||||||
|
|
||||||
|
|
||||||
LedDeviceFadeCandy::LedDeviceFadeCandy(const std::string& host, const uint16_t port, const unsigned channel) :
|
LedDeviceFadeCandy::LedDeviceFadeCandy(const std::string& host, const uint16_t port, const unsigned channel) :
|
||||||
|
@ -81,6 +81,9 @@ void ProtoClientConnection::socketClosed()
|
|||||||
|
|
||||||
void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message)
|
void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message)
|
||||||
{
|
{
|
||||||
|
// forward messages
|
||||||
|
emit newMessage(&message);
|
||||||
|
|
||||||
switch (message.command())
|
switch (message.command())
|
||||||
{
|
{
|
||||||
case proto::HyperionRequest::COLOR:
|
case proto::HyperionRequest::COLOR:
|
||||||
|
@ -6,12 +6,14 @@
|
|||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
// Hyperion includes
|
// Hyperion includes
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
// proto includes
|
// proto includes
|
||||||
#include "message.pb.h"
|
#include "message.pb.h"
|
||||||
|
#include "protoserver/ProtoConnection.h"
|
||||||
|
|
||||||
class ImageProcessor;
|
class ImageProcessor;
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ signals:
|
|||||||
/// @param connection This connection object
|
/// @param connection This connection object
|
||||||
///
|
///
|
||||||
void connectionClosed(ProtoClientConnection * connection);
|
void connectionClosed(ProtoClientConnection * connection);
|
||||||
|
void newMessage(const proto::HyperionRequest * message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
ProtoConnection::ProtoConnection(const std::string & a) :
|
ProtoConnection::ProtoConnection(const std::string & a) :
|
||||||
_socket(),
|
_socket(),
|
||||||
_skipReply(false)
|
_skipReply(false),
|
||||||
|
_prevSocketState(QAbstractSocket::UnconnectedState)
|
||||||
{
|
{
|
||||||
QString address(a.c_str());
|
QString address(a.c_str());
|
||||||
QStringList parts = address.split(":");
|
QStringList parts = address.split(":");
|
||||||
@ -29,10 +30,18 @@ ProtoConnection::ProtoConnection(const std::string & a) :
|
|||||||
// try to connect to host
|
// try to connect to host
|
||||||
std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
|
std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
|
||||||
connectToHost();
|
connectToHost();
|
||||||
|
|
||||||
|
// start the connection timer
|
||||||
|
_timer.setInterval(5000);
|
||||||
|
_timer.setSingleShot(false);
|
||||||
|
|
||||||
|
connect(&_timer,SIGNAL(timeout()), this, SLOT(connectToHost()) );
|
||||||
|
_timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtoConnection::~ProtoConnection()
|
ProtoConnection::~ProtoConnection()
|
||||||
{
|
{
|
||||||
|
_timer.stop();
|
||||||
_socket.close();
|
_socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,20 +100,37 @@ void ProtoConnection::clearAll()
|
|||||||
|
|
||||||
void ProtoConnection::connectToHost()
|
void ProtoConnection::connectToHost()
|
||||||
{
|
{
|
||||||
_socket.connectToHost(_host, _port);
|
// try connection only when
|
||||||
if (_socket.waitForConnected()) {
|
if (_socket.state() == QAbstractSocket::UnconnectedState)
|
||||||
std::cout << "Connected to Hyperion host" << std::endl;
|
{
|
||||||
|
_socket.connectToHost(_host, _port);
|
||||||
|
//_socket.waitForConnected(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoConnection::sendMessage(const proto::HyperionRequest &message)
|
void ProtoConnection::sendMessage(const proto::HyperionRequest &message)
|
||||||
{
|
{
|
||||||
if (_socket.state() == QAbstractSocket::UnconnectedState)
|
// print out connection message only when state is changed
|
||||||
|
if (_socket.state() != _prevSocketState )
|
||||||
{
|
{
|
||||||
std::cout << "Currently disconnected: trying to connect to host" << std::endl;
|
switch (_socket.state() )
|
||||||
connectToHost();
|
{
|
||||||
|
case QAbstractSocket::UnconnectedState:
|
||||||
|
std::cout << "No connection to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::ConnectedState:
|
||||||
|
std::cout << "Connected to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_prevSocketState = _socket.state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (_socket.state() != QAbstractSocket::ConnectedState)
|
if (_socket.state() != QAbstractSocket::ConnectedState)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
// project includes
|
// project includes
|
||||||
|
#include <hyperion/MessageForwarder.h>
|
||||||
#include <protoserver/ProtoServer.h>
|
#include <protoserver/ProtoServer.h>
|
||||||
|
#include "protoserver/ProtoConnection.h"
|
||||||
#include "ProtoClientConnection.h"
|
#include "ProtoClientConnection.h"
|
||||||
|
|
||||||
ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port) :
|
ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port) :
|
||||||
@ -11,6 +13,20 @@ ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port) :
|
|||||||
_server(),
|
_server(),
|
||||||
_openConnections()
|
_openConnections()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
MessageForwarder * forwarder = hyperion->getForwarder();
|
||||||
|
QStringList slaves = forwarder->getProtoSlaves();
|
||||||
|
|
||||||
|
for (int i = 0; i < slaves.size(); ++i) {
|
||||||
|
if ( QString("127.0.0.1:%1").arg(port) == slaves.at(i) ) {
|
||||||
|
throw std::runtime_error("Loop between proto server and forwarder detected. Fix your config!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoConnection* p = new ProtoConnection(slaves.at(i).toLocal8Bit().constData());
|
||||||
|
p->setSkipReply(true);
|
||||||
|
_proxy_connections << p;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_server.listen(QHostAddress::Any, port))
|
if (!_server.listen(QHostAddress::Any, port))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Proto server could not bind to port");
|
throw std::runtime_error("Proto server could not bind to port");
|
||||||
@ -25,6 +41,9 @@ ProtoServer::~ProtoServer()
|
|||||||
foreach (ProtoClientConnection * connection, _openConnections) {
|
foreach (ProtoClientConnection * connection, _openConnections) {
|
||||||
delete connection;
|
delete connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (!_proxy_connections.isEmpty())
|
||||||
|
delete _proxy_connections.takeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ProtoServer::getPort() const
|
uint16_t ProtoServer::getPort() const
|
||||||
@ -44,9 +63,23 @@ void ProtoServer::newConnection()
|
|||||||
|
|
||||||
// register slot for cleaning up after the connection closed
|
// register slot for cleaning up after the connection closed
|
||||||
connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*)));
|
connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*)));
|
||||||
|
connect(connection, SIGNAL(newMessage(const proto::HyperionRequest*)), this, SLOT(newMessage(const proto::HyperionRequest*)));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtoServer::newMessage(const proto::HyperionRequest * message)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _proxy_connections.size(); ++i)
|
||||||
|
_proxy_connections.at(i)->sendMessage(*message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoServer::sendImageToProtoSlaves(int priority, const Image<ColorRgb> & image, int duration_ms)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _proxy_connections.size(); ++i)
|
||||||
|
_proxy_connections.at(i)->setImage(image, priority, duration_ms);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtoServer::closedConnection(ProtoClientConnection *connection)
|
void ProtoServer::closedConnection(ProtoClientConnection *connection)
|
||||||
{
|
{
|
||||||
std::cout << "Proto connection closed" << std::endl;
|
std::cout << "Proto connection closed" << std::endl;
|
||||||
|
@ -15,4 +15,9 @@ if(ENABLE_PROTOBUF)
|
|||||||
if(ENABLE_X11)
|
if(ENABLE_X11)
|
||||||
add_subdirectory(hyperion-x11)
|
add_subdirectory(hyperion-x11)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_DISPMANX)
|
||||||
|
add_subdirectory(hyperion-dispmanx)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
38
src/hyperion-aml/AmlogicWrapper.cpp
Normal file
38
src/hyperion-aml/AmlogicWrapper.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
// Hyperion-AmLogic includes
|
||||||
|
#include "AmlogicWrapper.h"
|
||||||
|
|
||||||
|
AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz) :
|
||||||
|
_timer(this),
|
||||||
|
_grabber(grabWidth, grabHeight)
|
||||||
|
{
|
||||||
|
_timer.setSingleShot(false);
|
||||||
|
_timer.setInterval(updateRate_Hz);
|
||||||
|
|
||||||
|
// Connect capturing to the timeout signal of the timer
|
||||||
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image<ColorRgb> & AmlogicWrapper::getScreenshot()
|
||||||
|
{
|
||||||
|
capture();
|
||||||
|
return _screenshot_rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmlogicWrapper::start()
|
||||||
|
{
|
||||||
|
_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmlogicWrapper::stop()
|
||||||
|
{
|
||||||
|
_timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmlogicWrapper::capture()
|
||||||
|
{
|
||||||
|
_grabber.grabFrame(_screenshot);
|
||||||
|
_screenshot.toRgb(_screenshot_rgb);
|
||||||
|
|
||||||
|
emit sig_screenshot(_screenshot_rgb);
|
||||||
|
}
|
43
src/hyperion-aml/AmlogicWrapper.h
Normal file
43
src/hyperion-aml/AmlogicWrapper.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
// Hyperion-Dispmanx includes
|
||||||
|
#include <grabber/AmlogicGrabber.h>
|
||||||
|
|
||||||
|
class AmlogicWrapper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
|
||||||
|
|
||||||
|
const Image<ColorRgb> & getScreenshot();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Starts the timed capturing of screenshots
|
||||||
|
///
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sig_screenshot(const Image<ColorRgb> & screenshot);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
///
|
||||||
|
/// Performs a single screenshot capture and publishes the capture screenshot on the screenshot signal.
|
||||||
|
///
|
||||||
|
void capture();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The QT timer to generate capture-publish events
|
||||||
|
QTimer _timer;
|
||||||
|
|
||||||
|
/// The grabber for creating screenshots
|
||||||
|
AmlogicGrabber _grabber;
|
||||||
|
|
||||||
|
// image buffers
|
||||||
|
Image<ColorRgb> _screenshot_rgb;
|
||||||
|
Image<ColorBgr> _screenshot;
|
||||||
|
|
||||||
|
};
|
@ -14,6 +14,7 @@ include_directories(
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(Hyperion_AML_QT_HEADERS
|
set(Hyperion_AML_QT_HEADERS
|
||||||
|
AmlogicWrapper.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(Hyperion_AML_HEADERS
|
set(Hyperion_AML_HEADERS
|
||||||
@ -21,12 +22,13 @@ set(Hyperion_AML_HEADERS
|
|||||||
|
|
||||||
set(Hyperion_AML_SOURCES
|
set(Hyperion_AML_SOURCES
|
||||||
hyperion-aml.cpp
|
hyperion-aml.cpp
|
||||||
|
AmlogicWrapper.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_QT5)
|
if(ENABLE_QT5)
|
||||||
QT5_WRAP_CPP(Hyperion_AML_HEADERS_MOC ${Hyperion_AML_QT_HEADERS})
|
QT5_WRAP_CPP(Hyperion_AML_HEADERS_MOC ${Hyperion_AML_QT_HEADERS})
|
||||||
else(ENABLE_QT5)
|
else(ENABLE_QT5)
|
||||||
QT4_WRAP_CPP(Hyperion_AML_HEADERS_MOC ${Hyperion_AML_QT_HEADERS})
|
QT4_WRAP_CPP(Hyperion_AML_HEADERS_MOC ${Hyperion_AML_QT_HEADERS})
|
||||||
endif(ENABLE_QT5)
|
endif(ENABLE_QT5)
|
||||||
|
|
||||||
add_executable(hyperion-amlogic
|
add_executable(hyperion-amlogic
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
// getoptPlusPLus includes
|
// getoptPlusPLus includes
|
||||||
#include <getoptPlusPlus/getoptpp.h>
|
#include <getoptPlusPlus/getoptpp.h>
|
||||||
|
|
||||||
#include "../../libsrc/grabber/amlogic/AmlogicGrabber.h"
|
#include <protoserver/ProtoConnectionWrapper.h>
|
||||||
|
#include "AmlogicWrapper.h"
|
||||||
|
|
||||||
using namespace vlofgren;
|
using namespace vlofgren;
|
||||||
|
|
||||||
// save the image as screenshot
|
// save the image as screenshot
|
||||||
void saveScreenshot(const char * filename, const Image<ColorBgr> & image)
|
void saveScreenshot(const char * filename, const Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
// store as PNG
|
// store as PNG
|
||||||
QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
|
QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
|
||||||
pngImage = pngImage.rgbSwapped();
|
|
||||||
pngImage.save(filename);
|
pngImage.save(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,16 +30,17 @@ int main(int argc, char ** argv)
|
|||||||
OptionsParser optionParser("X11 capture application for Hyperion");
|
OptionsParser optionParser("X11 capture application for Hyperion");
|
||||||
ParameterSet & parameters = optionParser.getParameters();
|
ParameterSet & parameters = optionParser.getParameters();
|
||||||
|
|
||||||
//IntParameter & argFps = parameters.add<IntParameter> ('f', "framerate", "Capture frame rate [default=10]");
|
IntParameter & argFps = parameters.add<IntParameter> ('f', "framerate", "Capture frame rate [default=10]");
|
||||||
IntParameter & argWidth = parameters.add<IntParameter> (0x0, "width", "Width of the captured image [default=128]");
|
IntParameter & argWidth = parameters.add<IntParameter> (0x0, "width", "Width of the captured image [default=128]");
|
||||||
IntParameter & argHeight = parameters.add<IntParameter> (0x0, "height", "Height of the captured image [default=128]");
|
IntParameter & argHeight = parameters.add<IntParameter> (0x0, "height", "Height of the captured image [default=128]");
|
||||||
SwitchParameter<> & argScreenshot = parameters.add<SwitchParameter<>> (0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
SwitchParameter<> & argScreenshot = parameters.add<SwitchParameter<>> (0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
StringParameter & argAddress = parameters.add<StringParameter> ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]");
|
StringParameter & argAddress = parameters.add<StringParameter> ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]");
|
||||||
IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
|
IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
|
||||||
//SwitchParameter<> & argSkipReply = parameters.add<SwitchParameter<>> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion");
|
SwitchParameter<> & argSkipReply = parameters.add<SwitchParameter<>> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion");
|
||||||
SwitchParameter<> & argHelp = parameters.add<SwitchParameter<>> ('h', "help", "Show this help message and exit");
|
SwitchParameter<> & argHelp = parameters.add<SwitchParameter<>> ('h', "help", "Show this help message and exit");
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
|
argFps.setDefault(10);
|
||||||
argWidth.setDefault(160);
|
argWidth.setDefault(160);
|
||||||
argHeight.setDefault(160);
|
argHeight.setDefault(160);
|
||||||
argAddress.setDefault("127.0.0.1:19445");
|
argAddress.setDefault("127.0.0.1:19445");
|
||||||
@ -57,29 +58,36 @@ int main(int argc, char ** argv)
|
|||||||
|
|
||||||
int width = argWidth.getValue();
|
int width = argWidth.getValue();
|
||||||
int height = argHeight.getValue();
|
int height = argHeight.getValue();
|
||||||
if (width < 160 || height < 60)
|
if (width < 160 || height < 160)
|
||||||
{
|
{
|
||||||
std::cout << "Minimum width and height is 160" << std::endl;
|
std::cout << "Minimum width and height is 160" << std::endl;
|
||||||
width = std::max(160, width);
|
width = std::max(160, width);
|
||||||
height = std::max(160, height);
|
height = std::max(160, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int grabInterval = 1000 / argFps.getValue();
|
||||||
|
AmlogicWrapper amlWrapper(argWidth.getValue(),argHeight.getValue(),grabInterval);
|
||||||
|
|
||||||
if (argScreenshot.isSet())
|
if (argScreenshot.isSet())
|
||||||
{
|
{
|
||||||
|
|
||||||
// Create the grabber
|
|
||||||
AmlogicGrabber amlGrabber(width, height);
|
|
||||||
|
|
||||||
// Capture a single screenshot and finish
|
// Capture a single screenshot and finish
|
||||||
Image<ColorBgr> screenshot;
|
const Image<ColorRgb> & screenshot = amlWrapper.getScreenshot();
|
||||||
amlGrabber.grabFrame(screenshot);
|
|
||||||
saveScreenshot("screenshot.png", screenshot);
|
saveScreenshot("screenshot.png", screenshot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO[TvdZ]: Implement the proto-client mechanisme
|
// Create the Proto-connection with hyperiond
|
||||||
std::cerr << "The PROTO-interface has not been implemented yet" << std::endl;
|
ProtoConnectionWrapper protoWrapper(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet());
|
||||||
}
|
|
||||||
|
|
||||||
|
// Connect the screen capturing to the proto processing
|
||||||
|
QObject::connect(&amlWrapper, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &protoWrapper, SLOT(receiveImage(Image<ColorRgb>)));
|
||||||
|
|
||||||
|
// Start the capturing
|
||||||
|
amlWrapper.start();
|
||||||
|
|
||||||
|
// Start the application
|
||||||
|
app.exec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error & e)
|
catch (const std::runtime_error & e)
|
||||||
{
|
{
|
||||||
|
65
src/hyperion-dispmanx/CMakeLists.txt
Normal file
65
src/hyperion-dispmanx/CMakeLists.txt
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Configure minimum CMAKE version
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
# Set the project name
|
||||||
|
project(hyperion-dispmanx)
|
||||||
|
|
||||||
|
if(ENABLE_QT5)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
else(ENABLE_QT5)
|
||||||
|
# find Qt4
|
||||||
|
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork )
|
||||||
|
endif(ENABLE_QT5)
|
||||||
|
|
||||||
|
# Find the BCM-package (VC control)
|
||||||
|
find_package(BCM REQUIRED)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/protoserver
|
||||||
|
${QT_INCLUDES}
|
||||||
|
${BCM_INCLUDE_DIRS}
|
||||||
|
${PROTOBUF_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(Hyperion_Dispmanx_QT_HEADERS
|
||||||
|
DispmanxWrapper.h)
|
||||||
|
|
||||||
|
set(Hyperion_Dispmanx_HEADERS
|
||||||
|
)
|
||||||
|
|
||||||
|
set(Hyperion_Dispmanx_SOURCES
|
||||||
|
hyperion-dispmanx.cpp
|
||||||
|
DispmanxWrapper.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ENABLE_QT5)
|
||||||
|
QT5_WRAP_CPP(Hyperion_Dispmanx_HEADERS_MOC ${Hyperion_Dispmanx_QT_HEADERS})
|
||||||
|
else(ENABLE_QT5)
|
||||||
|
QT4_WRAP_CPP(Hyperion_Dispmanx_HEADERS_MOC ${Hyperion_Dispmanx_QT_HEADERS})
|
||||||
|
endif(ENABLE_QT5)
|
||||||
|
|
||||||
|
add_executable( ${PROJECT_NAME}
|
||||||
|
${Hyperion_Dispmanx_HEADERS}
|
||||||
|
${Hyperion_Dispmanx_SOURCES}
|
||||||
|
${Hyperion_Dispmanx_HEADERS_MOC}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries( ${PROJECT_NAME}
|
||||||
|
getoptPlusPlus
|
||||||
|
blackborder
|
||||||
|
hyperion-utils
|
||||||
|
protoserver
|
||||||
|
dispmanx-grabber
|
||||||
|
${Dispmanx_LIBRARIES}
|
||||||
|
pthread
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ENABLE_QT5)
|
||||||
|
qt5_use_modules(hyperion-dispmanx Widgets Core Gui Network)
|
||||||
|
else(ENABLE_QT5)
|
||||||
|
qt4_use_modules(hyperion-dispmanx
|
||||||
|
Core
|
||||||
|
Gui
|
||||||
|
Network
|
||||||
|
)
|
||||||
|
endif(ENABLE_QT5)
|
38
src/hyperion-dispmanx/DispmanxWrapper.cpp
Normal file
38
src/hyperion-dispmanx/DispmanxWrapper.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
// Hyperion-Dispmanx includes
|
||||||
|
#include "DispmanxWrapper.h"
|
||||||
|
|
||||||
|
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz) :
|
||||||
|
_timer(this),
|
||||||
|
_grabber(grabWidth, grabHeight)
|
||||||
|
{
|
||||||
|
_timer.setSingleShot(false);
|
||||||
|
_timer.setInterval(updateRate_Hz);
|
||||||
|
|
||||||
|
// Connect capturing to the timeout signal of the timer
|
||||||
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image<ColorRgb> & DispmanxWrapper::getScreenshot()
|
||||||
|
{
|
||||||
|
capture();
|
||||||
|
return _screenshot_rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxWrapper::start()
|
||||||
|
{
|
||||||
|
_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxWrapper::stop()
|
||||||
|
{
|
||||||
|
_timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxWrapper::capture()
|
||||||
|
{
|
||||||
|
_grabber.grabFrame(_screenshot);
|
||||||
|
_screenshot.toRgb(_screenshot_rgb);
|
||||||
|
|
||||||
|
emit sig_screenshot(_screenshot_rgb);
|
||||||
|
}
|
42
src/hyperion-dispmanx/DispmanxWrapper.h
Normal file
42
src/hyperion-dispmanx/DispmanxWrapper.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
// Hyperion-Dispmanx includes
|
||||||
|
#include <grabber/DispmanxFrameGrabber.h>
|
||||||
|
|
||||||
|
class DispmanxWrapper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
|
||||||
|
|
||||||
|
const Image<ColorRgb> & getScreenshot();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Starts the timed capturing of screenshots
|
||||||
|
///
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sig_screenshot(const Image<ColorRgb> & screenshot);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
///
|
||||||
|
/// Performs a single screenshot capture and publishes the capture screenshot on the screenshot
|
||||||
|
/// signal.
|
||||||
|
///
|
||||||
|
void capture();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The QT timer to generate capture-publish events
|
||||||
|
QTimer _timer;
|
||||||
|
|
||||||
|
/// The grabber for creating screenshots
|
||||||
|
DispmanxFrameGrabber _grabber;
|
||||||
|
Image<ColorRgb> _screenshot_rgb;
|
||||||
|
Image<ColorRgba> _screenshot;
|
||||||
|
|
||||||
|
};
|
92
src/hyperion-dispmanx/hyperion-dispmanx.cpp
Normal file
92
src/hyperion-dispmanx/hyperion-dispmanx.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
// getoptPlusPLus includes
|
||||||
|
#include <getoptPlusPlus/getoptpp.h>
|
||||||
|
|
||||||
|
#include <protoserver/ProtoConnectionWrapper.h>
|
||||||
|
#include "DispmanxWrapper.h"
|
||||||
|
|
||||||
|
using namespace vlofgren;
|
||||||
|
|
||||||
|
// save the image as screenshot
|
||||||
|
void saveScreenshot(const char * filename, const Image<ColorRgb> & image)
|
||||||
|
{
|
||||||
|
// store as PNG
|
||||||
|
QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
|
||||||
|
pngImage.save(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// create the option parser and initialize all parameters
|
||||||
|
OptionsParser optionParser("Dispmanx capture application for Hyperion");
|
||||||
|
ParameterSet & parameters = optionParser.getParameters();
|
||||||
|
|
||||||
|
IntParameter & argFps = parameters.add<IntParameter> ('f', "framerate", "Capture frame rate [default=10]");
|
||||||
|
IntParameter & argWidth = parameters.add<IntParameter> (0x0, "width", "The width of the grabbed frames [pixels]");
|
||||||
|
IntParameter & argHeight = parameters.add<IntParameter> (0x0, "height", "The height of the grabbed frames");
|
||||||
|
|
||||||
|
SwitchParameter<> & argScreenshot = parameters.add<SwitchParameter<>> (0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
|
StringParameter & argAddress = parameters.add<StringParameter> ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]");
|
||||||
|
IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
|
||||||
|
SwitchParameter<> & argSkipReply = parameters.add<SwitchParameter<>> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion");
|
||||||
|
SwitchParameter<> & argHelp = parameters.add<SwitchParameter<>> ('h', "help", "Show this help message and exit");
|
||||||
|
|
||||||
|
// set defaults
|
||||||
|
argFps.setDefault(10);
|
||||||
|
argWidth.setDefault(64);
|
||||||
|
argHeight.setDefault(64);
|
||||||
|
argAddress.setDefault("127.0.0.1:19445");
|
||||||
|
argPriority.setDefault(800);
|
||||||
|
|
||||||
|
// parse all options
|
||||||
|
optionParser.parse(argc, const_cast<const char **>(argv));
|
||||||
|
|
||||||
|
// check if we need to display the usage. exit if we do.
|
||||||
|
if (argHelp.isSet())
|
||||||
|
{
|
||||||
|
optionParser.usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the dispmanx grabbing stuff
|
||||||
|
int grabInterval = 1000 / argFps.getValue();
|
||||||
|
DispmanxWrapper dispmanxWrapper(argWidth.getValue(),argHeight.getValue(),grabInterval);
|
||||||
|
|
||||||
|
if (argScreenshot.isSet())
|
||||||
|
{
|
||||||
|
// Capture a single screenshot and finish
|
||||||
|
const Image<ColorRgb> & screenshot = dispmanxWrapper.getScreenshot();
|
||||||
|
saveScreenshot("screenshot.png", screenshot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create the Proto-connection with hyperiond
|
||||||
|
ProtoConnectionWrapper protoWrapper(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet());
|
||||||
|
|
||||||
|
// Connect the screen capturing to the proto processing
|
||||||
|
QObject::connect(&dispmanxWrapper, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &protoWrapper, SLOT(receiveImage(Image<ColorRgb>)));
|
||||||
|
|
||||||
|
// Start the capturing
|
||||||
|
dispmanxWrapper.start();
|
||||||
|
|
||||||
|
// Start the application
|
||||||
|
app.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error & e)
|
||||||
|
{
|
||||||
|
// An error occured. Display error and quit
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// C++ includes
|
// C++ includes
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// QT includes
|
// QT includes
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@ -188,6 +189,39 @@ int main(int argc, char** argv)
|
|||||||
std::cout << "XBMC video checker created and started" << std::endl;
|
std::cout << "XBMC video checker created and started" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- network services -----
|
||||||
|
|
||||||
|
// Create Json server if configuration is present
|
||||||
|
JsonServer * jsonServer = nullptr;
|
||||||
|
if (config.isMember("jsonServer"))
|
||||||
|
{
|
||||||
|
const Json::Value & jsonServerConfig = config["jsonServer"];
|
||||||
|
jsonServer = new JsonServer(&hyperion, jsonServerConfig["port"].asUInt());
|
||||||
|
std::cout << "Json server created and started on port " << jsonServer->getPort() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
// Create Proto server if configuration is present
|
||||||
|
ProtoServer * protoServer = nullptr;
|
||||||
|
if (config.isMember("protoServer"))
|
||||||
|
{
|
||||||
|
const Json::Value & protoServerConfig = config["protoServer"];
|
||||||
|
protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt() );
|
||||||
|
std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create Boblight server if configuration is present
|
||||||
|
BoblightServer * boblightServer = nullptr;
|
||||||
|
if (config.isMember("boblightServer"))
|
||||||
|
{
|
||||||
|
const Json::Value & boblightServerConfig = config["boblightServer"];
|
||||||
|
boblightServer = new BoblightServer(&hyperion, boblightServerConfig["port"].asUInt());
|
||||||
|
std::cout << "Boblight server created and started on port " << boblightServer->getPort() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- grabber -----
|
||||||
|
|
||||||
#ifdef ENABLE_DISPMANX
|
#ifdef ENABLE_DISPMANX
|
||||||
// Construct and start the frame-grabber if the configuration is present
|
// Construct and start the frame-grabber if the configuration is present
|
||||||
DispmanxWrapper * dispmanx = nullptr;
|
DispmanxWrapper * dispmanx = nullptr;
|
||||||
@ -206,6 +240,10 @@ int main(int argc, char** argv)
|
|||||||
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), dispmanx, SLOT(setVideoMode(VideoMode)));
|
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), dispmanx, SLOT(setVideoMode(VideoMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
QObject::connect(dispmanx, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
|
||||||
|
#endif
|
||||||
|
|
||||||
dispmanx->start();
|
dispmanx->start();
|
||||||
std::cout << "Frame grabber created and started" << std::endl;
|
std::cout << "Frame grabber created and started" << std::endl;
|
||||||
}
|
}
|
||||||
@ -213,7 +251,7 @@ int main(int argc, char** argv)
|
|||||||
#if !defined(ENABLE_OSX) && !defined(ENABLE_FB)
|
#if !defined(ENABLE_OSX) && !defined(ENABLE_FB)
|
||||||
if (config.isMember("framegrabber"))
|
if (config.isMember("framegrabber"))
|
||||||
{
|
{
|
||||||
std::cerr << "The dispmanx framegrabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The dispmanx framegrabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -245,14 +283,19 @@ int main(int argc, char** argv)
|
|||||||
grabberConfig.get("cropTop", 0).asInt(),
|
grabberConfig.get("cropTop", 0).asInt(),
|
||||||
grabberConfig.get("cropBottom", 0).asInt());
|
grabberConfig.get("cropBottom", 0).asInt());
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
QObject::connect(v4l2Grabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
|
||||||
|
#endif
|
||||||
|
|
||||||
v4l2Grabber->start();
|
v4l2Grabber->start();
|
||||||
std::cout << "V4l2 grabber created and started" << std::endl;
|
std::cout << "V4l2 grabber created and started" << std::endl;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (config.isMember("grabber-v4l2"))
|
if (config.isMember("grabber-v4l2"))
|
||||||
{
|
{
|
||||||
std::cerr << "The v4l2 grabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The v4l2 grabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_AMLOGIC
|
#ifdef ENABLE_AMLOGIC
|
||||||
@ -273,6 +316,10 @@ int main(int argc, char** argv)
|
|||||||
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), amlGrabber, SLOT(setVideoMode(VideoMode)));
|
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), amlGrabber, SLOT(setVideoMode(VideoMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
QObject::connect(amlGrabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
|
||||||
|
#endif
|
||||||
|
|
||||||
amlGrabber->start();
|
amlGrabber->start();
|
||||||
std::cout << "AMLOGIC grabber created and started" << std::endl;
|
std::cout << "AMLOGIC grabber created and started" << std::endl;
|
||||||
}
|
}
|
||||||
@ -302,18 +349,22 @@ int main(int argc, char** argv)
|
|||||||
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), fbGrabber, SLOT(setVideoMode(VideoMode)));
|
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), fbGrabber, SLOT(setVideoMode(VideoMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
QObject::connect(fbGrabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
|
||||||
|
#endif
|
||||||
|
|
||||||
fbGrabber->start();
|
fbGrabber->start();
|
||||||
std::cout << "Framebuffer grabber created and started" << std::endl;
|
std::cout << "Framebuffer grabber created and started" << std::endl;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (config.isMember("framebuffergrabber"))
|
if (config.isMember("framebuffergrabber"))
|
||||||
{
|
{
|
||||||
std::cerr << "The framebuffer grabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The framebuffer grabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX)
|
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX)
|
||||||
else if (config.isMember("framegrabber"))
|
else if (config.isMember("framegrabber"))
|
||||||
{
|
{
|
||||||
std::cerr << "The framebuffer grabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The framebuffer grabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -337,50 +388,26 @@ int main(int argc, char** argv)
|
|||||||
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), osxGrabber, SLOT(setVideoMode(VideoMode)));
|
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), osxGrabber, SLOT(setVideoMode(VideoMode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROTOBUF
|
||||||
|
QObject::connect(osxGrabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
|
||||||
|
#endif
|
||||||
|
|
||||||
osxGrabber->start();
|
osxGrabber->start();
|
||||||
std::cout << "OSX grabber created and started" << std::endl;
|
std::cout << "OSX grabber created and started" << std::endl;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (config.isMember("osxgrabber"))
|
if (config.isMember("osxgrabber"))
|
||||||
{
|
{
|
||||||
std::cerr << "The osx grabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The osx grabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_FB)
|
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_FB)
|
||||||
else if (config.isMember("framegrabber"))
|
else if (config.isMember("framegrabber"))
|
||||||
{
|
{
|
||||||
std::cerr << "The osx grabber can not be instantiated, becuse it has been left out from the build" << std::endl;
|
std::cerr << "The osx grabber can not be instantiated, because it has been left out from the build" << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create Json server if configuration is present
|
|
||||||
JsonServer * jsonServer = nullptr;
|
|
||||||
if (config.isMember("jsonServer"))
|
|
||||||
{
|
|
||||||
const Json::Value & jsonServerConfig = config["jsonServer"];
|
|
||||||
jsonServer = new JsonServer(&hyperion, jsonServerConfig["port"].asUInt());
|
|
||||||
std::cout << "Json server created and started on port " << jsonServer->getPort() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_PROTOBUF
|
|
||||||
// Create Proto server if configuration is present
|
|
||||||
ProtoServer * protoServer = nullptr;
|
|
||||||
if (config.isMember("protoServer"))
|
|
||||||
{
|
|
||||||
const Json::Value & protoServerConfig = config["protoServer"];
|
|
||||||
protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt());
|
|
||||||
std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Create Boblight server if configuration is present
|
|
||||||
BoblightServer * boblightServer = nullptr;
|
|
||||||
if (config.isMember("boblightServer"))
|
|
||||||
{
|
|
||||||
const Json::Value & boblightServerConfig = config["boblightServer"];
|
|
||||||
boblightServer = new BoblightServer(&hyperion, boblightServerConfig["port"].asUInt());
|
|
||||||
std::cout << "Boblight server created and started on port " << boblightServer->getPort() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// run the application
|
// run the application
|
||||||
int rc = app.exec();
|
int rc = app.exec();
|
||||||
|
@ -4,22 +4,42 @@
|
|||||||
|
|
||||||
// Utils includes
|
// Utils includes
|
||||||
#include <utils/Image.h>
|
#include <utils/Image.h>
|
||||||
|
#include <utils/ColorRgba.h>
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
|
#include <utils/ColorBgr.h>
|
||||||
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::cout << "Constructing image" << std::endl;
|
std::cout << "Constructing image" << std::endl;
|
||||||
Image<ColorRgb> image(64, 64, ColorRgb::BLACK);
|
int width = 64;
|
||||||
|
int height = 64;
|
||||||
|
Image<ColorRgb> image_rgb(width, height, ColorRgb::BLACK);
|
||||||
|
Image<ColorBgr> image_bgr(image_rgb.width(), image_rgb.height(), ColorBgr::BLACK);
|
||||||
|
|
||||||
std::cout << "Writing image" << std::endl;
|
std::cout << "Writing image" << std::endl;
|
||||||
for (unsigned y=0; y<64; ++y)
|
unsigned l = width * height;
|
||||||
|
|
||||||
|
// BGR
|
||||||
|
for (unsigned i=0; i<l; ++i)
|
||||||
|
image_bgr.memptr()[i] = ColorBgr{0,128,255};
|
||||||
|
|
||||||
|
|
||||||
|
// to RGB
|
||||||
|
image_bgr.toRgb(image_rgb);
|
||||||
|
|
||||||
|
// test
|
||||||
|
for (unsigned i=0; i<l; ++i)
|
||||||
{
|
{
|
||||||
for (unsigned x=0; x<64; ++x)
|
const ColorRgb rgb = image_rgb.memptr()[i];
|
||||||
{
|
if ( rgb.red != 255 || rgb.green != 128 || rgb.blue != 0 )
|
||||||
image(x,y) = ColorRgb::RED;
|
std::cout << "RGB error idx " << i << " " << rgb << std::endl;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "Finished (destruction will be performed)" << std::endl;
|
std::cout << "Finished (destruction will be performed)" << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <getoptPlusPlus/getoptpp.h>
|
#include <getoptPlusPlus/getoptpp.h>
|
||||||
|
|
||||||
// Dispmanx grabber includes
|
// Dispmanx grabber includes
|
||||||
#include <grabber/dispmanx/DispmanxFrameGrabber.h>
|
#include <grabber/DispmanxFrameGrabber.h>
|
||||||
|
|
||||||
using namespace vlofgren;
|
using namespace vlofgren;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user