mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Commits from @MartB and more ...
- Commit: 1d9165f403
- New default QT capture implementation
- UploadHandler added to Effects Configurator to allow uploading GIF files
- Docker compile script and instruction
- Travis Fix
This commit is contained in:
parent
7352ff4d42
commit
2dca1c93e6
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -4,4 +4,4 @@
|
|||||||
branch = master
|
branch = master
|
||||||
[submodule "dependencies/external/flatbuffers"]
|
[submodule "dependencies/external/flatbuffers"]
|
||||||
path = dependencies/external/flatbuffers
|
path = dependencies/external/flatbuffers
|
||||||
url = git://github.com/google/flatbuffers.git
|
url = https://github.com/google/flatbuffers
|
||||||
|
12
.travis.yml
12
.travis.yml
@ -5,11 +5,20 @@ cache:
|
|||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
language: cpp
|
language: cpp
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
env:
|
||||||
|
- DOCKER_TAG=ubuntu1604
|
||||||
|
- DOCKER_NAME="Ubuntu 16.04"
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
env:
|
||||||
|
- DOCKER_TAG=cross-qemu-rpistretch
|
||||||
|
- DOCKER_NAME="Raspberry Pi"
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode7.3
|
osx_image: xcode7.3
|
||||||
env:
|
env:
|
||||||
@ -18,6 +27,5 @@ before_install:
|
|||||||
- ./.travis/travis_install.sh
|
- ./.travis/travis_install.sh
|
||||||
script:
|
script:
|
||||||
- ./.travis/travis_build.sh
|
- ./.travis/travis_build.sh
|
||||||
- ./test/testrunner.sh
|
|
||||||
after_success:
|
after_success:
|
||||||
- ./.travis/travis_deploy.sh
|
- ./.travis/travis_deploy.sh
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
PLATFORM=x86
|
PLATFORM=x86
|
||||||
BUILD_TYPE=Debug
|
BUILD_TYPE=Debug
|
||||||
|
PACKAGES=""
|
||||||
|
|
||||||
# Detect number of processor cores
|
# Detect number of processor cores
|
||||||
# default is 4 jobs
|
# default is 4 jobs
|
||||||
@ -16,32 +17,48 @@ elif [[ "$TRAVIS_OS_NAME" == 'linux' ]]
|
|||||||
then
|
then
|
||||||
JOBS=$(nproc)
|
JOBS=$(nproc)
|
||||||
fi
|
fi
|
||||||
|
echo "compile jobs: ${JOBS:=4}"
|
||||||
|
|
||||||
# compile prepare
|
# Determine cmake build type; tag builds are Release, else Debug
|
||||||
mkdir build || exit 1
|
|
||||||
cd build
|
|
||||||
|
|
||||||
# Compile hyperion for tags
|
|
||||||
[ -n "${TRAVIS_TAG:-}" ] && BUILD_TYPE=Release
|
[ -n "${TRAVIS_TAG:-}" ] && BUILD_TYPE=Release
|
||||||
|
|
||||||
# Compile hyperion for cron - take default settings
|
# Determine package creation; True for cron and tag builds
|
||||||
|
[ "${TRAVIS_EVENT_TYPE:-}" == 'cron' ] || [ -n "${TRAVIS_TAG:-}" ] && PACKAGES=package
|
||||||
|
|
||||||
# Compile for PR (no tag and no cron)
|
# Determie -dev appends to platform;
|
||||||
[ "${TRAVIS_EVENT_TYPE:-}" != 'cron' -a -z "${TRAVIS_TAG:-}" ] && PLATFORM=${PLATFORM}-dev
|
[ "${TRAVIS_EVENT_TYPE:-}" != 'cron' -a -z "${TRAVIS_TAG:-}" ] && PLATFORM=${PLATFORM}-dev
|
||||||
|
|
||||||
cmake -DPLATFORM=$PLATFORM -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=/usr .. || exit 2
|
# Build the package on osx
|
||||||
if [[ "$TRAVIS_OS_NAME" == 'linux' ]]
|
if [[ "$TRAVIS_OS_NAME" == 'osx' || "$TRAVIS_OS_NAME" == 'darwin' ]]
|
||||||
then
|
then
|
||||||
# activate dispmanx and osx mocks
|
# compile prepare
|
||||||
cmake -DENABLE_OSX=ON -DENABLE_DISPMANX=ON .. || exit 5
|
mkdir build || exit 1
|
||||||
|
cd build
|
||||||
|
cmake -DPLATFORM=$PLATFORM -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=/usr .. || exit 2
|
||||||
|
make -j ${JOBS} || exit 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "compile jobs: ${JOBS:=4}"
|
# Build the package with docker
|
||||||
make -j ${JOBS} || exit 3
|
|
||||||
|
|
||||||
# Build the package on Linux
|
|
||||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]
|
if [[ $TRAVIS_OS_NAME == 'linux' ]]
|
||||||
then
|
then
|
||||||
make -j ${JOBS} package || exit 4
|
echo "Compile Hyperion with DOCKER_TAG = ${DOCKER_TAG} and friendly name DOCKER_NAME = ${DOCKER_NAME}"
|
||||||
fi
|
# take ownership of deploy dir
|
||||||
|
mkdir $TRAVIS_BUILD_DIR/deploy
|
||||||
|
# run docker
|
||||||
|
docker run --rm \
|
||||||
|
-v "${TRAVIS_BUILD_DIR}/deploy:/deploy" \
|
||||||
|
-v "${TRAVIS_BUILD_DIR}:/source:ro" \
|
||||||
|
hyperionorg/hyperion-ci:$DOCKER_TAG \
|
||||||
|
/bin/bash -c "mkdir build && cp -r /source/. /build &&
|
||||||
|
cd /build && mkdir build && cd build &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. || exit 2 &&
|
||||||
|
make -j $(nproc) ${PACKAGES} || exit 3 &&
|
||||||
|
echo '---> Copy binaries and packages to host folder: ${TRAVIS_BUILD_DIR}/deploy' &&
|
||||||
|
cp -v /build/build/bin/h* /deploy/ 2>/dev/null || : &&
|
||||||
|
cp -v /build/build/Hyperion-* /deploy/ 2>/dev/null || : &&
|
||||||
|
exit 0;
|
||||||
|
exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 4; }
|
||||||
|
|
||||||
|
# overwrite file owner to current user
|
||||||
|
sudo chown -fR $(stat -c "%U:%G" $TRAVIS_BUILD_DIR/deploy) $TRAVIS_BUILD_DIR/deploy
|
||||||
|
fi
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# sf_upload <deploylist> <sf_dir>
|
# sf_upload <FILES> <sf_dir>
|
||||||
sf_upload()
|
sf_upload()
|
||||||
{
|
{
|
||||||
|
echo "Uploading following files: ${1}
|
||||||
|
to dir /hyperion-project/${2}"
|
||||||
|
|
||||||
/usr/bin/expect <<-EOD
|
/usr/bin/expect <<-EOD
|
||||||
spawn scp $1 hyperionsf37@frs.sourceforge.net:/home/frs/project/hyperion-project/dev/$2
|
spawn scp $1hyperionsf37@frs.sourceforge.net:/home/frs/project/hyperion-project/$2
|
||||||
expect "*(yes/no)*"
|
expect "*(yes/no)*"
|
||||||
send "yes\r"
|
send "yes\r"
|
||||||
expect "*password:*"
|
expect "*password:*"
|
||||||
@ -13,18 +16,49 @@ sf_upload()
|
|||||||
EOD
|
EOD
|
||||||
}
|
}
|
||||||
|
|
||||||
deploylist="hyperion-2.0.0-Linux-x86.tar.gz"
|
# append current Date to filename (just packages no binaries)
|
||||||
|
appendDate()
|
||||||
|
{
|
||||||
|
D=$(date +%Y-%m-%d)
|
||||||
|
for F in $TRAVIS_BUILD_DIR/deploy/Hy*
|
||||||
|
do
|
||||||
|
mv "$F" "${F%.*}-$D.${F##*.}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# append friendly name (just packages no binaries)
|
||||||
|
appendName()
|
||||||
|
{
|
||||||
|
for F in $TRAVIS_BUILD_DIR/deploy/Hy*
|
||||||
|
do
|
||||||
|
mv "$F" "${F%.*}-($DOCKER_NAME).${F##*.}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# get all files to deploy (just packages no binaries)
|
||||||
|
getFiles()
|
||||||
|
{
|
||||||
|
FILES=""
|
||||||
|
for f in $TRAVIS_BUILD_DIR/deploy/Hy*;
|
||||||
|
do FILES+="${f} ";
|
||||||
|
done;
|
||||||
|
}
|
||||||
|
|
||||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||||
cd $TRAVIS_BUILD_DIR/build
|
|
||||||
if [[ -n $TRAVIS_TAG ]]; then
|
if [[ -n $TRAVIS_TAG ]]; then
|
||||||
echo "tag upload"
|
echo "tag upload"
|
||||||
sf_upload $deploylist release
|
appendName
|
||||||
|
appendDate
|
||||||
|
getFiles
|
||||||
|
sf_upload $FILES release
|
||||||
elif [[ $TRAVIS_EVENT_TYPE == 'cron' ]]; then
|
elif [[ $TRAVIS_EVENT_TYPE == 'cron' ]]; then
|
||||||
echo "cron upload"
|
echo "cron upload"
|
||||||
sf_upload $deploylist alpha
|
appendName
|
||||||
|
appendDate
|
||||||
|
getFiles
|
||||||
|
sf_upload $FILES dev/alpha
|
||||||
else
|
else
|
||||||
echo "PR can't be uploaded for security reasons"
|
echo "Direct pushed no upload, PRs not possible"
|
||||||
sf_upload $deploylist pr
|
#sf_upload $FILES pr
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -18,8 +18,8 @@ then
|
|||||||
elif [[ $TRAVIS_OS_NAME == 'linux' ]]
|
elif [[ $TRAVIS_OS_NAME == 'linux' ]]
|
||||||
then
|
then
|
||||||
echo "Install linux deps"
|
echo "Install linux deps"
|
||||||
sudo apt-get -qq update
|
#sudo apt-get -qq update
|
||||||
sudo apt-get install -qq -y qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev doxygen expect
|
#sudo apt-get install -qq -y qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev doxygen expect
|
||||||
else
|
else
|
||||||
echo "Unsupported platform: $TRAVIS_OS_NAME"
|
echo "Unsupported platform: $TRAVIS_OS_NAME"
|
||||||
exit 5
|
exit 5
|
||||||
|
@ -20,6 +20,7 @@ SET ( DEFAULT_AMLOGIC OFF )
|
|||||||
SET ( DEFAULT_DISPMANX OFF )
|
SET ( DEFAULT_DISPMANX OFF )
|
||||||
SET ( DEFAULT_OSX OFF )
|
SET ( DEFAULT_OSX OFF )
|
||||||
SET ( DEFAULT_X11 OFF )
|
SET ( DEFAULT_X11 OFF )
|
||||||
|
SET ( DEFAULT_QT ON )
|
||||||
SET ( DEFAULT_WS281XPWM OFF )
|
SET ( DEFAULT_WS281XPWM OFF )
|
||||||
SET ( DEFAULT_USE_SHARED_AVAHI_LIBS ON )
|
SET ( DEFAULT_USE_SHARED_AVAHI_LIBS ON )
|
||||||
SET ( DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF )
|
SET ( DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF )
|
||||||
@ -151,7 +152,8 @@ message(STATUS "ENABLE_USB_HID = ${ENABLE_USB_HID}")
|
|||||||
option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11})
|
option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11})
|
||||||
message(STATUS "ENABLE_X11 = ${ENABLE_X11}")
|
message(STATUS "ENABLE_X11 = ${ENABLE_X11}")
|
||||||
|
|
||||||
SET(ENABLE_QT5 ON)
|
option(ENABLE_QT "Enable the qt grabber" ${DEFAULT_QT})
|
||||||
|
message(STATUS "ENABLE_QT = ${ENABLE_QT}")
|
||||||
|
|
||||||
option(ENABLE_TESTS "Compile additional test applications" ${DEFAULT_TESTS})
|
option(ENABLE_TESTS "Compile additional test applications" ${DEFAULT_TESTS})
|
||||||
message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}")
|
message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}")
|
||||||
@ -159,7 +161,6 @@ message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}")
|
|||||||
option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
|
option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
|
||||||
message(STATUS "ENABLE_PROFILER = ${ENABLE_PROFILER}")
|
message(STATUS "ENABLE_PROFILER = ${ENABLE_PROFILER}")
|
||||||
|
|
||||||
|
|
||||||
SET ( FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
SET ( FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
||||||
SET ( FLATBUFFERS_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
SET ( FLATBUFFERS_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
||||||
|
|
||||||
|
@ -1,4 +1,18 @@
|
|||||||
# Install the required tools and dependencies
|
# With Docker
|
||||||
|
If you are using [Docker](https://www.docker.com/), you can compile Hyperion inside a docker container. This keeps your system clean and with a simple script it's easy to use. Supported is also cross compilation for Raspberry Pi (Raspbian stretch)
|
||||||
|
|
||||||
|
To compile Hyperion for Ubuntu 16.04 (x64) or higher just execute the following command
|
||||||
|
```
|
||||||
|
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh
|
||||||
|
```
|
||||||
|
To compile Hyperion for Raspberry Pi
|
||||||
|
```
|
||||||
|
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh -t cross-qemu-rpistretch
|
||||||
|
```
|
||||||
|
The compiled binaries and packages will be available at the deploy folder next to the script
|
||||||
|
Note: call the script with `./docker-compile.sh -h` for more options
|
||||||
|
|
||||||
|
# The usual way
|
||||||
|
|
||||||
## Debian/Ubuntu/Win10LinuxSubsystem
|
## Debian/Ubuntu/Win10LinuxSubsystem
|
||||||
|
|
||||||
@ -60,12 +74,12 @@ sudo make install/strip
|
|||||||
sudo make uninstall
|
sudo make uninstall
|
||||||
# ... or run it from compile directory
|
# ... or run it from compile directory
|
||||||
bin/hyperiond
|
bin/hyperiond
|
||||||
# webui is located on localhost:8099
|
# webui is located on localhost:8090 or 8091
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
Create hyperion directory and checkout the code from github
|
Creates hyperion directory and checkout the code from github
|
||||||
|
|
||||||
You might want to add `--depth 1` to the `git` command if you only want to compile the current source and have no need for the entire git repository
|
You might want to add `--depth 1` to the `git` command if you only want to compile the current source and have no need for the entire git repository
|
||||||
|
|
||||||
@ -74,7 +88,7 @@ export HYPERION_DIR="hyperion"
|
|||||||
git clone --recursive https://github.com/hyperion-project/hyperion.ng.git "$HYPERION_DIR"
|
git clone --recursive https://github.com/hyperion-project/hyperion.ng.git "$HYPERION_DIR"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** If you forget the --recursive in above statement or you are updating an existing clone you need to clone the protobuf submodule by runnning the follwing two statements:
|
**Note:** If you forget the --recursive in above statement or you are updating an existing clone you need to clone the flatbuffers submodule by runnning the follwing two statements:
|
||||||
```
|
```
|
||||||
git submodule init
|
git submodule init
|
||||||
git submodule update
|
git submodule update
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get upgrade
|
sudo apt-get upgrade
|
||||||
#TO-DO verify what is really required
|
#TO-DO verify what is really required
|
||||||
#blacklist: protobuf-compiler lib32z1 lib32ncurses5 lib32bz2-1.0 zlib1g-dev
|
#blacklist: lib32z1 lib32ncurses5 lib32bz2-1.0 zlib1g-dev
|
||||||
sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev
|
sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev
|
||||||
|
|
||||||
echo 'PATH=$PATH:$HOME/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin' >> .bashrc
|
echo 'PATH=$PATH:$HOME/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin' >> .bashrc
|
||||||
@ -58,12 +58,12 @@ git clone --depth 1 git://github.com/raspberrypi/tools.git "$RASCROSS_DIR/tools"
|
|||||||
# get the Hyperion sources
|
# get the Hyperion sources
|
||||||
git clone --recursive https://github.com/hyperion-project/hyperion.ng.git "$HYPERION_DIR"
|
git clone --recursive https://github.com/hyperion-project/hyperion.ng.git "$HYPERION_DIR"
|
||||||
|
|
||||||
# do a native build (to build the protobuf compiler for the native platform)
|
# do a native build (to build the flatbuffers compiler for the native platform)
|
||||||
mkdir -p "$NATIVE_BUILD_DIR"
|
mkdir -p "$NATIVE_BUILD_DIR"
|
||||||
cmake -DENABLE_DISPMANX=OFF --build "$NATIVE_BUILD_DIR" "$HYPERION_DIR"
|
cmake -DENABLE_DISPMANX=OFF --build "$NATIVE_BUILD_DIR" "$HYPERION_DIR"
|
||||||
|
|
||||||
# do the cross build
|
# do the cross build
|
||||||
# specify the protoc export file to import the protobuf compiler from the native build
|
# specify the protoc export file to import the flatbuffers compiler from the native build
|
||||||
mkdir -p "$TARGET_BUILD_DIR"
|
mkdir -p "$TARGET_BUILD_DIR"
|
||||||
cmake -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" -DIMPORT_PROTOC=$NATIVE_BUILD_DIR/protoc_export.cmake --build "$TARGET_BUILD_DIR" "$HYPERION_DIR"
|
cmake -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" -DIMPORT_PROTOC=$NATIVE_BUILD_DIR/protoc_export.cmake --build "$TARGET_BUILD_DIR" "$HYPERION_DIR"
|
||||||
|
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
// Define to enable the x11 grabber
|
// Define to enable the x11 grabber
|
||||||
#cmakedefine ENABLE_X11
|
#cmakedefine ENABLE_X11
|
||||||
|
|
||||||
|
// Define to enable the qt grabber
|
||||||
|
#cmakedefine ENABLE_QT
|
||||||
|
|
||||||
// Define to enable the spi-device
|
// Define to enable the spi-device
|
||||||
#cmakedefine ENABLE_SPIDEV
|
#cmakedefine ENABLE_SPIDEV
|
||||||
|
|
||||||
@ -42,5 +45,3 @@
|
|||||||
#define HYPERION_VERSION "${HYPERION_VERSION_MAJOR}.${HYPERION_VERSION_MINOR}.${HYPERION_VERSION_PATCH}"
|
#define HYPERION_VERSION "${HYPERION_VERSION_MAJOR}.${HYPERION_VERSION_MINOR}.${HYPERION_VERSION_PATCH}"
|
||||||
|
|
||||||
#define HYPERION_JSON_VERSION "1.0.0"
|
#define HYPERION_JSON_VERSION "1.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
@ -285,6 +285,7 @@
|
|||||||
"InfoDialog_nowrite_text" : "Hyperion hat keinen Schreibzugriff auf die aktuell geladene Konfiguration. Bitte korrigiere die Dateizugriffsrechte um fortzufahren.",
|
"InfoDialog_nowrite_text" : "Hyperion hat keinen Schreibzugriff auf die aktuell geladene Konfiguration. Bitte korrigiere die Dateizugriffsrechte um fortzufahren.",
|
||||||
"InfoDialog_nowrite_foottext" : "Die Webkonfiguration wird automatisch wieder freigegeben, sobald das Problem behoben wurde!",
|
"InfoDialog_nowrite_foottext" : "Die Webkonfiguration wird automatisch wieder freigegeben, sobald das Problem behoben wurde!",
|
||||||
"infoDialog_wizrgb_text" : "Deine RGB Byte Reihenfolge ist bereits richtig eingestellt.",
|
"infoDialog_wizrgb_text" : "Deine RGB Byte Reihenfolge ist bereits richtig eingestellt.",
|
||||||
|
"infoDialog_writeimage_error_text": "Die ausgewählte Datei \"$1\" ist keine Bilddatei oder ist beschädigt! Bitte wähle eine andere Bilddatei aus.",
|
||||||
"infoDialog_writeconf_error_text" : "Das speichern der Konfiguration ist fehlgeschlagen.",
|
"infoDialog_writeconf_error_text" : "Das speichern der Konfiguration ist fehlgeschlagen.",
|
||||||
"infoDialog_import_jsonerror_text" : "Die ausgewählte Konfigurations-Datei \"$1\" ist keine .json Datei oder ist beschädigt! Fehlermeldung: ($2)",
|
"infoDialog_import_jsonerror_text" : "Die ausgewählte Konfigurations-Datei \"$1\" ist keine .json Datei oder ist beschädigt! Fehlermeldung: ($2)",
|
||||||
"infoDialog_import_hyperror_text" : "Die ausgewählte Konfigurations-Datei \"$1\" kann nicht importiert werden. Sie ist nicht kompatibel mit Hyperion 2.0 und höher!",
|
"infoDialog_import_hyperror_text" : "Die ausgewählte Konfigurations-Datei \"$1\" kann nicht importiert werden. Sie ist nicht kompatibel mit Hyperion 2.0 und höher!",
|
||||||
|
@ -285,6 +285,7 @@
|
|||||||
"InfoDialog_nowrite_text" : "Hyperion can't write to your current loaded configuration file. Please repair the file permissions to proceed.",
|
"InfoDialog_nowrite_text" : "Hyperion can't write to your current loaded configuration file. Please repair the file permissions to proceed.",
|
||||||
"InfoDialog_nowrite_foottext" : "The WebUI will be unlocked automatically after you solved the problem!",
|
"InfoDialog_nowrite_foottext" : "The WebUI will be unlocked automatically after you solved the problem!",
|
||||||
"infoDialog_wizrgb_text" : "Your RGB Byte Order is already well adjusted.",
|
"infoDialog_wizrgb_text" : "Your RGB Byte Order is already well adjusted.",
|
||||||
|
"infoDialog_writeimage_error_text": "The selected file \"$1\" is no image file or it's corrupted! Please select another image file.",
|
||||||
"infoDialog_writeconf_error_text" : "Saving your configuration failed.",
|
"infoDialog_writeconf_error_text" : "Saving your configuration failed.",
|
||||||
"infoDialog_import_jsonerror_text" : "The selected configuration file \"$1\" is no .json file or it's corrupted. Error message: ($2)",
|
"infoDialog_import_jsonerror_text" : "The selected configuration file \"$1\" is no .json file or it's corrupted. Error message: ($2)",
|
||||||
"infoDialog_import_hyperror_text" : "The selected configuration file \"$1\" can't be imported. It's not compatible with Hyperion 2.0 and higher!",
|
"infoDialog_import_hyperror_text" : "The selected configuration file \"$1\" can't be imported. It's not compatible with Hyperion 2.0 and higher!",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"@metadata": {
|
"@metadata": {
|
||||||
"authors": [
|
"authors": [
|
||||||
"brindosch"
|
"brindosch, paulchen-panther"
|
||||||
],
|
],
|
||||||
"project" : "Hyperion WebUI string docu",
|
"project" : "Hyperion WebUI string docu",
|
||||||
"last-updated": "2016-11-30"
|
"last-updated": "2019-01-02"
|
||||||
},
|
},
|
||||||
"edt_msg_error_notset" : " When a property is not set",
|
"edt_msg_error_notset" : " When a property is not set",
|
||||||
"edt_msg_error_notempty" : "When a string must not be empty",
|
"edt_msg_error_notempty" : "When a string must not be empty",
|
||||||
@ -40,8 +40,14 @@
|
|||||||
"edt_msg_button_add_row_title" : "Title on Add Row buttons. $1 = This key takes one variable: The title of object to add",
|
"edt_msg_button_add_row_title" : "Title on Add Row buttons. $1 = This key takes one variable: The title of object to add",
|
||||||
"edt_msg_button_move_down_title" : "Title on Move Down buttons",
|
"edt_msg_button_move_down_title" : "Title on Move Down buttons",
|
||||||
"edt_msg_button_move_up_title" : "Title on Move Up buttons",
|
"edt_msg_button_move_up_title" : "Title on Move Up buttons",
|
||||||
"edt_msg_button_delete_row_titlet" : "Title on Delete Row buttons. $1 = This key takes one variable: The title of object to delete",
|
"edt_msg_button_delete_row_title" : "Title on Delete Row buttons. $1 = This key takes one variable: The title of object to delete",
|
||||||
"edt_msg_button_delete_row_title_short" : "Title on Delete Row buttons, short version (no parameter with the object title)",
|
"edt_msg_button_delete_row_title_short" : "Title on Delete Row buttons, short version (no parameter with the object title)",
|
||||||
"edt_msg_button_collapse" : "Title on Collapse buttons",
|
"edt_msg_button_collapse" : "Title on Collapse buttons",
|
||||||
"edt_msg_button_expand" : "Title on Expand buttons"
|
"edt_msg_button_expand" : "Title on Expand buttons",
|
||||||
}
|
"edt_msg_error_date" : "When a date is in incorrect format. $1 = This key takes one variable: The valid format",
|
||||||
|
"edt_msg_error_time" : "When a time is in incorrect format. $1 = This key takes one variable: The valid format",
|
||||||
|
"edt_msg_error_datetime_local" : "When a datetime-local is in incorrect format. $1 = This key takes one variable: The valid format",
|
||||||
|
"edt_msg_error_invalid_epoch" : "When a integer date is less than 1 January 1970",
|
||||||
|
"edt_msg_flatpickr_toggle_button" : "Title on Flatpickr toggle buttons",
|
||||||
|
"edt_msg_flatpickr_clear_button" : "Title on Flatpickr clear buttons"
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ $(document).ready( function() {
|
|||||||
performTranslation();
|
performTranslation();
|
||||||
var oldDelList = [];
|
var oldDelList = [];
|
||||||
var effectName = "";
|
var effectName = "";
|
||||||
|
var imageData = "";
|
||||||
var effects_editor = null;
|
var effects_editor = null;
|
||||||
var effectPy = "";
|
var effectPy = "";
|
||||||
var testrun;
|
var testrun;
|
||||||
@ -31,9 +32,30 @@ $(document).ready( function() {
|
|||||||
function triggerTestEffect() {
|
function triggerTestEffect() {
|
||||||
testrun = true;
|
testrun = true;
|
||||||
var args = effects_editor.getEditor('root.args');
|
var args = effects_editor.getEditor('root.args');
|
||||||
requestTestEffect(effectName, ":/effects/" + effectPy.slice(1), JSON.stringify(args.getValue()));
|
requestTestEffect(effectName, ":/effects/" + effectPy.slice(1), JSON.stringify(args.getValue()), imageData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specify upload handler for image files
|
||||||
|
JSONEditor.defaults.options.upload = function(type, file, cbs) {
|
||||||
|
var fileReader = new FileReader();
|
||||||
|
|
||||||
|
//check file
|
||||||
|
if (!file.type.startsWith('image')) {
|
||||||
|
imageData = "";
|
||||||
|
cbs.failure('File upload error');
|
||||||
|
// TODO clear file dialog.
|
||||||
|
showInfoDialog('error', "", $.i18n('infoDialog_writeimage_error_text', file.name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileReader.onload = function () {
|
||||||
|
imageData = this.result.split(',')[1];
|
||||||
|
console.log(imageData);
|
||||||
|
cbs.success(file.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
fileReader.readAsDataURL(file);
|
||||||
|
};
|
||||||
|
|
||||||
$("#effectslist").off().on("change", function(event) {
|
$("#effectslist").off().on("change", function(event) {
|
||||||
if(effects_editor != null)
|
if(effects_editor != null)
|
||||||
@ -48,6 +70,7 @@ $(document).ready( function() {
|
|||||||
|
|
||||||
effectPy = ':';
|
effectPy = ':';
|
||||||
effectPy += effects[idx].schemaContent.script;
|
effectPy += effects[idx].schemaContent.script;
|
||||||
|
imageData = "";
|
||||||
$("#name-input").trigger("change");
|
$("#name-input").trigger("change");
|
||||||
|
|
||||||
$("#eff_desc").html(createEffHint($.i18n(effects[idx].schemaContent.title),$.i18n(effects[idx].schemaContent.title+'_desc')));
|
$("#eff_desc").html(createEffHint($.i18n(effects[idx].schemaContent.title),$.i18n(effects[idx].schemaContent.title+'_desc')));
|
||||||
@ -84,7 +107,7 @@ $(document).ready( function() {
|
|||||||
|
|
||||||
// Save Effect
|
// Save Effect
|
||||||
$('#btn_write').off().on('click',function() {
|
$('#btn_write').off().on('click',function() {
|
||||||
requestWriteEffect(effectName,effectPy,JSON.stringify(effects_editor.getValue()));
|
requestWriteEffect(effectName,effectPy,JSON.stringify(effects_editor.getValue()),imageData);
|
||||||
$(hyperion).one("cmd-create-effect", function(event) {
|
$(hyperion).one("cmd-create-effect", function(event) {
|
||||||
if (event.response.success)
|
if (event.response.success)
|
||||||
showInfoDialog('success', "", $.i18n('infoDialog_effconf_created_text', effectName));
|
showInfoDialog('success', "", $.i18n('infoDialog_effconf_created_text', effectName));
|
||||||
@ -163,9 +186,9 @@ $(document).ready( function() {
|
|||||||
//create basic effect list
|
//create basic effect list
|
||||||
var effects = serverSchema.properties.effectSchemas.internal
|
var effects = serverSchema.properties.effectSchemas.internal
|
||||||
for(var idx=0; idx<effects.length; idx++)
|
for(var idx=0; idx<effects.length; idx++)
|
||||||
{
|
{
|
||||||
$("#effectslist").append(createSelOpt(effects[idx].schemaContent.script, $.i18n(effects[idx].schemaContent.title)));
|
$("#effectslist").append(createSelOpt(effects[idx].schemaContent.script, $.i18n(effects[idx].schemaContent.title)));
|
||||||
}
|
}
|
||||||
$("#effectslist").trigger("change");
|
$("#effectslist").trigger("change");
|
||||||
|
|
||||||
updateDelEffectlist();
|
updateDelEffectlist();
|
||||||
|
@ -41,7 +41,7 @@ $(document).ready( function() {
|
|||||||
currentVersion = sysInfo.hyperion.version;
|
currentVersion = sysInfo.hyperion.version;
|
||||||
});
|
});
|
||||||
|
|
||||||
$(hyperion).on("cmd-config-getschema", function(event) {
|
$(hyperion).one("cmd-config-getschema", function(event) {
|
||||||
serverSchema = event.response.info;
|
serverSchema = event.response.info;
|
||||||
requestServerConfig();
|
requestServerConfig();
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ $(document).ready( function() {
|
|||||||
requestServerConfigSchema();
|
requestServerConfigSchema();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(hyperion).on("ready", function(event) {
|
$(hyperion).one("ready", function(event) {
|
||||||
loadContent();
|
loadContent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -270,15 +270,15 @@ function requestWriteConfig(config, full)
|
|||||||
sendToHyperion("config","setconfig", '"config":'+JSON.stringify(serverConfig));
|
sendToHyperion("config","setconfig", '"config":'+JSON.stringify(serverConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWriteEffect(effectName,effectPy,effectArgs)
|
function requestWriteEffect(effectName,effectPy,effectArgs,data)
|
||||||
{
|
{
|
||||||
var cutArgs = effectArgs.slice(1, -1);
|
var cutArgs = effectArgs.slice(1, -1);
|
||||||
sendToHyperion("create-effect", "", '"name":"'+effectName+'", "script":"'+effectPy+'", '+cutArgs);
|
sendToHyperion("create-effect", "", '"name":"'+effectName+'", "script":"'+effectPy+'", '+cutArgs+',"imageData":"'+data+'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestTestEffect(effectName,effectPy,effectArgs)
|
function requestTestEffect(effectName,effectPy,effectArgs,data)
|
||||||
{
|
{
|
||||||
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'", "args":'+effectArgs+'}, "priority":'+webPrio+', "origin":"'+webOrigin+'", "pythonScript":"'+effectPy+'"');
|
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'", "args":'+effectArgs+'}, "priority":'+webPrio+', "origin":"'+webOrigin+'", "pythonScript":"'+effectPy+'", "imageData":"'+data+'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestDeleteEffect(effectName)
|
function requestDeleteEffect(effectName)
|
||||||
|
@ -10,7 +10,7 @@ $(document).ready(function() {
|
|||||||
var canvas_height;
|
var canvas_height;
|
||||||
var canvas_width;
|
var canvas_width;
|
||||||
var twoDPaths = [];
|
var twoDPaths = [];
|
||||||
var toggleLeds = false;
|
var toggleLeds, toggleLedsNum = false;
|
||||||
|
|
||||||
/// add prototype for simple canvas clear() method
|
/// add prototype for simple canvas clear() method
|
||||||
CanvasRenderingContext2D.prototype.clear = function(){
|
CanvasRenderingContext2D.prototype.clear = function(){
|
||||||
@ -148,9 +148,17 @@ $(document).ready(function() {
|
|||||||
// can be used as fallback when Path2D is not available
|
// can be used as fallback when Path2D is not available
|
||||||
//roundRect(ledsCanvasNodeCtx, led.hscan.minimum * canvas_width, led.vscan.minimum * canvas_height, (led.hscan.maximum-led.hscan.minimum) * canvas_width, (led.vscan.maximum-led.vscan.minimum) * canvas_height, 4, true, colors[idx])
|
//roundRect(ledsCanvasNodeCtx, led.hscan.minimum * canvas_width, led.vscan.minimum * canvas_height, (led.hscan.maximum-led.hscan.minimum) * canvas_width, (led.vscan.maximum-led.vscan.minimum) * canvas_height, 4, true, colors[idx])
|
||||||
//ledsCanvasNodeCtx.fillRect(led.hscan.minimum * canvas_width, led.vscan.minimum * canvas_height, (led.hscan.maximum-led.hscan.minimum) * canvas_width, (led.vscan.maximum-led.vscan.minimum) * canvas_height);
|
//ledsCanvasNodeCtx.fillRect(led.hscan.minimum * canvas_width, led.vscan.minimum * canvas_height, (led.hscan.maximum-led.hscan.minimum) * canvas_width, (led.vscan.maximum-led.vscan.minimum) * canvas_height);
|
||||||
|
|
||||||
ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba("+colors[idx].red+","+colors[idx].green+","+colors[idx].blue+",0.9)" : "hsl("+(idx*360/leds.length)+",100%,50%)";
|
ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba("+colors[idx].red+","+colors[idx].green+","+colors[idx].blue+",0.9)" : "hsl("+(idx*360/leds.length)+",100%,50%)";
|
||||||
ledsCanvasNodeCtx.fill(twoDPaths[idx]);
|
ledsCanvasNodeCtx.fill(twoDPaths[idx]);
|
||||||
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
|
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
|
||||||
|
|
||||||
|
if(toggleLedsNum)
|
||||||
|
{
|
||||||
|
ledsCanvasNodeCtx.fillStyle = "blue";
|
||||||
|
ledsCanvasNodeCtx.textAlign = "center";
|
||||||
|
ledsCanvasNodeCtx.fillText(idx, (led.hscan.minimum * canvas_width) + ( ((led.hscan.maximum-led.hscan.minimum) * canvas_width) / 2), (led.vscan.minimum * canvas_height) + ( ((led.vscan.maximum-led.vscan.minimum) * canvas_height) / 2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,12 +181,11 @@ $(document).ready(function() {
|
|||||||
resetImage()
|
resetImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------FIX THIS-------------------------
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// $('#leds_toggle_num').off().on("click", function() {
|
$('#leds_toggle_num').off().on("click", function() {
|
||||||
// $('.led_num').toggle();
|
toggleLedsNum = !toggleLedsNum
|
||||||
// toggleClass('#leds_toggle_num', "btn-danger", "btn-success");
|
toggleClass('#leds_toggle_num', "btn-danger", "btn-success");
|
||||||
//});
|
});
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
$('#leds_toggle').off().on("click", function() {
|
$('#leds_toggle').off().on("click", function() {
|
||||||
|
@ -5982,24 +5982,8 @@ JSONEditor.defaults.editors.upload = JSONEditor.AbstractEditor.extend({
|
|||||||
if(!this.preview_value) return;
|
if(!this.preview_value) return;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var mime = this.preview_value.match(/^data:([^;,]+)[;,]/);
|
|
||||||
if(mime) mime = mime[1];
|
|
||||||
if(!mime) mime = 'unknown';
|
|
||||||
|
|
||||||
var file = this.uploader.files[0];
|
var file = this.uploader.files[0];
|
||||||
|
|
||||||
this.preview.innerHTML = '<strong>Type:</strong> '+mime+', <strong>Size:</strong> '+file.size+' bytes';
|
|
||||||
if(mime.substr(0,5)==="image") {
|
|
||||||
this.preview.innerHTML += '<br>';
|
|
||||||
var img = document.createElement('img');
|
|
||||||
img.style.maxWidth = '100%';
|
|
||||||
img.style.maxHeight = '100px';
|
|
||||||
img.src = this.preview_value;
|
|
||||||
this.preview.appendChild(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.preview.innerHTML += '<br>';
|
|
||||||
var uploadButton = this.getButton('Upload', 'upload', 'Upload');
|
var uploadButton = this.getButton('Upload', 'upload', 'Upload');
|
||||||
this.preview.appendChild(uploadButton);
|
this.preview.appendChild(uploadButton);
|
||||||
uploadButton.addEventListener('click',function(event) {
|
uploadButton.addEventListener('click',function(event) {
|
||||||
@ -6036,6 +6020,11 @@ JSONEditor.defaults.editors.upload = JSONEditor.AbstractEditor.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.jsoneditor.options.auto_upload || this.schema.options.auto_upload) {
|
||||||
|
uploadButton.dispatchEvent(new MouseEvent('click'));
|
||||||
|
this.preview.removeChild(uploadButton);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
enable: function() {
|
enable: function() {
|
||||||
if(this.uploader) this.uploader.disabled = false;
|
if(this.uploader) this.uploader.disabled = false;
|
||||||
@ -6825,10 +6814,7 @@ JSONEditor.defaults.themes.bootstrap3 = JSONEditor.AbstractTheme.extend({
|
|||||||
},
|
},
|
||||||
getButton: function(text, icon, title) {
|
getButton: function(text, icon, title) {
|
||||||
var el = this._super(text, icon, title);
|
var el = this._super(text, icon, title);
|
||||||
if(icon.className.includes("fa-times"))
|
el.className += 'btn btn-default';
|
||||||
el.className += 'btn btn-sm btn-danger';
|
|
||||||
else
|
|
||||||
el.className += 'btn btn-sm btn-primary';
|
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
getTable: function() {
|
getTable: function() {
|
||||||
|
@ -316,8 +316,6 @@ function createJsonEditor(container,schema,setconfig,usePanel,arrayre)
|
|||||||
$('#'+container).off();
|
$('#'+container).off();
|
||||||
$('#'+container).html("");
|
$('#'+container).html("");
|
||||||
|
|
||||||
//JSONEditor.plugins.selectize.enable = true;
|
|
||||||
|
|
||||||
if (typeof arrayre === 'undefined')
|
if (typeof arrayre === 'undefined')
|
||||||
arrayre = true;
|
arrayre = true;
|
||||||
|
|
||||||
|
112
bin/scripts/docker-compile.sh
Normal file
112
bin/scripts/docker-compile.sh
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
DOCKER="docker"
|
||||||
|
# Git repo url of Hyperion
|
||||||
|
GIT_REPO_URL="https://github.com/hyperion-project/hyperion.ng.git"
|
||||||
|
# cmake build type
|
||||||
|
BUILD_TYPE="Release"
|
||||||
|
# the image tag at hyperionorg/hyperion-ci
|
||||||
|
BUILD_TARGET="ubuntu1604"
|
||||||
|
# build packages (.deb .zip ...)
|
||||||
|
BUILD_PACKAGES=true
|
||||||
|
# packages string inserted to cmake cmd
|
||||||
|
PACKAGES=""
|
||||||
|
|
||||||
|
# get current path to this script, independent of calling
|
||||||
|
pushd . > /dev/null
|
||||||
|
SCRIPT_PATH="${BASH_SOURCE[0]}"
|
||||||
|
if ([ -h "${SCRIPT_PATH}" ]); then
|
||||||
|
while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`;
|
||||||
|
SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
|
||||||
|
fi
|
||||||
|
cd `dirname ${SCRIPT_PATH}` > /dev/null
|
||||||
|
SCRIPT_PATH=`pwd`;
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
set +e
|
||||||
|
$DOCKER ps >/dev/null 2>&1
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
DOCKER="sudo docker"
|
||||||
|
fi
|
||||||
|
# check if docker is available
|
||||||
|
if ! $DOCKER ps >/dev/null; then
|
||||||
|
echo "Error connecting to docker:"
|
||||||
|
$DOCKER ps
|
||||||
|
printHelp
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# help print function
|
||||||
|
function printHelp {
|
||||||
|
echo "########################################################
|
||||||
|
## A script to compile Hyperion inside a docker container
|
||||||
|
## Requires installed Docker: https://www.docker.com/
|
||||||
|
## Without arguments it will compile Hyperion for Ubuntu 16.04 (x64) or higher.
|
||||||
|
## Supports Raspberry Pi (armv6) cross compilation (Raspbian Stretch)
|
||||||
|
##
|
||||||
|
## Homepage: https://www.hyperion-project.org
|
||||||
|
## Forum: https://forum.hyperion-project.org
|
||||||
|
########################################################
|
||||||
|
# These are possible arguments to modify the script behaviour with their default values
|
||||||
|
#
|
||||||
|
# docker-compile.sh -h # Show this help message
|
||||||
|
# docker-compile.sh -t ubuntu1604 # The docker tag, one of ubuntu1604 | cross-qemu-rpistretch
|
||||||
|
# docker-compile.sh -b Release # cmake Release or Debug build
|
||||||
|
# docker-compile.sh -p true # If true build packages with CPack
|
||||||
|
# More informations to docker tags at: https://hub.docker.com/r/hyperionorg/hyperion-ci/"
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts t:b:p:h option
|
||||||
|
do
|
||||||
|
case "${option}"
|
||||||
|
in
|
||||||
|
t) BUILD_TARGET=${OPTARG};;
|
||||||
|
b) BUILD_TYPE=${OPTARG};;
|
||||||
|
p) BUILD_PACKAGES=${OPTARG};;
|
||||||
|
h) printHelp; exit 0;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# determine package creation
|
||||||
|
if [ $BUILD_PACKAGES == "true" ]; then
|
||||||
|
PACKAGES="package"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "---> Initilize with BUILD_TARGET=${BUILD_TARGET}, BUILD_TYPE=${BUILD_TYPE}, BUILD_PACKAGES=${BUILD_PACKAGES}"
|
||||||
|
|
||||||
|
# cleanup deploy folder, create folder for ownership
|
||||||
|
sudo rm -fr $SCRIPT_PATH/deploy >/dev/null 2>&1
|
||||||
|
mkdir $SCRIPT_PATH/deploy >/dev/null 2>&1
|
||||||
|
|
||||||
|
# get Hyperion source, cleanup previous folder
|
||||||
|
echo "---> Downloading Hyperion source code from ${GIT_REPO_URL}"
|
||||||
|
sudo rm -fr $SCRIPT_PATH/hyperion >/dev/null 2>&1
|
||||||
|
git clone --recursive --depth 1 -q -b rework $GIT_REPO_URL $SCRIPT_PATH/hyperion || { echo "---> Failed to download Hyperion source code! Abort"; exit 1; }
|
||||||
|
|
||||||
|
# start compilation
|
||||||
|
# Remove container after stop
|
||||||
|
# Mount /deploy to /deploy
|
||||||
|
# Mount source dir to /source
|
||||||
|
# Target docker image
|
||||||
|
# execute inside container all commands on bash
|
||||||
|
echo "---> Startup docker..."
|
||||||
|
$DOCKER run --rm \
|
||||||
|
-v "${SCRIPT_PATH}/deploy:/deploy" \
|
||||||
|
-v "${SCRIPT_PATH}/hyperion:/source:ro" \
|
||||||
|
hyperionorg/hyperion-ci:$BUILD_TARGET \
|
||||||
|
/bin/bash -c "mkdir build && cp -r /source/. /build &&
|
||||||
|
cd /build && mkdir build && cd build &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. || exit 2 &&
|
||||||
|
make -j $(nproc) ${PACKAGES} || exit 3 &&
|
||||||
|
echo '---> Copy binaries and packages to host folder: ${SCRIPT_PATH}/deploy' &&
|
||||||
|
cp -v /build/build/bin/h* /deploy/ 2>/dev/null || : &&
|
||||||
|
cp -v /build/build/Hyperion-* /deploy/ 2>/dev/null || : &&
|
||||||
|
exit 0;
|
||||||
|
exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 4; }
|
||||||
|
|
||||||
|
# overwrite file owner to current user
|
||||||
|
sudo chown -fR $(stat -c "%U:%G" $SCRIPT_PATH/deploy) $SCRIPT_PATH/deploy
|
||||||
|
|
||||||
|
echo "---> Script finished, view folder ${SCRIPT_PATH}/deploy for compiled packages and binaries"
|
||||||
|
exit 0
|
@ -1,165 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Script to add a second or more hyperion instance(s) to the corresponding system service
|
|
||||||
|
|
||||||
# Make sure /sbin is on the path (for service to find sub scripts)
|
|
||||||
PATH="/sbin:$PATH"
|
|
||||||
|
|
||||||
#Check, if script is running as root
|
|
||||||
if [ $(id -u) != 0 ]; then
|
|
||||||
echo '---> Critical Error: Please run the script as root (sudo sh ./setup_hyperion_forward.sh) -> abort'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Welcome message
|
|
||||||
echo '*******************************************************************************'
|
|
||||||
echo 'This setup script will duplicate the hyperion service'
|
|
||||||
echo 'Choose the name(s) for one or more config files - one service for each config'
|
|
||||||
echo 'Created by brindosch - hyperion-project.org - the official Hyperion source.'
|
|
||||||
echo '*******************************************************************************'
|
|
||||||
|
|
||||||
#Prompt for confirmation to proceed
|
|
||||||
while true
|
|
||||||
do
|
|
||||||
echo -n "---> Do you really want to proceed? (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\". We will proceed!"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
#Check which system we are on
|
|
||||||
OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue`
|
|
||||||
USE_SYSTEMD=`grep -m1 -c systemd /proc/1/comm`
|
|
||||||
USE_INITCTL=`which /sbin/initctl | wc -l`
|
|
||||||
USE_SERVICE=`which /usr/sbin/service | wc -l`
|
|
||||||
|
|
||||||
#Setting up the paths to service files
|
|
||||||
if [ $USE_INITCTL -eq 1 ]; then
|
|
||||||
SERVICEPATH=/etc/init
|
|
||||||
elif [ $OS_OPENELEC -eq 1 ]; then
|
|
||||||
SERVICEPATH=/storage/.config
|
|
||||||
elif [ $USE_SYSTEMD -eq 1 ]; then
|
|
||||||
SERVICEPATH=/etc/systemd/system
|
|
||||||
elif [ $USE_SERVICE -eq 1 ]; then
|
|
||||||
SERVICEPATH/etc/init.d
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Setting up the default PROTO/JSON ports
|
|
||||||
JSONPORT=19444
|
|
||||||
PROTOPORT=19445
|
|
||||||
# and service count
|
|
||||||
SERVICEC=1
|
|
||||||
|
|
||||||
#Setting up the paths to config files
|
|
||||||
if [ $OS_OPENELEC -eq 1 ]; then
|
|
||||||
CONFIGPATH=/storage/.config
|
|
||||||
else CONFIGPATH=/opt/hyperion/config
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Ask the user for some informations regarding the setup
|
|
||||||
echo "---> Please enter the config name(s) you want to create"
|
|
||||||
echo "---> Information: One name creates one service and two names two services etc"
|
|
||||||
echo '---> Please enter them seperated with a space in a one line row!'
|
|
||||||
echo '---> example: hyperion.philipshue_1.json hyperion.AtmoOrb_2.json hypthreeconf.json'
|
|
||||||
echo '---> In any case, add ".json" at the end of each file name'
|
|
||||||
read -p 'Config file name(s): ' FILENAMES
|
|
||||||
echo '---> Thank you, we will modify your Hyperion installation now'
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
#Processing input
|
|
||||||
set $FILENAMES
|
|
||||||
FWCOUNT=${#}
|
|
||||||
|
|
||||||
#Convert all old config file paths to make sure this script is working (default for new installs with 1.02.0 and higher)
|
|
||||||
if [ $USE_INITCTL -eq 1 ]; then
|
|
||||||
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion.conf
|
|
||||||
elif [ $OS_OPENELEC -eq 1 ]; then
|
|
||||||
sleep 0
|
|
||||||
elif [ $USE_SYSTEMD -eq 1 ]; then
|
|
||||||
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion.service
|
|
||||||
elif [ $USE_SERVICE -eq 1 ]; then
|
|
||||||
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Processing service files
|
|
||||||
if [ $USE_INITCTL -eq 1 ]; then
|
|
||||||
echo "---> Initctl detected, processing service files"
|
|
||||||
while [ $SERVICEC -le $FWCOUNT ]; do
|
|
||||||
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}.conf\""
|
|
||||||
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}.conf" ]; then
|
|
||||||
echo "Service was already created - skipped"
|
|
||||||
echo "Input \"${1}\" was skipped"
|
|
||||||
else
|
|
||||||
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}.conf"
|
|
||||||
cp -s $SERVICEPATH/hyperion.conf $SERVICEPATH/hyperion_fw$SERVICEC.conf
|
|
||||||
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}.conf\""
|
|
||||||
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC.conf
|
|
||||||
initctl reload-configuration
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
SERVICEC=$((SERVICEC + 1))
|
|
||||||
done
|
|
||||||
elif [ $OS_OPENELEC -eq 1 ]; then
|
|
||||||
echo "---> OE/LE detected, processing autostart.sh"
|
|
||||||
while [ $SERVICEC -le $FWCOUNT ]; do
|
|
||||||
echo "${SERVICEC}. processing OE autostart.sh entry \"${1}\""
|
|
||||||
OE=`grep -m1 -c ${1} $SERVICEPATH/autostart.sh`
|
|
||||||
if [ $OE -eq 0 ]; then
|
|
||||||
echo "Add config name \"${1}\" to \"autostart.sh\""
|
|
||||||
echo "/storage/hyperion/bin/hyperiond.sh /storage/.config/${1} > /storage/logfiles/hyperion_fw${SERVICEC}.log 2>&1 &" >> /storage/.config/autostart.sh
|
|
||||||
else
|
|
||||||
echo "\"${1}\" was already added - skipped"
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
SERVICEC=$((SERVICEC + 1))
|
|
||||||
done
|
|
||||||
elif [ $USE_SYSTEMD -eq 1 ]; then
|
|
||||||
echo "---> Systemd detected, processing service files"
|
|
||||||
while [ $SERVICEC -le $FWCOUNT ]; do
|
|
||||||
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}.service\""
|
|
||||||
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}.service" ]; then
|
|
||||||
echo "Service was already created - skipped"
|
|
||||||
echo "Input \"${1}\" was skipped"
|
|
||||||
else
|
|
||||||
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}.service"
|
|
||||||
cp -s $SERVICEPATH/hyperion.service $SERVICEPATH/hyperion_fw$SERVICEC.service
|
|
||||||
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}.service\""
|
|
||||||
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC.service
|
|
||||||
systemctl -q enable hyperion_fw$SERVICEC.service
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
SERVICEC=$((SERVICEC + 1))
|
|
||||||
done
|
|
||||||
elif [ $USE_SERVICE -eq 1 ]; then
|
|
||||||
echo "---> Init.d detected, processing service files"
|
|
||||||
while [ $SERVICEC -le $FWCOUNT ]; do
|
|
||||||
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}\""
|
|
||||||
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}" ]; then
|
|
||||||
echo "Service was already created - skipped"
|
|
||||||
echo "Input \"${1}\" was skipped"
|
|
||||||
else
|
|
||||||
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}"
|
|
||||||
cp -s $SERVICEPATH/hyperion $SERVICEPATH/hyperion_fw$SERVICEC
|
|
||||||
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}\""
|
|
||||||
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC
|
|
||||||
update-rc.d hyperion_fw$SERVICEC defaults 98 02
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
SERVICEC=$((SERVICEC + 1))
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Service creation done
|
|
||||||
echo '*******************************************************************************'
|
|
||||||
echo 'Script done all actions - all input processed'
|
|
||||||
echo 'Now upload your configuration(s) with HyperCon at the SSH Tab'
|
|
||||||
echo 'All created Hyperion services will start with your chosen confignames'
|
|
||||||
echo 'Wiki: wiki.hyperion-project.org Webpage: www.hyperion-project.org'
|
|
||||||
echo '*******************************************************************************'
|
|
@ -14,7 +14,7 @@ ENDIF()
|
|||||||
SET ( CPACK_PACKAGE_NAME "Hyperion" )
|
SET ( CPACK_PACKAGE_NAME "Hyperion" )
|
||||||
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" )
|
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" )
|
||||||
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
|
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
|
||||||
SET ( CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_VERSION_MAJOR}.${HYPERION_VERSION_MINOR}.${HYPERION_VERSION_PATCH}")
|
SET ( CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_VERSION_MAJOR}.${HYPERION_VERSION_MINOR}.${HYPERION_VERSION_PATCH}-${CMAKE_SYSTEM_NAME}")
|
||||||
SET ( CPACK_PACKAGE_CONTACT "packages@hyperion-project.org")
|
SET ( CPACK_PACKAGE_CONTACT "packages@hyperion-project.org")
|
||||||
SET ( CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" )
|
SET ( CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" )
|
||||||
SET ( CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png")
|
SET ( CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png")
|
||||||
|
@ -136,7 +136,7 @@
|
|||||||
],
|
],
|
||||||
|
|
||||||
/// The configuration for the frame-grabber, contains the following items:
|
/// The configuration for the frame-grabber, contains the following items:
|
||||||
/// * type : type of grabber. (auto|osx|dispmanx|amlogic|x11|framebuffer) [auto]
|
/// * type : type of grabber. (auto|osx|dispmanx|amlogic|x11|framebuffer|qt) [auto]
|
||||||
/// * width : The width of the grabbed frames [pixels]
|
/// * width : The width of the grabbed frames [pixels]
|
||||||
/// * height : The height of the grabbed frames [pixels]
|
/// * height : The height of the grabbed frames [pixels]
|
||||||
/// * frequency_Hz : The frequency of the frame grab [Hz]
|
/// * frequency_Hz : The frequency of the frame grab [Hz]
|
||||||
@ -155,9 +155,12 @@
|
|||||||
"width" : 96,
|
"width" : 96,
|
||||||
"height" : 96,
|
"height" : 96,
|
||||||
|
|
||||||
// valid for x11
|
// valid for x11|qt
|
||||||
"pixelDecimation" : 8,
|
"pixelDecimation" : 8,
|
||||||
|
|
||||||
|
// valid for qt
|
||||||
|
"display" 0,
|
||||||
|
|
||||||
// valid for framebuffer
|
// valid for framebuffer
|
||||||
"device" : "/dev/fb0"
|
"device" : "/dev/fb0"
|
||||||
},
|
},
|
||||||
|
@ -3,11 +3,16 @@
|
|||||||
"script" : "gif.py",
|
"script" : "gif.py",
|
||||||
"title":"edt_eff_gif_header",
|
"title":"edt_eff_gif_header",
|
||||||
"required":true,
|
"required":true,
|
||||||
"properties":{
|
"properties": {
|
||||||
"image": {
|
"image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title":"edt_eff_image",
|
"title":"edt_eff_image",
|
||||||
"format" : "file",
|
"format" : "url",
|
||||||
|
"options" :
|
||||||
|
{
|
||||||
|
"upload" : true,
|
||||||
|
"auto_upload" : true
|
||||||
|
},
|
||||||
"default": "",
|
"default": "",
|
||||||
"propertyOrder" : 1
|
"propertyOrder" : 1
|
||||||
},
|
},
|
||||||
|
@ -114,7 +114,7 @@ private:
|
|||||||
///
|
///
|
||||||
/// @param message the incoming message
|
/// @param message the incoming message
|
||||||
///
|
///
|
||||||
void handleEffectCommand(const QJsonObject & message, const QString &command, const int tan);
|
void handleEffectCommand(const QJsonObject &message, const QString &command, const int tan);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle an incoming JSON Effect message (Write JSON Effect)
|
/// Handle an incoming JSON Effect message (Write JSON Effect)
|
||||||
|
@ -89,10 +89,9 @@ namespace hyperion
|
|||||||
// find first X pixel of the image
|
// find first X pixel of the image
|
||||||
for (int x = 0; x < width33percent; ++x)
|
for (int x = 0; x < width33percent; ++x)
|
||||||
{
|
{
|
||||||
const Pixel_T & color1 = image( (width - x), yCenter); // right side center line check
|
if (!isBlack(image((width - x), yCenter))
|
||||||
const Pixel_T & color2 = image(x, height33percent);
|
|| !isBlack(image(x, height33percent))
|
||||||
const Pixel_T & color3 = image(x, height66percent);
|
|| !isBlack(image(x, height66percent)))
|
||||||
if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
|
|
||||||
{
|
{
|
||||||
firstNonBlackXPixelIndex = x;
|
firstNonBlackXPixelIndex = x;
|
||||||
break;
|
break;
|
||||||
@ -102,10 +101,9 @@ namespace hyperion
|
|||||||
// find first Y pixel of the image
|
// find first Y pixel of the image
|
||||||
for (int y = 0; y < height33percent; ++y)
|
for (int y = 0; y < height33percent; ++y)
|
||||||
{
|
{
|
||||||
const Pixel_T & color1 = image(xCenter, (height - y)); // bottom center line check
|
if (!isBlack(image(xCenter, (height - y)))
|
||||||
const Pixel_T & color2 = image(width33percent, y );
|
|| !isBlack(image(width33percent, y))
|
||||||
const Pixel_T & color3 = image(width66percent, y);
|
|| !isBlack(image(width66percent, y)))
|
||||||
if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
|
|
||||||
{
|
{
|
||||||
firstNonBlackYPixelIndex = y;
|
firstNonBlackYPixelIndex = y;
|
||||||
break;
|
break;
|
||||||
@ -203,10 +201,9 @@ namespace hyperion
|
|||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width33percent; ++x)
|
for (x = 0; x < width33percent; ++x)
|
||||||
{
|
{
|
||||||
const Pixel_T & color1 = image( (width - x), yCenter); // right side center line check
|
if (!isBlack(image((width - x), yCenter))
|
||||||
const Pixel_T & color2 = image(x, height33percent);
|
|| !isBlack(image(x, height33percent))
|
||||||
const Pixel_T & color3 = image(x, height66percent);
|
|| !isBlack(image(x, height66percent)))
|
||||||
if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
|
|
||||||
{
|
{
|
||||||
firstNonBlackXPixelIndex = x;
|
firstNonBlackXPixelIndex = x;
|
||||||
break;
|
break;
|
||||||
@ -216,13 +213,13 @@ namespace hyperion
|
|||||||
// find first Y pixel of the image
|
// find first Y pixel of the image
|
||||||
for (int y = 0; y < height33percent; ++y)
|
for (int y = 0; y < height33percent; ++y)
|
||||||
{
|
{
|
||||||
const Pixel_T & color1 = image(x, y );// left side top check
|
// left side top + left side bottom + right side top + right side bottom
|
||||||
const Pixel_T & color2 = image(x, (height - y)); // left side bottom check
|
if (!isBlack(image(x, y))
|
||||||
const Pixel_T & color3 = image( (width - x), y); // right side top check
|
|| !isBlack(image(x, (height - y)))
|
||||||
const Pixel_T & color4 = image( (width - x), (height - y)); // right side bottom check
|
|| !isBlack(image((width - x), y))
|
||||||
if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3) || !isBlack(color4))
|
|| !isBlack(image((width - x), (height - y))))
|
||||||
{
|
{
|
||||||
// std::cout << "y " << y << " lt " << int(isBlack(color1)) << " lb " << int(isBlack(color2)) << " rt " << int(isBlack(color3)) << " rb " << int(isBlack(color4)) << std::endl;
|
// std::cout << "y " << y << " lt " << int(isBlack(color1)) << " lb " << int(isBlack(color2)) << " rt " << int(isBlack(color3)) << " rb " << int(isBlack(color4)) << std::endl;
|
||||||
firstNonBlackYPixelIndex = y;
|
firstNonBlackYPixelIndex = y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,14 @@ class Effect : public QThread
|
|||||||
public:
|
public:
|
||||||
friend class EffectModule;
|
friend class EffectModule;
|
||||||
|
|
||||||
Effect(Hyperion* hyperion, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject());
|
Effect(Hyperion *hyperion
|
||||||
|
, int priority
|
||||||
|
, int timeout
|
||||||
|
, const QString &script
|
||||||
|
, const QString &name
|
||||||
|
, const QJsonObject &args = QJsonObject()
|
||||||
|
, const QString &imageData = ""
|
||||||
|
);
|
||||||
virtual ~Effect();
|
virtual ~Effect();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
@ -55,14 +62,14 @@ public:
|
|||||||
QJsonObject getArgs() const { return _args; }
|
QJsonObject getArgs() const { return _args; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, const bool& clearEffect);
|
void setInput(const int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, const bool &clearEffect);
|
||||||
void setInputImage(const int priority, const Image<ColorRgb>& image, const int timeout_ms, const bool& clearEffect);
|
void setInputImage(const int priority, const Image<ColorRgb> &image, const int timeout_ms, const bool &clearEffect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void addImage();
|
void addImage();
|
||||||
|
|
||||||
Hyperion* _hyperion;
|
Hyperion *_hyperion;
|
||||||
|
|
||||||
const int _priority;
|
const int _priority;
|
||||||
|
|
||||||
@ -72,18 +79,19 @@ private:
|
|||||||
const QString _name;
|
const QString _name;
|
||||||
|
|
||||||
const QJsonObject _args;
|
const QJsonObject _args;
|
||||||
|
const QString _imageData;
|
||||||
|
|
||||||
int64_t _endTime;
|
int64_t _endTime;
|
||||||
|
|
||||||
/// Buffer for colorData
|
/// Buffer for colorData
|
||||||
QVector<ColorRgb> _colors;
|
QVector<ColorRgb> _colors;
|
||||||
|
|
||||||
Logger* _log;
|
Logger *_log;
|
||||||
// Reflects whenever this effects should interupt (timeout or external request)
|
// Reflects whenever this effects should interupt (timeout or external request)
|
||||||
bool _interupt = false;
|
bool _interupt = false;
|
||||||
|
|
||||||
QSize _imageSize;
|
QSize _imageSize;
|
||||||
QImage _image;
|
QImage _image;
|
||||||
QPainter* _painter;
|
QPainter *_painter;
|
||||||
QVector<QImage> _imageStack;
|
QVector<QImage> _imageStack;
|
||||||
};
|
};
|
||||||
|
@ -74,7 +74,15 @@ public slots:
|
|||||||
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
|
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
|
||||||
|
|
||||||
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
||||||
int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System", unsigned smoothCfg=0);
|
int runEffect(const QString &effectName
|
||||||
|
, const QJsonObject &args
|
||||||
|
, int priority
|
||||||
|
, int timeout = -1
|
||||||
|
, const QString &pythonScript = ""
|
||||||
|
, const QString &origin = "System"
|
||||||
|
, unsigned smoothCfg=0
|
||||||
|
, const QString &imageData = ""
|
||||||
|
);
|
||||||
|
|
||||||
/// Clear any effect running on the provided channel
|
/// Clear any effect running on the provided channel
|
||||||
void channelCleared(int priority);
|
void channelCleared(int priority);
|
||||||
@ -92,7 +100,15 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
||||||
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System", unsigned smoothCfg=0);
|
int runEffectScript(const QString &script
|
||||||
|
,const QString &name
|
||||||
|
, const QJsonObject &args
|
||||||
|
, int priority
|
||||||
|
, int timeout = -1
|
||||||
|
, const QString &origin="System"
|
||||||
|
, unsigned smoothCfg=0
|
||||||
|
, const QString &imageData = ""
|
||||||
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
|
96
include/grabber/QtGrabber.h
Normal file
96
include/grabber/QtGrabber.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
// Hyperion-utils includes
|
||||||
|
#include <utils/ColorRgb.h>
|
||||||
|
#include <hyperion/Grabber.h>
|
||||||
|
|
||||||
|
class QScreen;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief The platform capture implementation based on QT API
|
||||||
|
///
|
||||||
|
class QtGrabber : public Grabber
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
|
||||||
|
|
||||||
|
virtual ~QtGrabber();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||||
|
/// provided image should have the same dimensions as the configured values (_width and
|
||||||
|
/// _height)
|
||||||
|
///
|
||||||
|
/// @param[out] image The snapped screenshot (should be initialized with correct width and
|
||||||
|
/// height)
|
||||||
|
///
|
||||||
|
virtual int grabFrame(Image<ColorRgb> & image);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Set a new video mode
|
||||||
|
///
|
||||||
|
virtual void setVideoMode(VideoMode mode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions
|
||||||
|
///
|
||||||
|
virtual bool setWidthHeight(int width, int height) { return true; };
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new pixelDecimation
|
||||||
|
///
|
||||||
|
virtual void setPixelDecimation(int pixelDecimation);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the crop values
|
||||||
|
/// @param cropLeft Left pixel crop
|
||||||
|
/// @param cropRight Right pixel crop
|
||||||
|
/// @param cropTop Top pixel crop
|
||||||
|
/// @param cropBottom Bottom pixel crop
|
||||||
|
///
|
||||||
|
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply display index
|
||||||
|
///
|
||||||
|
virtual void setDisplayIndex(int index);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
///
|
||||||
|
/// @brief is called whenever the current _screen changes it's geometry
|
||||||
|
/// @param geo The new geometry
|
||||||
|
///
|
||||||
|
void geometryChanged(const QRect &geo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
///
|
||||||
|
/// @brief Setup a new capture display, will free the previous one
|
||||||
|
/// @return True on success, false if no display is found
|
||||||
|
///
|
||||||
|
const bool setupDisplay();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Is called whenever we need new screen dimension calculations based on window geometry
|
||||||
|
///
|
||||||
|
int updateScreenDimensions(const bool& force);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief free the _screen pointer
|
||||||
|
///
|
||||||
|
void freeResources();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned _display;
|
||||||
|
int _pixelDecimation;
|
||||||
|
unsigned _screenWidth;
|
||||||
|
unsigned _screenHeight;
|
||||||
|
unsigned _src_x;
|
||||||
|
unsigned _src_y;
|
||||||
|
unsigned _src_x_max;
|
||||||
|
unsigned _src_y_max;
|
||||||
|
QScreen* _screen;
|
||||||
|
};
|
38
include/grabber/QtWrapper.h
Normal file
38
include/grabber/QtWrapper.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyperion/GrabberWrapper.h>
|
||||||
|
#include <grabber/QtGrabber.h>
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The QtWrapper uses QtFramework API's to get a picture from system
|
||||||
|
///
|
||||||
|
class QtWrapper: public GrabberWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
|
||||||
|
///
|
||||||
|
/// @param[in] cropLeft Remove from left [pixels]
|
||||||
|
/// @param[in] cropRight Remove from right [pixels]
|
||||||
|
/// @param[in] cropTop Remove from top [pixels]
|
||||||
|
/// @param[in] cropBottom Remove from bottom [pixels]
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
///
|
||||||
|
QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Destructor of this qt frame grabber. Releases any claimed resources.
|
||||||
|
///
|
||||||
|
virtual ~QtWrapper() {};
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
///
|
||||||
|
/// Performs a single frame grab and computes the led-colors
|
||||||
|
///
|
||||||
|
virtual void action();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The actual grabber
|
||||||
|
QtGrabber _grabber;
|
||||||
|
};
|
@ -39,7 +39,7 @@ public:
|
|||||||
virtual bool setWidthHeight(int width, int height);
|
virtual bool setWidthHeight(int width, int height);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation (used from x11)
|
/// @brief Apply new pixelDecimation (used from x11 and qt)
|
||||||
///
|
///
|
||||||
virtual void setPixelDecimation(int pixelDecimation) {};
|
virtual void setPixelDecimation(int pixelDecimation) {};
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ public:
|
|||||||
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {};
|
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply display index (used from x11)
|
/// @brief Apply display index (used from qt)
|
||||||
///
|
///
|
||||||
virtual void setDisplayIndex(int index) {};
|
virtual void setDisplayIndex(int index) {};
|
||||||
|
|
||||||
|
@ -360,8 +360,14 @@ public slots:
|
|||||||
/// @param args arguments of the effect script
|
/// @param args arguments of the effect script
|
||||||
/// @param priority The priority channel of the effect
|
/// @param priority The priority channel of the effect
|
||||||
/// @param timeout The timeout of the effect (after the timout, the effect will be cleared)
|
/// @param timeout The timeout of the effect (after the timout, the effect will be cleared)
|
||||||
int setEffect(const QString & effectName, const QJsonObject & args, int priority,
|
int setEffect(const QString &effectName
|
||||||
int timeout = -1, const QString & pythonScript = "", const QString & origin="System");
|
, const QJsonObject &args
|
||||||
|
, int priority
|
||||||
|
, int timeout = -1
|
||||||
|
, const QString &pythonScript = ""
|
||||||
|
, const QString &origin="System"
|
||||||
|
, const QString &imageData = ""
|
||||||
|
);
|
||||||
|
|
||||||
/// sets the methode how image is maped to leds at ImageProcessor
|
/// sets the methode how image is maped to leds at ImageProcessor
|
||||||
void setLedMappingType(const int& mappingType);
|
void setLedMappingType(const int& mappingType);
|
||||||
|
@ -168,7 +168,9 @@ namespace hyperion
|
|||||||
template <typename Pixel_T>
|
template <typename Pixel_T>
|
||||||
ColorRgb calcMeanColor(const Image<Pixel_T> & image, const std::vector<unsigned> & colors) const
|
ColorRgb calcMeanColor(const Image<Pixel_T> & image, const std::vector<unsigned> & colors) const
|
||||||
{
|
{
|
||||||
if (colors.size() == 0)
|
const auto colorVecSize = colors.size();
|
||||||
|
|
||||||
|
if (colorVecSize == 0)
|
||||||
{
|
{
|
||||||
return ColorRgb::BLACK;
|
return ColorRgb::BLACK;
|
||||||
}
|
}
|
||||||
@ -177,18 +179,20 @@ namespace hyperion
|
|||||||
uint_fast16_t cummRed = 0;
|
uint_fast16_t cummRed = 0;
|
||||||
uint_fast16_t cummGreen = 0;
|
uint_fast16_t cummGreen = 0;
|
||||||
uint_fast16_t cummBlue = 0;
|
uint_fast16_t cummBlue = 0;
|
||||||
|
const auto& imgData = image.memptr();
|
||||||
|
|
||||||
for (const unsigned colorOffset : colors)
|
for (const unsigned colorOffset : colors)
|
||||||
{
|
{
|
||||||
const Pixel_T& pixel = image.memptr()[colorOffset];
|
const auto& pixel = imgData[colorOffset];
|
||||||
cummRed += pixel.red;
|
cummRed += pixel.red;
|
||||||
cummGreen += pixel.green;
|
cummGreen += pixel.green;
|
||||||
cummBlue += pixel.blue;
|
cummBlue += pixel.blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the average of each color channel
|
// Compute the average of each color channel
|
||||||
const uint8_t avgRed = uint8_t(cummRed/colors.size());
|
const uint8_t avgRed = uint8_t(cummRed/colorVecSize);
|
||||||
const uint8_t avgGreen = uint8_t(cummGreen/colors.size());
|
const uint8_t avgGreen = uint8_t(cummGreen/colorVecSize);
|
||||||
const uint8_t avgBlue = uint8_t(cummBlue/colors.size());
|
const uint8_t avgBlue = uint8_t(cummBlue/colorVecSize);
|
||||||
|
|
||||||
// Return the computed color
|
// Return the computed color
|
||||||
return {avgRed, avgGreen, avgBlue};
|
return {avgRed, avgGreen, avgBlue};
|
||||||
@ -211,9 +215,11 @@ namespace hyperion
|
|||||||
uint_fast16_t cummBlue = 0;
|
uint_fast16_t cummBlue = 0;
|
||||||
const unsigned imageSize = image.width() * image.height();
|
const unsigned imageSize = image.width() * image.height();
|
||||||
|
|
||||||
|
const auto& imgData = image.memptr();
|
||||||
|
|
||||||
for (unsigned idx=0; idx<imageSize; idx++)
|
for (unsigned idx=0; idx<imageSize; idx++)
|
||||||
{
|
{
|
||||||
const Pixel_T& pixel = image.memptr()[idx];
|
const auto& pixel = imgData[idx];
|
||||||
cummRed += pixel.red;
|
cummRed += pixel.red;
|
||||||
cummGreen += pixel.green;
|
cummGreen += pixel.green;
|
||||||
cummBlue += pixel.blue;
|
cummBlue += pixel.blue;
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
{
|
{
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"required" : true
|
"required" : true
|
||||||
|
},
|
||||||
|
"imageData" : {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
"pythonScript" : {
|
"pythonScript" : {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : false
|
"required" : false
|
||||||
|
},
|
||||||
|
"imageData" : {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
// #include <QFileInfo>
|
|
||||||
// #include <QDir>
|
|
||||||
// #include <QIODevice>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
@ -180,7 +177,7 @@ void JsonAPI::handleImageCommand(const QJsonObject& message, const QString& comm
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleEffectCommand(const QJsonObject& message, const QString& command, const int tan)
|
void JsonAPI::handleEffectCommand(const QJsonObject &message, const QString &command, const int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
|
|
||||||
@ -191,16 +188,12 @@ void JsonAPI::handleEffectCommand(const QJsonObject& message, const QString& com
|
|||||||
QString origin = message["origin"].toString() + "@"+_peerAddress;
|
QString origin = message["origin"].toString() + "@"+_peerAddress;
|
||||||
const QJsonObject & effect = message["effect"].toObject();
|
const QJsonObject & effect = message["effect"].toObject();
|
||||||
const QString & effectName = effect["name"].toString();
|
const QString & effectName = effect["name"].toString();
|
||||||
|
const QString & data = message["imageData"].toString("").toUtf8();
|
||||||
|
|
||||||
// set output
|
// set output
|
||||||
if (effect.contains("args"))
|
(effect.contains("args"))
|
||||||
{
|
? _hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript, origin, data)
|
||||||
_hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript, origin);
|
: _hyperion->setEffect(effectName, priority, duration, origin);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_hyperion->setEffect(effectName, priority, duration, origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send reply
|
// send reply
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
//impl
|
//impl
|
||||||
PyThreadState* mainThreadState;
|
PyThreadState* mainThreadState;
|
||||||
|
|
||||||
Effect::Effect(Hyperion* hyperion, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args)
|
Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &script, const QString &name, const QJsonObject &args, const QString &imageData)
|
||||||
: QThread()
|
: QThread()
|
||||||
, _hyperion(hyperion)
|
, _hyperion(hyperion)
|
||||||
, _priority(priority)
|
, _priority(priority)
|
||||||
@ -33,6 +33,7 @@ Effect::Effect(Hyperion* hyperion, int priority, int timeout, const QString & sc
|
|||||||
, _script(script)
|
, _script(script)
|
||||||
, _name(name)
|
, _name(name)
|
||||||
, _args(args)
|
, _args(args)
|
||||||
|
, _imageData(imageData)
|
||||||
, _endTime(-1)
|
, _endTime(-1)
|
||||||
, _colors()
|
, _colors()
|
||||||
, _imageSize(hyperion->getLedGridSize())
|
, _imageSize(hyperion->getLedGridSize())
|
||||||
|
@ -136,14 +136,14 @@ int EffectEngine::runEffect(const QString &effectName, int priority, int timeout
|
|||||||
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
|
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg)
|
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg, const QString &imageData)
|
||||||
{
|
{
|
||||||
Info( _log, "run effect %s on channel %d", QSTRING_CSTR(effectName), priority);
|
Info( _log, "run effect %s on channel %d", QSTRING_CSTR(effectName), priority);
|
||||||
|
|
||||||
if (pythonScript.isEmpty())
|
if (pythonScript.isEmpty())
|
||||||
{
|
{
|
||||||
const EffectDefinition * effectDefinition = nullptr;
|
const EffectDefinition *effectDefinition = nullptr;
|
||||||
for (const EffectDefinition & e : _availableEffects)
|
for (const EffectDefinition &e : _availableEffects)
|
||||||
{
|
{
|
||||||
if (e.name == effectName)
|
if (e.name == effectName)
|
||||||
{
|
{
|
||||||
@ -160,16 +160,16 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
|
|||||||
|
|
||||||
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin, effectDefinition->smoothCfg);
|
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin, effectDefinition->smoothCfg);
|
||||||
}
|
}
|
||||||
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin, smoothCfg);
|
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin, smoothCfg, imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin, unsigned smoothCfg)
|
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString &origin, unsigned smoothCfg, const QString &imageData)
|
||||||
{
|
{
|
||||||
// clear current effect on the channel
|
// clear current effect on the channel
|
||||||
channelCleared(priority);
|
channelCleared(priority);
|
||||||
|
|
||||||
// create the effect
|
// create the effect
|
||||||
Effect * effect = new Effect(_hyperion, priority, timeout, script, name, args);
|
Effect *effect = new Effect(_hyperion, priority, timeout, script, name, args, imageData);
|
||||||
connect(effect, &Effect::setInput, _hyperion, &Hyperion::setInput, Qt::QueuedConnection);
|
connect(effect, &Effect::setInput, _hyperion, &Hyperion::setInput, Qt::QueuedConnection);
|
||||||
connect(effect, &Effect::setInputImage, _hyperion, &Hyperion::setInputImage, Qt::QueuedConnection);
|
connect(effect, &Effect::setInputImage, _hyperion, &Hyperion::setInputImage, Qt::QueuedConnection);
|
||||||
connect(effect, &QThread::finished, this, &EffectEngine::effectFinished);
|
connect(effect, &QThread::finished, this, &EffectEngine::effectFinished);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
// createEffect helper
|
// createEffect helper
|
||||||
struct find_schema: std::unary_function<EffectSchema, bool>
|
struct find_schema: std::unary_function<EffectSchema, bool>
|
||||||
@ -69,7 +70,15 @@ const bool EffectFileHandler::deleteEffect(const QString& effectName, QString& r
|
|||||||
{
|
{
|
||||||
if (effectConfigurationFile.exists())
|
if (effectConfigurationFile.exists())
|
||||||
{
|
{
|
||||||
|
if ( (it->script == ":/effects/gif.py") && !it->args.value("image").toString("").isEmpty())
|
||||||
|
{
|
||||||
|
QFileInfo effectImageFile(effectConfigurationFile.absolutePath() + "/" + it->args.value("image").toString());
|
||||||
|
if (effectImageFile.exists())
|
||||||
|
QFile::remove(effectImageFile.absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
bool result = QFile::remove(effectConfigurationFile.absoluteFilePath());
|
bool result = QFile::remove(effectConfigurationFile.absoluteFilePath());
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
updateEffects();
|
updateEffects();
|
||||||
@ -141,6 +150,17 @@ const bool EffectFileHandler::saveEffect(const QJsonObject& message, QString& re
|
|||||||
newFileName.setFile(f);
|
newFileName.setFile(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO check if filename exist
|
||||||
|
if (!message["imageData"].toString("").isEmpty() && !message["args"].toObject().value("image").toString("").isEmpty())
|
||||||
|
{
|
||||||
|
QFileInfo imageFileName(effectArray[0].toString().replace("$ROOT",_rootPath) + "/" + message["args"].toObject().value("image").toString());
|
||||||
|
if(!FileUtils::writeFile(imageFileName.absoluteFilePath(), QByteArray::fromBase64(message["imageData"].toString("").toUtf8()), _log))
|
||||||
|
{
|
||||||
|
resultMsg = "Error while saving image file '" + message["args"].toObject().value("image").toString() + ", please check the Hyperion Log";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!JsonUtils::write(newFileName.absoluteFilePath(), effectJson, _log))
|
if(!JsonUtils::write(newFileName.absoluteFilePath(), effectJson, _log))
|
||||||
{
|
{
|
||||||
resultMsg = "Error while saving effect, please check the Hyperion Log";
|
resultMsg = "Error while saving effect, please check the Hyperion Log";
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
// create the hyperion module
|
// create the hyperion module
|
||||||
struct PyModuleDef EffectModule::moduleDef = {
|
struct PyModuleDef EffectModule::moduleDef = {
|
||||||
@ -257,25 +258,42 @@ PyObject* EffectModule::wrapSetImage(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
|
PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(EffectEngine);
|
Effect *effect = getEffect();
|
||||||
|
|
||||||
char *source;
|
QString file;
|
||||||
if(!PyArg_ParseTuple(args, "s", &source))
|
QBuffer buffer;
|
||||||
|
QImageReader reader;
|
||||||
|
|
||||||
|
if (effect->_imageData.isEmpty())
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_TypeError, "String required");
|
Q_INIT_RESOURCE(EffectEngine);
|
||||||
return NULL;
|
|
||||||
|
char *source;
|
||||||
|
if(!PyArg_ParseTuple(args, "s", &source))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "String required");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = QString::fromUtf8(source);
|
||||||
|
|
||||||
|
if (file.mid(0, 1) == ":")
|
||||||
|
file = ":/effects/"+file.mid(1);
|
||||||
|
|
||||||
|
reader.setDecideFormatFromContent(true);
|
||||||
|
reader.setFileName(file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.setData(QByteArray::fromBase64(effect->_imageData.toUtf8()));
|
||||||
|
buffer.open(QBuffer::ReadOnly);
|
||||||
|
reader.setDecideFormatFromContent(true);
|
||||||
|
reader.setDevice(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString file = QString::fromUtf8(source);
|
|
||||||
|
|
||||||
if (file.mid(0, 1) == ":")
|
|
||||||
file = ":/effects/"+file.mid(1);
|
|
||||||
|
|
||||||
QImageReader reader(file);
|
|
||||||
|
|
||||||
if (reader.canRead())
|
if (reader.canRead())
|
||||||
{
|
{
|
||||||
PyObject* result = PyList_New(reader.imageCount());
|
PyObject *result = PyList_New(reader.imageCount());
|
||||||
|
|
||||||
for (int i = 0; i < reader.imageCount(); ++i)
|
for (int i = 0; i < reader.imageCount(); ++i)
|
||||||
{
|
{
|
||||||
@ -290,7 +308,7 @@ PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
|
|||||||
QByteArray binaryImage;
|
QByteArray binaryImage;
|
||||||
for (int i = 0; i<height; ++i)
|
for (int i = 0; i<height; ++i)
|
||||||
{
|
{
|
||||||
const QRgb * scanline = reinterpret_cast<const QRgb *>(qimage.scanLine(i));
|
const QRgb *scanline = reinterpret_cast<const QRgb *>(qimage.scanLine(i));
|
||||||
for (int j = 0; j< width; ++j)
|
for (int j = 0; j< width; ++j)
|
||||||
{
|
{
|
||||||
binaryImage.append((char) qRed(scanline[j]));
|
binaryImage.append((char) qRed(scanline[j]));
|
||||||
|
@ -21,3 +21,7 @@ endif (ENABLE_V4L2)
|
|||||||
if (ENABLE_X11)
|
if (ENABLE_X11)
|
||||||
add_subdirectory(x11)
|
add_subdirectory(x11)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_QT)
|
||||||
|
add_subdirectory(qt)
|
||||||
|
endif()
|
||||||
|
16
libsrc/grabber/qt/CMakeLists.txt
Normal file
16
libsrc/grabber/qt/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Define the current source locations
|
||||||
|
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
|
||||||
|
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/qt)
|
||||||
|
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
|
include_directories( ${X11_INCLUDES} )
|
||||||
|
|
||||||
|
FILE ( GLOB QT_GRAB_SOURCES "${CURRENT_HEADER_DIR}/Qt*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" )
|
||||||
|
|
||||||
|
add_library(qt-grabber ${QT_GRAB_SOURCES} )
|
||||||
|
|
||||||
|
target_link_libraries(qt-grabber
|
||||||
|
hyperion
|
||||||
|
Qt5::Widgets
|
||||||
|
)
|
199
libsrc/grabber/qt/QtGrabber.cpp
Normal file
199
libsrc/grabber/qt/QtGrabber.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// proj
|
||||||
|
#include <grabber/QtGrabber.h>
|
||||||
|
|
||||||
|
// qt
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QWindow>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QScreen>
|
||||||
|
|
||||||
|
QtGrabber::QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display)
|
||||||
|
: Grabber("QTGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
||||||
|
, _display(unsigned(display))
|
||||||
|
, _pixelDecimation(pixelDecimation)
|
||||||
|
, _screenWidth(0)
|
||||||
|
, _screenHeight(0)
|
||||||
|
, _src_x(0)
|
||||||
|
, _src_y(0)
|
||||||
|
, _src_x_max(0)
|
||||||
|
, _src_y_max(0)
|
||||||
|
, _screen(nullptr)
|
||||||
|
{
|
||||||
|
_useImageResampler = false;
|
||||||
|
|
||||||
|
// init
|
||||||
|
setupDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
QtGrabber::~QtGrabber()
|
||||||
|
{
|
||||||
|
freeResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::freeResources()
|
||||||
|
{
|
||||||
|
// cleanup
|
||||||
|
if (_screen != nullptr)
|
||||||
|
{
|
||||||
|
delete _screen;
|
||||||
|
_screen = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool QtGrabber::setupDisplay()
|
||||||
|
{
|
||||||
|
// cleanup last screen
|
||||||
|
freeResources();
|
||||||
|
|
||||||
|
QScreen* primary = QGuiApplication::primaryScreen();
|
||||||
|
QList<QScreen *> screens = QGuiApplication::screens();
|
||||||
|
// inject main screen at 0, if not nullptr
|
||||||
|
if(primary != nullptr)
|
||||||
|
{
|
||||||
|
screens.prepend(primary);
|
||||||
|
// remove last main screen if twice in list
|
||||||
|
if(screens.lastIndexOf(primary) > 0)
|
||||||
|
screens.removeAt(screens.lastIndexOf(primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(screens.isEmpty())
|
||||||
|
{
|
||||||
|
Error(_log, "No displays found to capture from!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(_log,"Available Displays:");
|
||||||
|
int index = 0;
|
||||||
|
for(auto screen : screens)
|
||||||
|
{
|
||||||
|
const QRect geo = screen->geometry();
|
||||||
|
Info(_log,"Display %d: Name:%s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.left(), geo.top() ,geo.right(), geo.bottom(), screen->depth());
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// be sure the index is available
|
||||||
|
if(_display > unsigned(screens.size()-1))
|
||||||
|
{
|
||||||
|
Info(_log, "The requested display index '%d' is not available, falling back to display 0", _display);
|
||||||
|
_display = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init the requested display
|
||||||
|
_screen = screens.at(_display);
|
||||||
|
connect(_screen, &QScreen::geometryChanged, this, &QtGrabber::geometryChanged);
|
||||||
|
updateScreenDimensions(true);
|
||||||
|
|
||||||
|
Info(_log,"Initialized display %d", _display);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::geometryChanged(const QRect &geo)
|
||||||
|
{
|
||||||
|
Info(_log, "The current display changed geometry to (L,T,R,B) %d,%d,%d,%d", geo.left(), geo.top() ,geo.right(), geo.bottom());
|
||||||
|
updateScreenDimensions(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
|
{
|
||||||
|
if(_screen == nullptr)
|
||||||
|
{
|
||||||
|
// reinit, this will disable capture on failure
|
||||||
|
setEnabled(setupDisplay());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||||
|
QPixmap resizedPixmap = originalPixmap.scaled(_width,_height);
|
||||||
|
QImage img = resizedPixmap.toImage().convertToFormat( QImage::Format_RGB888);
|
||||||
|
memcpy(image.memptr(), img.bits(),_width*_height*3);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QtGrabber::updateScreenDimensions(const bool& force)
|
||||||
|
{
|
||||||
|
if(!_screen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const QRect& geo = _screen->geometry();
|
||||||
|
if (!force && _screenWidth == unsigned(geo.right()) && _screenHeight == unsigned(geo.bottom()))
|
||||||
|
{
|
||||||
|
// No update required
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _screenWidth, _screenHeight, geo.right(), geo.bottom());
|
||||||
|
_screenWidth = geo.right() - geo.left();
|
||||||
|
_screenHeight = geo.bottom() - geo.top();
|
||||||
|
|
||||||
|
int width=0, height=0;
|
||||||
|
|
||||||
|
// Image scaling is performed by Qt
|
||||||
|
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
|
||||||
|
? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
|
||||||
|
: (_screenWidth / _pixelDecimation);
|
||||||
|
|
||||||
|
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
|
||||||
|
? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
|
||||||
|
: (_screenHeight / _pixelDecimation);
|
||||||
|
|
||||||
|
|
||||||
|
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||||
|
switch (_videoMode)
|
||||||
|
{
|
||||||
|
case VIDEO_3DSBS:
|
||||||
|
_width = width /2;
|
||||||
|
_height = height;
|
||||||
|
_src_x = _cropLeft / 2;
|
||||||
|
_src_y = _cropTop;
|
||||||
|
_src_x_max = (_screenWidth / 2) - _cropRight;
|
||||||
|
_src_y_max = _screenHeight - _cropBottom;
|
||||||
|
break;
|
||||||
|
case VIDEO_3DTAB:
|
||||||
|
_width = width;
|
||||||
|
_height = height / 2;
|
||||||
|
_src_x = _cropLeft;
|
||||||
|
_src_y = _cropTop / 2;
|
||||||
|
_src_x_max = _screenWidth - _cropRight;
|
||||||
|
_src_y_max = (_screenHeight / 2) - _cropBottom;
|
||||||
|
break;
|
||||||
|
case VIDEO_2D:
|
||||||
|
default:
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
_src_x = _cropLeft;
|
||||||
|
_src_y = _cropTop;
|
||||||
|
_src_x_max = _screenWidth - _cropRight;
|
||||||
|
_src_y_max = _screenHeight - _cropBottom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(_log, "Update output image resolution to [%dx%d]", _width, _height);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::setVideoMode(VideoMode mode)
|
||||||
|
{
|
||||||
|
Grabber::setVideoMode(mode);
|
||||||
|
updateScreenDimensions(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::setPixelDecimation(int pixelDecimation)
|
||||||
|
{
|
||||||
|
_pixelDecimation = pixelDecimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
|
||||||
|
{
|
||||||
|
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
|
updateScreenDimensions(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtGrabber::setDisplayIndex(int index)
|
||||||
|
{
|
||||||
|
if(_display != unsigned(index))
|
||||||
|
{
|
||||||
|
_display = unsigned(index);
|
||||||
|
setupDisplay();
|
||||||
|
}
|
||||||
|
}
|
11
libsrc/grabber/qt/QtWrapper.cpp
Normal file
11
libsrc/grabber/qt/QtWrapper.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <grabber/QtWrapper.h>
|
||||||
|
|
||||||
|
QtWrapper::QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz)
|
||||||
|
: GrabberWrapper("Qt", &_grabber, 0, 0, updateRate_Hz)
|
||||||
|
, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void QtWrapper::action()
|
||||||
|
{
|
||||||
|
transferFrame(_grabber);
|
||||||
|
}
|
@ -77,6 +77,10 @@ QStringList GrabberWrapper::availableGrabbers()
|
|||||||
grabbers << "x11";
|
grabbers << "x11";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
grabbers << "qt";
|
||||||
|
#endif
|
||||||
|
|
||||||
return grabbers;
|
return grabbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,9 +529,9 @@ int Hyperion::setEffect(const QString &effectName, int priority, int timeout, co
|
|||||||
return _effectEngine->runEffect(effectName, priority, timeout, origin);
|
return _effectEngine->runEffect(effectName, priority, timeout, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString & pythonScript, const QString & origin)
|
int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, const QString &imageData)
|
||||||
{
|
{
|
||||||
return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript, origin);
|
return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript, origin, 0, imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hyperion::setLedMappingType(const int& mappingType)
|
void Hyperion::setLedMappingType(const int& mappingType)
|
||||||
|
@ -47,19 +47,24 @@ ImageToLedsMap::ImageToLedsMap(
|
|||||||
minX_idx = qMin(minX_idx, xOffset + actualWidth - 1);
|
minX_idx = qMin(minX_idx, xOffset + actualWidth - 1);
|
||||||
if (minX_idx == maxX_idx)
|
if (minX_idx == maxX_idx)
|
||||||
{
|
{
|
||||||
maxX_idx = minX_idx + 1;
|
maxX_idx++;
|
||||||
}
|
}
|
||||||
minY_idx = qMin(minY_idx, yOffset + actualHeight - 1);
|
minY_idx = qMin(minY_idx, yOffset + actualHeight - 1);
|
||||||
if (minY_idx == maxY_idx)
|
if (minY_idx == maxY_idx)
|
||||||
{
|
{
|
||||||
maxY_idx = minY_idx + 1;
|
maxY_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all the indices in the above defined rectangle to the indices for this led
|
// Add all the indices in the above defined rectangle to the indices for this led
|
||||||
|
const auto maxYLedCount = qMin(maxY_idx, yOffset+actualHeight);
|
||||||
|
const auto maxXLedCount = qMin(maxX_idx, xOffset+actualWidth);
|
||||||
|
|
||||||
std::vector<unsigned> ledColors;
|
std::vector<unsigned> ledColors;
|
||||||
for (unsigned y = minY_idx; y<maxY_idx && y<(yOffset+actualHeight); ++y)
|
ledColors.reserve(maxXLedCount*maxYLedCount);
|
||||||
|
|
||||||
|
for (unsigned y = minY_idx; y < maxYLedCount; ++y)
|
||||||
{
|
{
|
||||||
for (unsigned x = minX_idx; x<maxX_idx && x<(xOffset+actualWidth); ++x)
|
for (unsigned x = minX_idx; x < maxXLedCount; ++x)
|
||||||
{
|
{
|
||||||
ledColors.push_back(y*width + x);
|
ledColors.push_back(y*width + x);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{
|
{
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"title" : "edt_conf_fg_type_title",
|
"title" : "edt_conf_fg_type_title",
|
||||||
"enum" : ["auto","dispmanx","amlogic","x11","framebuffer"],
|
"enum" : ["auto","dispmanx","amlogic","x11","framebuffer","qt"],
|
||||||
"default" : "auto",
|
"default" : "auto",
|
||||||
"propertyOrder" : 2
|
"propertyOrder" : 2
|
||||||
},
|
},
|
||||||
|
@ -144,8 +144,8 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
|
|||||||
{
|
{
|
||||||
// apply gamma
|
// apply gamma
|
||||||
red = _mappingR[red];
|
red = _mappingR[red];
|
||||||
green = _mappingR[green];
|
green = _mappingG[green];
|
||||||
blue = _mappingR[blue];
|
blue = _mappingB[blue];
|
||||||
|
|
||||||
// apply brightnesss
|
// apply brightnesss
|
||||||
int rgbSum = red+green+blue;
|
int rgbSum = red+green+blue;
|
||||||
|
@ -23,6 +23,8 @@ QtHttpClientWrapper::QtHttpClientWrapper (QTcpSocket * sock, QtHttpServer * pare
|
|||||||
, m_sockClient (sock)
|
, m_sockClient (sock)
|
||||||
, m_currentRequest (Q_NULLPTR)
|
, m_currentRequest (Q_NULLPTR)
|
||||||
, m_serverHandle (parent)
|
, m_serverHandle (parent)
|
||||||
|
, m_websocketClient(nullptr)
|
||||||
|
, m_webJsonRpc (nullptr)
|
||||||
{
|
{
|
||||||
connect (m_sockClient, &QTcpSocket::readyRead, this, &QtHttpClientWrapper::onClientDataReceived);
|
connect (m_sockClient, &QTcpSocket::readyRead, this, &QtHttpClientWrapper::onClientDataReceived);
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ private:
|
|||||||
QTcpSocket * m_sockClient;
|
QTcpSocket * m_sockClient;
|
||||||
QtHttpRequest * m_currentRequest;
|
QtHttpRequest * m_currentRequest;
|
||||||
QtHttpServer * m_serverHandle;
|
QtHttpServer * m_serverHandle;
|
||||||
WebSocketClient * m_websocketClient = nullptr;
|
WebSocketClient * m_websocketClient;
|
||||||
WebJsonRpc * m_webJsonRpc = nullptr;
|
WebJsonRpc * m_webJsonRpc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QTHTTPCLIENTWRAPPER_H
|
#endif // QTHTTPCLIENTWRAPPER_H
|
||||||
|
42
src/hyperion-qt/CMakeLists.txt
Normal file
42
src/hyperion-qt/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0.0)
|
||||||
|
project(hyperion-qt)
|
||||||
|
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver
|
||||||
|
${FLATBUFFERS_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(Hyperion_QT_HEADERS
|
||||||
|
QtWrapper.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(Hyperion_QT_SOURCES
|
||||||
|
QtWrapper.cpp
|
||||||
|
hyperion-qt.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
${Hyperion_QT_HEADERS}
|
||||||
|
${Hyperion_QT_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
commandline
|
||||||
|
qt-grabber
|
||||||
|
flatbufserver
|
||||||
|
flatbuffers
|
||||||
|
ssdp
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Widgets
|
||||||
|
Qt5::Network
|
||||||
|
)
|
||||||
|
|
||||||
|
install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" )
|
||||||
|
|
||||||
|
if(CMAKE_HOST_UNIX)
|
||||||
|
install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "${PLATFORM}" )
|
||||||
|
install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "${PLATFORM}" )
|
||||||
|
install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "${PLATFORM}" )
|
||||||
|
endif(CMAKE_HOST_UNIX)
|
42
src/hyperion-qt/QtWrapper.cpp
Normal file
42
src/hyperion-qt/QtWrapper.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
// Hyperion-qt includes
|
||||||
|
#include "QtWrapper.h"
|
||||||
|
|
||||||
|
QtWrapper::QtWrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display) :
|
||||||
|
_timer(this),
|
||||||
|
_grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
||||||
|
{
|
||||||
|
_timer.setInterval(grabInterval);
|
||||||
|
// Connect capturing to the timeout signal of the timer
|
||||||
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image<ColorRgb> & QtWrapper::getScreenshot()
|
||||||
|
{
|
||||||
|
_grabber.grabFrame(_screenshot);
|
||||||
|
return _screenshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtWrapper::start()
|
||||||
|
{
|
||||||
|
_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtWrapper::stop()
|
||||||
|
{
|
||||||
|
_timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtWrapper::capture()
|
||||||
|
{
|
||||||
|
if(unsigned(_grabber.getImageWidth()) != unsigned(_screenshot.width()) || unsigned(_grabber.getImageHeight()) != unsigned(_screenshot.height()))
|
||||||
|
_screenshot.resize(_grabber.getImageWidth(),_grabber.getImageHeight());
|
||||||
|
|
||||||
|
_grabber.grabFrame(_screenshot);
|
||||||
|
emit sig_screenshot(_screenshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtWrapper::setVideoMode(const VideoMode mode)
|
||||||
|
{
|
||||||
|
_grabber.setVideoMode(mode);
|
||||||
|
}
|
51
src/hyperion-qt/QtWrapper.h
Normal file
51
src/hyperion-qt/QtWrapper.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
// Hyperion-Qt includes
|
||||||
|
#include <grabber/QtGrabber.h>
|
||||||
|
|
||||||
|
//Utils includes
|
||||||
|
#include <utils/VideoMode.h>
|
||||||
|
|
||||||
|
class QtWrapper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QtWrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
|
||||||
|
|
||||||
|
const Image<ColorRgb> & getScreenshot();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Starts the timed capturing of screenshots
|
||||||
|
///
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sig_screenshot(const Image<ColorRgb> & screenshot);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
///
|
||||||
|
/// Set the video mode (2D/3D)
|
||||||
|
/// @param[in] mode The new video mode
|
||||||
|
///
|
||||||
|
void setVideoMode(const VideoMode videoMode);
|
||||||
|
|
||||||
|
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
|
||||||
|
QtGrabber _grabber;
|
||||||
|
|
||||||
|
Image<ColorRgb> _screenshot;
|
||||||
|
};
|
111
src/hyperion-qt/hyperion-qt.cpp
Normal file
111
src/hyperion-qt/hyperion-qt.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
#include "QtWrapper.h"
|
||||||
|
#include <utils/ColorRgb.h>
|
||||||
|
#include <utils/Image.h>
|
||||||
|
#include <commandline/Parser.h>
|
||||||
|
|
||||||
|
//flatbuf sending
|
||||||
|
#include <flatbufserver/FlatBufferConnection.h>
|
||||||
|
|
||||||
|
// ssdp discover
|
||||||
|
#include <ssdp/SSDPDiscover.h>
|
||||||
|
|
||||||
|
using namespace commandline;
|
||||||
|
|
||||||
|
// save the image as screenshot
|
||||||
|
void saveScreenshot(QString 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);
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// create the option parser and initialize all parameters
|
||||||
|
Parser parser("Qt interface capture application for Hyperion");
|
||||||
|
|
||||||
|
Option & argDisplay = parser.add<Option> ('d', "display", "Set the display to capture [default: %1]","0");
|
||||||
|
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
|
||||||
|
IntOption & argCropLeft = parser.add<IntOption> (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)");
|
||||||
|
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
|
||||||
|
IntOption & argCropTop = parser.add<IntOption> (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
|
||||||
|
IntOption & argCropBottom = parser.add<IntOption> (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
|
||||||
|
IntOption & argSizeDecimation = parser.add<IntOption> ('s', "size-decimator", "Decimation factor for the output image size [default=%1]", "8", 1);
|
||||||
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
|
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
||||||
|
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
||||||
|
BooleanOption & argSkipReply = parser.add<BooleanOption>(0x0, "skip-reply", "Do not receive and check reply messages from Hyperion");
|
||||||
|
BooleanOption & argHelp = parser.add<BooleanOption>('h', "help", "Show this help message and exit");
|
||||||
|
|
||||||
|
// parse all arguments
|
||||||
|
parser.process(app);
|
||||||
|
|
||||||
|
// check if we need to display the usage. exit if we do.
|
||||||
|
if (parser.isSet(argHelp))
|
||||||
|
{
|
||||||
|
parser.showHelp(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QtWrapper grabber(
|
||||||
|
1000 / argFps.getInt(parser),
|
||||||
|
argCropLeft.getInt(parser),
|
||||||
|
argCropRight.getInt(parser),
|
||||||
|
argCropTop.getInt(parser),
|
||||||
|
argCropBottom.getInt(parser),
|
||||||
|
argSizeDecimation.getInt(parser),
|
||||||
|
parser.isSet(argDisplay));
|
||||||
|
|
||||||
|
if (parser.isSet(argScreenshot))
|
||||||
|
{
|
||||||
|
// Capture a single screenshot and finish
|
||||||
|
const Image<ColorRgb> &screenshot = grabber.getScreenshot();
|
||||||
|
saveScreenshot("screenshot.png", screenshot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// server searching by ssdp
|
||||||
|
QString address;
|
||||||
|
if(parser.isSet(argAddress))
|
||||||
|
{
|
||||||
|
address = argAddress.value(parser);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SSDPDiscover discover;
|
||||||
|
address = discover.getFirstService(STY_FLATBUFSERVER);
|
||||||
|
if(address.isEmpty())
|
||||||
|
{
|
||||||
|
address = argAddress.value(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create the Flabuf-connection
|
||||||
|
FlatBufferConnection flatbuf("Qt Standalone", address, argPriority.getInt(parser), parser.isSet(argSkipReply));
|
||||||
|
|
||||||
|
// Connect the screen capturing to flatbuf connection processing
|
||||||
|
QObject::connect(&grabber, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &flatbuf, SLOT(setImage(Image<ColorRgb>)));
|
||||||
|
|
||||||
|
// Start the capturing
|
||||||
|
grabber.start();
|
||||||
|
|
||||||
|
// Start the application
|
||||||
|
app.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error & e)
|
||||||
|
{
|
||||||
|
// An error occured. Display error and quit
|
||||||
|
Error(Logger::getInstance("QTGRABBER"), "%s", e.what());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
find_package(PythonLibs 3.5 REQUIRED)
|
find_package(PythonLibs 3.4 REQUIRED)
|
||||||
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
|
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
|
||||||
|
|
||||||
add_executable(hyperiond
|
add_executable(hyperiond
|
||||||
@ -55,7 +55,9 @@ if (ENABLE_X11)
|
|||||||
target_link_libraries(hyperiond x11-grabber )
|
target_link_libraries(hyperiond x11-grabber )
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
qt5_use_modules(hyperiond Core Gui Network Widgets)
|
if (ENABLE_QT)
|
||||||
|
target_link_libraries(hyperiond qt-grabber )
|
||||||
|
endif ()
|
||||||
|
|
||||||
install ( TARGETS hyperiond DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" )
|
install ( TARGETS hyperiond DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" )
|
||||||
install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "${PLATFORM}" )
|
install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "${PLATFORM}" )
|
||||||
|
@ -60,6 +60,7 @@ HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObje
|
|||||||
, _amlGrabber(nullptr)
|
, _amlGrabber(nullptr)
|
||||||
, _fbGrabber(nullptr)
|
, _fbGrabber(nullptr)
|
||||||
, _osxGrabber(nullptr)
|
, _osxGrabber(nullptr)
|
||||||
|
, _qtGrabber(nullptr)
|
||||||
, _hyperion(nullptr)
|
, _hyperion(nullptr)
|
||||||
, _stats(nullptr)
|
, _stats(nullptr)
|
||||||
, _ssdp(nullptr)
|
, _ssdp(nullptr)
|
||||||
@ -155,7 +156,8 @@ void HyperionDaemon::freeObjects()
|
|||||||
delete _dispmanx;
|
delete _dispmanx;
|
||||||
delete _fbGrabber;
|
delete _fbGrabber;
|
||||||
delete _osxGrabber;
|
delete _osxGrabber;
|
||||||
|
delete _qtGrabber;
|
||||||
|
|
||||||
for(V4L2Wrapper* grabber : _v4l2Grabbers)
|
for(V4L2Wrapper* grabber : _v4l2Grabbers)
|
||||||
{
|
{
|
||||||
delete grabber;
|
delete grabber;
|
||||||
@ -168,6 +170,7 @@ void HyperionDaemon::freeObjects()
|
|||||||
_dispmanx = nullptr;
|
_dispmanx = nullptr;
|
||||||
_fbGrabber = nullptr;
|
_fbGrabber = nullptr;
|
||||||
_osxGrabber = nullptr;
|
_osxGrabber = nullptr;
|
||||||
|
_qtGrabber = nullptr;
|
||||||
_webserver = nullptr;
|
_webserver = nullptr;
|
||||||
_jsonServer = nullptr;
|
_jsonServer = nullptr;
|
||||||
_udpListener = nullptr;
|
_udpListener = nullptr;
|
||||||
@ -269,10 +272,10 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
{
|
{
|
||||||
type = "x11";
|
type = "x11";
|
||||||
}
|
}
|
||||||
// framebuffer -> if nothing other applies
|
// qt -> if nothing other applies
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
type = "framebuffer";
|
type = "qt";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +299,9 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
#ifdef ENABLE_X11
|
#ifdef ENABLE_X11
|
||||||
if(_x11Grabber != nullptr) _x11Grabber->stop();
|
if(_x11Grabber != nullptr) _x11Grabber->stop();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
if(_qtGrabber != nullptr) _qtGrabber->stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
// create/start capture interface
|
// create/start capture interface
|
||||||
if(type == "framebuffer")
|
if(type == "framebuffer")
|
||||||
@ -338,6 +344,19 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
_x11Grabber->start();
|
_x11Grabber->start();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else if(type == "qt")
|
||||||
|
{
|
||||||
|
if(_qtGrabber == nullptr)
|
||||||
|
createGrabberQt(grabberConfig);
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
_qtGrabber->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(_log,"Unknown platform capture type: %s", QSTRING_CSTR(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
_prevType = type;
|
_prevType = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,6 +465,24 @@ void HyperionDaemon::createGrabberX11(const QJsonObject & grabberConfig)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HyperionDaemon::createGrabberQt(const QJsonObject & grabberConfig)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
_qtGrabber = new QtWrapper(
|
||||||
|
_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom,
|
||||||
|
grabberConfig["pixelDecimation"].toInt(8),
|
||||||
|
grabberConfig["display"].toInt(0),
|
||||||
|
_grabber_frequency );
|
||||||
|
|
||||||
|
// connect to HyperionDaemon signal
|
||||||
|
connect(this, &HyperionDaemon::videoMode, _qtGrabber, &QtWrapper::setVideoMode);
|
||||||
|
connect(this, &HyperionDaemon::settingsChanged, _qtGrabber, &QtWrapper::handleSettingsUpdate);
|
||||||
|
|
||||||
|
Info(_log, "Qt grabber created");
|
||||||
|
#else
|
||||||
|
Error(_log, "The Qt grabber can not be instantiated, because it has been left out from the build");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void HyperionDaemon::createGrabberFramebuffer(const QJsonObject & grabberConfig)
|
void HyperionDaemon::createGrabberFramebuffer(const QJsonObject & grabberConfig)
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,12 @@
|
|||||||
typedef QObject X11Wrapper;
|
typedef QObject X11Wrapper;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
#include <grabber/QtWrapper.h>
|
||||||
|
#else
|
||||||
|
typedef QObject QtWrapper;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
#include <utils/Image.h>
|
#include <utils/Image.h>
|
||||||
#include <utils/VideoMode.h>
|
#include <utils/VideoMode.h>
|
||||||
@ -122,6 +128,7 @@ private:
|
|||||||
void createGrabberFramebuffer(const QJsonObject & grabberConfig);
|
void createGrabberFramebuffer(const QJsonObject & grabberConfig);
|
||||||
void createGrabberOsx(const QJsonObject & grabberConfig);
|
void createGrabberOsx(const QJsonObject & grabberConfig);
|
||||||
void createGrabberX11(const QJsonObject & grabberConfig);
|
void createGrabberX11(const QJsonObject & grabberConfig);
|
||||||
|
void createGrabberQt(const QJsonObject & grabberConfig);
|
||||||
|
|
||||||
Logger* _log;
|
Logger* _log;
|
||||||
BonjourBrowserWrapper* _bonjourBrowserWrapper;
|
BonjourBrowserWrapper* _bonjourBrowserWrapper;
|
||||||
@ -135,6 +142,7 @@ private:
|
|||||||
AmlogicWrapper* _amlGrabber;
|
AmlogicWrapper* _amlGrabber;
|
||||||
FramebufferWrapper* _fbGrabber;
|
FramebufferWrapper* _fbGrabber;
|
||||||
OsxWrapper* _osxGrabber;
|
OsxWrapper* _osxGrabber;
|
||||||
|
QtWrapper* _qtGrabber;
|
||||||
Hyperion* _hyperion;
|
Hyperion* _hyperion;
|
||||||
Stats* _stats;
|
Stats* _stats;
|
||||||
SSDPHandler* _ssdp;
|
SSDPHandler* _ssdp;
|
||||||
|
Loading…
Reference in New Issue
Block a user