mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Media Foundation/V4L2 grabber ... (#1119)
* - New Media Foundation grabber - JsonAPI available grabber fix - commented json config removed * Added libjpeg-turbo to dependencies * Fix OSX build Removed Azure Pipelines from build scripts * Remove Platform from Dashboard * Correct Grabber Namings * Grabber UI improvements, generic JSONEditor Selection Update * Active grabber fix * Stop Framebuffer grabber on failure * - Image format NV12 and I420 added - Flip mode - Scaling factor for MJPEG - VSCode (compile before run) - CI (push) dependency libjpeg-turbo added * Refactor MediaFoundation (Part 1) * Remove QDebug output * Added image flipping ability to MF Grabber * fix issue 1160 * -Reload MF Grabber only once per WebUI update - Cleanup * Improvements * - Set 'Software Frame Decimation' begin to 0 - Removed grabber specific device name from Log - Keep pixel format when switching resolution - Display 'Flip mode' correct in Log - BGR24 images always flipped * Refactor MediaFoundation (Part 2) * Refactor V4L2 grabber (part 1) (#62) * Media Foundation grabber adapted to V4L2 change * Enable Media Foundation grabber on windows * Have fps as int, fix height typo * Added video standards to JsonAPI output * Error handling in source reader improved * Fix "Frame to small" error * Discovery VideoSources and Dynamically Update Editor * Hide all element when no video grabber discovered, upate naming * Do not show unsupported grabbers * Copy Log to Clipboard * Update Grabber schema and Defaults * Update access levels and validate crop ranges * Height and width in Qt grabber corrected * Correct formatting * Untabify * Global component states across instances * Components divided on the dashboard * refactor * Fix Merge-issues * Database migration aligning with updated grabber model * Align Grabber.js with new utility functions * Allow editor-validation for enum-lists * Handle "Show Explainations scenario" correctly * Grabber - Ensure save is only possible on valid content * Dashboard update + fix GlobalSignal connection * Ensure default database is populated with current release * Correct grabber4L2 access level * Display Signal detection area in preview * Write Hyperion version into default config on compiling. * Create defaultconfig.json dynamically * WebUI changes * Correct grabber config look-ups * Refactor i18n language loading * Fix en.json * Split global capture from instance capture config * Update grabber default values * Standalone grabber: Add --debug switch * Enhance showInputOptionsForKey for multiple keys * Add grabber instance link to system grabber config * Only show signal detection area, if grabber is enabled * Always show Active element on grabber page * Remote control - Only display gabber status, if global grabber is enabled * WebUI optimization (thx to @mkcologne) Start Grabber only when global settings are enabled Fixed an issue in the WebUI preview * V4L2/MF changes * Jsoneditor, Correct translation for default values * Refactor LED-Device handling in UI and make element naming consistent * MF Discovery extended * Fix LGTM finding * Support Grabber Bri, Hue, Sat and Con in UI, plus their defaults * Concider Access level for item filtering * Concider Access level for item filtering * Revert "Concider Access level for item filtering" This reverts commit 5b0ce3c0f2de67e0c43788190cfff45614706129. * Disable fpsSoftwareDecimation for framegrabber, as not supported yet * JSON-Editor- Add updated schema for validation on dynamic elements * added V4L2 color IDs * LGTM findings fix * destroy SR callback only on exit * Grabber.js - Hide elements not supported by platform * Fixed freezing start effect * Grabber UI - Hardware controls - Show current values and allow to reset to defaults * Grabber - Discovery - Add current values to properties * Small things * Clean-up Effects and have ENDLESS consistently defined * Fix on/off/on priority during startup, by initializing _prevVisComp in line with background priority * Add missing translation mappings * DirectX Grabber reactivated/ QT Grabber size decimation fixed * typo in push-master workflow * Use PreciseTimer for Grabber to ensure stable FPS timing * Set default Screencapture rate consistently * Fix libjpeg-turbo download * Remove Zero character from file * docker-compile Add PLATFORM parameter, only copy output file after successful compile * Framebuffer, Dispmanx, OSX, AML Grabber discovery, various clean-up and consistencies across grabbers * Fix merge problem - on docker-compile Add PLATFORM parameter, only copy output file after successful compile * Fix definition * OSXFRameGrabber - Revert cast * Clean-ups nach Feedback * Disable certain libraries when building armlogic via standard stretch image as developer * Add CEC availability to ServerInfo to have it platform independent * Grabber UI - Fix problem that crop values are not populated when refining editor rage * Preserve value when updating json-editor range * LEDVisualisation - Clear image when source changes * Fix - Preserve value when updating json-editor range * LEDVisualisation - Clear image when no component is active * Allow to have password handled by Password-Manager (#1263) * Update default signal detection area to green assuming rainbow grabber * LED Visualisation - Handle empty priority update * Fix yuv420 in v4l2 grabber * V4L2-Grabber discovery - Only report grabbers with valid video input information * Grabber - Update static variables to have them working in release build * LED Visualisation - ClearImage when no priorities * LED Visualisation - Fix Logo resizing issue * LED Visualisation - Have nearly black background and negative logo Co-authored-by: LordGrey <lordgrey.emmel@gmail.com> Co-authored-by: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
This commit is contained in:
parent
b0e1510a78
commit
c135d91986
@ -1,14 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# detect CI
|
# detect CI
|
||||||
if [ "$SYSTEM_COLLECTIONID" != "" ]; then
|
if [ "$HOME" != "" ]; then
|
||||||
# Azure Pipelines
|
|
||||||
echo "Azure detected"
|
|
||||||
CI_NAME="$(echo "$AGENT_OS" | tr '[:upper:]' '[:lower:]')"
|
|
||||||
CI_BUILD_DIR="$BUILD_SOURCESDIRECTORY"
|
|
||||||
elif [ "$HOME" != "" ]; then
|
|
||||||
# GitHub Actions
|
# GitHub Actions
|
||||||
echo "Github Actions detected"
|
|
||||||
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
||||||
else
|
else
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# detect CI
|
# detect CI
|
||||||
if [ "$SYSTEM_COLLECTIONID" != "" ]; then
|
if [ "$HOME" != "" ]; then
|
||||||
# Azure Pipelines
|
|
||||||
CI_NAME="$(echo "$AGENT_OS" | tr '[:upper:]' '[:lower:]')"
|
|
||||||
CI_BUILD_DIR="$BUILD_SOURCESDIRECTORY"
|
|
||||||
elif [ "$HOME" != "" ]; then
|
|
||||||
# GitHub Actions
|
# GitHub Actions
|
||||||
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
||||||
|
15
.github/workflows/pull-request.yml
vendored
15
.github/workflows/pull-request.yml
vendored
@ -159,10 +159,21 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-chocolatey
|
key: ${{ runner.os }}-chocolatey
|
||||||
|
|
||||||
- name: Install Python, NSIS, OpenSSL
|
- name: "Remove Redistributable"
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}
|
||||||
|
MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}
|
||||||
|
|
||||||
|
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
choco install --no-progress python nsis openssl -y
|
choco install --no-progress python nsis openssl directx-sdk -y
|
||||||
|
|
||||||
|
- name: Install libjpeg-turbo
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6-vc64.exe -OutFile libjpeg-turbo.exe -UserAgent NativeHost
|
||||||
|
.\libjpeg-turbo /S
|
||||||
|
|
||||||
- name: Set up x64 build architecture environment
|
- name: Set up x64 build architecture environment
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
15
.github/workflows/push-master.yml
vendored
15
.github/workflows/push-master.yml
vendored
@ -122,10 +122,21 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-chocolatey
|
key: ${{ runner.os }}-chocolatey
|
||||||
|
|
||||||
- name: Install Python, NSIS, OpenSSL
|
- name: "Remove Redistributable"
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}
|
||||||
|
MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}
|
||||||
|
|
||||||
|
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
choco install --no-progress python nsis openssl -y
|
choco install --no-progress python nsis openssl directx-sdk -y
|
||||||
|
|
||||||
|
- name: Install libjpeg-turbo
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6-vc64.exe -OutFile libjpeg-turbo.exe -UserAgent NativeHost
|
||||||
|
.\libjpeg-turbo /S
|
||||||
|
|
||||||
- name: Set up x64 build architecture environment
|
- name: Set up x64 build architecture environment
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -27,5 +27,11 @@ libsrc/flatbufserver/hyperion_request_generated.h
|
|||||||
*.kdev*
|
*.kdev*
|
||||||
|
|
||||||
# Visual Studio 2015/2017/2019 cache/options directory
|
# Visual Studio 2015/2017/2019 cache/options directory
|
||||||
.vs/
|
# Ignore
|
||||||
|
.vs/*
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
|
# Allow
|
||||||
|
!.vs/launch.vs.json
|
||||||
|
|
||||||
|
# LedDevice 'File' output
|
||||||
|
NULL
|
||||||
|
17
.vs/launch.vs.json
Normal file
17
.vs/launch.vs.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.1",
|
||||||
|
"defaults": {},
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"project": "CMakeLists.txt",
|
||||||
|
"projectTarget": "hyperiond.exe (bin\\hyperiond.exe)",
|
||||||
|
"name": "Run hyperion with debug option and external console",
|
||||||
|
"args": [
|
||||||
|
"-d",
|
||||||
|
"-c"
|
||||||
|
],
|
||||||
|
"externalConsole": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -27,12 +27,12 @@
|
|||||||
"name": "(Windows) hyperiond",
|
"name": "(Windows) hyperiond",
|
||||||
"type": "cppvsdbg",
|
"type": "cppvsdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/hyperiond.exe",
|
"program": "${command:cmake.launchTargetDirectory}/hyperiond",
|
||||||
"args": ["-d"],
|
"args": ["-d"],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false
|
"console": "internalConsole"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,15 @@ message( STATUS "CMake Version: ${CMAKE_VERSION}" )
|
|||||||
|
|
||||||
PROJECT(hyperion)
|
PROJECT(hyperion)
|
||||||
|
|
||||||
# Parse semantic version of version file
|
# Parse semantic version of version file and write version to config
|
||||||
include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cmake)
|
include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cmake)
|
||||||
file (STRINGS "version" HYPERION_VERSION)
|
file (STRINGS "version" HYPERION_VERSION)
|
||||||
SetVersionNumber(HYPERION ${HYPERION_VERSION})
|
SetVersionNumber(HYPERION ${HYPERION_VERSION})
|
||||||
|
set(DEFAULT_JSON_CONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/config/hyperion.config.json.default)
|
||||||
|
file(READ ${DEFAULT_JSON_CONFIG_FILE} DEFAULT_JSON_CONFIG_VAR)
|
||||||
|
string(REPLACE "configVersionValue" ${HYPERION_VERSION} DEFAULT_JSON_CONFIG_VAR "${DEFAULT_JSON_CONFIG_VAR}")
|
||||||
|
string(REPLACE "previousVersionValue" ${HYPERION_VERSION} DEFAULT_JSON_CONFIG_VAR "${DEFAULT_JSON_CONFIG_VAR}")
|
||||||
|
file(WRITE ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default "${DEFAULT_JSON_CONFIG_VAR}")
|
||||||
|
|
||||||
# Instruct CMake to run moc automatically when needed.
|
# Instruct CMake to run moc automatically when needed.
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
@ -50,6 +55,7 @@ SET ( DEFAULT_USE_SYSTEM_PROTO_LIBS OFF )
|
|||||||
SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF )
|
SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF )
|
||||||
SET ( DEFAULT_TESTS OFF )
|
SET ( DEFAULT_TESTS OFF )
|
||||||
SET ( DEFAULT_EXPERIMENTAL OFF )
|
SET ( DEFAULT_EXPERIMENTAL OFF )
|
||||||
|
SET ( DEFAULT_MF OFF )
|
||||||
SET ( DEFAULT_DEPLOY_DEPENDENCIES ON )
|
SET ( DEFAULT_DEPLOY_DEPENDENCIES ON )
|
||||||
|
|
||||||
IF ( ${CMAKE_SYSTEM} MATCHES "Linux" )
|
IF ( ${CMAKE_SYSTEM} MATCHES "Linux" )
|
||||||
@ -60,7 +66,8 @@ IF ( ${CMAKE_SYSTEM} MATCHES "Linux" )
|
|||||||
SET ( DEFAULT_USB_HID ON )
|
SET ( DEFAULT_USB_HID ON )
|
||||||
SET ( DEFAULT_CEC ON )
|
SET ( DEFAULT_CEC ON )
|
||||||
ELSEIF ( WIN32 )
|
ELSEIF ( WIN32 )
|
||||||
SET ( DEFAULT_DX OFF )
|
SET ( DEFAULT_DX ON )
|
||||||
|
SET ( DEFAULT_MF ON )
|
||||||
ELSE()
|
ELSE()
|
||||||
SET ( DEFAULT_V4L2 OFF )
|
SET ( DEFAULT_V4L2 OFF )
|
||||||
SET ( DEFAULT_FB OFF )
|
SET ( DEFAULT_FB OFF )
|
||||||
@ -122,6 +129,11 @@ elseif ( "${PLATFORM}" MATCHES "rpi" )
|
|||||||
SET ( DEFAULT_WS281XPWM ON )
|
SET ( DEFAULT_WS281XPWM ON )
|
||||||
elseif ( "${PLATFORM}" STREQUAL "amlogic" )
|
elseif ( "${PLATFORM}" STREQUAL "amlogic" )
|
||||||
SET ( DEFAULT_AMLOGIC ON )
|
SET ( DEFAULT_AMLOGIC ON )
|
||||||
|
elseif ( "${PLATFORM}" STREQUAL "amlogic-dev" )
|
||||||
|
SET ( DEFAULT_AMLOGIC ON )
|
||||||
|
SET ( DEFAULT_DISPMANX OFF )
|
||||||
|
SET ( DEFAULT_QT OFF )
|
||||||
|
SET ( DEFAULT_CEC OFF )
|
||||||
elseif ( "${PLATFORM}" STREQUAL "amlogic64" )
|
elseif ( "${PLATFORM}" STREQUAL "amlogic64" )
|
||||||
SET ( DEFAULT_AMLOGIC ON )
|
SET ( DEFAULT_AMLOGIC ON )
|
||||||
elseif ( "${PLATFORM}" MATCHES "x11" )
|
elseif ( "${PLATFORM}" MATCHES "x11" )
|
||||||
@ -150,17 +162,18 @@ ADD_DEFINITIONS( ${PLATFORM_DEFINE} )
|
|||||||
option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_AMLOGIC} )
|
option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_AMLOGIC} )
|
||||||
message(STATUS "ENABLE_AMLOGIC = ${ENABLE_AMLOGIC}")
|
message(STATUS "ENABLE_AMLOGIC = ${ENABLE_AMLOGIC}")
|
||||||
|
|
||||||
option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ${DEFAULT_DISPMANX} )
|
|
||||||
message(STATUS "ENABLE_DISPMANX = ${ENABLE_DISPMANX}")
|
|
||||||
|
|
||||||
if (ENABLE_AMLOGIC)
|
if (ENABLE_AMLOGIC)
|
||||||
SET(ENABLE_FB ON)
|
SET(ENABLE_FB ON)
|
||||||
else()
|
else()
|
||||||
option(ENABLE_FB "Enable the framebuffer grabber" ${DEFAULT_FB} )
|
option(ENABLE_FB "Enable the framebuffer grabber" ${DEFAULT_FB} )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "ENABLE_FB = ${ENABLE_FB}")
|
message(STATUS "ENABLE_FB = ${ENABLE_FB}")
|
||||||
|
|
||||||
option(ENABLE_OSX "Enable the osx grabber" ${DEFAULT_OSX} )
|
option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ${DEFAULT_DISPMANX} )
|
||||||
|
message(STATUS "ENABLE_DISPMANX = ${ENABLE_DISPMANX}")
|
||||||
|
|
||||||
|
option(ENABLE_OSX "Enable the OSX grabber" ${DEFAULT_OSX} )
|
||||||
message(STATUS "ENABLE_OSX = ${ENABLE_OSX}")
|
message(STATUS "ENABLE_OSX = ${ENABLE_OSX}")
|
||||||
|
|
||||||
option(ENABLE_SPIDEV "Enable the SPIDEV device" ${DEFAULT_SPIDEV} )
|
option(ENABLE_SPIDEV "Enable the SPIDEV device" ${DEFAULT_SPIDEV} )
|
||||||
@ -172,6 +185,9 @@ message(STATUS "ENABLE_TINKERFORGE = ${ENABLE_TINKERFORGE}")
|
|||||||
option(ENABLE_V4L2 "Enable the V4L2 grabber" ${DEFAULT_V4L2})
|
option(ENABLE_V4L2 "Enable the V4L2 grabber" ${DEFAULT_V4L2})
|
||||||
message(STATUS "ENABLE_V4L2 = ${ENABLE_V4L2}")
|
message(STATUS "ENABLE_V4L2 = ${ENABLE_V4L2}")
|
||||||
|
|
||||||
|
option(ENABLE_MF "Enable the Media Foundation grabber" ${DEFAULT_MF})
|
||||||
|
message(STATUS "ENABLE_MF = ${ENABLE_MF}")
|
||||||
|
|
||||||
option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_WS281XPWM} )
|
option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_WS281XPWM} )
|
||||||
message(STATUS "ENABLE_WS281XPWM = ${ENABLE_WS281XPWM}")
|
message(STATUS "ENABLE_WS281XPWM = ${ENABLE_WS281XPWM}")
|
||||||
|
|
||||||
@ -190,7 +206,7 @@ message(STATUS "ENABLE_X11 = ${ENABLE_X11}")
|
|||||||
option(ENABLE_XCB "Enable the XCB grabber" ${DEFAULT_XCB})
|
option(ENABLE_XCB "Enable the XCB grabber" ${DEFAULT_XCB})
|
||||||
message(STATUS "ENABLE_XCB = ${ENABLE_XCB}")
|
message(STATUS "ENABLE_XCB = ${ENABLE_XCB}")
|
||||||
|
|
||||||
option(ENABLE_QT "Enable the qt grabber" ${DEFAULT_QT})
|
option(ENABLE_QT "Enable the Qt grabber" ${DEFAULT_QT})
|
||||||
message(STATUS "ENABLE_QT = ${ENABLE_QT}")
|
message(STATUS "ENABLE_QT = ${ENABLE_QT}")
|
||||||
|
|
||||||
option(ENABLE_DX "Enable the DirectX grabber" ${DEFAULT_DX})
|
option(ENABLE_DX "Enable the DirectX grabber" ${DEFAULT_DX})
|
||||||
@ -216,10 +232,7 @@ SET ( PROTOBUF_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/proto )
|
|||||||
|
|
||||||
# check all json files
|
# check all json files
|
||||||
FILE ( GLOB_RECURSE HYPERION_SCHEMAS RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc/*schema*.json )
|
FILE ( GLOB_RECURSE HYPERION_SCHEMAS RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc/*schema*.json )
|
||||||
SET( JSON_FILES
|
SET( JSON_FILES ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default ${HYPERION_SCHEMAS})
|
||||||
config/hyperion.config.json.default
|
|
||||||
${HYPERION_SCHEMAS}
|
|
||||||
)
|
|
||||||
|
|
||||||
EXECUTE_PROCESS (
|
EXECUTE_PROCESS (
|
||||||
COMMAND ${PYTHON_EXECUTABLE} test/jsonchecks/checkjson.py ${JSON_FILES}
|
COMMAND ${PYTHON_EXECUTABLE} test/jsonchecks/checkjson.py ${JSON_FILES}
|
||||||
@ -243,7 +256,7 @@ ENDIF ()
|
|||||||
# TODO on windows it can't resolve the path inside the file (Das System kann den angegebenen Pfad nicht finden: '\\schema\\schema-general.json')
|
# TODO on windows it can't resolve the path inside the file (Das System kann den angegebenen Pfad nicht finden: '\\schema\\schema-general.json')
|
||||||
IF (NOT WIN32)
|
IF (NOT WIN32)
|
||||||
EXECUTE_PROCESS (
|
EXECUTE_PROCESS (
|
||||||
COMMAND python test/jsonchecks/checkschema.py config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json
|
COMMAND python test/jsonchecks/checkschema.py ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
RESULT_VARIABLE CHECK_CONFIG_FAILED
|
RESULT_VARIABLE CHECK_CONFIG_FAILED
|
||||||
)
|
)
|
||||||
@ -399,31 +412,6 @@ find_package(libusb-1.0 REQUIRED)
|
|||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
add_definitions(${QT_DEFINITIONS})
|
add_definitions(${QT_DEFINITIONS})
|
||||||
|
|
||||||
# Add JPEG library
|
|
||||||
if (ENABLE_V4L2)
|
|
||||||
# Turbo JPEG
|
|
||||||
find_package(TurboJPEG)
|
|
||||||
if (TURBOJPEG_FOUND)
|
|
||||||
add_definitions(-DHAVE_TURBO_JPEG)
|
|
||||||
message( STATUS "Using Turbo JPEG library: ${TurboJPEG_LIBRARY}")
|
|
||||||
include_directories(${TurboJPEG_INCLUDE_DIRS})
|
|
||||||
else()
|
|
||||||
# System JPEG
|
|
||||||
find_package(JPEG)
|
|
||||||
if (JPEG_FOUND)
|
|
||||||
add_definitions(-DHAVE_JPEG)
|
|
||||||
message( STATUS "Using system JPEG library: ${JPEG_LIBRARIES}")
|
|
||||||
include_directories(${JPEG_INCLUDE_DIR})
|
|
||||||
else()
|
|
||||||
message( STATUS "JPEG library not found, MJPEG camera format won't work in V4L2 grabber.")
|
|
||||||
endif()
|
|
||||||
endif (TURBOJPEG_FOUND)
|
|
||||||
|
|
||||||
if (TURBOJPEG_FOUND OR JPEG_FOUND)
|
|
||||||
add_definitions(-DHAVE_JPEG_DECODER)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
|
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,48 +1,51 @@
|
|||||||
// Generated config file
|
// Generated config file
|
||||||
|
|
||||||
// Define to enable the dispmanx grabber
|
// Define to enable the DispmanX grabber
|
||||||
#cmakedefine ENABLE_DISPMANX
|
#cmakedefine ENABLE_DISPMANX
|
||||||
|
|
||||||
// Define to enable the v4l2 grabber
|
// Define to enable the V4L2 grabber
|
||||||
#cmakedefine ENABLE_V4L2
|
#cmakedefine ENABLE_V4L2
|
||||||
|
|
||||||
// Define to enable the framebuffer grabber
|
// Define to enable the Media Foundation grabber
|
||||||
|
#cmakedefine ENABLE_MF
|
||||||
|
|
||||||
|
// Define to enable the Framebuffer grabber
|
||||||
#cmakedefine ENABLE_FB
|
#cmakedefine ENABLE_FB
|
||||||
|
|
||||||
// Define to enable the amlogic grabber
|
// Define to enable the AMLogic grabber
|
||||||
#cmakedefine ENABLE_AMLOGIC
|
#cmakedefine ENABLE_AMLOGIC
|
||||||
|
|
||||||
// Define to enable the osx grabber
|
// Define to enable the OSX grabber
|
||||||
#cmakedefine ENABLE_OSX
|
#cmakedefine ENABLE_OSX
|
||||||
|
|
||||||
// Define to enable the x11 grabber
|
// Define to enable the X11 grabber
|
||||||
#cmakedefine ENABLE_X11
|
#cmakedefine ENABLE_X11
|
||||||
|
|
||||||
// Define to enable the xcb grabber
|
// Define to enable the XCB grabber
|
||||||
#cmakedefine ENABLE_XCB
|
#cmakedefine ENABLE_XCB
|
||||||
|
|
||||||
// Define to enable the qt grabber
|
// Define to enable the Qt grabber
|
||||||
#cmakedefine ENABLE_QT
|
#cmakedefine ENABLE_QT
|
||||||
|
|
||||||
// Define to enable the DirectX grabber
|
// Define to enable the DirectX grabber
|
||||||
#cmakedefine ENABLE_DX
|
#cmakedefine ENABLE_DX
|
||||||
|
|
||||||
// Define to enable the spi-device
|
// Define to enable the SPI-Device
|
||||||
#cmakedefine ENABLE_SPIDEV
|
#cmakedefine ENABLE_SPIDEV
|
||||||
|
|
||||||
// Define to enable the ws281x-pwm-via-dma-device using jgarff's library
|
// Define to enable the WS281x-PWM-via-DMA-device using jgarff's library
|
||||||
#cmakedefine ENABLE_WS281XPWM
|
#cmakedefine ENABLE_WS281XPWM
|
||||||
|
|
||||||
// Define to enable the tinkerforge device
|
// Define to enable the Tinkerforge device
|
||||||
#cmakedefine ENABLE_TINKERFORGE
|
#cmakedefine ENABLE_TINKERFORGE
|
||||||
|
|
||||||
// Define to enable avahi
|
// Define to enable AVAHI
|
||||||
#cmakedefine ENABLE_AVAHI
|
#cmakedefine ENABLE_AVAHI
|
||||||
|
|
||||||
// Define to enable cec
|
// Define to enable CEC
|
||||||
#cmakedefine ENABLE_CEC
|
#cmakedefine ENABLE_CEC
|
||||||
|
|
||||||
// Define to enable the usb / hid devices
|
// Define to enable the USB / HID devices
|
||||||
#cmakedefine ENABLE_USB_HID
|
#cmakedefine ENABLE_USB_HID
|
||||||
|
|
||||||
// Define to enable profiler for development purpose
|
// Define to enable profiler for development purpose
|
||||||
|
24
assets/webconfig/content/conf_instcapture.html
Normal file
24
assets/webconfig/content/conf_instcapture.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<h3 class="page-header"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_grabber_conf_token">Capturing Hardware</span></h3>
|
||||||
|
|
||||||
|
<div class="panel panel-default" style="border:0px;">
|
||||||
|
<div class="panel-heading panel-instance" style="border-radius:3px; border-bottom:0px;">
|
||||||
|
<div class="dropdown">
|
||||||
|
<a id="active_instance_dropdown" class="dropdown-toggle" data-toggle="dropdown" href="#" style="text-decoration:none;display:flex;align-items:center;">
|
||||||
|
<div id="active_instance_friendly_name"></div>
|
||||||
|
<div id="btn_hypinstanceswitch" style="white-space:nowrap;"><span class="mdi mdi-lightbulb-group mdi-24px" style="margin-right:0; margin-left:5px;"></span><span class="mdi mdi-menu-down mdi-24px"></span></div>
|
||||||
|
</a>
|
||||||
|
<ul id="hyp_inst_listing" class="dropdown-menu dropdown-alerts" style="cursor:pointer;"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="conf_cont"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/content_instcapture.js"></script>
|
@ -37,10 +37,10 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="btn_wiz_holder"></div>
|
<div id="btn_wiz_holder"></div>
|
||||||
<div id='editor_container_leddevice'></div>
|
<div id='editor_container_leddevice'></div>
|
||||||
<div class="bs-callout bs-callout-info" style="margin-top:0px"><h4 data-i18n="dashboard_infobox_label_title">Information</h4><span data-i18n="conf_leds_device_info_log"> In case your LEDs do not work, check here for errors: </span> <a onclick="SwitchToMenuItem('MenuItemLogging')" href="#" data-i18n="main_menu_logging_token"></a></div>
|
<div class="bs-callout bs-callout-info" style="margin-top:0px"><h4 data-i18n="dashboard_infobox_label_title">Information</h4><span data-i18n="conf_leds_device_info_log"> In case your LEDs do not work, check here for errors: </span> <a onclick="SwitchToMenuItem('MenuItemLogging')" data-i18n="main_menu_logging_token" style="cursor:pointer"></a></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer" style="text-align:right">
|
<div class="panel-footer" style="text-align:right">
|
||||||
<button id='btn_test_controller' class="btn btn-primary hidden" disabled data-toggle="tooltip" data-placement="top" title="Identify configured device by lighting it up">
|
<button id='btn_test_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Identify configured device by lighting it up">
|
||||||
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_identify">Identify/Test</span>
|
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_identify">Identify/Test</span>
|
||||||
</button>
|
</button>
|
||||||
<button id='btn_submit_controller' class="btn btn-primary" data-toggle="tooltip" data-placement="top" title="Save the device's connectivity configuration">
|
<button id='btn_submit_controller' class="btn btn-primary" data-toggle="tooltip" data-placement="top" title="Save the device's connectivity configuration">
|
||||||
|
@ -16,6 +16,34 @@
|
|||||||
<span id="dash_config_status">Status</span>
|
<span id="dash_config_status">Status</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
<table class="table borderless">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3">
|
||||||
|
<i class="mdi mdi-camera"></i>
|
||||||
|
<span data-i18n="main_menu_grabber_conf_token">Capturing Hardware</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td data-i18n="edt_conf_fg_heading_title">Screen-Grabber</td>
|
||||||
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_screen_grabber">disabled</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemGrabber', 'editor_container_screengrabber')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td data-i18n="edt_conf_v4l2_heading_title">Video-Grabber</td>
|
||||||
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_video_grabber">disabled</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemGrabber', 'editor_container_videograbber')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<table class="table borderless">
|
<table class="table borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -29,22 +57,34 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_port_proto">proto</td>
|
<td data-i18n="dashboard_infobox_label_port_proto">proto</td>
|
||||||
<td id="dash_pbPort" style="text-align:right">unknown</td>
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_pbPort">unknown</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemNetwork', 'editor_container_protoserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_port_flat">flat</td>
|
<td data-i18n="dashboard_infobox_label_port_flat">flat</td>
|
||||||
<td id="dash_fbPort" style="text-align:right">unknown</td>
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_fbPort">unknown</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemNetwork', 'editor_container_fbserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_port_json">json</td>
|
<td data-i18n="dashboard_infobox_label_port_json">json</td>
|
||||||
<td id="dash_jsonPort" style="text-align:right">unknown</td>
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_jsonPort">unknown</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemNetwork', 'editor_container_jsonserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_ports_websocket">websocket</td>
|
<td data-i18n="dashboard_infobox_label_ports_websocket">websocket</td>
|
||||||
<td id="dash_wsPorts" style="text-align:right">unknown</td>
|
<td style="text-align: right; padding-right: 0">
|
||||||
|
<span id="dash_wsPorts">unknown</span>
|
||||||
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemWeb')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -61,17 +101,17 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_currenthyp">Hyperion version:</td>
|
<td data-i18n="dashboard_infobox_label_currenthyp">Hyperion version:</td>
|
||||||
<td id="dash_currv" style="text-align:right">unknown</td>
|
<td id="dash_currv" style="text-align: right">unknown</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_watchedversionbranch">Watched version branch:</td>
|
<td data-i18n="dashboard_infobox_label_watchedversionbranch">Watched version branch:</td>
|
||||||
<td id="dash_watchedversionbranch" style="text-align:right">unknown</td>
|
<td id="dash_watchedversionbranch" style="text-align: right">unknown</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_latesthyp">Latest version:</td>
|
<td data-i18n="dashboard_infobox_label_latesthyp">Latest version:</td>
|
||||||
<td id="dash_latev" style="text-align:right">unknown</td>
|
<td id="dash_latev" style="text-align: right">unknown</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form>
|
<form>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<input type="hidden" name="username" class="form-control" type="text" id="username" value="hyperion"/>
|
||||||
<input name="password" class="form-control" type="password" id="password" placeholder="Password" autocomplete="off" />
|
<input name="password" class="form-control" type="password" id="password" placeholder="Password" autocomplete="off" />
|
||||||
<input name="show_pw" type="checkbox" id="show_pw" /><label for="show_pw">Show/Hide Password</label>
|
<input name="show_pw" type="checkbox" id="show_pw" /><label for="show_pw">Show/Hide Password</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,14 +24,34 @@ body{
|
|||||||
*/
|
*/
|
||||||
/* fixed brand icon */
|
/* fixed brand icon */
|
||||||
@media (min-width: 768px){
|
@media (min-width: 768px){
|
||||||
.navbar-brand{position:fixed}
|
#wrapper{
|
||||||
#main-nav{position:absolute !important;}
|
padding-left: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
.navbar-brand{
|
||||||
|
position:fixed;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
#main-nav{
|
||||||
|
position:absolute !important;
|
||||||
|
}
|
||||||
|
.navbar-top-links li a > .fa{
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*mobile nav*/
|
/*mobile nav*/
|
||||||
@media (max-width: 768px){
|
@media (max-width: 768px){
|
||||||
.navbar-toggle{position:fixed;right:0px;}
|
#wrapper{
|
||||||
#main-nav{position:fixed;right:-200px;}
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.navbar-toggle{
|
||||||
|
position:fixed;right:0px;
|
||||||
|
}
|
||||||
|
#main-nav{
|
||||||
|
position:fixed;right:-200px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navbar-toggle .icon-bar {
|
.navbar-toggle .icon-bar {
|
||||||
background-color:#4c4c4c !important;
|
background-color:#4c4c4c !important;
|
||||||
@ -72,23 +92,25 @@ table.input-group{width:100%}
|
|||||||
@media (max-width: 767px) {.ltd{white-space:normal;}}
|
@media (max-width: 767px) {.ltd{white-space:normal;}}
|
||||||
|
|
||||||
/*icon spacing*/
|
/*icon spacing*/
|
||||||
.fa-fw,.mdi-24px{margin-right:5px;}
|
.fa-fw, .mdi-24px{margin-right:5px;}
|
||||||
|
|
||||||
/*table*/
|
/*table*/
|
||||||
table.borderless td,table.borderless th{border: none !important;}
|
table.borderless td,table.borderless th{border: none !important;}
|
||||||
|
table.borderless td:first-child{width: 25px !important;}
|
||||||
.borderless {margin-bottom:0px}
|
.borderless {margin-bottom:0px}
|
||||||
table label{margin:0}
|
table label{margin:0}
|
||||||
table.first_cell_borderless td:first-child,table.first_cell_borderless th:first-child{border: none !important;}
|
table.first_cell_borderless td:first-child,table.first_cell_borderless th:first-child{border: none !important;}
|
||||||
|
table.first_cell_borderless td:first-child{width: 25px !important;}
|
||||||
|
|
||||||
/*Header*/
|
/*Header*/
|
||||||
.navbar-brand{padding-top:4px;padding-bottom:0px;padding-left:2;}
|
.navbar-brand{top:0px;left:17px;padding-top:0;}
|
||||||
.sidebar{margin-top:65px;}
|
.sidebar{margin-top:85px;}
|
||||||
.dropdown{font-size:18px;}
|
.dropdown{font-size:18px;}
|
||||||
@media (max-width: 767px) {.sidebar{margin-top:0px;padding-top:0px !important;}}
|
@media (max-width: 767px) {.sidebar{margin-top:0px;padding-top:0px !important;}}
|
||||||
.page-header{margin-top:0px;}
|
.page-header{margin-top:0px;}
|
||||||
|
|
||||||
.navbar-top-links li a {
|
.navbar-top-links li a {
|
||||||
min-height: 64px;
|
min-height: 84px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@ -216,6 +238,7 @@ table.first_cell_borderless td:first-child,table.first_cell_borderless th:first-
|
|||||||
.btn-transparent {
|
.btn-transparent {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-style: none;
|
border-style: none;
|
||||||
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*general instance management button*/
|
/*general instance management button*/
|
||||||
|
@ -274,6 +274,9 @@
|
|||||||
"edt_conf_enum_NTSC": "NTSC",
|
"edt_conf_enum_NTSC": "NTSC",
|
||||||
"edt_conf_enum_PAL": "PAL",
|
"edt_conf_enum_PAL": "PAL",
|
||||||
"edt_conf_enum_SECAM": "SECAM",
|
"edt_conf_enum_SECAM": "SECAM",
|
||||||
|
"edt_conf_enum_HORIZONTAL": "Horizontal",
|
||||||
|
"edt_conf_enum_VERTICAL": "Vertikal",
|
||||||
|
"edt_conf_enum_BOTH": "Horizontal & Vertikal",
|
||||||
"edt_conf_enum_automatic": "Automatisch",
|
"edt_conf_enum_automatic": "Automatisch",
|
||||||
"edt_conf_enum_bbclassic": "Klassisch",
|
"edt_conf_enum_bbclassic": "Klassisch",
|
||||||
"edt_conf_enum_bbdefault": "Standard",
|
"edt_conf_enum_bbdefault": "Standard",
|
||||||
@ -442,6 +445,8 @@
|
|||||||
"edt_conf_v4l2_sizeDecimation_title": "Bildverkleinerung Faktor",
|
"edt_conf_v4l2_sizeDecimation_title": "Bildverkleinerung Faktor",
|
||||||
"edt_conf_v4l2_standard_expl": "Wähle das passende Videoformat deiner Region. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
|
"edt_conf_v4l2_standard_expl": "Wähle das passende Videoformat deiner Region. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
|
||||||
"edt_conf_v4l2_standard_title": "Videoformat",
|
"edt_conf_v4l2_standard_title": "Videoformat",
|
||||||
|
"edt_conf_v4l2_flip_expl": "Hiermit kannst du das Bild in horizontaler, vertikaler oder beiden Richtung spiegeln.",
|
||||||
|
"edt_conf_v4l2_flip_title": "Spiegelung",
|
||||||
"edt_conf_webc_crtPath_expl": "Pfad zur Zertifikats-Datei (Format sollte PEM sein)",
|
"edt_conf_webc_crtPath_expl": "Pfad zur Zertifikats-Datei (Format sollte PEM sein)",
|
||||||
"edt_conf_webc_crtPath_title": "Zertifikats-Pfad",
|
"edt_conf_webc_crtPath_title": "Zertifikats-Pfad",
|
||||||
"edt_conf_webc_docroot_expl": "Lokaler Pfad zum WebUI Wurzelverzeichnis (Nur für WebUI Entwickler)",
|
"edt_conf_webc_docroot_expl": "Lokaler Pfad zum WebUI Wurzelverzeichnis (Nur für WebUI Entwickler)",
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
"InfoDialog_changePassword_title": "Change Password",
|
"InfoDialog_changePassword_title": "Change Password",
|
||||||
"InfoDialog_iswitch_text": "If you run Hyperion more than once in your local network, you could switch between the web configurations. Select the Hyperion instance below and switch!",
|
"InfoDialog_iswitch_text": "If you run Hyperion more than once in your local network, you could switch between the web configurations. Select the Hyperion instance below and switch!",
|
||||||
"InfoDialog_iswitch_title": "Hyperion switcher",
|
"InfoDialog_iswitch_title": "Hyperion switcher",
|
||||||
"InfoDialog_lang_text": "If you don't like the result of the automatic language detection you could overwrite it here.",
|
"InfoDialog_nostorage_text": "Your browser does not support localStorage. You cannot save a specific language setting (fallback to 'auto detection') and access level (fallback to 'default'). Some wizards may be hidden. You could still use the webinterface without further issues",
|
||||||
"InfoDialog_lang_title": "Language setting",
|
"InfoDialog_nostorage_title": "Cannot store settings",
|
||||||
"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_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_title": "write permission error!",
|
"InfoDialog_nowrite_title": "write permission error!",
|
||||||
|
"infoDialog_password_current_text": "Current password",
|
||||||
|
"infoDialog_password_new_text": "New password",
|
||||||
"about_3rd_party_licenses": "3rd party licenses",
|
"about_3rd_party_licenses": "3rd party licenses",
|
||||||
"about_3rd_party_licenses_error": "We had trouble collecting 3rd party licenses information from web. <br />Please follow this link to the GitHub Resource.",
|
"about_3rd_party_licenses_error": "We had trouble collecting 3rd party licenses information from web. <br />Please follow this link to the GitHub Resource.",
|
||||||
"about_build": "Build",
|
"about_build": "Build",
|
||||||
@ -42,7 +44,8 @@
|
|||||||
"conf_general_intro": "Basic settings around Hyperion and WebUI that don't fit into another category.",
|
"conf_general_intro": "Basic settings around Hyperion and WebUI that don't fit into another category.",
|
||||||
"conf_general_label_title": "General settings",
|
"conf_general_label_title": "General settings",
|
||||||
"conf_grabber_fg_intro": "Screen capture is your local system capture as input source, Hyperion is installed on.",
|
"conf_grabber_fg_intro": "Screen capture is your local system capture as input source, Hyperion is installed on.",
|
||||||
"conf_grabber_v4l_intro": "USB capture is a (capture)device connected via USB which is used to input source pictures for processing.",
|
"conf_grabber_inst_grabber_config_info": "Configure your capturing hardware devices to be used by the instance in advance",
|
||||||
|
"conf_grabber_v4l_intro": "USB capture is a (capture) device connected via USB which is used to input source pictures for processing.",
|
||||||
"conf_helptable_expl": "Explanation",
|
"conf_helptable_expl": "Explanation",
|
||||||
"conf_helptable_option": "Option",
|
"conf_helptable_option": "Option",
|
||||||
"conf_leds_config_error": "Error in LED/LED layout configuration",
|
"conf_leds_config_error": "Error in LED/LED layout configuration",
|
||||||
@ -127,10 +130,12 @@
|
|||||||
"conf_leds_optgroup_RPiGPIO": "RPi GPIO",
|
"conf_leds_optgroup_RPiGPIO": "RPi GPIO",
|
||||||
"conf_leds_optgroup_RPiPWM": "RPi PWM",
|
"conf_leds_optgroup_RPiPWM": "RPi PWM",
|
||||||
"conf_leds_optgroup_RPiSPI": "RPi SPI",
|
"conf_leds_optgroup_RPiSPI": "RPi SPI",
|
||||||
|
"conf_leds_optgroup_debug": "Debug",
|
||||||
"conf_leds_optgroup_network": "Network",
|
"conf_leds_optgroup_network": "Network",
|
||||||
"conf_leds_optgroup_other": "Other",
|
"conf_leds_optgroup_other": "Other",
|
||||||
"conf_leds_optgroup_usb": "USB/Serial",
|
"conf_leds_optgroup_usb": "USB/Serial",
|
||||||
"conf_logging_btn_autoscroll": "Auto scrolling",
|
"conf_logging_btn_autoscroll": "Auto scrolling",
|
||||||
|
"conf_logging_btn_clipboard": "Copy Log to Clipboard",
|
||||||
"conf_logging_btn_pbupload": "Upload a report for support requests",
|
"conf_logging_btn_pbupload": "Upload a report for support requests",
|
||||||
"conf_logging_contpolicy": "Report Privacy Policy",
|
"conf_logging_contpolicy": "Report Privacy Policy",
|
||||||
"conf_logging_label_intro": "Area to check log messages, you will see more or less information depending on the logging level set.",
|
"conf_logging_label_intro": "Area to check log messages, you will see more or less information depending on the logging level set.",
|
||||||
@ -274,6 +279,9 @@
|
|||||||
"edt_conf_enum_NTSC": "NTSC",
|
"edt_conf_enum_NTSC": "NTSC",
|
||||||
"edt_conf_enum_PAL": "PAL",
|
"edt_conf_enum_PAL": "PAL",
|
||||||
"edt_conf_enum_SECAM": "SECAM",
|
"edt_conf_enum_SECAM": "SECAM",
|
||||||
|
"edt_conf_enum_HORIZONTAL": "Horizontal",
|
||||||
|
"edt_conf_enum_VERTICAL": "Vertical",
|
||||||
|
"edt_conf_enum_BOTH": "Horizontal & Vertical",
|
||||||
"edt_conf_enum_automatic": "Automatic",
|
"edt_conf_enum_automatic": "Automatic",
|
||||||
"edt_conf_enum_bbclassic": "Classic",
|
"edt_conf_enum_bbclassic": "Classic",
|
||||||
"edt_conf_enum_bbdefault": "Default",
|
"edt_conf_enum_bbdefault": "Default",
|
||||||
@ -358,11 +366,20 @@
|
|||||||
"edt_conf_general_port_title": "Port",
|
"edt_conf_general_port_title": "Port",
|
||||||
"edt_conf_general_priority_expl": "The priority of this component",
|
"edt_conf_general_priority_expl": "The priority of this component",
|
||||||
"edt_conf_general_priority_title": "Priority channel",
|
"edt_conf_general_priority_title": "Priority channel",
|
||||||
"edt_conf_instC_systemEnable_expl": "Enables the screen capture for this LED hardware instance",
|
"edt_conf_grabber_discovered_expl": "Select your capture device discovered",
|
||||||
|
"edt_conf_grabber_discovered_none": "No capture device discovered",
|
||||||
|
"edt_conf_grabber_discovered_title": "Device discovered",
|
||||||
|
"edt_conf_grabber_discovered_title_info": "Select your capture device discovered",
|
||||||
|
"edt_conf_grabber_discovery_inprogress": "Discovery in progress",
|
||||||
|
"edt_conf_instC_screen_grabber_device_expl": "The screen capture device used",
|
||||||
|
"edt_conf_instC_screen_grabber_device_title": "Screen capture device",
|
||||||
|
"edt_conf_instC_systemEnable_expl": "Enables the screen capture for this led hardware instance",
|
||||||
"edt_conf_instC_systemEnable_title": "Enable screen capture",
|
"edt_conf_instC_systemEnable_title": "Enable screen capture",
|
||||||
"edt_conf_instC_v4lEnable_expl": "Enables the USB capture for this LED hardware instance",
|
"edt_conf_instC_v4lEnable_expl": "Enables the USB capture for this LED hardware instance",
|
||||||
"edt_conf_instC_v4lEnable_title": "Enable USB capture",
|
"edt_conf_instC_v4lEnable_title": "Enable USB capture",
|
||||||
"edt_conf_instCapture_heading_title": "Instance Capture",
|
"edt_conf_instC_video_grabber_device_expl": "The video capture device used",
|
||||||
|
"edt_conf_instC_video_grabber_device_title": "Video capture device",
|
||||||
|
"edt_conf_instCapture_heading_title": "Capture Devices",
|
||||||
"edt_conf_js_heading_title": "JSON Server",
|
"edt_conf_js_heading_title": "JSON Server",
|
||||||
"edt_conf_log_heading_title": "Logging",
|
"edt_conf_log_heading_title": "Logging",
|
||||||
"edt_conf_log_level_expl": "Depending on loglevel you see less or more messages in your log.",
|
"edt_conf_log_level_expl": "Depending on loglevel you see less or more messages in your log.",
|
||||||
@ -415,6 +432,8 @@
|
|||||||
"edt_conf_v4l2_cropRight_title": "Crop right",
|
"edt_conf_v4l2_cropRight_title": "Crop right",
|
||||||
"edt_conf_v4l2_cropTop_expl": "Count of pixels on the top side that are removed from the picture.",
|
"edt_conf_v4l2_cropTop_expl": "Count of pixels on the top side that are removed from the picture.",
|
||||||
"edt_conf_v4l2_cropTop_title": "Crop top",
|
"edt_conf_v4l2_cropTop_title": "Crop top",
|
||||||
|
"edt_conf_v4l2_cropWidthValidation_error": "Crop left + Crop right cannot be greater than Width ($1)",
|
||||||
|
"edt_conf_v4l2_cropHeightValidation_error": "Crop top + Crop bottom cannot be greater than Height ($1)",
|
||||||
"edt_conf_v4l2_device_expl": "The path to the USB capture interface. Set to 'Automatic' for automatic detection. Example: '/dev/video0'",
|
"edt_conf_v4l2_device_expl": "The path to the USB capture interface. Set to 'Automatic' for automatic detection. Example: '/dev/video0'",
|
||||||
"edt_conf_v4l2_device_title": "Device",
|
"edt_conf_v4l2_device_title": "Device",
|
||||||
"edt_conf_v4l2_framerate_expl": "The supported frames per second of the active device",
|
"edt_conf_v4l2_framerate_expl": "The supported frames per second of the active device",
|
||||||
@ -442,6 +461,24 @@
|
|||||||
"edt_conf_v4l2_sizeDecimation_title": "Size decimation",
|
"edt_conf_v4l2_sizeDecimation_title": "Size decimation",
|
||||||
"edt_conf_v4l2_standard_expl": "Select the video standard for your region. 'Automatic' keeps the value chosen by the v4l2 interface.",
|
"edt_conf_v4l2_standard_expl": "Select the video standard for your region. 'Automatic' keeps the value chosen by the v4l2 interface.",
|
||||||
"edt_conf_v4l2_standard_title": "Video standard",
|
"edt_conf_v4l2_standard_title": "Video standard",
|
||||||
|
"edt_conf_v4l2_flip_expl": "This allows you to flip the image horizontally, vertically, or both.",
|
||||||
|
"edt_conf_v4l2_flip_title": "Image flip",
|
||||||
|
"edt_conf_v4l2_fpsSoftwareDecimation_title": "Software frame skipping",
|
||||||
|
"edt_conf_v4l2_fpsSoftwareDecimation_expl": "To save resources every n'th frame will be processed only. For ex. if grabber is set to 30FPS with this option set to 5 the final result will be around 6FPS (1 - disabled)",
|
||||||
|
"edt_conf_v4l2_encoding_title": "Encoding format",
|
||||||
|
"edt_conf_v4l2_encoding_expl": "Force video encoding for multiformat capable grabbers",
|
||||||
|
"edt_conf_v4l2_hardware_brightness_title": "Hardware brightness control",
|
||||||
|
"edt_conf_v4l2_hardware_brightness_expl": "Set hardware brightness if device supports it, check logs (0=disabled)",
|
||||||
|
"edt_conf_v4l2_hardware_contrast_title": "Hardware contrast control",
|
||||||
|
"edt_conf_v4l2_hardware_contrast_expl": "Set hardware contrast if device supports it, check logs (0=disabled)",
|
||||||
|
"edt_conf_v4l2_hardware_hue_title": "Hardware hue control",
|
||||||
|
"edt_conf_v4l2_hardware_hue_expl": "Set hardware hue if device supports it, check logs (0=disabled)",
|
||||||
|
"edt_conf_v4l2_hardware_saturation_title": "Hardware saturation control",
|
||||||
|
"edt_conf_v4l2_hardware_saturation_expl": "Set hardware saturation if device supports it, check logs (0=disabled)",
|
||||||
|
"edt_conf_v4l2_hardware_set_defaults": "Default hardware controls",
|
||||||
|
"edt_conf_v4l2_hardware_set_defaults_tip": "Set device's default values for brightness, contrast, hue and saturation",
|
||||||
|
"edt_conf_v4l2_noSignalCounterThreshold_title": "Signal Counter Threshold",
|
||||||
|
"edt_conf_v4l2_noSignalCounterThreshold_expl": "Count of frames (check that with grabber's current FPS mode) after which the no signal is triggered",
|
||||||
"edt_conf_webc_crtPath_expl": "Path to the certification file (format should be PEM)",
|
"edt_conf_webc_crtPath_expl": "Path to the certification file (format should be PEM)",
|
||||||
"edt_conf_webc_crtPath_title": "Certificate path",
|
"edt_conf_webc_crtPath_title": "Certificate path",
|
||||||
"edt_conf_webc_docroot_expl": "Local webinterface root path (just for webui developer)",
|
"edt_conf_webc_docroot_expl": "Local webinterface root path (just for webui developer)",
|
||||||
@ -607,6 +644,7 @@
|
|||||||
"edt_eff_height": "Height",
|
"edt_eff_height": "Height",
|
||||||
"edt_eff_huechange": "Color change",
|
"edt_eff_huechange": "Color change",
|
||||||
"edt_eff_image": "Image file",
|
"edt_eff_image": "Image file",
|
||||||
|
"edt_eff_initial_blink" : "Flash for attention",
|
||||||
"edt_eff_interval": "Interval",
|
"edt_eff_interval": "Interval",
|
||||||
"edt_eff_knightrider_header": "Knight Rider",
|
"edt_eff_knightrider_header": "Knight Rider",
|
||||||
"edt_eff_knightrider_header_desc": "K.I.T.T is back! The front-scanner of the well known car, this time not just in red.",
|
"edt_eff_knightrider_header_desc": "K.I.T.T is back! The front-scanner of the well known car, this time not just in red.",
|
||||||
@ -644,6 +682,7 @@
|
|||||||
"edt_eff_reversedirection": "Reverse direction",
|
"edt_eff_reversedirection": "Reverse direction",
|
||||||
"edt_eff_rotationtime": "Rotation time",
|
"edt_eff_rotationtime": "Rotation time",
|
||||||
"edt_eff_saturation": "Saturation",
|
"edt_eff_saturation": "Saturation",
|
||||||
|
"edt_eff_set_post_color" : "Set post color after alam",
|
||||||
"edt_eff_showseconds": "Show seconds",
|
"edt_eff_showseconds": "Show seconds",
|
||||||
"edt_eff_sleeptime": "Sleep time",
|
"edt_eff_sleeptime": "Sleep time",
|
||||||
"edt_eff_smooth_custom": "Enable smoothing",
|
"edt_eff_smooth_custom": "Enable smoothing",
|
||||||
@ -748,11 +787,11 @@
|
|||||||
"general_comp_BOBLIGHTSERVER": "Boblight Server",
|
"general_comp_BOBLIGHTSERVER": "Boblight Server",
|
||||||
"general_comp_FLATBUFSERVER": "Flatbuffers Server",
|
"general_comp_FLATBUFSERVER": "Flatbuffers Server",
|
||||||
"general_comp_FORWARDER": "Forwarder",
|
"general_comp_FORWARDER": "Forwarder",
|
||||||
"general_comp_GRABBER": "Screen Capture",
|
"general_comp_GRABBER": "Capture Screen",
|
||||||
"general_comp_LEDDEVICE": "LED device",
|
"general_comp_LEDDEVICE": "LED Output",
|
||||||
"general_comp_PROTOSERVER": "Protocol Buffers Server",
|
"general_comp_PROTOSERVER": "Protocol Buffers Server",
|
||||||
"general_comp_SMOOTHING": "Smoothing",
|
"general_comp_SMOOTHING": "Smoothing",
|
||||||
"general_comp_V4L": "USB Capture",
|
"general_comp_V4L": "Capture USB-Input",
|
||||||
"general_country_cn": "China",
|
"general_country_cn": "China",
|
||||||
"general_country_de": "Germany",
|
"general_country_de": "Germany",
|
||||||
"general_country_es": "Spain",
|
"general_country_es": "Spain",
|
||||||
@ -812,6 +851,7 @@
|
|||||||
"main_ledsim_btn_togglelednumber": "LED numbers",
|
"main_ledsim_btn_togglelednumber": "LED numbers",
|
||||||
"main_ledsim_btn_toggleleds": "Show LEDs",
|
"main_ledsim_btn_toggleleds": "Show LEDs",
|
||||||
"main_ledsim_btn_togglelivevideo": "Live video",
|
"main_ledsim_btn_togglelivevideo": "Live video",
|
||||||
|
"main_ledsim_btn_togglesigdetect": "Signal detection area",
|
||||||
"main_ledsim_text": "Live visualization of LED colors and optional the current video stream of your capture device.",
|
"main_ledsim_text": "Live visualization of LED colors and optional the current video stream of your capture device.",
|
||||||
"main_ledsim_title": "LED Visualization",
|
"main_ledsim_title": "LED Visualization",
|
||||||
"main_menu_about_token": "About Hyperion",
|
"main_menu_about_token": "About Hyperion",
|
||||||
@ -823,7 +863,8 @@
|
|||||||
"main_menu_general_conf_token": "General",
|
"main_menu_general_conf_token": "General",
|
||||||
"main_menu_grabber_conf_token": "Capturing Hardware",
|
"main_menu_grabber_conf_token": "Capturing Hardware",
|
||||||
"main_menu_input_selection_token": "Input Selection",
|
"main_menu_input_selection_token": "Input Selection",
|
||||||
"main_menu_leds_conf_token": "LED Hardware",
|
"main_menu_instcapture_conf_token": "Sources",
|
||||||
|
"main_menu_leds_conf_token": "LED Output",
|
||||||
"main_menu_logging_token": "Log",
|
"main_menu_logging_token": "Log",
|
||||||
"main_menu_network_conf_token": "Network Services",
|
"main_menu_network_conf_token": "Network Services",
|
||||||
"main_menu_remotecontrol_token": "Remote Control",
|
"main_menu_remotecontrol_token": "Remote Control",
|
||||||
@ -956,6 +997,7 @@
|
|||||||
"wiz_hue_title": "Philips Hue Wizard",
|
"wiz_hue_title": "Philips Hue Wizard",
|
||||||
"wiz_hue_username": "User ID:",
|
"wiz_hue_username": "User ID:",
|
||||||
"wiz_identify": "Identify",
|
"wiz_identify": "Identify",
|
||||||
|
"wiz_identify_tip": "Identify configured device by lighting it up",
|
||||||
"wiz_identify_light": "Identify $1",
|
"wiz_identify_light": "Identify $1",
|
||||||
"wiz_ids_disabled": "Deactivated",
|
"wiz_ids_disabled": "Deactivated",
|
||||||
"wiz_ids_entire": "Whole picture",
|
"wiz_ids_entire": "Whole picture",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<script>
|
<script>
|
||||||
if (/MSIE/.test(navigator.userAgent) || /Trident/.test(navigator.userAgent))
|
if (/MSIE/.test(navigator.userAgent) || /Trident/.test(navigator.userAgent)) {
|
||||||
{
|
|
||||||
window.location.pathname = '/content/ie_not_supported.html';
|
window.location.pathname = '/content/ie_not_supported.html';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -52,6 +51,8 @@
|
|||||||
<script src="js/lib/jquery.i18n/jquery.i18n.language.js"></script>
|
<script src="js/lib/jquery.i18n/jquery.i18n.language.js"></script>
|
||||||
<script src="js/lib/jquery.i18n/CLDRPluralRuleParser.js"></script>
|
<script src="js/lib/jquery.i18n/CLDRPluralRuleParser.js"></script>
|
||||||
|
|
||||||
|
<script src="js/languages.js"></script>
|
||||||
|
|
||||||
<!-- Bootstrap Core CSS -->
|
<!-- Bootstrap Core CSS -->
|
||||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
@ -83,21 +84,24 @@
|
|||||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<div style="color:red;margin: 40px 0;text-align:center">
|
<div style="color:red;margin: 40px 0;text-align:center">
|
||||||
<img src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!">
|
<img src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!">
|
||||||
<h3>Hyperion Web Configuration requires Javascript. Please enable Javascript in your browser for this page in order to use it!</h3>
|
<h3>Hyperion Web Configuration requires Javascript. Please enable Javascript in your browser for this page in order to use it!</h3>
|
||||||
</div>
|
</div>
|
||||||
<style type="text/css"> #loading_overlay, #wrapper{ display: none } </style>
|
<style type="text/css">
|
||||||
|
#loading_overlay, #wrapper {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<div id="loading_overlay" class="overlay"></div>
|
<div id="loading_overlay" class="overlay"></div>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0; min-height: 65px">
|
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0; min-height: 85px">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle closed" aria-controls="navbar">
|
<button type="button" class="navbar-toggle closed" aria-controls="navbar">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
@ -105,7 +109,7 @@
|
|||||||
<span class="icon-bar middle-bar"></span>
|
<span class="icon-bar middle-bar"></span>
|
||||||
<span class="icon-bar bottom-bar"></span>
|
<span class="icon-bar bottom-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="https://www.hyperion-project.org" target="_blank"><img id="navbar_brand_logo" src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!" height="60"></a>
|
<a class="navbar-brand" href="https://www.hyperion-project.org" target="_blank"><img id="navbar_brand_logo" src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!" height="80"></a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- /.navbar-header -->
|
<!-- /.navbar-header -->
|
||||||
@ -166,8 +170,8 @@
|
|||||||
<li id="btn_setlang">
|
<li id="btn_setlang">
|
||||||
<a>
|
<a>
|
||||||
<div>
|
<div>
|
||||||
<i class="fa fa-globe"></i>
|
<i class="fa fa-globe fa-fw"></i>
|
||||||
<select id="language-select" class="selectpicker" data-width="fit" data-style="btn-transparent" > </select>
|
<select id="language-select" class="selectpicker" data-width="fit" data-style="btn-transparent"> </select>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -207,22 +211,23 @@
|
|||||||
<li> <a class="inactive mnava" href="#dashboard"><i class="fa fa-dashboard fa-fw"></i><span data-i18n="main_menu_dashboard_token">Dashboard</span></a> </li>
|
<li> <a class="inactive mnava" href="#dashboard"><i class="fa fa-dashboard fa-fw"></i><span data-i18n="main_menu_dashboard_token">Dashboard</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#conf_general"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_general_conf_token">General</span></a> </li>
|
<li> <a class="inactive mnava" href="#conf_general"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_general_conf_token">General</span></a> </li>
|
||||||
<li>
|
<li>
|
||||||
<a class="inactive"><i class="fa fa-cog fa-fw"></i><span data-i18n="main_menu_configuration_token">Configuration</span><span class="fa arrow"></span></a>
|
<a class="inactive"><i class="fa fa-cog fa-fw"></i><span data-i18n="main_menu_configuration_token">LED-Instances</span><span class="fa arrow"></span></a>
|
||||||
<ul class="nav nav-second-level">
|
<ul class="nav nav-second-level">
|
||||||
<li> <a class="inactive mnava" href="#conf_leds"><i class="mdi mdi-lightbulb-on fa-fw"></i><span data-i18n="main_menu_leds_conf_token">LED Hardware</span></a> </li>
|
<li> <a class="inactive mnava" id="MenuItemLeds" href="#conf_leds"><i class="mdi mdi-lightbulb-on fa-fw"></i><span data-i18n="main_menu_leds_conf_token">LED Hardware</span></a> </li>
|
||||||
|
<li> <a class="inactive mnava" id="MenuItemInstCapture" href="#conf_instcapture"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_instcapture_conf_token">Sources</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#conf_effect"><i class="fa fa-spinner fa-fw"></i><span data-i18n="main_menu_effect_conf_token">Effects</span></a> </li>
|
<li> <a class="inactive mnava" href="#conf_effect"><i class="fa fa-spinner fa-fw"></i><span data-i18n="main_menu_effect_conf_token">Effects</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#conf_colors"><i class="fa fa-photo fa-fw"></i><span data-i18n="main_menu_colors_conf_token">Image Processing</span></a> </li>
|
<li> <a class="inactive mnava" href="#conf_colors"><i class="fa fa-photo fa-fw"></i><span data-i18n="main_menu_colors_conf_token">Image Processing</span></a> </li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li> <a class="inactive mnava" href="#conf_grabber"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_grabber_conf_token">Capturing Hardware</span></a> </li>
|
<li> <a class="inactive mnava" id="MenuItemGrabber" href="#conf_grabber"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_grabber_conf_token">Capturing Hardware</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#conf_network"><i class="fa fa-sitemap fa-fw"></i><span data-i18n="main_menu_network_conf_token">Network</span></a> </li>
|
<li> <a class="inactive mnava" id="MenuItemNetwork" href="#conf_network"><i class="fa fa-sitemap fa-fw"></i><span data-i18n="main_menu_network_conf_token">Network</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#remote"><i class="fa fa-wifi fa-fw"></i><span data-i18n="main_menu_remotecontrol_token">Remote Control</span></a> </li>
|
<li> <a class="inactive mnava" href="#remote"><i class="fa fa-wifi fa-fw"></i><span data-i18n="main_menu_remotecontrol_token">Remote Control</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#effects_configurator"><i class="fa fa-cogs fa-fw"></i><span data-i18n="main_menu_effectsconfigurator_token">Effects Configurator</span></a> </li>
|
<li> <a class="inactive mnava" href="#effects_configurator"><i class="fa fa-cogs fa-fw"></i><span data-i18n="main_menu_effectsconfigurator_token">Effects Configurator</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#support"><i class="fa fa-info fa-fw"></i><span data-i18n="main_menu_support_token">Support</span></a> </li>
|
<li> <a class="inactive mnava" href="#support"><i class="fa fa-info fa-fw"></i><span data-i18n="main_menu_support_token">Support</span></a> </li>
|
||||||
<li>
|
<li>
|
||||||
<a class="inactive"><i class="fa fa-industry fa-fw"></i><span data-i18n="main_menu_system_token">System</span><span class="fa arrow"></span></a>
|
<a class="inactive"><i class="fa fa-industry fa-fw"></i><span data-i18n="main_menu_system_token">System</span><span class="fa arrow"></span></a>
|
||||||
<ul class="nav nav-second-level">
|
<ul class="nav nav-second-level">
|
||||||
<li> <a class="inactive mnava" href="#conf_webconfig" id="load_webconfig"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_webconfig_token">Webconfiguration</span></a> </li>
|
<li> <a class="inactive mnava" id="MenuItemWeb" href="#conf_webconfig" id="load_webconfig"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_webconfig_token">Webconfiguration</span></a> </li>
|
||||||
<li> <a class="inactive mnava" id="MenuItemLogging" href="#conf_logging"><i class="fa fa-reorder fa-fw"></i><span data-i18n="main_menu_logging_token">Log</span></a> </li>
|
<li> <a class="inactive mnava" id="MenuItemLogging" href="#conf_logging"><i class="fa fa-reorder fa-fw"></i><span data-i18n="main_menu_logging_token">Log</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#update"><i class="fa fa-download fa-fw"></i><span data-i18n="main_menu_update_token">Update</span></a> </li>
|
<li> <a class="inactive mnava" href="#update"><i class="fa fa-download fa-fw"></i><span data-i18n="main_menu_update_token">Update</span></a> </li>
|
||||||
<li> <a class="inactive mnava" href="#about"><i class="fa fa-info-circle fa-fw"></i><span data-i18n="main_menu_about_token">About</span></a> </li>
|
<li> <a class="inactive mnava" href="#about"><i class="fa fa-info-circle fa-fw"></i><span data-i18n="main_menu_about_token">About</span></a> </li>
|
||||||
@ -285,7 +290,7 @@
|
|||||||
<div id="wizp1">
|
<div id="wizp1">
|
||||||
<div class="modal-body" style="text-align:center">
|
<div class="modal-body" style="text-align:center">
|
||||||
<img id="wizard_logo" src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!" style="margin-bottom:15px">
|
<img id="wizard_logo" src="img/hyperion/logo_positiv.png" alt="Redefine ambient light!" style="margin-bottom:15px">
|
||||||
<div id="wizp1_body" ></div>
|
<div id="wizp1_body"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="wizp1_footer" class="modal-footer" style="text-align:center"></div>
|
<div id="wizp1_footer" class="modal-footer" style="text-align:center"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -320,6 +325,7 @@
|
|||||||
<div data-role="footer" style="text-align:center">
|
<div data-role="footer" style="text-align:center">
|
||||||
<button type="button" class="btn btn-success" id="leds_toggle"><i class="fa fa-fw fa-lightbulb-o"></i><span data-i18n="main_ledsim_btn_toggleleds">leds</span></button>
|
<button type="button" class="btn btn-success" id="leds_toggle"><i class="fa fa-fw fa-lightbulb-o"></i><span data-i18n="main_ledsim_btn_toggleleds">leds</span></button>
|
||||||
<button type="button" class="btn btn-danger" id="leds_toggle_num"> <i class="fa fa-fw fa-info"></i><span data-i18n="main_ledsim_btn_togglelednumber">led numbers</span></button>
|
<button type="button" class="btn btn-danger" id="leds_toggle_num"> <i class="fa fa-fw fa-info"></i><span data-i18n="main_ledsim_btn_togglelednumber">led numbers</span></button>
|
||||||
|
<button type="button" class="btn btn-danger" id="sigDetectArea_toggle"><i class="fa fa-fw fa-info"></i><span data-i18n="main_ledsim_btn_togglesigdetect">signal detection area</span></button>
|
||||||
<button type="button" class="btn btn-danger" id="leds_toggle_live_video"><i class="fa fa-fw fa-television"></i><span data-i18n="main_ledsim_btn_togglelivevideo">live video</span></button>
|
<button type="button" class="btn btn-danger" id="leds_toggle_live_video"><i class="fa fa-fw fa-television"></i><span data-i18n="main_ledsim_btn_togglelivevideo">live video</span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,7 +13,6 @@ $(document).ready(function () {
|
|||||||
instances_html += '</a><ul id="hyp_inst_listing" class="dropdown-menu dropdown-alerts" style="cursor:pointer;"></ul>'
|
instances_html += '</a><ul id="hyp_inst_listing" class="dropdown-menu dropdown-alerts" style="cursor:pointer;"></ul>'
|
||||||
instances_html += '</div></div>';
|
instances_html += '</div></div>';
|
||||||
|
|
||||||
|
|
||||||
instances_html += '<div class="panel-body">';
|
instances_html += '<div class="panel-body">';
|
||||||
instances_html += '<table class="table borderless">';
|
instances_html += '<table class="table borderless">';
|
||||||
instances_html += '<thead><tr><th style="vertical-align:middle"><i class="mdi mdi-lightbulb-on fa-fw"></i>';
|
instances_html += '<thead><tr><th style="vertical-align:middle"><i class="mdi mdi-lightbulb-on fa-fw"></i>';
|
||||||
@ -39,10 +38,13 @@ $(document).ready(function () {
|
|||||||
instances_html += '<i class="fa fa-info-circle fa-fw"></i>';
|
instances_html += '<i class="fa fa-info-circle fa-fw"></i>';
|
||||||
instances_html += '<span>' + $.i18n('dashboard_infobox_label_title') + '</span>';
|
instances_html += '<span>' + $.i18n('dashboard_infobox_label_title') + '</span>';
|
||||||
instances_html += '</th></tr></thead>';
|
instances_html += '</th></tr></thead>';
|
||||||
instances_html += '<tbody><tr><td></td>';
|
instances_html += '<tbody>';
|
||||||
instances_html += '<td>' + $.i18n('conf_leds_contr_label_contrtype') + '</td>';
|
instances_html += '<tr><td></td><td>' + $.i18n('conf_leds_contr_label_contrtype') + '</td>';
|
||||||
instances_html += '<td style="text-align:right">' + window.serverConfig.device.type + '</td>';
|
instances_html += '<td style="text-align:right; padding-right:0">';
|
||||||
instances_html += '</tr><tr></tbody></table>';
|
instances_html += '<span>' + window.serverConfig.device.type + '</span>';
|
||||||
|
instances_html += '<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem(\'MenuItemLeds\')" style="text-decoration:none;cursor:pointer"></a>';
|
||||||
|
instances_html += '</td></tr>';
|
||||||
|
instances_html += '</tbody></table>';
|
||||||
|
|
||||||
instances_html += '<table class="table first_cell_borderless">';
|
instances_html += '<table class="table first_cell_borderless">';
|
||||||
instances_html += '<thead><tr><th colspan="3">';
|
instances_html += '<thead><tr><th colspan="3">';
|
||||||
@ -50,12 +52,18 @@ $(document).ready(function () {
|
|||||||
instances_html += '<span>' + $.i18n('dashboard_componentbox_label_title') + '</span>';
|
instances_html += '<span>' + $.i18n('dashboard_componentbox_label_title') + '</span>';
|
||||||
instances_html += '</th></tr></thead>';
|
instances_html += '</th></tr></thead>';
|
||||||
|
|
||||||
var tab_components = "";
|
var componentBtn = "";
|
||||||
|
var instance_components = "";
|
||||||
for (var idx = 0; idx < components.length; idx++) {
|
for (var idx = 0; idx < components.length; idx++) {
|
||||||
if (components[idx].name != "ALL") {
|
if (components[idx].name != "ALL") {
|
||||||
|
if ((components[idx].name === "FORWARDER" && window.currentHyperionInstance != 0) ||
|
||||||
|
(components[idx].name === "GRABBER" && !window.serverConfig.framegrabber.enable) ||
|
||||||
|
(components[idx].name === "V4L" && !window.serverConfig.grabberV4L2.enable))
|
||||||
|
continue;
|
||||||
|
|
||||||
var comp_enabled = components[idx].enabled ? "checked" : "";
|
var comp_enabled = components[idx].enabled ? "checked" : "";
|
||||||
const general_comp = "general_comp_" + components[idx].name;
|
const general_comp = "general_comp_" + components[idx].name;
|
||||||
var componentBtn = '<input ' +
|
componentBtn = '<input ' +
|
||||||
'id="' + general_comp + '" ' + comp_enabled +
|
'id="' + general_comp + '" ' + comp_enabled +
|
||||||
' type="checkbox" ' +
|
' type="checkbox" ' +
|
||||||
'data-toggle="toggle" ' +
|
'data-toggle="toggle" ' +
|
||||||
@ -64,14 +72,15 @@ $(document).ready(function () {
|
|||||||
'data-on="' + $.i18n('general_btn_on') + '" ' +
|
'data-on="' + $.i18n('general_btn_on') + '" ' +
|
||||||
'data-off="' + $.i18n('general_btn_off') + '">';
|
'data-off="' + $.i18n('general_btn_off') + '">';
|
||||||
|
|
||||||
tab_components += '<tr><td></td><td>' + $.i18n('general_comp_' + components[idx].name) + '</td><td style="text-align:right">' + componentBtn + '</td></tr>';
|
instance_components += '<tr><td></td><td>' + $.i18n('general_comp_' + components[idx].name) + '</td><td style="text-align:right">' + componentBtn + '</td></tr>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instances_html += '<tbody>' + tab_components + '</tbody></table>';
|
instances_html += '<tbody>' + instance_components + '</tbody></table>';
|
||||||
instances_html += '</div></div></div>';
|
instances_html += '</div></div></div>';
|
||||||
|
|
||||||
$('.instances').prepend(instances_html);
|
$('.instances').prepend(instances_html);
|
||||||
|
|
||||||
updateUiOnInstance(window.currentHyperionInstance);
|
updateUiOnInstance(window.currentHyperionInstance);
|
||||||
updateHyperionInstanceListing();
|
updateHyperionInstanceListing();
|
||||||
|
|
||||||
@ -83,7 +92,7 @@ $(document).ready(function () {
|
|||||||
for (var idx = 0; idx < components.length; idx++) {
|
for (var idx = 0; idx < components.length; idx++) {
|
||||||
if (components[idx].name != "ALL") {
|
if (components[idx].name != "ALL") {
|
||||||
$("#general_comp_" + components[idx].name).bootstrapToggle();
|
$("#general_comp_" + components[idx].name).bootstrapToggle();
|
||||||
$("#general_comp_" + components[idx].name).bootstrapToggle(hyperion_enabled ? "enable" : "disable")
|
$("#general_comp_" + components[idx].name).bootstrapToggle(hyperion_enabled ? "enable" : "disable");
|
||||||
$("#general_comp_" + components[idx].name).change(e => {
|
$("#general_comp_" + components[idx].name).change(e => {
|
||||||
requestSetComponentState(e.currentTarget.id.split('_')[2], e.currentTarget.checked);
|
requestSetComponentState(e.currentTarget.id.split('_')[2], e.currentTarget.checked);
|
||||||
});
|
});
|
||||||
@ -92,6 +101,12 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add more info
|
// add more info
|
||||||
|
|
||||||
|
var screenGrabber = window.serverConfig.framegrabber.enable ? $.i18n('general_enabled') : $.i18n('general_disabled');
|
||||||
|
$('#dash_screen_grabber').html(screenGrabber);
|
||||||
|
var videoGrabber = window.serverConfig.grabberV4L2.enable ? $.i18n('general_enabled') : $.i18n('general_disabled');
|
||||||
|
$('#dash_video_grabber').html(videoGrabber);
|
||||||
|
|
||||||
var fbPort = window.serverConfig.flatbufServer.enable ? window.serverConfig.flatbufServer.port : $.i18n('general_disabled');
|
var fbPort = window.serverConfig.flatbufServer.enable ? window.serverConfig.flatbufServer.port : $.i18n('general_disabled');
|
||||||
$('#dash_fbPort').html(fbPort);
|
$('#dash_fbPort').html(fbPort);
|
||||||
var pbPort = window.serverConfig.protoServer.enable ? window.serverConfig.protoServer.port : $.i18n('general_disabled');
|
var pbPort = window.serverConfig.protoServer.enable ? window.serverConfig.protoServer.port : $.i18n('general_disabled');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
$(document).ready( function() {
|
$(document).ready(function () {
|
||||||
performTranslation();
|
performTranslation();
|
||||||
|
|
||||||
var importedConf;
|
var importedConf;
|
||||||
@ -6,8 +6,7 @@ $(document).ready( function() {
|
|||||||
var conf_editor = null;
|
var conf_editor = null;
|
||||||
|
|
||||||
$('#conf_cont').append(createOptPanel('fa-wrench', $.i18n("edt_conf_gen_heading_title"), 'editor_container', 'btn_submit', 'panel-system'));
|
$('#conf_cont').append(createOptPanel('fa-wrench', $.i18n("edt_conf_gen_heading_title"), 'editor_container', 'btn_submit', 'panel-system'));
|
||||||
if(window.showOptHelp)
|
if (window.showOptHelp) {
|
||||||
{
|
|
||||||
$('#conf_cont').append(createHelpTable(window.schema.general.properties, $.i18n("edt_conf_gen_heading_title")));
|
$('#conf_cont').append(createHelpTable(window.schema.general.properties, $.i18n("edt_conf_gen_heading_title")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -17,19 +16,19 @@ $(document).ready( function() {
|
|||||||
general: window.schema.general
|
general: window.schema.general
|
||||||
}, true, true);
|
}, true, true);
|
||||||
|
|
||||||
conf_editor.on('change',function() {
|
conf_editor.on('change', function () {
|
||||||
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#btn_submit').off().on('click',function() {
|
$('#btn_submit').off().on('click', function () {
|
||||||
|
window.showOptHelp = conf_editor.getEditor("root.general.showOptHelp").getValue();
|
||||||
requestWriteConfig(conf_editor.getValue());
|
requestWriteConfig(conf_editor.getValue());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Instance handling
|
// Instance handling
|
||||||
function handleInstanceRename(e)
|
function handleInstanceRename(e) {
|
||||||
{
|
|
||||||
|
|
||||||
conf_editor.on('change',function() {
|
conf_editor.on('change', function () {
|
||||||
window.readOnlyMode ? $('#btn_cl_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
window.readOnlyMode ? $('#btn_cl_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
window.readOnlyMode ? $('#btn_ma_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
window.readOnlyMode ? $('#btn_ma_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
});
|
});
|
||||||
@ -37,52 +36,48 @@ $(document).ready( function() {
|
|||||||
var inst = e.currentTarget.id.split("_")[1];
|
var inst = e.currentTarget.id.split("_")[1];
|
||||||
showInfoDialog('renInst', $.i18n('conf_general_inst_renreq_t'), getInstanceNameByIndex(inst));
|
showInfoDialog('renInst', $.i18n('conf_general_inst_renreq_t'), getInstanceNameByIndex(inst));
|
||||||
|
|
||||||
$("#id_btn_ok").off().on('click', function(){
|
$("#id_btn_ok").off().on('click', function () {
|
||||||
requestInstanceRename(inst, $('#renInst_name').val())
|
requestInstanceRename(inst, $('#renInst_name').val())
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#renInst_name').off().on('input',function(e) {
|
$('#renInst_name').off().on('input', function (e) {
|
||||||
(e.currentTarget.value.length >= 5 && e.currentTarget.value != getInstanceNameByIndex(inst)) ? $('#id_btn_ok').attr('disabled', false) : $('#id_btn_ok').attr('disabled', true);
|
(e.currentTarget.value.length >= 5 && e.currentTarget.value != getInstanceNameByIndex(inst)) ? $('#id_btn_ok').attr('disabled', false) : $('#id_btn_ok').attr('disabled', true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInstanceDelete(e)
|
function handleInstanceDelete(e) {
|
||||||
{
|
|
||||||
var inst = e.currentTarget.id.split("_")[1];
|
var inst = e.currentTarget.id.split("_")[1];
|
||||||
showInfoDialog('delInst',$.i18n('conf_general_inst_delreq_h'),$.i18n('conf_general_inst_delreq_t',getInstanceNameByIndex(inst)));
|
showInfoDialog('delInst', $.i18n('conf_general_inst_delreq_h'), $.i18n('conf_general_inst_delreq_t', getInstanceNameByIndex(inst)));
|
||||||
$("#id_btn_yes").off().on('click', function(){
|
$("#id_btn_yes").off().on('click', function () {
|
||||||
requestInstanceDelete(inst)
|
requestInstanceDelete(inst)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildInstanceList()
|
function buildInstanceList() {
|
||||||
{
|
|
||||||
var inst = serverInfo.instance
|
var inst = serverInfo.instance
|
||||||
$('.itbody').html("");
|
$('.itbody').html("");
|
||||||
for(var key in inst)
|
for (var key in inst) {
|
||||||
{
|
|
||||||
var enable_style = inst[key].running ? "checked" : "";
|
var enable_style = inst[key].running ? "checked" : "";
|
||||||
var renameBtn = '<button id="instren_'+inst[key].instance+'" type="button" class="btn btn-primary"><i class="mdi mdi-lead-pencil""></i></button>';
|
var renameBtn = '<button id="instren_' + inst[key].instance + '" type="button" class="btn btn-primary"><i class="mdi mdi-lead-pencil""></i></button>';
|
||||||
var startBtn = ""
|
var startBtn = ""
|
||||||
var delBtn = "";
|
var delBtn = "";
|
||||||
if(inst[key].instance > 0)
|
if (inst[key].instance > 0) {
|
||||||
{
|
delBtn = '<button id="instdel_' + inst[key].instance + '" type="button" class="btn btn-danger"><i class="mdi mdi-delete-forever""></i></button>';
|
||||||
delBtn = '<button id="instdel_'+inst[key].instance+'" type="button" class="btn btn-danger"><i class="mdi mdi-delete-forever""></i></button>';
|
startBtn = '<input id="inst_' + inst[key].instance + '"' + enable_style + ' type="checkbox" data-toggle="toggle" data-onstyle="success font-weight-bold" data-on="' + $.i18n('general_btn_on') + '" data-offstyle="default font-weight-bold" data-off="' + $.i18n('general_btn_off') + '">';
|
||||||
startBtn = '<input id="inst_'+inst[key].instance+'"'+enable_style+' type="checkbox" data-toggle="toggle" data-onstyle="success font-weight-bold" data-on="'+$.i18n('general_btn_on')+'" data-offstyle="default font-weight-bold" data-off="'+$.i18n('general_btn_off')+'">';
|
|
||||||
|
|
||||||
}
|
}
|
||||||
$('.itbody').append(createTableRow([inst[key].friendly_name, startBtn, renameBtn, delBtn], false, true));
|
$('.itbody').append(createTableRow([inst[key].friendly_name, startBtn, renameBtn, delBtn], false, true));
|
||||||
$('#instren_'+inst[key].instance).off().on('click', handleInstanceRename);
|
$('#instren_' + inst[key].instance).off().on('click', handleInstanceRename);
|
||||||
|
|
||||||
$('#inst_'+inst[key].instance).bootstrapToggle();
|
$('#inst_' + inst[key].instance).bootstrapToggle();
|
||||||
$('#inst_'+inst[key].instance).change(e => {
|
$('#inst_' + inst[key].instance).change(e => {
|
||||||
requestInstanceStartStop(e.currentTarget.id.split('_').pop(), e.currentTarget.checked);
|
requestInstanceStartStop(e.currentTarget.id.split('_').pop(), e.currentTarget.checked);
|
||||||
});
|
});
|
||||||
$('#instdel_'+inst[key].instance).off().on('click', handleInstanceDelete);
|
$('#instdel_' + inst[key].instance).off().on('click', handleInstanceDelete);
|
||||||
|
|
||||||
window.readOnlyMode ? $('#instren_'+inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
window.readOnlyMode ? $('#instren_' + inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
window.readOnlyMode ? $('#inst_'+inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
window.readOnlyMode ? $('#inst_' + inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
window.readOnlyMode ? $('#instdel_'+inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
window.readOnlyMode ? $('#instdel_' + inst[key].instance).attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,59 +85,51 @@ $(document).ready( function() {
|
|||||||
$('.ithead').html(createTableRow([$.i18n('conf_general_inst_namehead'), "", $.i18n('conf_general_inst_actionhead'), ""], true, true));
|
$('.ithead').html(createTableRow([$.i18n('conf_general_inst_namehead'), "", $.i18n('conf_general_inst_actionhead'), ""], true, true));
|
||||||
buildInstanceList();
|
buildInstanceList();
|
||||||
|
|
||||||
$('#inst_name').off().on('input',function(e) {
|
$('#inst_name').off().on('input', function (e) {
|
||||||
(e.currentTarget.value.length >= 5) && !window.readOnlyMode ? $('#btn_create_inst').attr('disabled', false) : $('#btn_create_inst').attr('disabled', true);
|
(e.currentTarget.value.length >= 5) && !window.readOnlyMode ? $('#btn_create_inst').attr('disabled', false) : $('#btn_create_inst').attr('disabled', true);
|
||||||
if(5-e.currentTarget.value.length >= 1 && 5-e.currentTarget.value.length <= 4)
|
if (5 - e.currentTarget.value.length >= 1 && 5 - e.currentTarget.value.length <= 4)
|
||||||
$('#inst_chars_needed').html(5-e.currentTarget.value.length + " " + $.i18n('general_chars_needed'))
|
$('#inst_chars_needed').html(5 - e.currentTarget.value.length + " " + $.i18n('general_chars_needed'))
|
||||||
else
|
else
|
||||||
$('#inst_chars_needed').html("<br />")
|
$('#inst_chars_needed').html("<br />")
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#btn_create_inst').off().on('click',function(e) {
|
$('#btn_create_inst').off().on('click', function (e) {
|
||||||
requestInstanceCreate($('#inst_name').val());
|
requestInstanceCreate($('#inst_name').val());
|
||||||
$('#inst_name').val("");
|
$('#inst_name').val("");
|
||||||
$('#btn_create_inst').attr('disabled', true)
|
$('#btn_create_inst').attr('disabled', true)
|
||||||
});
|
});
|
||||||
|
|
||||||
$(hyperion).off("instance-updated").on("instance-updated", function(event) {
|
$(hyperion).off("instance-updated").on("instance-updated", function (event) {
|
||||||
buildInstanceList()
|
buildInstanceList()
|
||||||
});
|
});
|
||||||
|
|
||||||
//import
|
//import
|
||||||
function dis_imp_btn(state)
|
function dis_imp_btn(state) {
|
||||||
{
|
|
||||||
state || window.readOnlyMode ? $('#btn_import_conf').attr('disabled', true) : $('#btn_import_conf').attr('disabled', false);
|
state || window.readOnlyMode ? $('#btn_import_conf').attr('disabled', true) : $('#btn_import_conf').attr('disabled', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFile(evt)
|
function readFile(evt) {
|
||||||
{
|
|
||||||
var f = evt.target.files[0];
|
var f = evt.target.files[0];
|
||||||
|
|
||||||
if (f)
|
if (f) {
|
||||||
{
|
|
||||||
var r = new FileReader();
|
var r = new FileReader();
|
||||||
r.onload = function(e)
|
r.onload = function (e) {
|
||||||
{
|
|
||||||
var content = e.target.result.replace(/[^:]?\/\/.*/g, ''); //remove Comments
|
var content = e.target.result.replace(/[^:]?\/\/.*/g, ''); //remove Comments
|
||||||
|
|
||||||
//check file is json
|
//check file is json
|
||||||
var check = isJsonString(content);
|
var check = isJsonString(content);
|
||||||
if(check.length != 0)
|
if (check.length != 0) {
|
||||||
{
|
|
||||||
showInfoDialog('error', "", $.i18n('infoDialog_import_jsonerror_text', f.name, JSON.stringify(check)));
|
showInfoDialog('error', "", $.i18n('infoDialog_import_jsonerror_text', f.name, JSON.stringify(check)));
|
||||||
dis_imp_btn(true);
|
dis_imp_btn(true);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
content = JSON.parse(content);
|
content = JSON.parse(content);
|
||||||
//check for hyperion json
|
//check for hyperion json
|
||||||
if(typeof content.leds === 'undefined' || typeof content.general === 'undefined')
|
if (typeof content.leds === 'undefined' || typeof content.general === 'undefined') {
|
||||||
{
|
|
||||||
showInfoDialog('error', "", $.i18n('infoDialog_import_hyperror_text', f.name));
|
showInfoDialog('error', "", $.i18n('infoDialog_import_hyperror_text', f.name));
|
||||||
dis_imp_btn(true);
|
dis_imp_btn(true);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
dis_imp_btn(false);
|
dis_imp_btn(false);
|
||||||
importedConf = content;
|
importedConf = content;
|
||||||
confName = f.name;
|
confName = f.name;
|
||||||
@ -153,16 +140,16 @@ $(document).ready( function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#btn_import_conf').off().on('click', function(){
|
$('#btn_import_conf').off().on('click', function () {
|
||||||
showInfoDialog('import', $.i18n('infoDialog_import_confirm_title'), $.i18n('infoDialog_import_confirm_text', confName));
|
showInfoDialog('import', $.i18n('infoDialog_import_confirm_title'), $.i18n('infoDialog_import_confirm_text', confName));
|
||||||
|
|
||||||
$('#id_btn_import').off().on('click', function(){
|
$('#id_btn_import').off().on('click', function () {
|
||||||
requestWriteConfig(importedConf, true);
|
requestWriteConfig(importedConf, true);
|
||||||
setTimeout(initRestart, 100);
|
setTimeout(initRestart, 100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#select_import_conf').off().on('change', function(e){
|
$('#select_import_conf').off().on('change', function (e) {
|
||||||
if (window.File && window.FileReader && window.FileList && window.Blob)
|
if (window.File && window.FileReader && window.FileList && window.Blob)
|
||||||
readFile(e);
|
readFile(e);
|
||||||
else
|
else
|
||||||
@ -170,23 +157,22 @@ $(document).ready( function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//export
|
//export
|
||||||
$('#btn_export_conf').off().on('click', function(){
|
$('#btn_export_conf').off().on('click', function () {
|
||||||
var name = window.serverConfig.general.name;
|
var name = window.serverConfig.general.name;
|
||||||
|
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
var month = d.getMonth()+1;
|
var month = d.getMonth() + 1;
|
||||||
var day = d.getDate();
|
var day = d.getDate();
|
||||||
|
|
||||||
var timestamp = d.getFullYear() + '.' +
|
var timestamp = d.getFullYear() + '.' +
|
||||||
(month<10 ? '0' : '') + month + '.' +
|
(month < 10 ? '0' : '') + month + '.' +
|
||||||
(day<10 ? '0' : '') + day;
|
(day < 10 ? '0' : '') + day;
|
||||||
|
|
||||||
download(JSON.stringify(window.serverConfig, null, "\t"), 'Hyperion-'+window.currentVersion+'-Backup ('+name+') '+timestamp+'.json', "application/json");
|
download(JSON.stringify(window.serverConfig, null, "\t"), 'Hyperion-' + window.currentVersion + '-Backup (' + name + ') ' + timestamp + '.json', "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
//create introduction
|
//create introduction
|
||||||
if(window.showOptHelp)
|
if (window.showOptHelp) {
|
||||||
{
|
|
||||||
createHint("intro", $.i18n('conf_general_intro'), "editor_container");
|
createHint("intro", $.i18n('conf_general_intro'), "editor_container");
|
||||||
createHint("intro", $.i18n('conf_general_tok_desc'), "tok_desc_cont");
|
createHint("intro", $.i18n('conf_general_tok_desc'), "tok_desc_cont");
|
||||||
createHint("intro", $.i18n('conf_general_inst_desc'), "inst_desc_cont");
|
createHint("intro", $.i18n('conf_general_inst_desc'), "inst_desc_cont");
|
||||||
|
1085
assets/webconfig/js/content_grabber.js
Normal file → Executable file
1085
assets/webconfig/js/content_grabber.js
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -307,12 +307,17 @@ $(document).ready(function () {
|
|||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).scroll(function(){
|
$(window).scroll(function() {
|
||||||
if ($(window).scrollTop() > 65)
|
if ($(window).scrollTop() > 65)
|
||||||
$("#navbar_brand_logo").css("display", "none");
|
$("#navbar_brand_logo").css("display", "none");
|
||||||
else
|
else
|
||||||
$("#navbar_brand_logo").css("display", "");
|
$("#navbar_brand_logo").css("display", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#side-menu li a, #side-menu li ul li a').click(function() {
|
||||||
|
$('#side-menu').find('.active').toggleClass('inactive'); // find all active classes and set inactive;
|
||||||
|
$(this).addClass('active');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function suppressDefaultPwWarning() {
|
function suppressDefaultPwWarning() {
|
||||||
@ -349,7 +354,7 @@ $("#btn_darkmode").off().on("click", function (e) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Menuitem toggle;
|
// Menuitem toggle;
|
||||||
function SwitchToMenuItem(target) {
|
function SwitchToMenuItem(target, item) {
|
||||||
document.getElementById(target).click(); // Get <a href menu item;
|
document.getElementById(target).click(); // Get <a href menu item;
|
||||||
let sidebar = $('#side-menu'); // Get sidebar menu;
|
let sidebar = $('#side-menu'); // Get sidebar menu;
|
||||||
sidebar.find('.active').toggleClass('inactive'); // find all active classes and set inactive;
|
sidebar.find('.active').toggleClass('inactive'); // find all active classes and set inactive;
|
||||||
@ -357,6 +362,21 @@ function SwitchToMenuItem(target) {
|
|||||||
$('#' + target).removeClass('inactive'); // Remove inactive state by classname;
|
$('#' + target).removeClass('inactive'); // Remove inactive state by classname;
|
||||||
$('#' + target).addClass('active'); // Add active state by classname;
|
$('#' + target).addClass('active'); // Add active state by classname;
|
||||||
let cl_object = $('#' + target).closest('ul'); // Find closest ul sidemenu header;
|
let cl_object = $('#' + target).closest('ul'); // Find closest ul sidemenu header;
|
||||||
cl_object.addClass('in'); // add class "in" to expand header in sidebar menu;
|
cl_object.addClass('in'); // Add class "in" to expand header in sidebar menu;
|
||||||
|
if (item) { // Jump to div "item" if available. Time limit 3 seconds
|
||||||
|
function scrollTo(counter) {
|
||||||
|
if(counter < 30) {
|
||||||
|
setTimeout(function() {
|
||||||
|
counter++;
|
||||||
|
if ($('#' + item).length)
|
||||||
|
$('#' + item)[0].scrollIntoView();
|
||||||
|
else
|
||||||
|
scrollTo(counter);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollTo(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
99
assets/webconfig/js/content_instcapture.js
Normal file
99
assets/webconfig/js/content_instcapture.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
performTranslation();
|
||||||
|
|
||||||
|
// update instance listing
|
||||||
|
updateHyperionInstanceListing();
|
||||||
|
|
||||||
|
var conf_editor_instCapt = null;
|
||||||
|
|
||||||
|
// Instance Capture
|
||||||
|
$('#conf_cont').append(createRow('conf_cont_instCapt'));
|
||||||
|
$('#conf_cont_instCapt').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt', ''));
|
||||||
|
if (window.showOptHelp) {
|
||||||
|
$('#conf_cont_instCapt').append(createHelpTable(window.schema.instCapture.properties, $.i18n("edt_conf_instCapture_heading_title")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance Capture
|
||||||
|
conf_editor_instCapt = createJsonEditor('editor_container_instCapt', {
|
||||||
|
instCapture: window.schema.instCapture
|
||||||
|
}, true, true);
|
||||||
|
|
||||||
|
var grabber_config_info_html = '<div class="bs-callout bs-callout-info" style="margin-top:0px"><h4>' + $.i18n('dashboard_infobox_label_title') + '</h4 >';
|
||||||
|
grabber_config_info_html += '<span>' + $.i18n('conf_grabber_inst_grabber_config_info') + '</span>';
|
||||||
|
grabber_config_info_html += '<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem(\'MenuItemGrabber\')" style="text-decoration:none;cursor:pointer"></a>';
|
||||||
|
grabber_config_info_html += '</div>';
|
||||||
|
$('#editor_container_instCapt').append(grabber_config_info_html);
|
||||||
|
|
||||||
|
conf_editor_instCapt.on('ready', function () {
|
||||||
|
|
||||||
|
if (!window.serverConfig.framegrabber.enable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(false);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").disable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(window.serverConfig.instCapture.systemEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.serverConfig.grabberV4L2.enable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(false);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(window.serverConfig.instCapture.v4lEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_instCapt.on('change', function () {
|
||||||
|
|
||||||
|
if (!conf_editor_instCapt.validate().length) {
|
||||||
|
if (!window.serverConfig.framegrabber.enable && !window.serverConfig.grabberV4L2.enable) {
|
||||||
|
$('#btn_submit_instCapt').attr('disabled', true);
|
||||||
|
} else {
|
||||||
|
window.readOnlyMode ? $('#btn_submit_instCapt').attr('disabled', true) : $('#btn_submit_instCapt').attr('disabled', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#btn_submit_instCapt').attr('disabled', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_instCapt.watch('root.instCapture.systemEnable', () => {
|
||||||
|
|
||||||
|
var screenEnable = conf_editor_instCapt.getEditor("root.instCapture.systemEnable").getValue();
|
||||||
|
if (screenEnable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").setValue(window.serverConfig.framegrabber.available_devices);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").disable();
|
||||||
|
showInputOptions("instCapture", ["systemGrabberDevice"], true);
|
||||||
|
showInputOptions("instCapture", ["systemPriority"], true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
showInputOptions("instCapture", ["systemGrabberDevice"], false);
|
||||||
|
showInputOptions("instCapture", ["systemPriority"], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_instCapt.watch('root.instCapture.v4lEnable', () => {
|
||||||
|
var videoEnable = conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").getValue();
|
||||||
|
if (videoEnable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lGrabberDevice").setValue(window.serverConfig.grabberV4L2.available_devices);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lGrabberDevice").disable();
|
||||||
|
showInputOptions("instCapture", ["v4lGrabberDevice"], true);
|
||||||
|
showInputOptions("instCapture", ["v4lPriority"], true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!window.serverConfig.grabberV4L2.enable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
||||||
|
}
|
||||||
|
showInputOptions("instCapture", ["v4lGrabberDevice"], false);
|
||||||
|
showInputOptions("instCapture", ["v4lPriority"], false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#btn_submit_instCapt').off().on('click', function () {
|
||||||
|
requestWriteConfig(conf_editor_instCapt.getValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
removeOverlay();
|
||||||
|
});
|
@ -701,6 +701,8 @@ $(document).ready(function () {
|
|||||||
var hwLedCountDefault = 1;
|
var hwLedCountDefault = 1;
|
||||||
var colorOrderDefault = "rgb";
|
var colorOrderDefault = "rgb";
|
||||||
|
|
||||||
|
$('#btn_test_controller').hide();
|
||||||
|
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
case "cololight":
|
case "cololight":
|
||||||
case "wled":
|
case "wled":
|
||||||
@ -769,11 +771,38 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
conf_editor.on('change', function () {
|
conf_editor.on('change', function () {
|
||||||
//Check, if device can be identified/tested and/or saved
|
// //Check, if device can be identified/tested and/or saved
|
||||||
var canIdentify = false;
|
var canIdentify = false;
|
||||||
var canSave = false;
|
var canSave = false;
|
||||||
|
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
|
|
||||||
|
case "atmoorb":
|
||||||
|
case "fadecandy":
|
||||||
|
case "tinkerforge":
|
||||||
|
case "tpm2net":
|
||||||
|
case "udpe131":
|
||||||
|
case "udpartnet":
|
||||||
|
case "udph801":
|
||||||
|
case "udpraw":
|
||||||
|
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
||||||
|
if (host !== "") {
|
||||||
|
canSave = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "philipshue":
|
||||||
|
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
||||||
|
var username = conf_editor.getEditor("root.specificOptions.username").getValue();
|
||||||
|
if (host !== "" && username != "") {
|
||||||
|
var useEntertainmentAPI = conf_editor.getEditor("root.specificOptions.useEntertainmentAPI").getValue();
|
||||||
|
var clientkey = conf_editor.getEditor("root.specificOptions.clientkey").getValue();
|
||||||
|
if (!useEntertainmentAPI || clientkey !== "") {
|
||||||
|
canSave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case "cololight":
|
case "cololight":
|
||||||
case "wled":
|
case "wled":
|
||||||
var hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
|
var hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
|
||||||
@ -797,48 +826,20 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "adalight":
|
|
||||||
var output = conf_editor.getEditor("root.specificOptions.output").getValue();
|
|
||||||
if (output !== "NONE" && output !== "SELECT" && output !== "") {
|
|
||||||
canIdentify = true;
|
|
||||||
}
|
|
||||||
case "atmo":
|
|
||||||
case "dmx":
|
|
||||||
case "karate":
|
|
||||||
case "sedu":
|
|
||||||
case "tpm2":
|
|
||||||
case "apa102":
|
|
||||||
case "apa104":
|
|
||||||
case "ws2801":
|
|
||||||
case "lpd6803":
|
|
||||||
case "lpd8806":
|
|
||||||
case "p9813":
|
|
||||||
case "sk6812spi":
|
|
||||||
case "sk6822spi":
|
|
||||||
case "sk9822":
|
|
||||||
case "ws2812spi":
|
|
||||||
case "piblaster":
|
|
||||||
var output = conf_editor.getEditor("root.specificOptions.output").getValue();
|
|
||||||
if (output !== "NONE" && output !== "SELECT" && output !== "") {
|
|
||||||
canSave = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
canIdentify = false;
|
canIdentify = false;
|
||||||
canSave = true;
|
canSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!conf_editor.validate().length) {
|
||||||
if (canIdentify) {
|
if (canIdentify) {
|
||||||
$("#btn_test_controller").removeClass('hidden');
|
$("#btn_test_controller").show();
|
||||||
$('#btn_test_controller').attr('disabled', false);
|
$('#btn_test_controller').attr('disabled', false);
|
||||||
}
|
} else {
|
||||||
else {
|
$('#btn_test_controller').hide();
|
||||||
$('#btn_test_controller').attr('disabled', true);
|
$('#btn_test_controller').attr('disabled', true);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
var hardwareLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
|
|
||||||
if (hardwareLedCount < 1) {
|
|
||||||
canSave = false;
|
canSave = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -886,9 +887,9 @@ $(document).ready(function () {
|
|||||||
conf_editor.getEditor(specOptPath + "host").setValue(val);
|
conf_editor.getEditor(specOptPath + "host").setValue(val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
showAllDeviceInputOptions("hostList", showOptions);
|
showAllDeviceInputOptions("hostList", showOptions);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
conf_editor.watch('root.specificOptions.host', () => {
|
conf_editor.watch('root.specificOptions.host', () => {
|
||||||
@ -900,8 +901,10 @@ $(document).ready(function () {
|
|||||||
else {
|
else {
|
||||||
let params = {};
|
let params = {};
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
|
|
||||||
case "cololight":
|
case "cololight":
|
||||||
params = { host: host };
|
params = { host: host };
|
||||||
|
getProperties_device(ledType, host, params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "nanoleaf":
|
case "nanoleaf":
|
||||||
@ -910,33 +913,70 @@ $(document).ready(function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
params = { host: host, token: token };
|
params = { host: host, token: token };
|
||||||
|
getProperties_device(ledType, host, params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "wled":
|
case "wled":
|
||||||
params = { host: host, filter: "info" };
|
params = { host: host, filter: "info" };
|
||||||
|
getProperties_device(ledType, host, params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
getProperties_device(ledType, host, params);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
conf_editor.watch('root.specificOptions.output', () => {
|
conf_editor.watch('root.specificOptions.output', () => {
|
||||||
var output = conf_editor.getEditor("root.specificOptions.output").getValue();
|
var output = conf_editor.getEditor("root.specificOptions.output").getValue();
|
||||||
if (output === "NONE" || output === "SELECT" || output === "") {
|
if (output === "NONE" || output === "SELECT" || output === "") {
|
||||||
|
|
||||||
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
|
$('#btn_test_controller').attr('disabled', true);
|
||||||
|
$('#btn_test_controller').hide();
|
||||||
|
|
||||||
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(1);
|
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(1);
|
||||||
showAllDeviceInputOptions("output", false);
|
showAllDeviceInputOptions("output", false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showAllDeviceInputOptions("output", true);
|
showAllDeviceInputOptions("output", true);
|
||||||
let params = {};
|
let params = {};
|
||||||
|
var canIdentify = false;
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
|
case "adalight":
|
||||||
|
canIdentify = true;
|
||||||
|
break;
|
||||||
case "atmo":
|
case "atmo":
|
||||||
case "karate":
|
case "karate":
|
||||||
params = { serialPort: output };
|
params = { serialPort: output };
|
||||||
getProperties_device(ledType, output, params);
|
getProperties_device(ledType, output, params);
|
||||||
break;
|
break;
|
||||||
|
case "dmx":
|
||||||
|
case "sedu":
|
||||||
|
case "tpm2":
|
||||||
|
case "apa102":
|
||||||
|
case "apa104":
|
||||||
|
case "ws2801":
|
||||||
|
case "lpd6803":
|
||||||
|
case "lpd8806":
|
||||||
|
case "p9813":
|
||||||
|
case "sk6812spi":
|
||||||
|
case "sk6822spi":
|
||||||
|
case "sk9822":
|
||||||
|
case "ws2812spi":
|
||||||
|
case "piblaster":
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conf_editor.validate().length) {
|
||||||
|
if (canIdentify) {
|
||||||
|
$("#btn_test_controller").show();
|
||||||
|
$('#btn_test_controller').attr('disabled', false);
|
||||||
|
} else {
|
||||||
|
$('#btn_test_controller').hide();
|
||||||
|
$('#btn_test_controller').attr('disabled', true);
|
||||||
|
}
|
||||||
|
if (!window.readOnlyMode) {
|
||||||
|
$('#btn_submit_controller').attr('disabled', false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1229,6 +1269,8 @@ function saveLedConfig(genDefLayout = false) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Rewrite whole LED & Layout configuration, in case changes were done accross tabs and no default layout
|
//Rewrite whole LED & Layout configuration, in case changes were done accross tabs and no default layout
|
||||||
if (genDefLayout !== true) {
|
if (genDefLayout !== true) {
|
||||||
result.ledConfig = getLedConfig();
|
result.ledConfig = getLedConfig();
|
||||||
@ -1269,8 +1311,6 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
|||||||
ledTypeGroup = "devRPiGPIO";
|
ledTypeGroup = "devRPiGPIO";
|
||||||
}
|
}
|
||||||
|
|
||||||
var specOpt = conf_editor.getEditor('root.specificOptions'); // get specificOptions of the editor
|
|
||||||
|
|
||||||
switch (ledTypeGroup) {
|
switch (ledTypeGroup) {
|
||||||
case "devNET":
|
case "devNET":
|
||||||
key = "hostList";
|
key = "hostList";
|
||||||
@ -1434,11 +1474,14 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enumVals.length > 0) {
|
if (enumVals.length > 0) {
|
||||||
updateJsonEditorSelection(specOpt, key, addSchemaElements, enumVals, enumTitelVals, enumDefaultVal, addSelect, addCustom);
|
updateJsonEditorSelection(conf_editor, 'root.specificOptions', key, addSchemaElements, enumVals, enumTitelVals, enumDefaultVal, addSelect, addCustom);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function discover_device(ledType, params) {
|
async function discover_device(ledType, params) {
|
||||||
|
|
||||||
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
|
|
||||||
const result = await requestLedDeviceDiscovery(ledType, params);
|
const result = await requestLedDeviceDiscovery(ledType, params);
|
||||||
|
|
||||||
var discoveryResult;
|
var discoveryResult;
|
||||||
@ -1479,6 +1522,7 @@ async function getProperties_device(ledType, key, params) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#btn_submit_controller').attr('disabled', true);
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
|
$('#btn_test_controller').attr('disabled', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1544,8 +1588,7 @@ function updateElements(ledType, key) {
|
|||||||
if (ledProperties && ledProperties.ledCount) {
|
if (ledProperties && ledProperties.ledCount) {
|
||||||
if (ledProperties.ledCount.length > 0) {
|
if (ledProperties.ledCount.length > 0) {
|
||||||
var configuredLedCount = window.serverConfig.device.hardwareLedCount;
|
var configuredLedCount = window.serverConfig.device.hardwareLedCount;
|
||||||
var generalOpt = conf_editor.getEditor('root.generalOptions');
|
updateJsonEditorSelection(conf_editor, 'root.generalOptions', "hardwareLedCount", {}, ledProperties.ledCount, [], configuredLedCount);
|
||||||
updateJsonEditorSelection(generalOpt, "hardwareLedCount", {}, ledProperties.ledCount, [], configuredLedCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -25,7 +25,7 @@ $(document).ready(function () {
|
|||||||
$('#btn_submit').off().on('click', function () {
|
$('#btn_submit').off().on('click', function () {
|
||||||
|
|
||||||
var displayedLogLevel = conf_editor.getEditor("root.logger.level").getValue();
|
var displayedLogLevel = conf_editor.getEditor("root.logger.level").getValue();
|
||||||
var newLogLevel = {logger:{}};
|
var newLogLevel = { logger: {} };
|
||||||
newLogLevel.logger.level = displayedLogLevel;
|
newLogLevel.logger.level = displayedLogLevel;
|
||||||
|
|
||||||
requestWriteConfig(newLogLevel);
|
requestWriteConfig(newLogLevel);
|
||||||
@ -103,7 +103,7 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#log_footer').append('<button class="btn btn-primary pull-right" id="btn_clipboard"><i class="fa fa-fw fa-clipboard"></i>Copy Log to Clipboard</button>');
|
$('#log_footer').append('<button class="btn btn-primary pull-right" id="btn_clipboard"><i class="fa fa-fw fa-clipboard"></i>' + $.i18n("conf_logging_btn_clipboard") + '</button>');
|
||||||
|
|
||||||
$('#btn_clipboard').off().on('click', function () {
|
$('#btn_clipboard').off().on('click', function () {
|
||||||
const temp = document.createElement('textarea');
|
const temp = document.createElement('textarea');
|
||||||
|
@ -7,7 +7,7 @@ $(document).ready(function () {
|
|||||||
var oldEffects = [];
|
var oldEffects = [];
|
||||||
var cpcolor = '#B500FF';
|
var cpcolor = '#B500FF';
|
||||||
var mappingList = window.serverSchema.properties.color.properties.imageToLedMappingType.enum;
|
var mappingList = window.serverSchema.properties.color.properties.imageToLedMappingType.enum;
|
||||||
var duration = 0;
|
var duration = ENDLESS;
|
||||||
var rgb = { r: 255, g: 0, b: 0 };
|
var rgb = { r: 255, g: 0, b: 0 };
|
||||||
var lastImgData = "";
|
var lastImgData = "";
|
||||||
var lastFileName = "";
|
var lastFileName = "";
|
||||||
@ -201,7 +201,9 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const comp of components) {
|
for (const comp of components) {
|
||||||
if (comp.name === "ALL")
|
if (comp.name === "ALL" || (comp.name === "FORWARDER" && window.currentHyperionInstance != 0) ||
|
||||||
|
(comp.name === "GRABBER" && !window.serverConfig.framegrabber.enable) ||
|
||||||
|
(comp.name === "V4L" && !window.serverConfig.grabberV4L2.enable))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const enable_style = (comp.enabled ? "checked" : "");
|
const enable_style = (comp.enabled ? "checked" : "");
|
||||||
|
@ -33,6 +33,8 @@ window.comps = [];
|
|||||||
window.defaultPasswordIsSet = null;
|
window.defaultPasswordIsSet = null;
|
||||||
tokenList = {};
|
tokenList = {};
|
||||||
|
|
||||||
|
const ENDLESS = -1;
|
||||||
|
|
||||||
function initRestart()
|
function initRestart()
|
||||||
{
|
{
|
||||||
$(window.hyperion).off();
|
$(window.hyperion).off();
|
||||||
@ -470,8 +472,14 @@ async function requestLedDeviceProperties(type, params)
|
|||||||
|
|
||||||
function requestLedDeviceIdentification(type, params)
|
function requestLedDeviceIdentification(type, params)
|
||||||
{
|
{
|
||||||
//sendToHyperion("leddevice", "identify", '"ledDeviceType": "'+type+'","params": '+JSON.stringify(params)+'');
|
|
||||||
let data = { ledDeviceType: type, params: params };
|
let data = { ledDeviceType: type, params: params };
|
||||||
|
|
||||||
return sendAsyncToHyperion("leddevice", "identify", data, Math.floor(Math.random() * 1000));
|
return sendAsyncToHyperion("leddevice", "identify", data, Math.floor(Math.random() * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function requestInputSourcesDiscovery(type, params) {
|
||||||
|
let data = { sourceType: type, params: params };
|
||||||
|
|
||||||
|
return sendAsyncToHyperion("inputsource", "discover", data, Math.floor(Math.random() * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
33
assets/webconfig/js/languages.js
Normal file
33
assets/webconfig/js/languages.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
var storedLang;
|
||||||
|
var availLang = ['cs', 'de', 'en', 'es', 'fr', 'it', 'nl', 'nb', 'pl', 'pt', 'ro', 'sv', 'vi', 'ru', 'tr', 'zh-CN'];
|
||||||
|
var availLangText = ['Čeština', 'Deutsch', 'English', 'Español', 'Français', 'Italiano', 'Nederlands', 'Norsk Bokmål', 'Polski', 'Português', 'Română', 'Svenska', 'Tiếng Việt', 'русский', 'Türkçe', '汉语'];
|
||||||
|
|
||||||
|
//$.i18n.debug = true;
|
||||||
|
|
||||||
|
//i18n
|
||||||
|
function initTrans(lc) {
|
||||||
|
$.i18n().load("i18n", lc).done(
|
||||||
|
function () {
|
||||||
|
$.i18n().locale = lc;
|
||||||
|
performTranslation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
storedLang = getStorage("langcode");
|
||||||
|
if (storedLang == null || storedLang === "undefined") {
|
||||||
|
|
||||||
|
var langLocale = $.i18n().locale.substring(0, 2);
|
||||||
|
//Test, if language is supported by hyperion
|
||||||
|
var langIdx = availLang.indexOf(langLocale);
|
||||||
|
if (langIdx === -1) {
|
||||||
|
// If language is not supported by hyperion, try fallback language
|
||||||
|
langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
|
||||||
|
langIdx = availLang.indexOf(langLocale);
|
||||||
|
if (langIdx === -1) {
|
||||||
|
langLocale = 'en';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storedLang = langLocale;
|
||||||
|
setStorage("langcode", storedLang);
|
||||||
|
}
|
||||||
|
initTrans(storedLang);
|
@ -1,28 +1,35 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function () {
|
||||||
var modalOpened = false;
|
var modalOpened = false;
|
||||||
var ledsim_width = 540;
|
var ledsim_width = 540;
|
||||||
var ledsim_height = 489;
|
var ledsim_height = 489;
|
||||||
var dialog;
|
var dialog;
|
||||||
var leds;
|
var leds;
|
||||||
|
var grabberConfig;
|
||||||
var lC = false;
|
var lC = false;
|
||||||
var imageCanvasNodeCtx;
|
var imageCanvasNodeCtx;
|
||||||
var ledsCanvasNodeCtx;
|
var ledsCanvasNodeCtx;
|
||||||
var canvas_height;
|
var canvas_height;
|
||||||
var canvas_width;
|
var canvas_width;
|
||||||
var twoDPaths = [];
|
var twoDPaths = [];
|
||||||
var toggleLeds, toggleLedsNum = false;
|
var toggleLeds = false;
|
||||||
|
var toggleLedsNum = false;
|
||||||
|
var toggleSigDetectArea = false;
|
||||||
|
|
||||||
|
var activeComponent = "";
|
||||||
|
|
||||||
|
const image = new Image()
|
||||||
|
image.src = "img/hyperion/logo_negativ.png",
|
||||||
|
|
||||||
/// add prototype for simple canvas clear() method
|
/// add prototype for simple canvas clear() method
|
||||||
CanvasRenderingContext2D.prototype.clear = function(){
|
CanvasRenderingContext2D.prototype.clear = function () {
|
||||||
this.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
this.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||||
};
|
};
|
||||||
|
|
||||||
function create2dPaths(){
|
function create2dPaths() {
|
||||||
twoDPaths = [];
|
twoDPaths = [];
|
||||||
for(var idx=0; idx<leds.length; idx++)
|
for (var idx = 0; idx < leds.length; idx++) {
|
||||||
{
|
|
||||||
var led = leds[idx];
|
var led = leds[idx];
|
||||||
twoDPaths.push( build2DPath(led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height, 5) );
|
twoDPaths.push(build2DPath(led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax - led.hmin) * canvas_width, (led.vmax - led.vmin) * canvas_height, 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,9 +51,9 @@ $(document).ready(function() {
|
|||||||
*/
|
*/
|
||||||
function build2DPath(x, y, width, height, radius) {
|
function build2DPath(x, y, width, height, radius) {
|
||||||
if (typeof radius == 'number') {
|
if (typeof radius == 'number') {
|
||||||
radius = {tl: radius, tr: radius, br: radius, bl: radius};
|
radius = { tl: radius, tr: radius, br: radius, bl: radius };
|
||||||
} else {
|
} else {
|
||||||
var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};
|
var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
|
||||||
for (var side in defaultRadius) {
|
for (var side in defaultRadius) {
|
||||||
radius[side] = radius[side] || defaultRadius[side];
|
radius[side] = radius[side] || defaultRadius[side];
|
||||||
}
|
}
|
||||||
@ -67,18 +74,17 @@ $(document).ready(function() {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(window.hyperion).one("ready",function(){
|
$(window.hyperion).one("ready", function () {
|
||||||
leds = window.serverConfig.leds;
|
leds = window.serverConfig.leds;
|
||||||
|
grabberConfig = window.serverConfig.grabberV4L2;
|
||||||
|
|
||||||
if(window.showOptHelp)
|
if (window.showOptHelp) {
|
||||||
{
|
|
||||||
createHint('intro', $.i18n('main_ledsim_text'), 'ledsim_text');
|
createHint('intro', $.i18n('main_ledsim_text'), 'ledsim_text');
|
||||||
$('#ledsim_text').css({'margin':'10px 15px 0px 15px'});
|
$('#ledsim_text').css({ 'margin': '10px 15px 0px 15px' });
|
||||||
$('#ledsim_text .bs-callout').css("margin","0px")
|
$('#ledsim_text .bs-callout').css("margin", "0px")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getStorage('ledsim_width') != null)
|
if (getStorage('ledsim_width') != null) {
|
||||||
{
|
|
||||||
ledsim_width = getStorage('ledsim_width');
|
ledsim_width = getStorage('ledsim_width');
|
||||||
ledsim_height = getStorage('ledsim_height');
|
ledsim_height = getStorage('ledsim_height');
|
||||||
}
|
}
|
||||||
@ -98,8 +104,7 @@ $(document).ready(function() {
|
|||||||
updateLedLayout();
|
updateLedLayout();
|
||||||
},
|
},
|
||||||
opened: function (e) {
|
opened: function (e) {
|
||||||
if(!lC)
|
if (!lC) {
|
||||||
{
|
|
||||||
updateLedLayout();
|
updateLedLayout();
|
||||||
lC = true;
|
lC = true;
|
||||||
}
|
}
|
||||||
@ -107,11 +112,12 @@ $(document).ready(function() {
|
|||||||
requestLedColorsStart();
|
requestLedColorsStart();
|
||||||
|
|
||||||
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-danger", "btn-success");
|
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-danger", "btn-success");
|
||||||
if($('#leds_toggle_live_video').hasClass('btn-success'))
|
if ($('#leds_toggle_live_video').hasClass('btn-success'))
|
||||||
requestLedImageStart();
|
requestLedImageStart();
|
||||||
},
|
},
|
||||||
closed: function (e) {
|
closed: function (e) {
|
||||||
modalOpened = false;
|
modalOpened = false;
|
||||||
|
lC = false;
|
||||||
},
|
},
|
||||||
resizeStop: function (e) {
|
resizeStop: function (e) {
|
||||||
setStorage("ledsim_width", $("#ledsim_dialog").outerWidth());
|
setStorage("ledsim_width", $("#ledsim_dialog").outerWidth());
|
||||||
@ -119,48 +125,58 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// apply new serverinfos
|
// apply new serverinfos
|
||||||
$(window.hyperion).on("cmd-config-getconfig",function(event){
|
$(window.hyperion).on("cmd-config-getconfig", function (event) {
|
||||||
leds = event.response.info.leds;
|
leds = event.response.info.leds;
|
||||||
|
grabberConfig = event.response.info.grabberV4L2;
|
||||||
updateLedLayout();
|
updateLedLayout();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function printLedsToCanvas(colors)
|
function printLedsToCanvas(colors) {
|
||||||
{
|
|
||||||
|
if (grabberConfig.enable && grabberConfig.signalDetection && toggleSigDetectArea && storedAccess === 'expert') {
|
||||||
|
|
||||||
|
sigDetectAreaCanvasNodeCtx.setLineDash([5, 5]);
|
||||||
|
sigDetectAreaCanvasNodeCtx.stroke(build2DPath(grabberConfig.sDHOffsetMin * canvas_width,
|
||||||
|
grabberConfig.sDVOffsetMin * canvas_height,
|
||||||
|
(grabberConfig.sDHOffsetMax - grabberConfig.sDHOffsetMin) * canvas_width,
|
||||||
|
(grabberConfig.sDVOffsetMax - grabberConfig.sDVOffsetMin) * canvas_height,
|
||||||
|
5));
|
||||||
|
}
|
||||||
|
|
||||||
// toggle leds, do not print
|
// toggle leds, do not print
|
||||||
if(toggleLeds)
|
if (toggleLeds)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var useColor = false;
|
var useColor = false;
|
||||||
var cPos = 0;
|
var cPos = 0;
|
||||||
ledsCanvasNodeCtx.clear();
|
ledsCanvasNodeCtx.clear();
|
||||||
if(typeof colors != "undefined")
|
if (typeof colors != "undefined")
|
||||||
useColor = true;
|
useColor = true;
|
||||||
|
|
||||||
// check size of ledcolors with leds length
|
// check size of ledcolors with leds length
|
||||||
if(colors && colors.length/3 < leds.length)
|
if (colors && colors.length / 3 < leds.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(var idx=0; idx<leds.length; idx++)
|
for (var idx = 0; idx < leds.length; idx++) {
|
||||||
{
|
|
||||||
var led = leds[idx];
|
var led = leds[idx];
|
||||||
// can be used as fallback when Path2D is not available
|
// can be used as fallback when Path2D is not available
|
||||||
//roundRect(ledsCanvasNodeCtx, led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height, 4, true, colors[idx])
|
//roundRect(ledsCanvasNodeCtx, led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height, 4, true, colors[idx])
|
||||||
//ledsCanvasNodeCtx.fillRect(led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height);
|
//ledsCanvasNodeCtx.fillRect(led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height);
|
||||||
|
|
||||||
ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba("+colors[cPos]+","+colors[cPos+1]+","+colors[cPos+2]+",0.75)" : "hsla("+(idx*360/leds.length)+",100%,50%,0.75)";
|
ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba(" + colors[cPos] + "," + colors[cPos + 1] + "," + colors[cPos + 2] + ",0.75)" : "hsla(" + (idx * 360 / leds.length) + ",100%,50%,0.75)";
|
||||||
ledsCanvasNodeCtx.fill(twoDPaths[idx]);
|
ledsCanvasNodeCtx.fill(twoDPaths[idx]);
|
||||||
|
ledsCanvasNodeCtx.strokeStyle = '#323232';
|
||||||
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
|
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
|
||||||
|
|
||||||
if(toggleLedsNum)
|
if (toggleLedsNum) {
|
||||||
{
|
|
||||||
//ledsCanvasNodeCtx.shadowOffsetX = 1;
|
//ledsCanvasNodeCtx.shadowOffsetX = 1;
|
||||||
//ledsCanvasNodeCtx.shadowOffsetY = 1;
|
//ledsCanvasNodeCtx.shadowOffsetY = 1;
|
||||||
//ledsCanvasNodeCtx.shadowColor = "black";
|
//ledsCanvasNodeCtx.shadowColor = "black";
|
||||||
//ledsCanvasNodeCtx.shadowBlur = 4;
|
//ledsCanvasNodeCtx.shadowBlur = 4;
|
||||||
ledsCanvasNodeCtx.fillStyle = "white";
|
ledsCanvasNodeCtx.fillStyle = "white";
|
||||||
ledsCanvasNodeCtx.textAlign = "center";
|
ledsCanvasNodeCtx.textAlign = "center";
|
||||||
ledsCanvasNodeCtx.fillText(((led.name) ? led.name : idx), (led.hmin * canvas_width) + ( ((led.hmax-led.hmin) * canvas_width) / 2), (led.vmin * canvas_height) + ( ((led.vmax-led.vmin) * canvas_height) / 2));
|
ledsCanvasNodeCtx.fillText(((led.name) ? led.name : idx), (led.hmin * canvas_width) + (((led.hmax - led.hmin) * canvas_width) / 2), (led.vmin * canvas_height) + (((led.vmax - led.vmin) * canvas_height) / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// increment colorsPosition
|
// increment colorsPosition
|
||||||
@ -168,112 +184,146 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLedLayout()
|
function updateLedLayout() {
|
||||||
{
|
if (grabberConfig.enable && grabberConfig.signalDetection && storedAccess === 'expert') {
|
||||||
|
$("#sigDetectArea_toggle").show();
|
||||||
|
} else {
|
||||||
|
$("#sigDetectArea_toggle").hide();
|
||||||
|
}
|
||||||
|
|
||||||
//calculate body size
|
//calculate body size
|
||||||
canvas_height = $('#ledsim_dialog').outerHeight()-$('#ledsim_text').outerHeight()-$('[data-role=footer]').outerHeight()-$('[data-role=header]').outerHeight()-40;
|
canvas_height = $('#ledsim_dialog').outerHeight() - $('#ledsim_text').outerHeight() - $('[data-role=footer]').outerHeight() - $('[data-role=header]').outerHeight() - 40;
|
||||||
canvas_width = $('#ledsim_dialog').outerWidth()-30;
|
canvas_width = $('#ledsim_dialog').outerWidth() - 30;
|
||||||
|
|
||||||
$('#leds_canvas').html("");
|
$('#leds_canvas').html("");
|
||||||
var leds_html = '<canvas id="image_preview_canv" width="'+canvas_width+'" height="'+canvas_height+'" style="position: absolute; left: 0; top: 0; z-index: 99998;"></canvas>';
|
var leds_html = '<canvas id="image_preview_canv" width="' + canvas_width + '" height="' + canvas_height + '" style="position: absolute; left: 0; top: 0; z-index: 99998;"></canvas>';
|
||||||
leds_html += '<canvas id="leds_preview_canv" width="'+canvas_width+'" height="'+canvas_height+'" style="position: absolute; left: 0; top: 0; z-index: 99999;"></canvas>';
|
leds_html += '<canvas id="leds_preview_canv" width="' + canvas_width + '" height="' + canvas_height + '" style="position: absolute; left: 0; top: 0; z-index: 99999;"></canvas>';
|
||||||
|
leds_html += '<canvas id="grab_preview_canv" width="' + canvas_width + '" height="' + canvas_height + '" style="position: absolute; left: 0; top: 0; z-index: 99999;"></canvas>';
|
||||||
|
|
||||||
$('#leds_canvas').html(leds_html);
|
$('#leds_canvas').html(leds_html);
|
||||||
|
|
||||||
imageCanvasNodeCtx = document.getElementById("image_preview_canv").getContext("2d");
|
imageCanvasNodeCtx = document.getElementById("image_preview_canv").getContext("2d");
|
||||||
ledsCanvasNodeCtx = document.getElementById("leds_preview_canv").getContext("2d");
|
ledsCanvasNodeCtx = document.getElementById("leds_preview_canv").getContext("2d");
|
||||||
|
sigDetectAreaCanvasNodeCtx = document.getElementById("grab_preview_canv").getContext("2d");
|
||||||
create2dPaths();
|
create2dPaths();
|
||||||
printLedsToCanvas();
|
printLedsToCanvas();
|
||||||
resetImage();
|
resetImage();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
$('#leds_toggle_num').off().on("click", function() {
|
$('#leds_toggle_num').off().on("click", function () {
|
||||||
toggleLedsNum = !toggleLedsNum
|
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 () {
|
||||||
toggleLeds = !toggleLeds
|
toggleLeds = !toggleLeds
|
||||||
ledsCanvasNodeCtx.clear();
|
ledsCanvasNodeCtx.clear();
|
||||||
toggleClass('#leds_toggle', "btn-success", "btn-danger");
|
toggleClass('#leds_toggle', "btn-success", "btn-danger");
|
||||||
|
|
||||||
|
if (!toggleLeds) {
|
||||||
|
$("#leds_toggle_num").show();
|
||||||
|
} else {
|
||||||
|
$("#leds_toggle_num").hide();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
$('#leds_toggle_live_video').off().on("click", function() {
|
$('#leds_toggle_live_video').off().on("click", function () {
|
||||||
setClassByBool('#leds_toggle_live_video',window.imageStreamActive,"btn-success","btn-danger");
|
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-success", "btn-danger");
|
||||||
if ( window.imageStreamActive )
|
if (window.imageStreamActive) {
|
||||||
{
|
|
||||||
requestLedImageStop();
|
requestLedImageStop();
|
||||||
resetImage();
|
resetImage();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
requestLedImageStart();
|
requestLedImageStart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#sigDetectArea_toggle').off().on("click", function () {
|
||||||
|
toggleSigDetectArea = !toggleSigDetectArea
|
||||||
|
sigDetectAreaCanvasNodeCtx.clear();
|
||||||
|
toggleClass('#sigDetectArea_toggle', "btn-success", "btn-danger");
|
||||||
|
});
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
$(window.hyperion).on("cmd-ledcolors-ledstream-update",function(event){
|
$(window.hyperion).on("cmd-ledcolors-ledstream-update", function (event) {
|
||||||
if (!modalOpened)
|
if (!modalOpened) {
|
||||||
{
|
|
||||||
requestLedColorsStop();
|
requestLedColorsStop();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
printLedsToCanvas(event.response.result.leds)
|
printLedsToCanvas(event.response.result.leds)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
$(window.hyperion).on("cmd-ledcolors-imagestream-update",function(event){
|
$(window.hyperion).on("cmd-ledcolors-imagestream-update", function (event) {
|
||||||
|
//console.log("cmd-ledcolors-imagestream-update", event.response);
|
||||||
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-danger", "btn-success");
|
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-danger", "btn-success");
|
||||||
if (!modalOpened)
|
if (!modalOpened) {
|
||||||
{
|
|
||||||
if ($('#leds_prev_toggle_live_video').length > 0)
|
if ($('#leds_prev_toggle_live_video').length > 0)
|
||||||
return;
|
return;
|
||||||
requestLedImageStop();
|
requestLedImageStop();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
var imageData = (event.response.result.image);
|
var imageData = (event.response.result.image);
|
||||||
|
|
||||||
var image = new Image();
|
var image = new Image();
|
||||||
image.onload = function() {
|
image.onload = function () {
|
||||||
imageCanvasNodeCtx.drawImage(image, 0, 0, canvas_width, canvas_height);
|
imageCanvasNodeCtx.drawImage(image, 0, 0, canvas_width, canvas_height);
|
||||||
};
|
};
|
||||||
image.src = imageData;
|
image.src = imageData;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_open_ledsim").off().on("click", function(event) {
|
$("#btn_open_ledsim").off().on("click", function (event) {
|
||||||
dialog.open();
|
dialog.open();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
$(window.hyperion).on("cmd-settings-update",function(event){
|
$(window.hyperion).on("cmd-settings-update", function (event) {
|
||||||
|
|
||||||
var obj = event.response.data
|
var obj = event.response.data
|
||||||
if ( obj.leds) {
|
if (obj.leds || obj.grabberV4L2) {
|
||||||
console.log("ledsim: cmd-settings-update", event.response.data);
|
//console.log("ledsim: cmd-settings-update", event.response.data);
|
||||||
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
|
Object.getOwnPropertyNames(obj).forEach(function (val, idx, array) {
|
||||||
window.serverInfo[val] = obj[val];
|
window.serverInfo[val] = obj[val];
|
||||||
});
|
});
|
||||||
leds = window.serverConfig.leds
|
leds = window.serverConfig.leds;
|
||||||
|
grabberConfig = window.serverConfig.grabberV4L2;
|
||||||
updateLedLayout();
|
updateLedLayout();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function resetImage(){
|
$(window.hyperion).on("cmd-priorities-update", function (event) {
|
||||||
if (getStorage("darkMode", false) == "on") {
|
//console.log("cmd-priorities-update", event.response.data);
|
||||||
imageCanvasNodeCtx.clear();
|
|
||||||
} else {
|
var prios = event.response.data.priorities;
|
||||||
imageCanvasNodeCtx.fillStyle = "rgb(225,225,225)"
|
if (prios.length > 0)
|
||||||
imageCanvasNodeCtx.fillRect(0, 0, canvas_width, canvas_height);
|
{
|
||||||
|
//Clear image when new input
|
||||||
|
if (prios[0].componentId !== activeComponent) {
|
||||||
|
resetImage();
|
||||||
|
activeComponent = prios[0].componentId;
|
||||||
|
}
|
||||||
|
else if (!prios[0].active) {
|
||||||
|
resetImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resetImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
var image = document.getElementById('navbar_brand_logo');
|
});
|
||||||
|
|
||||||
|
function resetImage() {
|
||||||
|
if (typeof imageCanvasNodeCtx !== "undefined") {
|
||||||
|
|
||||||
|
imageCanvasNodeCtx.fillStyle = "#1c1c1c"; //90% gray
|
||||||
|
imageCanvasNodeCtx.fillRect(0, 0, canvas_width, canvas_height);
|
||||||
imageCanvasNodeCtx.drawImage(image, canvas_width / 2 - image.width / 2, canvas_height / 2 - image.height / 2, image.width, image.height);
|
imageCanvasNodeCtx.drawImage(image, canvas_width / 2 - image.width / 2, canvas_height / 2 - image.height / 2, image.width, image.height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -1839,7 +1839,14 @@ JSONEditor.AbstractEditor = Class.extend({
|
|||||||
this.parent = null;
|
this.parent = null;
|
||||||
},
|
},
|
||||||
getDefault: function() {
|
getDefault: function() {
|
||||||
if(this.schema["default"]) return this.schema["default"];
|
var def = this.schema["default"];
|
||||||
|
if(def) {
|
||||||
|
if (typeof def === "string") {
|
||||||
|
return $.i18n(def);
|
||||||
|
} else {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(this.schema["enum"]) return this.schema["enum"][0];
|
if(this.schema["enum"]) return this.schema["enum"][0];
|
||||||
|
|
||||||
var type = this.schema.type || this.schema.oneOf;
|
var type = this.schema.type || this.schema.oneOf;
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
var storedAccess;
|
|
||||||
var storedLang;
|
|
||||||
var availLang = ['cs', 'de', 'en', 'es', 'fr', 'it', 'nl', 'nb', 'pl', 'pt', 'ro', 'sv', 'vi', 'ru', 'tr', 'zh-CN'];
|
|
||||||
var availLangText = ['Čeština', 'Deutsch', 'English', 'Español', 'Français', 'Italiano', 'Nederlands', 'Norsk Bokmål', 'Polski', 'Português', 'Română', 'Svenska', 'Tiếng Việt', 'русский', 'Türkçe', '汉语'];
|
|
||||||
var availAccess = ['default', 'advanced', 'expert'];
|
var availAccess = ['default', 'advanced', 'expert'];
|
||||||
|
var storedAccess;
|
||||||
//$.i18n.debug = true;
|
|
||||||
|
|
||||||
//Change Password
|
//Change Password
|
||||||
function changePassword(){
|
function changePassword(){
|
||||||
@ -26,48 +21,11 @@ function changePassword(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready( function() {
|
$(document).ready(function () {
|
||||||
|
|
||||||
//i18n
|
if (!storageComp()) {
|
||||||
function initTrans(lc){
|
|
||||||
if (lc == 'auto')
|
|
||||||
{
|
|
||||||
$.i18n().load().done(
|
|
||||||
function() {
|
|
||||||
performTranslation();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$.i18n().locale = lc;
|
|
||||||
$.i18n().load( "i18n", lc ).done(
|
|
||||||
function() {
|
|
||||||
performTranslation();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storageComp())
|
|
||||||
{
|
|
||||||
storedLang = getStorage("langcode");
|
|
||||||
if (storedLang == null)
|
|
||||||
{
|
|
||||||
setStorage("langcode", 'auto');
|
|
||||||
storedLang = 'auto';
|
|
||||||
initTrans(storedLang);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
initTrans(storedLang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
showInfoDialog('warning', "Can't store settings", "Your browser doesn't support localStorage. You can't save a specific language setting (fallback to 'auto detection') and access level (fallback to 'default'). Some wizards may be hidden. You could still use the webinterface without further issues");
|
showInfoDialog('warning', "Can't store settings", "Your browser doesn't support localStorage. You can't save a specific language setting (fallback to 'auto detection') and access level (fallback to 'default'). Some wizards may be hidden. You could still use the webinterface without further issues");
|
||||||
initTrans('auto');
|
$('#language-select').attr("disabled", true);
|
||||||
storedLang = 'auto';
|
|
||||||
storedAccess = "default";
|
|
||||||
$('#btn_setlang').attr("disabled", true);
|
|
||||||
$('#btn_setaccess').attr("disabled", true);
|
$('#btn_setaccess').attr("disabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,10 +33,14 @@ $(document).ready( function() {
|
|||||||
|
|
||||||
//access
|
//access
|
||||||
storedAccess = getStorage("accesslevel");
|
storedAccess = getStorage("accesslevel");
|
||||||
if (storedAccess == null)
|
if (storedAccess == null) {
|
||||||
{
|
|
||||||
setStorage("accesslevel", "default");
|
|
||||||
storedAccess = "default";
|
storedAccess = "default";
|
||||||
|
setStorage("accesslevel", storedAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storageComp()) {
|
||||||
|
showInfoDialog('warning', $.i18n('InfoDialog_nostorage_title'), $.i18n('InfoDialog_nostorage_text'));
|
||||||
|
$('#btn_setlang').attr("disabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#btn_setaccess').off().on('click',function() {
|
$('#btn_setaccess').off().on('click',function() {
|
||||||
|
100
assets/webconfig/js/ui_utils.js
Executable file → Normal file
100
assets/webconfig/js/ui_utils.js
Executable file → Normal file
@ -67,7 +67,7 @@ function updateSessions() {
|
|||||||
|
|
||||||
function validateDuration(d) {
|
function validateDuration(d) {
|
||||||
if (typeof d === "undefined" || d < 0)
|
if (typeof d === "undefined" || d < 0)
|
||||||
return 0;
|
return ENDLESS;
|
||||||
else
|
else
|
||||||
return d *= 1000;
|
return d *= 1000;
|
||||||
}
|
}
|
||||||
@ -162,25 +162,22 @@ function initLanguageSelection() {
|
|||||||
|
|
||||||
var langLocale = storedLang;
|
var langLocale = storedLang;
|
||||||
|
|
||||||
// If no language has been set, resolve browser locale
|
|
||||||
if (langLocale === 'auto') {
|
|
||||||
langLocale = $.i18n().locale.substring(0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve text for language code
|
|
||||||
var langText = 'Please Select';
|
|
||||||
|
|
||||||
//Test, if language is supported by hyperion
|
//Test, if language is supported by hyperion
|
||||||
var langIdx = availLang.indexOf(langLocale);
|
var langIdx = availLang.indexOf(langLocale);
|
||||||
if (langIdx > -1) {
|
if (langIdx > -1) {
|
||||||
langText = availLangText[langIdx];
|
langText = availLangText[langIdx];
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// If language is not supported by hyperion, try fallback language
|
// If language is not supported by hyperion, try fallback language
|
||||||
langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
|
langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
|
||||||
langIdx = availLang.indexOf(langLocale);
|
langIdx = availLang.indexOf(langLocale);
|
||||||
if (langIdx > -1) {
|
if (langIdx > -1) {
|
||||||
langText = availLangText[langIdx];
|
langText = availLangText[langIdx];
|
||||||
|
} else {
|
||||||
|
langLocale = 'en';
|
||||||
|
langIdx = availLang.indexOf(langLocale);
|
||||||
|
if (langIdx > -1) {
|
||||||
|
langText = availLangText[langIdx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,10 +192,12 @@ function updateUiOnInstance(inst) {
|
|||||||
$('#btn_hypinstanceswitch').toggle(true);
|
$('#btn_hypinstanceswitch').toggle(true);
|
||||||
$('#active_instance_dropdown').prop('disabled', false);
|
$('#active_instance_dropdown').prop('disabled', false);
|
||||||
$('#active_instance_dropdown').css('cursor', 'pointer');
|
$('#active_instance_dropdown').css('cursor', 'pointer');
|
||||||
|
$("#active_instance_dropdown").css("pointer-events", "auto");
|
||||||
} else {
|
} else {
|
||||||
$('#btn_hypinstanceswitch').toggle(false);
|
$('#btn_hypinstanceswitch').toggle(false);
|
||||||
$('#active_instance_dropdown').prop('disabled', true);
|
$('#active_instance_dropdown').prop('disabled', true);
|
||||||
$("#active_instance_dropdown").css('cursor', 'default');
|
$("#active_instance_dropdown").css('cursor', 'default');
|
||||||
|
$("#active_instance_dropdown").css("pointer-events", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,10 +287,12 @@ function showInfoDialog(type, header, message) {
|
|||||||
}
|
}
|
||||||
else if (type == "changePassword") {
|
else if (type == "changePassword") {
|
||||||
$('#id_body_rename').html('<i style="margin-bottom:20px" class="fa fa-key modal-icon-edit"><br>');
|
$('#id_body_rename').html('<i style="margin-bottom:20px" class="fa fa-key modal-icon-edit"><br>');
|
||||||
$('#id_body_rename').append('<h4>' + header + '</h4>');
|
$('#id_body_rename').append('<h4>' + header + '</h4><br>');
|
||||||
$('#id_body_rename').append('<input class="form-control" id="oldPw" placeholder="Old" type="text"> <br />');
|
$('#id_body_rename').append('<div class="row"><div class="col-md-3"><p class="text-left">' + $.i18n('infoDialog_password_current_text') +
|
||||||
$('#id_body_rename').append('<input class="form-control" id="newPw" placeholder="New" type="password">');
|
'</p></div><div class="col-md-8"><input class="form-control" id="oldPw" placeholder="Old" type="password"></div></div><br>');
|
||||||
$('#id_footer_rename').html('<button type="button" id="id_btn_ok" class="btn btn-success" data-dismiss-modal="#modal_dialog_rename" disabled><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_ok') + '</button>');
|
$('#id_body_rename').append('<div class="row"><div class="col-md-3"><p class="text-left">' + $.i18n('infoDialog_password_new_text')+
|
||||||
|
'</p></div><div class="col-md-8"><input class="form-control" id="newPw" placeholder="New" type="password"></div></div>');
|
||||||
|
$('#id_footer_rename').html('<button type="button" id="id_btn_ok" class="btn btn-success" data-dismiss-modal="#modal_dialog_rename" disabled><i class="fa fa-fw fa-save"></ul>' + $.i18n('general_btn_ok') + '</button>');
|
||||||
$('#id_footer_rename').append('<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
$('#id_footer_rename').append('<button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
||||||
}
|
}
|
||||||
else if (type == "checklist") {
|
else if (type == "checklist") {
|
||||||
@ -461,7 +462,8 @@ function createJsonEditor(container, schema, setconfig, usePanel, arrayre) {
|
|||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateJsonEditorSelection(editor, key, addElements, newEnumVals, newTitelVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
|
function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
|
||||||
|
var editor = rootEditor.getEditor(path);
|
||||||
var orginalProperties = editor.schema.properties[key];
|
var orginalProperties = editor.schema.properties[key];
|
||||||
|
|
||||||
var newSchema = [];
|
var newSchema = [];
|
||||||
@ -536,13 +538,15 @@ function updateJsonEditorSelection(editor, key, addElements, newEnumVals, newTit
|
|||||||
|
|
||||||
editor.original_schema.properties[key] = orginalProperties;
|
editor.original_schema.properties[key] = orginalProperties;
|
||||||
editor.schema.properties[key] = newSchema[key];
|
editor.schema.properties[key] = newSchema[key];
|
||||||
|
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||||
|
|
||||||
editor.removeObjectProperty(key);
|
editor.removeObjectProperty(key);
|
||||||
delete editor.cached_editors[key];
|
delete editor.cached_editors[key];
|
||||||
editor.addObjectProperty(key);
|
editor.addObjectProperty(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateJsonEditorMultiSelection(editor, key, addElements, newEnumVals, newTitelVals, newDefaultVal) {
|
function updateJsonEditorMultiSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal) {
|
||||||
|
var editor = rootEditor.getEditor(path);
|
||||||
var orginalProperties = editor.schema.properties[key];
|
var orginalProperties = editor.schema.properties[key];
|
||||||
|
|
||||||
var newSchema = [];
|
var newSchema = [];
|
||||||
@ -593,36 +597,55 @@ function updateJsonEditorMultiSelection(editor, key, addElements, newEnumVals, n
|
|||||||
|
|
||||||
editor.original_schema.properties[key] = orginalProperties;
|
editor.original_schema.properties[key] = orginalProperties;
|
||||||
editor.schema.properties[key] = newSchema[key];
|
editor.schema.properties[key] = newSchema[key];
|
||||||
|
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||||
|
|
||||||
editor.removeObjectProperty(key);
|
editor.removeObjectProperty(key);
|
||||||
delete editor.cached_editors[key];
|
delete editor.cached_editors[key];
|
||||||
editor.addObjectProperty(key);
|
editor.addObjectProperty(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateJsonEditorRange(editor, key, minimum, maximum, defaultValue, step) {
|
function updateJsonEditorRange(rootEditor, path, key, minimum, maximum, defaultValue, step, clear) {
|
||||||
|
var editor = rootEditor.getEditor(path);
|
||||||
|
|
||||||
|
//Preserve current value when updating range
|
||||||
|
var currentValue = rootEditor.getEditor(path + "." + key).getValue();
|
||||||
|
|
||||||
var orginalProperties = editor.schema.properties[key];
|
var orginalProperties = editor.schema.properties[key];
|
||||||
var newSchema = [];
|
var newSchema = [];
|
||||||
newSchema[key] = orginalProperties;
|
newSchema[key] = orginalProperties;
|
||||||
|
|
||||||
if (minimum) {
|
if (clear) {
|
||||||
|
delete newSchema[key]["minimum"];
|
||||||
|
delete newSchema[key]["maximum"];
|
||||||
|
delete newSchema[key]["default"];
|
||||||
|
delete newSchema[key]["step"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof minimum !== "undefined") {
|
||||||
newSchema[key]["minimum"] = minimum;
|
newSchema[key]["minimum"] = minimum;
|
||||||
}
|
}
|
||||||
if (maximum) {
|
if (typeof maximum !== "undefined") {
|
||||||
newSchema[key]["maximum"] = maximum;
|
newSchema[key]["maximum"] = maximum;
|
||||||
}
|
}
|
||||||
if (defaultValue) {
|
if (typeof defaultValue !== "undefined") {
|
||||||
newSchema[key]["default"] = defaultValue;
|
newSchema[key]["default"] = defaultValue;
|
||||||
|
currentValue = defaultValue;
|
||||||
}
|
}
|
||||||
if (step) {
|
|
||||||
|
if (typeof step !== "undefined") {
|
||||||
newSchema[key]["step"] = step;
|
newSchema[key]["step"] = step;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.original_schema.properties[key] = orginalProperties;
|
editor.original_schema.properties[key] = orginalProperties;
|
||||||
editor.schema.properties[key] = newSchema[key];
|
editor.schema.properties[key] = newSchema[key];
|
||||||
|
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||||
|
|
||||||
editor.removeObjectProperty(key);
|
editor.removeObjectProperty(key);
|
||||||
delete editor.cached_editors[key];
|
delete editor.cached_editors[key];
|
||||||
editor.addObjectProperty(key);
|
editor.addObjectProperty(key);
|
||||||
|
|
||||||
|
// Restore current (new default) value for new range
|
||||||
|
rootEditor.getEditor(path + "." + key).setValue(currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildWL(link, linkt, cl) {
|
function buildWL(link, linkt, cl) {
|
||||||
@ -807,14 +830,15 @@ function createRow(id) {
|
|||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createOptPanel(phicon, phead, bodyid, footerid, css) {
|
function createOptPanel(phicon, phead, bodyid, footerid, css, panelId) {
|
||||||
phead = '<i class="fa ' + phicon + ' fa-fw"></i>' + phead;
|
phead = '<i class="fa ' + phicon + ' fa-fw"></i>' + phead;
|
||||||
|
|
||||||
var pfooter = document.createElement('button');
|
var pfooter = document.createElement('button');
|
||||||
pfooter.className = "btn btn-primary";
|
pfooter.className = "btn btn-primary";
|
||||||
pfooter.setAttribute("id", footerid);
|
pfooter.setAttribute("id", footerid);
|
||||||
pfooter.innerHTML = '<i class="fa fa-fw fa-save"></i>' + $.i18n('general_button_savesettings');
|
pfooter.innerHTML = '<i class="fa fa-fw fa-save"></i>' + $.i18n('general_button_savesettings');
|
||||||
|
|
||||||
return createPanel(phead, "", pfooter, "panel-default", bodyid, css);
|
return createPanel(phead, "", pfooter, "panel-default", bodyid, css, panelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareTwoValues(key1, key2, order = 'asc') {
|
function compareTwoValues(key1, key2, order = 'asc') {
|
||||||
@ -1141,14 +1165,34 @@ function isAccessLevelCompliant(accessLevel) {
|
|||||||
|
|
||||||
function showInputOptions(path, elements, state) {
|
function showInputOptions(path, elements, state) {
|
||||||
for (var i = 0; i < elements.length; i++) {
|
for (var i = 0; i < elements.length; i++) {
|
||||||
$('[data-schemapath="' + path + '.' + elements[i] + '"]').toggle(state);
|
$('[data-schemapath="root.' + path + '.' + elements[i] + '"]').toggle(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showInputOptionsForKey(editor, item, showForKey, state) {
|
function showInputOptionForItem(editor, path, item, state) {
|
||||||
|
var accessLevel = editor.schema.properties[path].properties[item].access;
|
||||||
|
// Enable element only, if access level compliant
|
||||||
|
if (!state || isAccessLevelCompliant(accessLevel)) {
|
||||||
|
showInputOptions(path, [item], state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showInputOptionsForKey(editor, item, showForKeys, state) {
|
||||||
var elements = [];
|
var elements = [];
|
||||||
|
var keysToshow = [];
|
||||||
|
|
||||||
|
if (Array.isArray(showForKeys)) {
|
||||||
|
keysToshow = showForKeys;
|
||||||
|
} else {
|
||||||
|
if (typeof showForKeys === 'string') {
|
||||||
|
keysToshow.push(showForKeys);
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (var key in editor.schema.properties[item].properties) {
|
for (var key in editor.schema.properties[item].properties) {
|
||||||
if (showForKey !== key) {
|
if ($.inArray(key, keysToshow) === -1) {
|
||||||
var accessLevel = editor.schema.properties[item].properties[key].access;
|
var accessLevel = editor.schema.properties[item].properties[key].access;
|
||||||
|
|
||||||
//Always disable all elements, but only enable elements, if access level compliant
|
//Always disable all elements, but only enable elements, if access level compliant
|
||||||
@ -1157,5 +1201,5 @@ function showInputOptionsForKey(editor, item, showForKey, state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showInputOptions("root." + item, elements, state);
|
showInputOptions(item, elements, state);
|
||||||
}
|
}
|
||||||
|
1
bin/compile.sh
Executable file → Normal file
1
bin/compile.sh
Executable file → Normal file
@ -25,7 +25,6 @@ sudo apt-get install \
|
|||||||
libavahi-core-dev \
|
libavahi-core-dev \
|
||||||
libavahi-compat-libdnssd-dev \
|
libavahi-compat-libdnssd-dev \
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
libjpeg-dev \
|
|
||||||
libqt5sql5-sqlite \
|
libqt5sql5-sqlite \
|
||||||
libqt5svg5-dev \
|
libqt5svg5-dev \
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
|
17
bin/scripts/docker-compile.sh
Normal file → Executable file
17
bin/scripts/docker-compile.sh
Normal file → Executable file
@ -15,6 +15,8 @@ BUILD_TAG="buster"
|
|||||||
BUILD_PACKAGES=true
|
BUILD_PACKAGES=true
|
||||||
# packages string inserted to cmake cmd
|
# packages string inserted to cmake cmd
|
||||||
PACKAGES=""
|
PACKAGES=""
|
||||||
|
# platform string inserted to cmake cmd
|
||||||
|
BUILD_PLATFORM=""
|
||||||
#Run build using GitHub code files
|
#Run build using GitHub code files
|
||||||
BUILD_LOCAL=0
|
BUILD_LOCAL=0
|
||||||
#Build from scratch
|
#Build from scratch
|
||||||
@ -73,6 +75,7 @@ echo "########################################################
|
|||||||
# docker-compile.sh -p true # If true, build packages with CPack
|
# docker-compile.sh -p true # If true, build packages with CPack
|
||||||
# docker-compile.sh -l # Run build using local code files
|
# docker-compile.sh -l # Run build using local code files
|
||||||
# docker-compile.sh -c # Run incremental build, i.e. do not delete files created during previous build
|
# docker-compile.sh -c # Run incremental build, i.e. do not delete files created during previous build
|
||||||
|
# docker-compile.sh -f x11 # cmake PLATFORM parameter
|
||||||
# More informations to docker tags at: https://github.com/Hyperion-Project/hyperion.docker-ci"
|
# More informations to docker tags at: https://github.com/Hyperion-Project/hyperion.docker-ci"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +87,7 @@ function log () {
|
|||||||
|
|
||||||
echo "Compile Hyperion using a Docker container"
|
echo "Compile Hyperion using a Docker container"
|
||||||
|
|
||||||
while getopts i:t:b:p:lcvh option
|
while getopts i:t:b:p:f:lcvh option
|
||||||
do
|
do
|
||||||
case "${option}"
|
case "${option}"
|
||||||
in
|
in
|
||||||
@ -92,6 +95,7 @@ do
|
|||||||
t) BUILD_TAG=${OPTARG};;
|
t) BUILD_TAG=${OPTARG};;
|
||||||
b) BUILD_TYPE=${OPTARG};;
|
b) BUILD_TYPE=${OPTARG};;
|
||||||
p) BUILD_PACKAGES=${OPTARG};;
|
p) BUILD_PACKAGES=${OPTARG};;
|
||||||
|
f) BUILD_PLATFORM=${OPTARG,,};;
|
||||||
l) BUILD_LOCAL=1;;
|
l) BUILD_LOCAL=1;;
|
||||||
c) BUILD_INCREMENTAL=1;;
|
c) BUILD_INCREMENTAL=1;;
|
||||||
v) _VERBOSE=1;;
|
v) _VERBOSE=1;;
|
||||||
@ -104,7 +108,12 @@ if [ ${BUILD_PACKAGES} == "true" ]; then
|
|||||||
PACKAGES="package"
|
PACKAGES="package"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "---> Initialize with IMAGE:TAG=${BUILD_IMAGE}:${BUILD_TAG}, BUILD_TYPE=${BUILD_TYPE}, BUILD_PACKAGES=${BUILD_PACKAGES}, BUILD_LOCAL=${BUILD_LOCAL}, BUILD_INCREMENTAL=${BUILD_INCREMENTAL}"
|
# determine platform cmake parameter
|
||||||
|
if [[ ! -z ${BUILD_PLATFORM} ]]; then
|
||||||
|
PLATFORM="-DPLATFORM=${BUILD_PLATFORM}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "---> Initialize with IMAGE:TAG=${BUILD_IMAGE}:${BUILD_TAG}, BUILD_TYPE=${BUILD_TYPE}, BUILD_PACKAGES=${BUILD_PACKAGES}, PLATFORM=${BUILD_PLATFORM}, BUILD_LOCAL=${BUILD_LOCAL}, BUILD_INCREMENTAL=${BUILD_INCREMENTAL}"
|
||||||
|
|
||||||
log "---> BASE_PATH = ${BASE_PATH}"
|
log "---> BASE_PATH = ${BASE_PATH}"
|
||||||
CODE_PATH=${BASE_PATH};
|
CODE_PATH=${BASE_PATH};
|
||||||
@ -155,7 +164,7 @@ $DOCKER run --rm \
|
|||||||
-v "${CODE_PATH}/:/source:rw" \
|
-v "${CODE_PATH}/:/source:rw" \
|
||||||
${REGISTRY_URL}/${BUILD_IMAGE}:${BUILD_TAG} \
|
${REGISTRY_URL}/${BUILD_IMAGE}:${BUILD_TAG} \
|
||||||
/bin/bash -c "mkdir -p /source/${BUILD_DIR} && cd /source/${BUILD_DIR} &&
|
/bin/bash -c "mkdir -p /source/${BUILD_DIR} && cd /source/${BUILD_DIR} &&
|
||||||
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. || exit 2 &&
|
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${PLATFORM} .. || exit 2 &&
|
||||||
make -j $(nproc) ${PACKAGES} || exit 3 || : &&
|
make -j $(nproc) ${PACKAGES} || exit 3 || : &&
|
||||||
exit 0;
|
exit 0;
|
||||||
exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 4; }
|
exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 4; }
|
||||||
@ -164,7 +173,6 @@ DOCKERRC=${?}
|
|||||||
|
|
||||||
# overwrite file owner to current user
|
# overwrite file owner to current user
|
||||||
sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${BUILD_PATH}
|
sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${BUILD_PATH}
|
||||||
sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${DEPLOY_PATH}
|
|
||||||
|
|
||||||
if [ ${DOCKERRC} == 0 ]; then
|
if [ ${DOCKERRC} == 0 ]; then
|
||||||
if [ ${BUILD_LOCAL} == 1 ]; then
|
if [ ${BUILD_LOCAL} == 1 ]; then
|
||||||
@ -175,6 +183,7 @@ if [ ${DOCKERRC} == 0 ]; then
|
|||||||
echo "---> Copying packages to host folder: ${DEPLOY_PATH}" &&
|
echo "---> Copying packages to host folder: ${DEPLOY_PATH}" &&
|
||||||
cp -v ${BUILD_PATH}/Hyperion-* ${DEPLOY_PATH} 2>/dev/null
|
cp -v ${BUILD_PATH}/Hyperion-* ${DEPLOY_PATH} 2>/dev/null
|
||||||
echo "---> Find deployment packages in: ${DEPLOY_PATH}"
|
echo "---> Find deployment packages in: ${DEPLOY_PATH}"
|
||||||
|
sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${DEPLOY_PATH}
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "---> Script finished [${DOCKERRC}]"
|
echo "---> Script finished [${DOCKERRC}]"
|
||||||
|
@ -241,7 +241,7 @@ macro(DeployWindows TARGET)
|
|||||||
list(REMOVE_AT DEPENDENCIES 0 1)
|
list(REMOVE_AT DEPENDENCIES 0 1)
|
||||||
endwhile()
|
endwhile()
|
||||||
|
|
||||||
# Copy OpenSSL Libs
|
# Copy libssl/libcrypto to 'hyperion'
|
||||||
if (OPENSSL_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
string(REGEX MATCHALL "[0-9]+" openssl_versions "${OPENSSL_VERSION}")
|
string(REGEX MATCHALL "[0-9]+" openssl_versions "${OPENSSL_VERSION}")
|
||||||
list(GET openssl_versions 0 openssl_version_major)
|
list(GET openssl_versions 0 openssl_version_major)
|
||||||
@ -271,6 +271,27 @@ macro(DeployWindows TARGET)
|
|||||||
)
|
)
|
||||||
endif(OPENSSL_FOUND)
|
endif(OPENSSL_FOUND)
|
||||||
|
|
||||||
|
# Copy libjpeg-turbo to 'hyperion'
|
||||||
|
if (ENABLE_MF AND TURBOJPEG_FOUND)
|
||||||
|
find_file(TURBOJPEG_DLL
|
||||||
|
NAMES "turbojpeg.dll"
|
||||||
|
PATHS ${TurboJPEG_INCLUDE_DIRS}/.. ${TurboJPEG_INCLUDE_DIRS}/../bin
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
find_file(JPEG_DLL
|
||||||
|
NAMES "jpeg62.dll"
|
||||||
|
PATHS ${TurboJPEG_INCLUDE_DIRS}/.. ${TurboJPEG_INCLUDE_DIRS}/../bin
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${TURBOJPEG_DLL} ${JPEG_DLL}
|
||||||
|
DESTINATION "bin"
|
||||||
|
COMPONENT "Hyperion"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Create a qt.conf file in 'bin' to override hard-coded search paths in Qt plugins
|
# Create a qt.conf file in 'bin' to override hard-coded search paths in Qt plugins
|
||||||
file(WRITE "${CMAKE_BINARY_DIR}/qt.conf" "[Paths]\nPlugins=../lib/\n")
|
file(WRITE "${CMAKE_BINARY_DIR}/qt.conf" "[Paths]\nPlugins=../lib/\n")
|
||||||
install(
|
install(
|
||||||
@ -318,6 +339,30 @@ macro(DeployWindows TARGET)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(ENABLE_DX)
|
||||||
|
# Download DirectX End-User Runtimes (June 2010)
|
||||||
|
set(url "https://download.microsoft.com/download/8/4/A/84A35BF1-DAFE-4AE8-82AF-AD2AE20B6B14/directx_Jun2010_redist.exe")
|
||||||
|
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/dx_redist.exe")
|
||||||
|
file(DOWNLOAD "${url}" "${CMAKE_CURRENT_BINARY_DIR}/dx_redist.exe"
|
||||||
|
STATUS result
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if the download is successful
|
||||||
|
list(GET result 0 result_code)
|
||||||
|
if(NOT result_code EQUAL 0)
|
||||||
|
list(GET result 1 reason)
|
||||||
|
message(FATAL_ERROR "Could not download DirectX End-User Runtimes: ${reason}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Copy DirectX End-User Runtimes to 'hyperion'
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/dx_redist.exe
|
||||||
|
DESTINATION "bin"
|
||||||
|
COMPONENT "Hyperion"
|
||||||
|
)
|
||||||
|
endif (ENABLE_DX)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
# Run CMake after target was built
|
# Run CMake after target was built
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
@ -3,15 +3,31 @@
|
|||||||
# TurboJPEG_INCLUDE_DIRS
|
# TurboJPEG_INCLUDE_DIRS
|
||||||
# TurboJPEG_LIBRARY
|
# TurboJPEG_LIBRARY
|
||||||
|
|
||||||
find_path(TurboJPEG_INCLUDE_DIRS
|
if (ENABLE_MF)
|
||||||
|
find_path(TurboJPEG_INCLUDE_DIRS
|
||||||
|
NAMES turbojpeg.h
|
||||||
|
PATHS
|
||||||
|
"C:/libjpeg-turbo64"
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(TurboJPEG_LIBRARY
|
||||||
|
NAMES turbojpeg turbojpeg-static
|
||||||
|
PATHS
|
||||||
|
"C:/libjpeg-turbo64"
|
||||||
|
PATH_SUFFIXES bin lib
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
find_path(TurboJPEG_INCLUDE_DIRS
|
||||||
NAMES turbojpeg.h
|
NAMES turbojpeg.h
|
||||||
PATH_SUFFIXES include
|
PATH_SUFFIXES include
|
||||||
)
|
)
|
||||||
|
|
||||||
find_library(TurboJPEG_LIBRARY
|
find_library(TurboJPEG_LIBRARY
|
||||||
NAMES turbojpeg turbojpeg-static
|
NAMES turbojpeg turbojpeg-static
|
||||||
PATH_SUFFIXES bin lib
|
PATH_SUFFIXES bin lib
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
||||||
include(CheckCSourceCompiles)
|
include(CheckCSourceCompiles)
|
||||||
@ -26,7 +42,7 @@ if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(TurboJpeg
|
find_package_handle_standard_args(TurboJPEG
|
||||||
FOUND_VAR TURBOJPEG_FOUND
|
FOUND_VAR TURBOJPEG_FOUND
|
||||||
REQUIRED_VARS TurboJPEG_LIBRARY TurboJPEG_INCLUDE_DIRS TURBOJPEG_WORKS
|
REQUIRED_VARS TurboJPEG_LIBRARY TurboJPEG_INCLUDE_DIRS TURBOJPEG_WORKS
|
||||||
TurboJPEG_INCLUDE_DIRS TurboJPEG_LIBRARY
|
TurboJPEG_INCLUDE_DIRS TurboJPEG_LIBRARY
|
||||||
|
@ -16,7 +16,7 @@ install_file()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
echo "---Hyperion ambient light postinstall ---"
|
echo "--- Hyperion ambient light postinstall ---"
|
||||||
|
|
||||||
#check system
|
#check system
|
||||||
CPU_RPI=`grep -m1 -c 'BCM2708\|BCM2709\|BCM2710\|BCM2835\|BCM2836\|BCM2837\|BCM2711' /proc/cpuinfo`
|
CPU_RPI=`grep -m1 -c 'BCM2708\|BCM2709\|BCM2710\|BCM2835\|BCM2836\|BCM2837\|BCM2711' /proc/cpuinfo`
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 18 KiB |
@ -790,7 +790,13 @@ Section "-Core installation"
|
|||||||
;End:
|
;End:
|
||||||
|
|
||||||
; Install Visual c++ Redistributable
|
; Install Visual c++ Redistributable
|
||||||
ExecWait '"$INSTDIR\bin\vc_redist.x64.exe" /install /quiet'
|
ExecWait '"$INSTDIR\bin\vc_redist.x64.exe" /install /quiet /norestart'
|
||||||
|
|
||||||
|
; Install DirectX 9 Redistributable
|
||||||
|
ExecWait '"$INSTDIR\bin\dx_redist.exe" /q /t:"$INSTDIR\tmp"'
|
||||||
|
ExecWait '"$INSTDIR\tmp\DXSETUP.exe" /silent'
|
||||||
|
Delete '$INSTDIR\tmp\*.*'
|
||||||
|
RMDir '$INSTDIR\tmp'
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
|
@ -1,535 +0,0 @@
|
|||||||
// This is a example config (hyperion.config.json) with comments, in any case you need to create your own one with HyperCon!
|
|
||||||
// location of all configs: /etc/hyperion
|
|
||||||
// Webpage: https://www.hyperion-project.org
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
/// general Settings
|
|
||||||
/// * 'name' : The user friendly name of the hyperion instance (used for network things)
|
|
||||||
/// * 'versionBranch' : Which branch should be used for hyperion version
|
|
||||||
/// * 'showOptHelp' : Show option expanations at the webui. Highly recommended for beginners.
|
|
||||||
"general" :
|
|
||||||
{
|
|
||||||
"name" : "MyHyperionConfig",
|
|
||||||
"watchedVersionBranch" : "Stable",
|
|
||||||
"showOptHelp" : true
|
|
||||||
},
|
|
||||||
/// set log level: silent warn verbose debug
|
|
||||||
"logger" :
|
|
||||||
{
|
|
||||||
"level" : "warn"
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Device configuration contains the following fields:
|
|
||||||
/// * 'name' : The user friendly name of the device (only used for display purposes)
|
|
||||||
/// * 'type' : The type of the device
|
|
||||||
/// * [device type specific configuration]
|
|
||||||
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
|
|
||||||
/// * 'rewriteTime': in ms. Data is resend to leds, if no new data is available in thistime. 0 means no refresh
|
|
||||||
"device" :
|
|
||||||
{
|
|
||||||
"type" : "file",
|
|
||||||
"hardwareLedCount" : 1,
|
|
||||||
"output" : "/dev/null",
|
|
||||||
"rate" : 1000000,
|
|
||||||
"colorOrder" : "rgb",
|
|
||||||
"rewriteTime": 5000
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Color manipulation configuration used to tune the output colors to specific surroundings.
|
|
||||||
/// The configuration contains a list of color-transforms. Each transform contains the
|
|
||||||
/// following fields:
|
|
||||||
/// * 'imageToLedMappingType' : multicolor_mean - every led has it's own calculatedmean color
|
|
||||||
/// unicolor_mean - every led has same color, color is the mean of whole image
|
|
||||||
/// * 'channelAdjustment'
|
|
||||||
/// * 'id' : The unique identifier of the channel adjustments (eg 'device_1')
|
|
||||||
/// * 'leds' : The indices (or index ranges) of the leds to which this channel adjustment applies
|
|
||||||
/// (eg '0-5, 9, 11, 12-17'). The indices are zero based.
|
|
||||||
/// * 'white'/'red'/'green'/'blue'/'cyan'/'magenta'/'yellow' : Array of RGB to adjust the output color
|
|
||||||
/// * 'gammaRed'/'gammaGreen'/'gammaBlue' : Gamma value for each channel
|
|
||||||
/// * 'id' : The unique identifier of the channel adjustments (eg 'device_1')
|
|
||||||
/// * 'id' : The unique identifier of the channel adjustments (eg 'device_1')
|
|
||||||
/// * 'backlightThreshold' : Minimum brightness (backlight)
|
|
||||||
/// * 'backlightColored' : backlight with color, instead of white
|
|
||||||
/// * 'brightness' : overall brightness
|
|
||||||
/// * 'brightnessCompensation' : 100 means brightness differences are compensated (white is as bright as red, is as bright as yellow.
|
|
||||||
/// 0 means white is 3x brighter than red, yellow is 2x brighter than red
|
|
||||||
"color" :
|
|
||||||
{
|
|
||||||
"imageToLedMappingType" : "multicolor_mean",
|
|
||||||
"channelAdjustment" :
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id" : "default",
|
|
||||||
"leds" : "*",
|
|
||||||
"white" : [255,255,255],
|
|
||||||
"red" : [255,0,0],
|
|
||||||
"green" : [0,255,0],
|
|
||||||
"blue" : [0,0,255],
|
|
||||||
"cyan" : [0,255,255],
|
|
||||||
"magenta" : [255,0,255],
|
|
||||||
"yellow" : [255,255,0],
|
|
||||||
"gammaRed" : 1.5,
|
|
||||||
"gammaGreen" : 1.5,
|
|
||||||
"gammaBlue" : 1.5,
|
|
||||||
"backlightThreshold" : 0,
|
|
||||||
"backlightColored" : false,
|
|
||||||
"brightness" : 100,
|
|
||||||
"brightnessCompensation" : 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
/// smoothing
|
|
||||||
/// * 'smoothing' : Smoothing of the colors in the time-domain with the following tuning
|
|
||||||
/// parameters:
|
|
||||||
/// - 'enable' Enable or disable the smoothing (true/false)
|
|
||||||
/// - 'type' The type of smoothing algorithm ('linear' or 'none')
|
|
||||||
/// - 'time_ms' The time constant for smoothing algorithm in milliseconds
|
|
||||||
/// - 'updateFrequency' The update frequency of the leds in Hz
|
|
||||||
/// - 'updateDelay' The delay of the output to leds (in periods of smoothing)
|
|
||||||
/// - 'continuousOutput' Flag for enabling continuous output to Leds regardless of new input or not
|
|
||||||
"smoothing" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"type" : "linear",
|
|
||||||
"time_ms" : 200,
|
|
||||||
"updateFrequency" : 25.0000,
|
|
||||||
"updateDelay" : 0,
|
|
||||||
"continuousOutput" : true
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Configuration for the embedded V4L2 grabber
|
|
||||||
/// * device : V4L2 Device to use [default="auto"] (Auto detection)
|
|
||||||
/// * width : The width of the grabbed frames (pixels) [default=0]
|
|
||||||
/// * height : The height of the grabbed frames (pixels) [default=0]
|
|
||||||
/// * standard : Video standard (PAL/NTSC/SECAM/NO_CHANGE) [default="NO_CHANGE"]
|
|
||||||
/// * sizeDecimation : Size decimation factor [default=8]
|
|
||||||
/// * cropLeft : Cropping from the left [default=0]
|
|
||||||
/// * cropRight : Cropping from the right [default=0]
|
|
||||||
/// * cropTop : Cropping from the top [default=0]
|
|
||||||
/// * cropBottom : Cropping from the bottom [default=0]
|
|
||||||
/// * signalDetection : enable/disable signal detection [default=false]
|
|
||||||
/// * cecDetection : enable/disable cec detection [default=false]
|
|
||||||
/// * redSignalThreshold : Signal threshold for the red channel between 0 and 100 [default=5]
|
|
||||||
/// * greenSignalThreshold : Signal threshold for the green channel between 0 and 100 [default=5]
|
|
||||||
/// * blueSignalThreshold : Signal threshold for the blue channel between 0 and 100 [default=5]
|
|
||||||
/// * sDHOffsetMin : area for signal detection - horizontal minimum offset value. Values between 0.0 and 1.0
|
|
||||||
/// * sDVOffsetMin : area for signal detection - vertical minimum offset value. Values between 0.0 and 1.0
|
|
||||||
/// * sDHOffsetMax : area for signal detection - horizontal maximum offset value. Values between 0.0 and 1.0
|
|
||||||
/// * sDVOffsetMax : area for signal detection - vertical maximum offset value. Values between 0.0 and 1.0
|
|
||||||
"grabberV4L2" :
|
|
||||||
{
|
|
||||||
"device" : "auto",
|
|
||||||
"width" : 0,
|
|
||||||
"height" : 0,
|
|
||||||
"standard" : "NO_CHANGE",
|
|
||||||
"sizeDecimation" : 8,
|
|
||||||
"priority" : 240,
|
|
||||||
"cropLeft" : 0,
|
|
||||||
"cropRight" : 0,
|
|
||||||
"cropTop" : 0,
|
|
||||||
"cropBottom" : 0,
|
|
||||||
"redSignalThreshold" : 5,
|
|
||||||
"greenSignalThreshold" : 5,
|
|
||||||
"blueSignalThreshold" : 5,
|
|
||||||
"signalDetection" : false,
|
|
||||||
"cecDetection" : false,
|
|
||||||
"sDVOffsetMin" : 0.25,
|
|
||||||
"sDHOffsetMin" : 0.25,
|
|
||||||
"sDVOffsetMax" : 0.75,
|
|
||||||
"sDHOffsetMax" : 0.75
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration for the frame-grabber, contains the following items:
|
|
||||||
/// * type : type of grabber. (auto|osx|dispmanx|amlogic|x11|xcb|framebuffer|qt) [auto]
|
|
||||||
/// * width : The width of the grabbed frames [pixels]
|
|
||||||
/// * height : The height of the grabbed frames [pixels]
|
|
||||||
/// * frequency_Hz : The frequency of the frame grab [Hz]
|
|
||||||
/// * ATTENTION : Power-of-Two resolution is not supported and leads to unexpected behaviour!
|
|
||||||
"framegrabber" :
|
|
||||||
{
|
|
||||||
// for all type of grabbers
|
|
||||||
"type" : "framebuffer",
|
|
||||||
"frequency_Hz" : 10,
|
|
||||||
"cropLeft" : 0,
|
|
||||||
"cropRight" : 0,
|
|
||||||
"cropTop" : 0,
|
|
||||||
"cropBottom" : 0,
|
|
||||||
|
|
||||||
// valid for grabber: osx|dispmanx|amlogic|framebuffer
|
|
||||||
"width" : 96,
|
|
||||||
"height" : 96,
|
|
||||||
|
|
||||||
// valid for x11|xcb|qt
|
|
||||||
"pixelDecimation" : 8,
|
|
||||||
|
|
||||||
// valid for qt
|
|
||||||
"display" 0
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The black border configuration, contains the following items:
|
|
||||||
/// * enable : true if the detector should be activated
|
|
||||||
/// * threshold : Value below which a pixel is regarded as black (value between 0 and 100 [%])
|
|
||||||
/// * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600)
|
|
||||||
/// * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50)
|
|
||||||
/// * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency
|
|
||||||
/// * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1)
|
|
||||||
/// * mode : Border detection mode (values=default,classic,osd,letterbox)
|
|
||||||
"blackborderdetector" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"threshold" : 5,
|
|
||||||
"unknownFrameCnt" : 600,
|
|
||||||
"borderFrameCnt" : 50,
|
|
||||||
"maxInconsistentCnt" : 10,
|
|
||||||
"blurRemoveCnt" : 1,
|
|
||||||
"mode" : "default"
|
|
||||||
},
|
|
||||||
|
|
||||||
/// foregroundEffect sets a "booteffect" or "bootcolor" during startup for a given period in ms (duration_ms)
|
|
||||||
/// * enable : if true, foreground effect is enabled
|
|
||||||
/// * type : choose between "color" or "effect"
|
|
||||||
/// * color : if type is color, a color is used (RGB) (example: [0,0,255])
|
|
||||||
/// * effect : if type is effect a effect is used (example: "Rainbow swirl fast")
|
|
||||||
/// * duration_ms : The duration of the selected effect or color (0=endless)
|
|
||||||
/// HINT: "foregroundEffect" starts always with priority 0, so it blocks all remotes and grabbers if the duration_ms is endless (0)
|
|
||||||
"foregroundEffect" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"type" : "effect",
|
|
||||||
"color" : [0,0,255],
|
|
||||||
"effect" : "Rainbow swirl fast",
|
|
||||||
"duration_ms" : 3000
|
|
||||||
},
|
|
||||||
|
|
||||||
/// backgroundEffect sets a background effect or color. It is used when all capture devices are stopped (manual via remote). Could be also selected via priorities selection.
|
|
||||||
/// * enable : if true, background effect is enabled
|
|
||||||
/// * type : choose between "color" or "effect"
|
|
||||||
/// * color : if type is color, a color is used (RGB) (example: [255,134,0])
|
|
||||||
/// * effect : if type is effect a effect is used (example: "Rainbow swirl fast")
|
|
||||||
"backgroundEffect" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"type" : "effect",
|
|
||||||
"color" : [255,138,0],
|
|
||||||
"effect" : "Warm mood blobs"
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Json/Proto forwarder. Forward messages to multiple instances of Hyperion on same and/or other hosts
|
|
||||||
/// 'proto' is mostly used for video streams and 'json' for effects
|
|
||||||
/// * enable : Enable or disable the forwarder (true/false)
|
|
||||||
/// * proto : Proto server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19401"] or more instances to forward ["127.0.0.1:19401","192.168.0.24:19403"]
|
|
||||||
/// * json : Json server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19446"] or more instances to forward ["127.0.0.1:19446","192.168.0.24:19448"]
|
|
||||||
/// HINT:If you redirect to "127.0.0.1" (localhost) you could start a second hyperion with another device/led config!
|
|
||||||
/// Be sure your client(s) is/are listening on the configured ports. The second Hyperion (if used) also needs to be configured! (WebUI -> Settings Level (Expert) -> Configuration -> Network Services -> Forwarder)
|
|
||||||
"forwarder" :
|
|
||||||
{
|
|
||||||
"enable" : false,
|
|
||||||
"flat" : ["127.0.0.1:19401"],
|
|
||||||
"json" : ["127.0.0.1:19446"]
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Json server which enables the json remote interface
|
|
||||||
/// * port : Port at which the json server is started
|
|
||||||
"jsonServer" :
|
|
||||||
{
|
|
||||||
"port" : 19444
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Flatbuffer server which enables the Flatbuffer remote interface
|
|
||||||
/// * port : Port at which the flatbuffer server is started
|
|
||||||
"flatbufServer" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"port" : 19400,
|
|
||||||
"timeout" : 5
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the Protobuffer server which enables the Protobuffer remote interface
|
|
||||||
/// * port : Port at which the protobuffer server is started
|
|
||||||
"protoServer" :
|
|
||||||
{
|
|
||||||
"enable" : true,
|
|
||||||
"port" : 19445,
|
|
||||||
"timeout" : 5
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the boblight server which enables the boblight remote interface
|
|
||||||
/// * enable : Enable or disable the boblight server (true/false)
|
|
||||||
/// * port : Port at which the boblight server is started
|
|
||||||
/// * priority : Priority of the boblight server (Default=128) HINT: lower value result in HIGHER priority!
|
|
||||||
"boblightServer" :
|
|
||||||
{
|
|
||||||
"enable" : false,
|
|
||||||
"port" : 19333,
|
|
||||||
"priority" : 128
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Configuration of the Hyperion webserver
|
|
||||||
/// * document_root : path to hyperion webapp files (webconfig developer only)
|
|
||||||
/// * port : the port where hyperion webapp is accasible
|
|
||||||
/// * sslPort : the secure (HTTPS) port of the hyperion webapp
|
|
||||||
/// * crtPath : the path to a certificate file to allow HTTPS connections. Should be in PEM format
|
|
||||||
/// * keyPath : the path to a private key file to allow HTTPS connections. Should be in PEM format and RSA encrypted
|
|
||||||
/// * keyPassPhrase : optional: If the key file requires a password add it here
|
|
||||||
"webConfig" :
|
|
||||||
{
|
|
||||||
"document_root" : "/path/to/files",
|
|
||||||
"port" : 8090,
|
|
||||||
"sslPort" : 8092,
|
|
||||||
"crtPath" : "/path/to/mycert.crt",
|
|
||||||
"keyPath" : "/path/to/mykey.key",
|
|
||||||
"keyPassPhrase" : ""
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the effect engine, contains the following items:
|
|
||||||
/// * paths : An array with absolute location(s) of directories with effects,
|
|
||||||
/// $ROOT is a keyword which will be replaced with the current rootPath that can be specified on startup from the commandline (defaults to your home directory)
|
|
||||||
/// * disable : An array with effect names that shouldn't be loaded
|
|
||||||
"effects" :
|
|
||||||
{
|
|
||||||
"paths" :
|
|
||||||
[
|
|
||||||
"$ROOT/custom-effects",
|
|
||||||
"/usr/share/hyperion/effects"
|
|
||||||
],
|
|
||||||
"disable" :
|
|
||||||
[
|
|
||||||
"Rainbow swirl",
|
|
||||||
"X-Mas"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"instCapture" :
|
|
||||||
{
|
|
||||||
"systemEnable" : true,
|
|
||||||
"systemPriority" : 250,
|
|
||||||
"v4lEnable" : false,
|
|
||||||
"v4lPriority" : 240
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration of the network security restrictions, contains the following items:
|
|
||||||
/// * internetAccessAPI : When true allows connection from internet to the API. When false it blocks all outside connections
|
|
||||||
/// * restirctedInternetAccessAPI : webui voodoo only - ignore it
|
|
||||||
/// * ipWhitelist : Whitelist ip addresses from the internet to allow access to the API
|
|
||||||
/// * apiAuth : When true the API requires authentication through tokens to use the API. Read also "localApiAuth"
|
|
||||||
/// * localApiAuth : When false connections from the local network don't require an API authentification.
|
|
||||||
/// * localAdminApiAuth : When false connections from the local network don't require an authentification for administration access.
|
|
||||||
"network" :
|
|
||||||
{
|
|
||||||
"internetAccessAPI" : false,
|
|
||||||
"restirctedInternetAccessAPI" : false,
|
|
||||||
"ipWhitelist" : [],
|
|
||||||
"apiAuth" : true,
|
|
||||||
"localApiAuth" : false,
|
|
||||||
"localAdminAuth": true
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Recreate and save led layouts made with web config. These values are just helpers for ui, not for Hyperion.
|
|
||||||
"ledConfig" :
|
|
||||||
{
|
|
||||||
"classic":
|
|
||||||
{
|
|
||||||
"top" : 8,
|
|
||||||
"bottom" : 8,
|
|
||||||
"left" : 5,
|
|
||||||
"right" : 5,
|
|
||||||
"glength" : 0,
|
|
||||||
"gpos" : 0,
|
|
||||||
"position" : 0,
|
|
||||||
"reverse" : false,
|
|
||||||
"hdepth" : 8,
|
|
||||||
"vdepth" : 5,
|
|
||||||
"overlap" : 0,
|
|
||||||
"edgegap" : 0,
|
|
||||||
"ptlh" : 0,
|
|
||||||
"ptlv" : 0,
|
|
||||||
"ptrh" : 100,
|
|
||||||
"ptrv" : 0,
|
|
||||||
"pblh" : 0,
|
|
||||||
"pblv" : 100,
|
|
||||||
"pbrh" : 100,
|
|
||||||
"pbrv" : 100
|
|
||||||
|
|
||||||
},
|
|
||||||
"matrix":
|
|
||||||
{
|
|
||||||
"ledshoriz": 10,
|
|
||||||
"ledsvert" : 10,
|
|
||||||
"cabling" : "snake",
|
|
||||||
"start" : "top-left"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The configuration for each individual led. This contains the specification of the area
|
|
||||||
/// averaged of an input image for each led to determine its color. Each item in the list
|
|
||||||
/// contains the following fields:
|
|
||||||
/// * hmin: The fractional part of the image along the horizontal used for the averaging (minimum)
|
|
||||||
/// * hmax: The fractional part of the image along the horizontal used for the averaging (maximum)
|
|
||||||
/// * vmin: The fractional part of the image along the vertical used for the averaging (minimum)
|
|
||||||
/// * vmax: The fractional part of the image along the vertical used for the averaging (maximum)
|
|
||||||
/// * colorOrder: Usually the global colorOrder is set at the device section, you can overwrite it here per led
|
|
||||||
|
|
||||||
"leds":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"hmax": 0.125,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.25,
|
|
||||||
"hmin": 0.125,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.375,
|
|
||||||
"hmin": 0.25,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.5,
|
|
||||||
"hmin": 0.375,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.625,
|
|
||||||
"hmin": 0.5,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.75,
|
|
||||||
"hmin": 0.625,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.875,
|
|
||||||
"hmin": 0.75,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.875,
|
|
||||||
"vmax": 0.08,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.95,
|
|
||||||
"vmax": 0.2,
|
|
||||||
"vmin": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.95,
|
|
||||||
"vmax": 0.4,
|
|
||||||
"vmin": 0.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.95,
|
|
||||||
"vmax": 0.6,
|
|
||||||
"vmin": 0.4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.95,
|
|
||||||
"vmax": 0.8,
|
|
||||||
"vmin": 0.6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.95,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 1,
|
|
||||||
"hmin": 0.875,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.875,
|
|
||||||
"hmin": 0.75,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.75,
|
|
||||||
"hmin": 0.625,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.625,
|
|
||||||
"hmin": 0.5,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.5,
|
|
||||||
"hmin": 0.375,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.375,
|
|
||||||
"hmin": 0.25,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.25,
|
|
||||||
"hmin": 0.125,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.125,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.05,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 1,
|
|
||||||
"vmin": 0.8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.05,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 0.8,
|
|
||||||
"vmin": 0.6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.05,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 0.6,
|
|
||||||
"vmin": 0.4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.05,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 0.4,
|
|
||||||
"vmin": 0.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hmax": 0.05,
|
|
||||||
"hmin": 0,
|
|
||||||
"vmax": 0.2,
|
|
||||||
"vmin": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -2,6 +2,8 @@
|
|||||||
"general" :
|
"general" :
|
||||||
{
|
{
|
||||||
"name" : "My Hyperion Config",
|
"name" : "My Hyperion Config",
|
||||||
|
"configVersion": "configVersionValue",
|
||||||
|
"previousVersion": "previousVersionValue",
|
||||||
"watchedVersionBranch" : "Stable",
|
"watchedVersionBranch" : "Stable",
|
||||||
"showOptHelp" : true
|
"showOptHelp" : true
|
||||||
},
|
},
|
||||||
@ -62,40 +64,49 @@
|
|||||||
|
|
||||||
"grabberV4L2" :
|
"grabberV4L2" :
|
||||||
{
|
{
|
||||||
"device" : "auto",
|
"enable" : false,
|
||||||
|
"device" : "none",
|
||||||
"input" : 0,
|
"input" : 0,
|
||||||
|
"encoding" : "NO_CHANGE",
|
||||||
"width" : 0,
|
"width" : 0,
|
||||||
"height" : 0,
|
"height" : 0,
|
||||||
"fps" : 15,
|
"fps" : 15,
|
||||||
"standard" : "NO_CHANGE",
|
"flip" : "NO_CHANGE",
|
||||||
|
"fpsSoftwareDecimation" : 0,
|
||||||
"sizeDecimation" : 8,
|
"sizeDecimation" : 8,
|
||||||
"cropLeft" : 0,
|
"cropLeft" : 0,
|
||||||
"cropRight" : 0,
|
"cropRight" : 0,
|
||||||
"cropTop" : 0,
|
"cropTop" : 0,
|
||||||
"cropBottom" : 0,
|
"cropBottom" : 0,
|
||||||
"redSignalThreshold" : 5,
|
"redSignalThreshold" : 0,
|
||||||
"greenSignalThreshold" : 5,
|
"greenSignalThreshold" : 100,
|
||||||
"blueSignalThreshold" : 5,
|
"blueSignalThreshold" : 0,
|
||||||
"signalDetection" : false,
|
"signalDetection" : false,
|
||||||
|
"noSignalCounterThreshold" : 200,
|
||||||
"cecDetection" : false,
|
"cecDetection" : false,
|
||||||
"sDVOffsetMin" : 0.25,
|
"sDVOffsetMin" : 0.1,
|
||||||
"sDHOffsetMin" : 0.25,
|
"sDVOffsetMax" : 0.9,
|
||||||
"sDVOffsetMax" : 0.75,
|
"sDHOffsetMin" : 0.4,
|
||||||
"sDHOffsetMax" : 0.75
|
"sDHOffsetMax" : 0.46,
|
||||||
|
"hardware_brightness" : 0,
|
||||||
|
"hardware_contrast" : 0,
|
||||||
|
"hardware_saturation" : 0,
|
||||||
|
"hardware_hue" : 0
|
||||||
},
|
},
|
||||||
|
|
||||||
"framegrabber" :
|
"framegrabber" :
|
||||||
{
|
{
|
||||||
"type" : "auto",
|
"enable" : false,
|
||||||
|
"device" : "auto",
|
||||||
|
"input" : 0,
|
||||||
"width" : 80,
|
"width" : 80,
|
||||||
"height" : 45,
|
"height" : 45,
|
||||||
"frequency_Hz" : 10,
|
"fps" : 10,
|
||||||
"pixelDecimation" : 8,
|
"pixelDecimation" : 8,
|
||||||
"cropLeft" : 0,
|
"cropLeft" : 0,
|
||||||
"cropRight" : 0,
|
"cropRight" : 0,
|
||||||
"cropTop" : 0,
|
"cropTop" : 0,
|
||||||
"cropBottom" : 0,
|
"cropBottom" : 0
|
||||||
"display" : 0
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"blackborderdetector" :
|
"blackborderdetector" :
|
||||||
@ -177,9 +188,11 @@
|
|||||||
|
|
||||||
"instCapture" :
|
"instCapture" :
|
||||||
{
|
{
|
||||||
"systemEnable" : true,
|
"systemEnable" : false,
|
||||||
|
"systemGrabberDevice" : "NONE",
|
||||||
"systemPriority" : 250,
|
"systemPriority" : 250,
|
||||||
"v4lEnable" : false,
|
"v4lEnable" : false,
|
||||||
|
"v4lGrabberDevice" : "NONE",
|
||||||
"v4lPriority" : 240
|
"v4lPriority" : 240
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Note: call the script with `./docker-compile.sh -h` for more options.
|
|||||||
```console
|
```console
|
||||||
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh -i rpi-raspbian
|
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh -i rpi-raspbian
|
||||||
```
|
```
|
||||||
**Raspbian Buster**
|
**Raspbian Buster/Raspberry Pi OS**
|
||||||
```console
|
```console
|
||||||
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh -i rpi-raspbian -t buster
|
wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/docker-compile.sh && chmod +x *.sh && ./docker-compile.sh -i rpi-raspbian -t buster
|
||||||
```
|
```
|
||||||
@ -58,7 +58,7 @@ cd $HYPERION_HOME
|
|||||||
|
|
||||||
```console
|
```console
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5x11extras5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-image0-dev libxcb-util0-dev libxcb-shm0-dev libxcb-render0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libssl-dev zlib1g-dev
|
sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5x11extras5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-image0-dev libxcb-util0-dev libxcb-shm0-dev libxcb-render0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libturbojpeg0-dev libssl-dev zlib1g-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**on RPI you need the videocore IV headers**
|
**on RPI you need the videocore IV headers**
|
||||||
@ -83,7 +83,7 @@ See [AUR](https://aur.archlinux.org/packages/?O=0&SeB=nd&K=hyperion&outdated=&SB
|
|||||||
The following dependencies are needed to build hyperion.ng on fedora.
|
The following dependencies are needed to build hyperion.ng on fedora.
|
||||||
```console
|
```console
|
||||||
sudo dnf -y groupinstall "Development Tools"
|
sudo dnf -y groupinstall "Development Tools"
|
||||||
sudo dnf install python3-devel qt-devel qt5-qtbase-devel qt5-qtserialport-devel libjpeg-devel xrandr xcb-util-image-devel qt5-qtx11extras-devel turbojpeg-devel libusb-devel avahi-libs avahi-compat-libdns_sd-devel xcb-util-devel dbus-devel openssl-devel fedora-packager rpmdevtools gcc libcec-devel
|
sudo dnf install python3-devel qt-devel qt5-qtbase-devel qt5-qtserialport-devel xrandr xcb-util-image-devel qt5-qtx11extras-devel turbojpeg-devel libusb-devel avahi-libs avahi-compat-libdns_sd-devel xcb-util-devel dbus-devel openssl-devel fedora-packager rpmdevtools gcc libcec-devel
|
||||||
```
|
```
|
||||||
After installing the dependencies, you can continue with the compile instructions later on this page (the more detailed way..).
|
After installing the dependencies, you can continue with the compile instructions later on this page (the more detailed way..).
|
||||||
|
|
||||||
@ -98,18 +98,20 @@ brew install qt5 python3 cmake libusb doxygen zlib
|
|||||||
## Windows (WIP)
|
## Windows (WIP)
|
||||||
We assume a 64bit Windows 10. Install the following;
|
We assume a 64bit Windows 10. Install the following;
|
||||||
- [Git](https://git-scm.com/downloads) (Check: Add to PATH)
|
- [Git](https://git-scm.com/downloads) (Check: Add to PATH)
|
||||||
- [CMake (Windows win64-x64 Installer)](https://cmake.org/download/) (Check: Add to PATH)
|
- [CMake (Windows win64-x64 installer)](https://cmake.org/download/) (Check: Add to PATH)
|
||||||
- [Visual Studio 2019 Build Tools](https://go.microsoft.com/fwlink/?linkid=840931) ([direct link](https://aka.ms/vs/16/release/vs_buildtools.exe))
|
- [Visual Studio 2019 Build Tools](https://go.microsoft.com/fwlink/?linkid=840931) ([direct link](https://aka.ms/vs/16/release/vs_buildtools.exe))
|
||||||
- Select C++ Buildtools
|
- Select C++ Buildtools
|
||||||
- On the right, just select `MSVC v142 VS 2019 C++ x64/x86-Buildtools` and latest `Windows 10 SDK`. Everything else is not needed.
|
- On the right, just select `MSVC v142 VS 2019 C++ x64/x86-Buildtools` and latest `Windows 10 SDK`. Everything else is not needed.
|
||||||
- [Win64 OpenSSL v1.1.1h](https://slproweb.com/products/Win32OpenSSL.html) ([direct link](https://slproweb.com/download/Win64OpenSSL-1_1_1h.exe))
|
- [Win64 OpenSSL v1.1.1k](https://slproweb.com/products/Win32OpenSSL.html) ([direct link](https://slproweb.com/download/Win64OpenSSL-1_1_1k.exe))
|
||||||
- [Python 3 (Windows x86-64 executable installer)](https://www.python.org/downloads/windows/) (Check: Add to PATH and Debug Symbols)
|
- [Python 3 (Windows x86-64 executable installer)](https://www.python.org/downloads/windows/) (Check: Add to PATH and Debug Symbols)
|
||||||
- Open a console window and execute `pip install aqtinstall`.
|
- Open a console window and execute `pip install aqtinstall`.
|
||||||
- Now we can download Qt to _C:\Qt_ `mkdir c:\Qt && aqt install -O c:\Qt 5.15.0 windows desktop win64_msvc2019_64`
|
- Now we can download Qt to _C:\Qt_ `mkdir c:\Qt && aqt install -O c:\Qt 5.15.0 windows desktop win64_msvc2019_64`
|
||||||
|
- [libjpeg-turbo SDK for Visual C++](https://sourceforge.net/projects/libjpeg-turbo/files/)
|
||||||
|
- Download the latest 64bit installer (currently `libjpeg-turbo-2.1.0-vc64.exe`) and install to its default location `C:\libjpeg-turbo64`.
|
||||||
|
|
||||||
### Optional:
|
### Optional:
|
||||||
- For DirectX9 grabber:
|
- For DirectX9 grabber:
|
||||||
- DirectX Software Development Kit. The download link is no longer available, so you will have to search for it yourself.
|
- [DirectX Software Development Kit](https://www.microsoft.com/en-us/download/details.aspx?id=6812) ([direct link](https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe))
|
||||||
- For package creation:
|
- For package creation:
|
||||||
- [NSIS 3.x](https://sourceforge.net/projects/nsis/files/NSIS%203/) ([direct link](https://sourceforge.net/projects/nsis/files/latest/download))
|
- [NSIS 3.x](https://sourceforge.net/projects/nsis/files/NSIS%203/) ([direct link](https://sourceforge.net/projects/nsis/files/latest/download))
|
||||||
|
|
||||||
|
@ -278,6 +278,12 @@ private:
|
|||||||
///
|
///
|
||||||
void handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan);
|
void handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan);
|
||||||
|
|
||||||
|
/// Handle an incoming JSON message regarding Input Sources (Grabbers)
|
||||||
|
///
|
||||||
|
/// @param message the incoming message
|
||||||
|
///
|
||||||
|
void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle an incoming JSON message of unknown type
|
/// Handle an incoming JSON message of unknown type
|
||||||
///
|
///
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
QString getName() const { return _name; }
|
QString getName() const { return _name; }
|
||||||
|
|
||||||
int getTimeout() const {return _timeout; }
|
int getTimeout() const {return _timeout; }
|
||||||
|
bool isEndless() const { return _isEndless; }
|
||||||
|
|
||||||
QJsonObject getArgs() const { return _args; }
|
QJsonObject getArgs() const { return _args; }
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ private:
|
|||||||
const int _priority;
|
const int _priority;
|
||||||
|
|
||||||
const int _timeout;
|
const int _timeout;
|
||||||
|
bool _isEndless;
|
||||||
|
|
||||||
const QString _script;
|
const QString _script;
|
||||||
const QString _name;
|
const QString _name;
|
||||||
|
@ -14,12 +14,16 @@ public:
|
|||||||
///
|
///
|
||||||
/// Construct a AmlogicGrabber that will capture snapshots with specified dimensions.
|
/// Construct a AmlogicGrabber that will capture snapshots with specified dimensions.
|
||||||
///
|
///
|
||||||
/// @param[in] width The width of the captured screenshot
|
|
||||||
/// @param[in] height The heigth of the captured screenshot
|
|
||||||
///
|
///
|
||||||
AmlogicGrabber(unsigned width, unsigned height);
|
AmlogicGrabber();
|
||||||
~AmlogicGrabber() override;
|
~AmlogicGrabber() override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Setup a new capture screen, will free the previous one
|
||||||
|
/// @return True on success, false if no screen is found
|
||||||
|
///
|
||||||
|
bool setupScreen();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// 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
|
/// provided image should have the same dimensions as the configured values (_width and
|
||||||
@ -31,14 +35,51 @@ public:
|
|||||||
///
|
///
|
||||||
int grabFrame(Image<ColorRgb> & image);
|
int grabFrame(Image<ColorRgb> & image);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover AmLogic screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the video mode (2D/3D)
|
||||||
|
/// @param[in] mode The new video mode
|
||||||
|
///
|
||||||
|
void setVideoMode(VideoMode mode) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new crop values, on errors reject the values
|
||||||
|
///
|
||||||
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new width/height values, on errors (collide with cropping) reject the values
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
bool setWidthHeight(int width, int height) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new framerate
|
||||||
|
/// @param fps framesPerSecond
|
||||||
|
///
|
||||||
|
bool setFramerate(int fps) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new pixelDecimation
|
||||||
|
///
|
||||||
|
bool setPixelDecimation(int pixelDecimation) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Returns true if video is playing over the amlogic chip
|
* Returns true if video is playing over the amlogic chip
|
||||||
* @return True if video is playing else false
|
* @return True if video is playing else false
|
||||||
*/
|
*/
|
||||||
bool isVideoPlaying();
|
bool isVideoPlaying();
|
||||||
void closeDev(int &fd);
|
void closeDevice(int &fd);
|
||||||
bool openDev(int &fd, const char* dev);
|
bool openDevice(int &fd, const char* dev);
|
||||||
|
|
||||||
int grabFrame_amvideocap(Image<ColorRgb> & image);
|
int grabFrame_amvideocap(Image<ColorRgb> & image);
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#include <grabber/AmlogicGrabber.h>
|
#include <grabber/AmlogicGrabber.h>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the
|
/// The Amlogic uses an instance of the AmlogicGrabber to obtain ImageRgb's from the
|
||||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and committed to the
|
||||||
/// attached Hyperion.
|
/// attached Hyperion.
|
||||||
///
|
///
|
||||||
class AmlogicWrapper : public GrabberWrapper
|
class AmlogicWrapper : public GrabberWrapper
|
||||||
@ -13,12 +13,14 @@ class AmlogicWrapper : public GrabberWrapper
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
|
/// Constructs the Amlogic frame grabber
|
||||||
///
|
///
|
||||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
||||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
///
|
///
|
||||||
AmlogicWrapper(unsigned grabWidth, unsigned grabHeight);
|
AmlogicWrapper(int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
|
||||||
|
int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
|
@ -8,8 +8,14 @@
|
|||||||
|
|
||||||
// Hyperion-utils includes
|
// Hyperion-utils includes
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
|
#include <hyperion/GrabberWrapper.h>
|
||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
|
|
||||||
|
// qt includes
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief The DirectX9 capture implementation
|
/// @brief The DirectX9 capture implementation
|
||||||
///
|
///
|
||||||
@ -17,33 +23,32 @@ class DirectXGrabber : public Grabber
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
|
DirectXGrabber(int display=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
||||||
|
|
||||||
virtual ~DirectXGrabber();
|
virtual ~DirectXGrabber();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// 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
|
/// provided image should have the same dimensions as the configured values (_width and _height)
|
||||||
/// _height)
|
|
||||||
///
|
///
|
||||||
/// @param[out] image The snapped screenshot
|
/// @param[out] image The snapped screenshot
|
||||||
///
|
///
|
||||||
virtual int grabFrame(Image<ColorRgb> & image);
|
int grabFrame(Image<ColorRgb> & image);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Set a new video mode
|
/// @brief Set a new video mode
|
||||||
///
|
///
|
||||||
virtual void setVideoMode(VideoMode mode);
|
void setVideoMode(VideoMode mode) override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new width/height values, overwrite Grabber.h implementation
|
/// @brief Apply new width/height values, overwrite Grabber.h implementation
|
||||||
///
|
///
|
||||||
virtual bool setWidthHeight(int width, int height) { return true; };
|
bool setWidthHeight(int /* width */, int /*height*/) override { return true; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation
|
/// @brief Apply new pixelDecimation
|
||||||
///
|
///
|
||||||
virtual void setPixelDecimation(int pixelDecimation);
|
bool setPixelDecimation(int pixelDecimation) override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the crop values
|
/// Set the crop values
|
||||||
@ -52,12 +57,20 @@ public:
|
|||||||
/// @param cropTop Top pixel crop
|
/// @param cropTop Top pixel crop
|
||||||
/// @param cropBottom Bottom pixel crop
|
/// @param cropBottom Bottom pixel crop
|
||||||
///
|
///
|
||||||
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply display index
|
/// @brief Apply display index
|
||||||
///
|
///
|
||||||
void setDisplayIndex(int index) override;
|
bool setDisplayIndex(int index) override;
|
||||||
|
|
||||||
|
/// @brief Discover QT screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
@ -72,7 +85,6 @@ private:
|
|||||||
void freeResources();
|
void freeResources();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _pixelDecimation;
|
|
||||||
unsigned _display;
|
unsigned _display;
|
||||||
unsigned _displayWidth;
|
unsigned _displayWidth;
|
||||||
unsigned _displayHeight;
|
unsigned _displayHeight;
|
||||||
|
@ -9,15 +9,21 @@ public:
|
|||||||
///
|
///
|
||||||
/// Constructs the DirectX grabber with a specified grab size and update rate.
|
/// Constructs the DirectX grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
/// @param[in] display Display to be grabbed
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
/// @param[in] cropLeft Remove from left [pixels]
|
/// @param[in] cropLeft Remove from left [pixels]
|
||||||
/// @param[in] cropRight Remove from right [pixels]
|
/// @param[in] cropRight Remove from right [pixels]
|
||||||
/// @param[in] cropTop Remove from top [pixels]
|
/// @param[in] cropTop Remove from top [pixels]
|
||||||
/// @param[in] cropBottom Remove from bottom [pixels]
|
/// @param[in] cropBottom Remove from bottom [pixels]
|
||||||
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
|
||||||
/// @param[in] display The display used[index]
|
|
||||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
|
||||||
///
|
///
|
||||||
DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz);
|
DirectXWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int display=0,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
|
||||||
|
int cropLeft=0, int cropRight=0,
|
||||||
|
int cropTop=0, int cropBottom=0
|
||||||
|
);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Destructor of this DirectX grabber. Releases any claimed resources.
|
/// Destructor of this DirectX grabber. Releases any claimed resources.
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a
|
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a downsized and scaled resolution.
|
||||||
/// downsized and scaled resolution.
|
|
||||||
///
|
///
|
||||||
class DispmanxFrameGrabber : public Grabber
|
class DispmanxFrameGrabber : public Grabber
|
||||||
{
|
{
|
||||||
@ -23,12 +22,16 @@ public:
|
|||||||
///
|
///
|
||||||
/// Construct a DispmanxFrameGrabber that will capture snapshots with specified dimensions.
|
/// Construct a DispmanxFrameGrabber that will capture snapshots with specified dimensions.
|
||||||
///
|
///
|
||||||
/// @param[in] width The width of the captured screenshot
|
DispmanxFrameGrabber();
|
||||||
/// @param[in] height The heigth of the captured screenshot
|
|
||||||
///
|
|
||||||
DispmanxFrameGrabber(unsigned width, unsigned height);
|
|
||||||
~DispmanxFrameGrabber() override;
|
~DispmanxFrameGrabber() override;
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Setup a new capture screen, will free the previous one
|
||||||
|
/// @return True on success, false if no screen is found
|
||||||
|
///
|
||||||
|
bool setupScreen();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||||
@ -44,13 +47,24 @@ public:
|
|||||||
///@brief Set new width and height for dispmanx, overwrite Grabber.h impl
|
///@brief Set new width and height for dispmanx, overwrite Grabber.h impl
|
||||||
bool setWidthHeight(int width, int height) override;
|
bool setWidthHeight(int width, int height) override;
|
||||||
|
|
||||||
|
QSize getScreenSize(int display=0) const;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover DispmanX screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
/// Updates the frame-grab flags as used by the VC library for frame grabbing
|
/// Updates the frame-grab flags as used by the VC library for frame grabbing
|
||||||
///
|
///
|
||||||
/// @param vc_flags The snapshot grabbing mask
|
/// @param vc_flags The snapshot grabbing mask
|
||||||
///
|
///
|
||||||
void setFlags(int vc_flags);
|
void setFlags(DISPMANX_TRANSFORM_T vc_flags);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief free _vc_resource and captureBuffer
|
/// @brief free _vc_resource and captureBuffer
|
||||||
@ -63,11 +77,11 @@ private:
|
|||||||
/// Handle to the resource for storing the captured snapshot
|
/// Handle to the resource for storing the captured snapshot
|
||||||
DISPMANX_RESOURCE_HANDLE_T _vc_resource;
|
DISPMANX_RESOURCE_HANDLE_T _vc_resource;
|
||||||
|
|
||||||
/// Rectangle of the captured resource that is transfered to user space
|
/// Rectangle of the captured resource that is transferred to user space
|
||||||
VC_RECT_T _rectangle;
|
VC_RECT_T _rectangle;
|
||||||
|
|
||||||
/// Flags (transforms) for creating snapshots
|
/// Flags (transforms) for creating snapshots
|
||||||
int _vc_flags;
|
DISPMANX_TRANSFORM_T _vc_flags;
|
||||||
|
|
||||||
// temp buffer when capturing with unsupported pitch size or
|
// temp buffer when capturing with unsupported pitch size or
|
||||||
// when we need to crop the image
|
// when we need to crop the image
|
||||||
@ -78,5 +92,4 @@ private:
|
|||||||
|
|
||||||
// rgba output buffer
|
// rgba output buffer
|
||||||
Image<ColorRgba> _image_rgba;
|
Image<ColorRgba> _image_rgba;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@ typedef int DISPMANX_TRANSFORM_T;
|
|||||||
struct DISPMANX_MODEINFO_T {
|
struct DISPMANX_MODEINFO_T {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
uint32_t display_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VC_RECT_T {
|
struct VC_RECT_T {
|
||||||
@ -34,6 +35,6 @@ DISPMANX_RESOURCE_HANDLE_T vc_dispmanx_resource_create(int,int width,int height,
|
|||||||
void vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T resource);
|
void vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T resource);
|
||||||
int vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T vc_resource, VC_RECT_T *rectangle, void* capturePtr, unsigned capturePitch);
|
int vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T vc_resource, VC_RECT_T *rectangle, void* capturePtr, unsigned capturePitch);
|
||||||
void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, int height);
|
void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, int height);
|
||||||
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags);
|
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, DISPMANX_TRANSFORM_T vc_flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,11 +16,14 @@ public:
|
|||||||
///
|
///
|
||||||
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
|
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
|
||||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
///
|
///
|
||||||
DispmanxWrapper(unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
|
DispmanxWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
|
||||||
|
);
|
||||||
|
|
||||||
|
bool screenInit();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
|
176
include/grabber/EncoderThread.h
Normal file
176
include/grabber/EncoderThread.h
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
// util includes
|
||||||
|
#include <utils/PixelFormat.h>
|
||||||
|
#include <utils/ImageResampler.h>
|
||||||
|
|
||||||
|
// Determine the cmake options
|
||||||
|
#include <HyperionConfig.h>
|
||||||
|
|
||||||
|
// Turbo JPEG decoder
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
#include <turbojpeg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Encoder thread for USB devices
|
||||||
|
class EncoderThread : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EncoderThread();
|
||||||
|
~EncoderThread();
|
||||||
|
|
||||||
|
void setup(
|
||||||
|
PixelFormat pixelFormat, uint8_t* sharedData,
|
||||||
|
int size, int width, int height, int lineLength,
|
||||||
|
unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
|
||||||
|
VideoMode videoMode, FlipMode flipMode, int pixelDecimation);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
bool isBusy() { return _busy; }
|
||||||
|
QAtomicInt _busy = false;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newFrame(const Image<ColorRgb>& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PixelFormat _pixelFormat;
|
||||||
|
uint8_t* _localData,
|
||||||
|
*_flipBuffer;
|
||||||
|
int _scalingFactorsCount,
|
||||||
|
_width,
|
||||||
|
_height,
|
||||||
|
_lineLength,
|
||||||
|
_currentFrame,
|
||||||
|
_pixelDecimation;
|
||||||
|
unsigned long _size;
|
||||||
|
unsigned _cropLeft,
|
||||||
|
_cropTop,
|
||||||
|
_cropBottom,
|
||||||
|
_cropRight;
|
||||||
|
FlipMode _flipMode;
|
||||||
|
ImageResampler _imageResampler;
|
||||||
|
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
tjhandle _transform, _decompress;
|
||||||
|
tjscalingfactor* _scalingFactors;
|
||||||
|
tjtransform* _xform;
|
||||||
|
|
||||||
|
void processImageMjpeg();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TThread> class Thread : public QThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TThread *_thread;
|
||||||
|
explicit Thread(TThread *thread, QObject *parent = nullptr)
|
||||||
|
: QThread(parent)
|
||||||
|
, _thread(thread)
|
||||||
|
{
|
||||||
|
_thread->moveToThread(this);
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Thread()
|
||||||
|
{
|
||||||
|
quit();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
EncoderThread* thread() const { return qobject_cast<EncoderThread*>(_thread); }
|
||||||
|
|
||||||
|
void setup(
|
||||||
|
PixelFormat pixelFormat, uint8_t* sharedData,
|
||||||
|
int size, int width, int height, int lineLength,
|
||||||
|
unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
|
||||||
|
VideoMode videoMode, FlipMode flipMode, int pixelDecimation)
|
||||||
|
{
|
||||||
|
auto encThread = qobject_cast<EncoderThread*>(_thread);
|
||||||
|
if (encThread != nullptr)
|
||||||
|
encThread->setup(pixelFormat, sharedData,
|
||||||
|
size, width, height, lineLength,
|
||||||
|
cropLeft, cropTop, cropBottom, cropRight,
|
||||||
|
videoMode, flipMode, pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBusy()
|
||||||
|
{
|
||||||
|
auto encThread = qobject_cast<EncoderThread*>(_thread);
|
||||||
|
if (encThread != nullptr)
|
||||||
|
return encThread->isBusy();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process()
|
||||||
|
{
|
||||||
|
auto encThread = qobject_cast<EncoderThread*>(_thread);
|
||||||
|
if (encThread != nullptr)
|
||||||
|
encThread->process();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
QThread::run();
|
||||||
|
delete _thread;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class EncoderThreadManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EncoderThreadManager(QObject *parent = nullptr)
|
||||||
|
: QObject(parent)
|
||||||
|
, _threadCount(qMax(QThread::idealThreadCount(), 1))
|
||||||
|
, _threads(nullptr)
|
||||||
|
{
|
||||||
|
_threads = new Thread<EncoderThread>*[_threadCount];
|
||||||
|
for (int i = 0; i < _threadCount; i++)
|
||||||
|
{
|
||||||
|
_threads[i] = new Thread<EncoderThread>(new EncoderThread, this);
|
||||||
|
_threads[i]->setObjectName("Encoder " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~EncoderThreadManager()
|
||||||
|
{
|
||||||
|
if (_threads != nullptr)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < _threadCount; i++)
|
||||||
|
{
|
||||||
|
_threads[i]->deleteLater();
|
||||||
|
_threads[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] _threads;
|
||||||
|
_threads = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
if (_threads != nullptr)
|
||||||
|
for (int i = 0; i < _threadCount; i++)
|
||||||
|
connect(_threads[i]->thread(), &EncoderThread::newFrame, this, &EncoderThreadManager::newFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
if (_threads != nullptr)
|
||||||
|
for(int i = 0; i < _threadCount; i++)
|
||||||
|
disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _threadCount;
|
||||||
|
Thread<EncoderThread>** _threads;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newFrame(const Image<ColorRgb>& data);
|
||||||
|
};
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <linux/fb.h>
|
||||||
|
|
||||||
// Utils includes
|
// Utils includes
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
@ -14,10 +16,10 @@ public:
|
|||||||
/// Construct a FramebufferFrameGrabber that will capture snapshots with specified dimensions.
|
/// Construct a FramebufferFrameGrabber that will capture snapshots with specified dimensions.
|
||||||
///
|
///
|
||||||
/// @param[in] device The framebuffer device name/path
|
/// @param[in] device The framebuffer device name/path
|
||||||
/// @param[in] width The width of the captured screenshot
|
|
||||||
/// @param[in] height The heigth of the captured screenshot
|
|
||||||
///
|
///
|
||||||
FramebufferFrameGrabber(const QString & device, unsigned width, unsigned height);
|
FramebufferFrameGrabber(const QString & device="/dev/fb0");
|
||||||
|
|
||||||
|
~FramebufferFrameGrabber() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||||
@ -30,11 +32,42 @@ public:
|
|||||||
int grabFrame(Image<ColorRgb> & image);
|
int grabFrame(Image<ColorRgb> & image);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Overwrite Grabber.h implememtation
|
/// @brief Setup a new capture screen, will free the previous one
|
||||||
|
/// @return True on success, false if no screen is found
|
||||||
///
|
///
|
||||||
void setDevicePath(const QString& path) override;
|
bool setupScreen();
|
||||||
|
|
||||||
|
|
||||||
|
QSize getScreenSize() const;
|
||||||
|
QSize getScreenSize(const QString& device) const;
|
||||||
|
|
||||||
|
///
|
||||||
|
///@brief Set new width and height for framegrabber, overwrite Grabber.h implementation
|
||||||
|
bool setWidthHeight(int width, int height) override;
|
||||||
|
|
||||||
|
QString getPath() const {return _fbDevice;}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover Framebuffer screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool openDevice();
|
||||||
|
bool closeDevice();
|
||||||
|
bool getScreenInfo();
|
||||||
|
|
||||||
/// Framebuffer device e.g. /dev/fb0
|
/// Framebuffer device e.g. /dev/fb0
|
||||||
QString _fbDevice;
|
QString _fbDevice;
|
||||||
|
|
||||||
|
int _fbfd;
|
||||||
|
struct fb_var_screeninfo _varInfo;
|
||||||
|
struct fb_fix_screeninfo _fixInfo;
|
||||||
|
|
||||||
|
PixelFormat _pixelFormat;
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the
|
/// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the
|
||||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and committed to the
|
||||||
/// attached Hyperion.
|
/// attached Hyperion.
|
||||||
///
|
///
|
||||||
class FramebufferWrapper: public GrabberWrapper
|
class FramebufferWrapper: public GrabberWrapper
|
||||||
@ -15,12 +15,14 @@ public:
|
|||||||
///
|
///
|
||||||
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
|
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
/// @param[in] device Framebuffer device name/path
|
|
||||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
|
||||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
|
||||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
/// @param[in] device Framebuffer device name/path
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
///
|
///
|
||||||
FramebufferWrapper(const QString & device, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
|
FramebufferWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
const QString & device = "/dev/fb0",
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
|
||||||
|
);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
|
129
include/grabber/MFGrabber.h
Normal file
129
include/grabber/MFGrabber.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Windows include
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
// COM includes
|
||||||
|
#include <Guiddef.h>
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QObject>
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMultiMap>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
// utils includes
|
||||||
|
#include <utils/PixelFormat.h>
|
||||||
|
#include <utils/Components.h>
|
||||||
|
#include <hyperion/Grabber.h>
|
||||||
|
|
||||||
|
// decoder thread includes
|
||||||
|
#include <grabber/EncoderThread.h>
|
||||||
|
|
||||||
|
/// Forward class declaration
|
||||||
|
class SourceReaderCB;
|
||||||
|
/// Forward struct declaration
|
||||||
|
struct IMFSourceReader;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Media Foundation capture class
|
||||||
|
///
|
||||||
|
|
||||||
|
class MFGrabber : public Grabber
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SourceReaderCB;
|
||||||
|
public:
|
||||||
|
struct DeviceProperties
|
||||||
|
{
|
||||||
|
QString symlink = QString();
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int fps = 0;
|
||||||
|
int numerator = 0;
|
||||||
|
int denominator = 0;
|
||||||
|
PixelFormat pf = PixelFormat::NO_CHANGE;
|
||||||
|
GUID guid = GUID_NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeviceControls
|
||||||
|
{
|
||||||
|
QString property = QString();
|
||||||
|
int minValue = 0;
|
||||||
|
int maxValue = 0;
|
||||||
|
int step = 0;
|
||||||
|
int default = 0;
|
||||||
|
int currentValue = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
MFGrabber();
|
||||||
|
~MFGrabber() override;
|
||||||
|
|
||||||
|
void receive_image(const void *frameImageBuffer, int size);
|
||||||
|
void setDevice(const QString& device);
|
||||||
|
bool setInput(int input) override;
|
||||||
|
bool setWidthHeight(int width, int height) override;
|
||||||
|
void setEncoding(QString enc);
|
||||||
|
void setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
|
||||||
|
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold);
|
||||||
|
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
|
||||||
|
void setSignalDetectionEnable(bool enable);
|
||||||
|
bool reload(bool force = false);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover available Media Foundation USB devices (for configuration).
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
/// @return A JSON structure holding a list of USB devices found
|
||||||
|
///
|
||||||
|
QJsonArray discover(const QJsonObject& params);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool prepare();
|
||||||
|
bool start();
|
||||||
|
void stop();
|
||||||
|
void newThreadFrame(Image<ColorRgb> image);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newFrame(const Image<ColorRgb> & image);
|
||||||
|
void readError(const char* err);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool init();
|
||||||
|
void uninit();
|
||||||
|
HRESULT init_device(QString device, DeviceProperties props);
|
||||||
|
void enumVideoCaptureDevices();
|
||||||
|
void start_capturing();
|
||||||
|
void process_image(const void *frameImageBuffer, int size);
|
||||||
|
|
||||||
|
QString _currentDeviceName,
|
||||||
|
_newDeviceName;
|
||||||
|
QMap<QString, QList<DeviceProperties>> _deviceProperties;
|
||||||
|
QMap<QString, QList<DeviceControls>> _deviceControls;
|
||||||
|
HRESULT _hr;
|
||||||
|
IMFSourceReader* _sourceReader;
|
||||||
|
SourceReaderCB* _sourceReaderCB;
|
||||||
|
EncoderThreadManager* _threadManager;
|
||||||
|
PixelFormat _pixelFormat,
|
||||||
|
_pixelFormatConfig;
|
||||||
|
int _lineLength,
|
||||||
|
_frameByteSize,
|
||||||
|
_noSignalCounterThreshold,
|
||||||
|
_noSignalCounter,
|
||||||
|
_brightness,
|
||||||
|
_contrast,
|
||||||
|
_saturation,
|
||||||
|
_hue;
|
||||||
|
QAtomicInt _currentFrame;
|
||||||
|
ColorRgb _noSignalThresholdColor;
|
||||||
|
bool _signalDetectionEnabled,
|
||||||
|
_noSignalDetected,
|
||||||
|
_initialized,
|
||||||
|
_reload;
|
||||||
|
double _x_frac_min,
|
||||||
|
_y_frac_min,
|
||||||
|
_x_frac_max,
|
||||||
|
_y_frac_max;
|
||||||
|
};
|
@ -21,12 +21,17 @@ public:
|
|||||||
/// Construct a OsxFrameGrabber that will capture snapshots with specified dimensions.
|
/// Construct a OsxFrameGrabber that will capture snapshots with specified dimensions.
|
||||||
///
|
///
|
||||||
/// @param[in] display The index of the display to capture
|
/// @param[in] display The index of the display to capture
|
||||||
/// @param[in] width The width of the captured screenshot
|
|
||||||
/// @param[in] height The heigth of the captured screenshot
|
|
||||||
///
|
///
|
||||||
OsxFrameGrabber(unsigned display, unsigned width, unsigned height);
|
OsxFrameGrabber(int display=kCGDirectMainDisplay);
|
||||||
~OsxFrameGrabber() override;
|
~OsxFrameGrabber() override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Setup a new capture screen, will free the previous one
|
||||||
|
/// @return True on success, false if no screen is found
|
||||||
|
///
|
||||||
|
bool setupDisplay();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// 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
|
/// provided image should have the same dimensions as the configured values (_width and
|
||||||
@ -40,12 +45,21 @@ public:
|
|||||||
///
|
///
|
||||||
/// @brief Overwrite Grabber.h implementation
|
/// @brief Overwrite Grabber.h implementation
|
||||||
///
|
///
|
||||||
void setDisplayIndex(int index) override;
|
bool setDisplayIndex(int index) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover OSX screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// display
|
/// display
|
||||||
unsigned _screenIndex;
|
int _screenIndex;
|
||||||
|
|
||||||
/// Reference to the captured diaplay
|
/// Reference to the captured display
|
||||||
CGDirectDisplayID _display;
|
CGDirectDisplayID _display;
|
||||||
};
|
};
|
||||||
|
@ -5,21 +5,79 @@
|
|||||||
* this is a mock up for compiling and testing osx wrapper on no osx platform.
|
* this is a mock up for compiling and testing osx wrapper on no osx platform.
|
||||||
* this will show a test image and rotate the colors.
|
* this will show a test image and rotate the colors.
|
||||||
*
|
*
|
||||||
|
* see https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.8.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <utils/Image.h>
|
#include <utils/Image.h>
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
|
|
||||||
typedef int CGDirectDisplayID;
|
enum _CGError {
|
||||||
|
kCGErrorSuccess = 0,
|
||||||
|
kCGErrorFailure = 1000,
|
||||||
|
kCGErrorIllegalArgument = 1001,
|
||||||
|
kCGErrorInvalidConnection = 1002,
|
||||||
|
kCGErrorInvalidContext = 1003,
|
||||||
|
kCGErrorCannotComplete = 1004,
|
||||||
|
kCGErrorNotImplemented = 1006,
|
||||||
|
kCGErrorRangeCheck = 1007,
|
||||||
|
kCGErrorTypeCheck = 1008,
|
||||||
|
kCGErrorInvalidOperation = 1010,
|
||||||
|
kCGErrorNoneAvailable = 1011,
|
||||||
|
|
||||||
|
/* Obsolete errors. */
|
||||||
|
kCGErrorNameTooLong = 1005,
|
||||||
|
kCGErrorNoCurrentPoint = 1009,
|
||||||
|
kCGErrorApplicationRequiresNewerSystem = 1015,
|
||||||
|
kCGErrorApplicationNotPermittedToExecute = 1016,
|
||||||
|
kCGErrorApplicationIncorrectExecutableFormatFound = 1023,
|
||||||
|
kCGErrorApplicationIsLaunching = 1024,
|
||||||
|
kCGErrorApplicationAlreadyRunning = 1025,
|
||||||
|
kCGErrorApplicationCanOnlyBeRunInOneSessionAtATime = 1026,
|
||||||
|
kCGErrorClassicApplicationsMustBeLaunchedByClassic = 1027,
|
||||||
|
kCGErrorForkFailed = 1028,
|
||||||
|
kCGErrorRetryRegistration = 1029,
|
||||||
|
kCGErrorFirst = 1000,
|
||||||
|
kCGErrorLast = 1029
|
||||||
|
};
|
||||||
|
typedef int32_t CGError;
|
||||||
|
typedef double CGFloat;
|
||||||
|
|
||||||
|
struct CGSize {
|
||||||
|
CGFloat width;
|
||||||
|
CGFloat height;
|
||||||
|
};
|
||||||
|
typedef struct CGSize CGSize;
|
||||||
|
|
||||||
|
struct CGPoint {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
typedef struct CGPoint CGPoint;
|
||||||
|
|
||||||
|
struct CGRect {
|
||||||
|
CGPoint origin;
|
||||||
|
CGSize size;
|
||||||
|
};
|
||||||
|
typedef struct CGRect CGRect;
|
||||||
|
|
||||||
|
typedef CGError CGDisplayErr;
|
||||||
|
typedef uint32_t CGDirectDisplayID;
|
||||||
|
typedef uint32_t CGDisplayCount;;
|
||||||
|
typedef struct CGDisplayMode *CGDisplayModeRef;
|
||||||
|
|
||||||
typedef Image<ColorRgb> CGImage;
|
typedef Image<ColorRgb> CGImage;
|
||||||
typedef CGImage* CGImageRef;
|
typedef CGImage* CGImageRef;
|
||||||
typedef unsigned char CFData;
|
typedef unsigned char CFData;
|
||||||
typedef CFData* CFDataRef;
|
typedef CFData* CFDataRef;
|
||||||
typedef unsigned CGDisplayCount;
|
|
||||||
|
|
||||||
const int kCGDirectMainDisplay = 0;
|
const int kCGDirectMainDisplay = 0;
|
||||||
|
|
||||||
void CGGetActiveDisplayList(int max, CGDirectDisplayID *displays, CGDisplayCount *displayCount);
|
CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount);
|
||||||
|
CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display);
|
||||||
|
CGRect CGDisplayBounds(CGDirectDisplayID display);
|
||||||
|
void CGDisplayModeRelease(CGDisplayModeRef mode);
|
||||||
|
|
||||||
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display);
|
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display);
|
||||||
void CGImageRelease(CGImageRef image);
|
void CGImageRelease(CGImageRef image);
|
||||||
CGImageRef CGImageGetDataProvider(CGImageRef image);
|
CGImageRef CGImageGetDataProvider(CGImageRef image);
|
||||||
@ -31,4 +89,5 @@ unsigned CGImageGetBitsPerPixel(CGImageRef image);
|
|||||||
unsigned CGImageGetBytesPerRow(CGImageRef image);
|
unsigned CGImageGetBytesPerRow(CGImageRef image);
|
||||||
void CFRelease(CFDataRef imgData);
|
void CFRelease(CFDataRef imgData);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
#include <grabber/OsxFrameGrabber.h>
|
#include <grabber/OsxFrameGrabber.h>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the
|
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the displayed content.
|
||||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
|
||||||
/// attached Hyperion.
|
|
||||||
///
|
///
|
||||||
class OsxWrapper: public GrabberWrapper
|
class OsxWrapper: public GrabberWrapper
|
||||||
{
|
{
|
||||||
@ -15,12 +14,14 @@ public:
|
|||||||
///
|
///
|
||||||
/// Constructs the osx frame grabber with a specified grab size and update rate.
|
/// Constructs the osx frame grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
/// @param[in] display Index of the display to grab
|
|
||||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
|
||||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
|
||||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
/// @param[in] display Index of the display to grab
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
///
|
///
|
||||||
OsxWrapper(unsigned display, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz);
|
OsxWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int display = kCGDirectMainDisplay,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
|
||||||
|
);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
|
@ -15,14 +15,13 @@ class QtGrabber : public Grabber
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
|
QtGrabber(int display=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
||||||
|
|
||||||
~QtGrabber() override;
|
~QtGrabber() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// 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
|
/// provided image should have the same dimensions as the configured values (_width and _height)
|
||||||
/// _height)
|
|
||||||
///
|
///
|
||||||
/// @param[out] image The snapped screenshot (should be initialized with correct width and
|
/// @param[out] image The snapped screenshot (should be initialized with correct width and
|
||||||
/// height)
|
/// height)
|
||||||
@ -37,12 +36,12 @@ public:
|
|||||||
///
|
///
|
||||||
/// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions
|
/// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions
|
||||||
///
|
///
|
||||||
bool setWidthHeight(int width, int height) override { return true; }
|
bool setWidthHeight(int /*width*/, int /*height*/) override { return true; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation
|
/// @brief Apply new pixelDecimation
|
||||||
///
|
///
|
||||||
void setPixelDecimation(int pixelDecimation) override;
|
bool setPixelDecimation(int pixelDecimation) override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the crop values
|
/// Set the crop values
|
||||||
@ -51,14 +50,37 @@ public:
|
|||||||
/// @param cropTop Top pixel crop
|
/// @param cropTop Top pixel crop
|
||||||
/// @param cropBottom Bottom pixel crop
|
/// @param cropBottom Bottom pixel crop
|
||||||
///
|
///
|
||||||
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply display index
|
/// @brief Apply display index
|
||||||
///
|
///
|
||||||
void setDisplayIndex(int index) override;
|
bool setDisplayIndex(int index) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover QT screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Setup a new capture display, will free the previous one
|
||||||
|
/// @return True on success, false if no display is found
|
||||||
|
///
|
||||||
|
bool setupDisplay();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the input device.
|
||||||
|
///
|
||||||
|
/// @return Zero, on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
bool open();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief is called whenever the current _screen changes it's geometry
|
/// @brief is called whenever the current _screen changes it's geometry
|
||||||
/// @param geo The new geometry
|
/// @param geo The new geometry
|
||||||
@ -66,11 +88,6 @@ private slots:
|
|||||||
void geometryChanged(const QRect &geo);
|
void geometryChanged(const QRect &geo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
|
||||||
/// @brief Setup a new capture display, will free the previous one
|
|
||||||
/// @return True on success, false if no display is found
|
|
||||||
///
|
|
||||||
bool setupDisplay();
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Is called whenever we need new screen dimension calculations based on window geometry
|
/// @brief Is called whenever we need new screen dimension calculations based on window geometry
|
||||||
@ -84,13 +101,19 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned _display;
|
int _display;
|
||||||
int _pixelDecimation;
|
int _numberOfSDisplays;
|
||||||
unsigned _screenWidth;
|
|
||||||
unsigned _screenHeight;
|
int _calculatedWidth;
|
||||||
unsigned _src_x;
|
int _calculatedHeight;
|
||||||
unsigned _src_y;
|
int _src_x;
|
||||||
unsigned _src_x_max;
|
int _src_y;
|
||||||
unsigned _src_y_max;
|
int _src_x_max;
|
||||||
|
int _src_y_max;
|
||||||
|
bool _isWayland;
|
||||||
|
|
||||||
QScreen* _screen;
|
QScreen* _screen;
|
||||||
|
bool _isVirtual;
|
||||||
|
|
||||||
|
Logger * _logger;
|
||||||
};
|
};
|
||||||
|
@ -10,16 +10,28 @@ class QtWrapper: public GrabberWrapper
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
|
/// Constructs the QT frame grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
/// @param[in] display Display to be grabbed
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
/// @param[in] cropLeft Remove from left [pixels]
|
/// @param[in] cropLeft Remove from left [pixels]
|
||||||
/// @param[in] cropRight Remove from right [pixels]
|
/// @param[in] cropRight Remove from right [pixels]
|
||||||
/// @param[in] cropTop Remove from top [pixels]
|
/// @param[in] cropTop Remove from top [pixels]
|
||||||
/// @param[in] cropBottom Remove from bottom [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, unsigned updateRate_Hz);
|
QtWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int display=0,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
|
||||||
|
int cropLeft=0, int cropRight=0,
|
||||||
|
int cropTop=0, int cropBottom=0
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Starts the grabber which produces led values with the specified update rate
|
||||||
|
///
|
||||||
|
bool open() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
|
@ -14,30 +14,24 @@
|
|||||||
// util includes
|
// util includes
|
||||||
#include <utils/PixelFormat.h>
|
#include <utils/PixelFormat.h>
|
||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
#include <grabber/VideoStandard.h>
|
#include <hyperion/GrabberWrapper.h>
|
||||||
|
#include <utils/VideoStandard.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
#include <cec/CECEvent.h>
|
|
||||||
|
|
||||||
// general JPEG decoder includes
|
// decoder thread includes
|
||||||
#ifdef HAVE_JPEG_DECODER
|
#include <grabber/EncoderThread.h>
|
||||||
#include <QImage>
|
|
||||||
#include <QColor>
|
// Determine the cmake options
|
||||||
#endif
|
#include <HyperionConfig.h>
|
||||||
|
|
||||||
// System JPEG decoder
|
#if defined(ENABLE_CEC)
|
||||||
#ifdef HAVE_JPEG
|
#include <cec/CECEvent.h>
|
||||||
#include <jpeglib.h>
|
|
||||||
#include <csetjmp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TurboJPEG decoder
|
|
||||||
#ifdef HAVE_TURBO_JPEG
|
|
||||||
#include <turbojpeg.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///
|
||||||
/// Capture class for V4L2 devices
|
/// Capture class for V4L2 devices
|
||||||
///
|
///
|
||||||
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
|
|
||||||
class V4L2Grabber : public Grabber
|
class V4L2Grabber : public Grabber
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -46,117 +40,66 @@ public:
|
|||||||
struct DeviceProperties
|
struct DeviceProperties
|
||||||
{
|
{
|
||||||
QString name = QString();
|
QString name = QString();
|
||||||
QMultiMap<QString, int> inputs = QMultiMap<QString, int>();
|
struct InputProperties
|
||||||
QStringList resolutions = QStringList();
|
{
|
||||||
QStringList framerates = QStringList();
|
QString inputName = QString();
|
||||||
|
QList<VideoStandard> standards = QList<VideoStandard>();
|
||||||
|
struct EncodingProperties
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
QList<int> framerates = QList<int>();
|
||||||
|
};
|
||||||
|
QMultiMap<PixelFormat, EncodingProperties> encodingFormats = QMultiMap<PixelFormat, EncodingProperties>();
|
||||||
|
};
|
||||||
|
QMap<int, InputProperties> inputs = QMap<int, InputProperties>();
|
||||||
};
|
};
|
||||||
|
|
||||||
V4L2Grabber(const QString & device,
|
struct DeviceControls
|
||||||
const unsigned width,
|
{
|
||||||
const unsigned height,
|
QString property = QString();
|
||||||
const unsigned fps,
|
int minValue = 0;
|
||||||
const unsigned input,
|
int maxValue = 0;
|
||||||
VideoStandard videoStandard,
|
int step = 0;
|
||||||
PixelFormat pixelFormat,
|
int defaultValue = 0;
|
||||||
int pixelDecimation
|
int currentValue = 0;
|
||||||
);
|
};
|
||||||
|
|
||||||
|
V4L2Grabber();
|
||||||
~V4L2Grabber() override;
|
~V4L2Grabber() override;
|
||||||
|
|
||||||
QRectF getSignalDetectionOffset() const
|
|
||||||
{
|
|
||||||
return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getSignalDetectionEnabled() const { return _signalDetectionEnabled; }
|
|
||||||
bool getCecDetectionEnabled() const { return _cecDetectionEnabled; }
|
|
||||||
|
|
||||||
int grabFrame(Image<ColorRgb> &);
|
int grabFrame(Image<ColorRgb> &);
|
||||||
|
void setDevice(const QString& devicePath, const QString& deviceName);
|
||||||
///
|
|
||||||
/// @brief set new PixelDecimation value to ImageResampler
|
|
||||||
/// @param pixelDecimation The new pixelDecimation value
|
|
||||||
///
|
|
||||||
void setPixelDecimation(int pixelDecimation) override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
void setSignalThreshold(
|
|
||||||
double redSignalThreshold,
|
|
||||||
double greenSignalThreshold,
|
|
||||||
double blueSignalThreshold,
|
|
||||||
int noSignalCounterThreshold = 50) override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
void setSignalDetectionOffset(
|
|
||||||
double verticalMin,
|
|
||||||
double horizontalMin,
|
|
||||||
double verticalMax,
|
|
||||||
double horizontalMax) override;
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
void setSignalDetectionEnable(bool enable) override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
void setCecDetectionEnable(bool enable) override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
void setDeviceVideoStandard(QString device, VideoStandard videoStandard) override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
bool setInput(int input) override;
|
bool setInput(int input) override;
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
bool setWidthHeight(int width, int height) override;
|
bool setWidthHeight(int width, int height) override;
|
||||||
|
void setEncoding(QString enc);
|
||||||
|
void setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
|
||||||
|
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold = 50);
|
||||||
|
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
|
||||||
|
void setSignalDetectionEnable(bool enable);
|
||||||
|
void setCecDetectionEnable(bool enable);
|
||||||
|
bool reload(bool force = false);
|
||||||
|
|
||||||
|
QRectF getSignalDetectionOffset() const { return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); } //used from hyperion-v4l2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief overwrite Grabber.h implementation
|
/// @brief Discover available V4L2 USB devices (for configuration).
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
/// @return A JSON structure holding a list of USB devices found
|
||||||
///
|
///
|
||||||
bool setFramerate(int fps) override;
|
QJsonArray discover(const QJsonObject& params);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
QStringList getV4L2devices() const override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
QString getV4L2deviceName(const QString& devicePath) const override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
QMultiMap<QString, int> getV4L2deviceInputs(const QString& devicePath) const override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
QStringList getResolutions(const QString& devicePath) const override;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief overwrite Grabber.h implementation
|
|
||||||
///
|
|
||||||
QStringList getFramerates(const QString& devicePath) const override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
bool prepare();
|
||||||
bool start();
|
bool start();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
void newThreadFrame(Image<ColorRgb> image);
|
||||||
|
|
||||||
|
#if defined(ENABLE_CEC)
|
||||||
void handleCecEvent(CECEvent event);
|
void handleCecEvent(CECEvent event);
|
||||||
|
#endif
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newFrame(const Image<ColorRgb> & image);
|
void newFrame(const Image<ColorRgb> & image);
|
||||||
@ -166,36 +109,19 @@ private slots:
|
|||||||
int read_frame();
|
int read_frame();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getV4Ldevices();
|
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
void uninit();
|
void uninit();
|
||||||
|
|
||||||
bool open_device();
|
bool open_device();
|
||||||
|
|
||||||
void close_device();
|
void close_device();
|
||||||
|
|
||||||
void init_read(unsigned int buffer_size);
|
void init_read(unsigned int buffer_size);
|
||||||
|
|
||||||
void init_mmap();
|
void init_mmap();
|
||||||
|
|
||||||
void init_userp(unsigned int buffer_size);
|
void init_userp(unsigned int buffer_size);
|
||||||
|
|
||||||
void init_device(VideoStandard videoStandard);
|
void init_device(VideoStandard videoStandard);
|
||||||
|
|
||||||
void uninit_device();
|
void uninit_device();
|
||||||
|
|
||||||
void start_capturing();
|
void start_capturing();
|
||||||
|
|
||||||
void stop_capturing();
|
void stop_capturing();
|
||||||
|
|
||||||
bool process_image(const void *p, int size);
|
bool process_image(const void *p, int size);
|
||||||
|
|
||||||
void process_image(const uint8_t *p, int size);
|
|
||||||
|
|
||||||
int xioctl(int request, void *arg);
|
int xioctl(int request, void *arg);
|
||||||
|
|
||||||
int xioctl(int fileDescriptor, int request, void *arg);
|
int xioctl(int fileDescriptor, int request, void *arg);
|
||||||
|
|
||||||
void throw_exception(const QString & error)
|
void throw_exception(const QString & error)
|
||||||
@ -222,56 +148,28 @@ private:
|
|||||||
size_t length;
|
size_t length;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
|
||||||
struct errorManager
|
|
||||||
{
|
|
||||||
jpeg_error_mgr pub;
|
|
||||||
jmp_buf setjmp_buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void errorHandler(j_common_ptr cInfo)
|
|
||||||
{
|
|
||||||
errorManager* mgr = reinterpret_cast<errorManager*>(cInfo->err);
|
|
||||||
longjmp(mgr->setjmp_buffer, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void outputHandler(j_common_ptr cInfo)
|
|
||||||
{
|
|
||||||
// Suppress fprintf warnings.
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_decompress_struct* _decompress;
|
|
||||||
errorManager* _error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_TURBO_JPEG
|
|
||||||
tjhandle _decompress = nullptr;
|
|
||||||
int _subsamp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _deviceName;
|
QString _currentDevicePath, _currentDeviceName;
|
||||||
std::map<QString, QString> _v4lDevices;
|
EncoderThreadManager* _threadManager;
|
||||||
QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
|
QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
|
||||||
|
QMap<QString, QList<DeviceControls>> _deviceControls;
|
||||||
|
|
||||||
VideoStandard _videoStandard;
|
|
||||||
io_method _ioMethod;
|
io_method _ioMethod;
|
||||||
int _fileDescriptor;
|
int _fileDescriptor;
|
||||||
std::vector<buffer> _buffers;
|
std::vector<buffer> _buffers;
|
||||||
|
|
||||||
PixelFormat _pixelFormat;
|
PixelFormat _pixelFormat, _pixelFormatConfig;
|
||||||
int _pixelDecimation;
|
|
||||||
int _lineLength;
|
int _lineLength;
|
||||||
int _frameByteSize;
|
int _frameByteSize;
|
||||||
|
|
||||||
|
QAtomicInt _currentFrame;
|
||||||
|
|
||||||
// signal detection
|
// signal detection
|
||||||
int _noSignalCounterThreshold;
|
int _noSignalCounterThreshold;
|
||||||
ColorRgb _noSignalThresholdColor;
|
ColorRgb _noSignalThresholdColor;
|
||||||
bool _signalDetectionEnabled;
|
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected;
|
||||||
bool _cecDetectionEnabled;
|
|
||||||
bool _cecStandbyActivated;
|
|
||||||
bool _noSignalDetected;
|
|
||||||
int _noSignalCounter;
|
int _noSignalCounter;
|
||||||
|
int _brightness, _contrast, _saturation, _hue;
|
||||||
double _x_frac_min;
|
double _x_frac_min;
|
||||||
double _y_frac_min;
|
double _y_frac_min;
|
||||||
double _x_frac_max;
|
double _x_frac_max;
|
||||||
@ -279,9 +177,9 @@ private:
|
|||||||
|
|
||||||
QSocketNotifier *_streamNotifier;
|
QSocketNotifier *_streamNotifier;
|
||||||
|
|
||||||
bool _initialized;
|
bool _initialized, _reload;
|
||||||
bool _deviceAutoDiscoverEnabled;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void enumFrameIntervals(QStringList &framerates, int fileDescriptor, int pixelformat, int width, int height);
|
void enumVideoCaptureDevices();
|
||||||
|
void enumFrameIntervals(QList<int> &framerates, int fileDescriptor, int pixelformat, int width, int height);
|
||||||
};
|
};
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hyperion/GrabberWrapper.h>
|
|
||||||
#include <grabber/V4L2Grabber.h>
|
|
||||||
|
|
||||||
class V4L2Wrapper : public GrabberWrapper
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
V4L2Wrapper(const QString & device,
|
|
||||||
const unsigned grabWidth,
|
|
||||||
const unsigned grabHeight,
|
|
||||||
const unsigned fps,
|
|
||||||
const unsigned input,
|
|
||||||
VideoStandard videoStandard,
|
|
||||||
PixelFormat pixelFormat,
|
|
||||||
int pixelDecimation );
|
|
||||||
~V4L2Wrapper() override;
|
|
||||||
|
|
||||||
bool getSignalDetectionEnable() const;
|
|
||||||
bool getCecDetectionEnable() const;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool start() override;
|
|
||||||
void stop() override;
|
|
||||||
|
|
||||||
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold);
|
|
||||||
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
|
|
||||||
void setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
|
|
||||||
void setSignalDetectionEnable(bool enable);
|
|
||||||
void setCecDetectionEnable(bool enable);
|
|
||||||
void setDeviceVideoStandard(const QString& device, VideoStandard videoStandard);
|
|
||||||
void handleCecEvent(CECEvent event);
|
|
||||||
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void newFrame(const Image<ColorRgb> & image);
|
|
||||||
void readError(const char* err);
|
|
||||||
|
|
||||||
void action() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// The V4L2 grabber
|
|
||||||
V4L2Grabber _grabber;
|
|
||||||
};
|
|
47
include/grabber/VideoWrapper.h
Normal file
47
include/grabber/VideoWrapper.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <HyperionConfig.h> // Required to determine the cmake options
|
||||||
|
#include <hyperion/GrabberWrapper.h>
|
||||||
|
|
||||||
|
#if defined(ENABLE_MF)
|
||||||
|
#include <grabber/MFGrabber.h>
|
||||||
|
#elif defined(ENABLE_V4L2)
|
||||||
|
#include <grabber/V4L2Grabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_CEC)
|
||||||
|
#include <cec/CECEvent.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class VideoWrapper : public GrabberWrapper
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
VideoWrapper();
|
||||||
|
~VideoWrapper() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
#if defined(ENABLE_CEC)
|
||||||
|
void handleCecEvent(CECEvent event);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void newFrame(const Image<ColorRgb> & image);
|
||||||
|
void readError(const char* err);
|
||||||
|
|
||||||
|
void action() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The Media Foundation or V4L2 grabber
|
||||||
|
#if defined(ENABLE_MF)
|
||||||
|
MFGrabber _grabber;
|
||||||
|
#elif defined(ENABLE_V4L2)
|
||||||
|
V4L2Grabber _grabber;
|
||||||
|
#endif
|
||||||
|
};
|
@ -2,7 +2,13 @@
|
|||||||
#include <QAbstractEventDispatcher>
|
#include <QAbstractEventDispatcher>
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
// QT includes
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
|
||||||
// Hyperion-utils includes
|
// Hyperion-utils includes
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
@ -20,11 +26,13 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
|
X11Grabber(int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
||||||
|
|
||||||
~X11Grabber() override;
|
~X11Grabber() override;
|
||||||
|
|
||||||
bool Setup();
|
bool open();
|
||||||
|
|
||||||
|
bool setupDisplay();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||||
@ -50,7 +58,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation
|
/// @brief Apply new pixelDecimation
|
||||||
///
|
///
|
||||||
void setPixelDecimation(int pixelDecimation) override;
|
bool setPixelDecimation(int pixelDecimation) override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the crop values
|
/// Set the crop values
|
||||||
@ -59,22 +67,33 @@ public:
|
|||||||
/// @param cropTop Top pixel crop
|
/// @param cropTop Top pixel crop
|
||||||
/// @param cropBottom Bottom pixel crop
|
/// @param cropBottom Bottom pixel crop
|
||||||
///
|
///
|
||||||
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover X11 screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable, _XRandRAvailable;
|
|
||||||
|
|
||||||
XImage* _xImage;
|
void freeResources();
|
||||||
XShmSegmentInfo _shminfo;
|
void setupResources();
|
||||||
|
|
||||||
/// Reference to the X11 display (nullptr if not opened)
|
/// Reference to the X11 display (nullptr if not opened)
|
||||||
Display* _x11Display;
|
Display* _x11Display;
|
||||||
Window _window;
|
Window _window;
|
||||||
XWindowAttributes _windowAttr;
|
XWindowAttributes _windowAttr;
|
||||||
|
|
||||||
|
XImage* _xImage;
|
||||||
|
XShmSegmentInfo _shminfo;
|
||||||
|
|
||||||
Pixmap _pixmap;
|
Pixmap _pixmap;
|
||||||
XRenderPictFormat* _srcFormat;
|
XRenderPictFormat* _srcFormat;
|
||||||
XRenderPictFormat* _dstFormat;
|
XRenderPictFormat* _dstFormat;
|
||||||
@ -85,15 +104,19 @@ private:
|
|||||||
int _XRandREventBase;
|
int _XRandREventBase;
|
||||||
|
|
||||||
XTransform _transform;
|
XTransform _transform;
|
||||||
int _pixelDecimation;
|
|
||||||
|
|
||||||
unsigned _screenWidth;
|
unsigned _calculatedWidth;
|
||||||
unsigned _screenHeight;
|
unsigned _calculatedHeight;
|
||||||
unsigned _src_x;
|
unsigned _src_x;
|
||||||
unsigned _src_y;
|
unsigned _src_y;
|
||||||
|
|
||||||
Image<ColorRgb> _image;
|
bool _XShmAvailable;
|
||||||
|
bool _XShmPixmapAvailable;
|
||||||
|
bool _XRenderAvailable;
|
||||||
|
bool _XRandRAvailable;
|
||||||
|
bool _isWayland;
|
||||||
|
|
||||||
void freeResources();
|
Logger * _logger;
|
||||||
void setupResources();
|
|
||||||
|
Image<ColorRgb> _image;
|
||||||
};
|
};
|
||||||
|
@ -9,25 +9,26 @@
|
|||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the
|
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the displayed content.
|
||||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
|
||||||
/// attached Hyperion.
|
|
||||||
///
|
///
|
||||||
class X11Wrapper: public GrabberWrapper
|
class X11Wrapper: public GrabberWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
|
/// Constructs the X11 frame grabber with a specified grab size and update rate.
|
||||||
///
|
///
|
||||||
/// @param[in] device X11 device name/path
|
|
||||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
|
||||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
|
||||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||||
|
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||||
///
|
///
|
||||||
X11Wrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, unsigned updateRate_Hz);
|
X11Wrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
|
||||||
|
int cropLeft=0, int cropRight=0,
|
||||||
|
int cropTop=0, int cropBottom=0
|
||||||
|
);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Destructor of this framebuffer frame grabber. Releases any claimed resources.
|
/// Destructor of this frame grabber. Releases any claimed resources.
|
||||||
///
|
///
|
||||||
~X11Wrapper() override;
|
~X11Wrapper() override;
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
|
// QT includes
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <hyperion/Grabber.h>
|
#include <hyperion/Grabber.h>
|
||||||
@ -21,16 +25,28 @@ class XcbGrabber : public Grabber, public QAbstractNativeEventFilter
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XcbGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
|
XcbGrabber(int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
||||||
|
|
||||||
~XcbGrabber() override;
|
~XcbGrabber() override;
|
||||||
|
|
||||||
bool Setup();
|
bool open();
|
||||||
|
bool setupDisplay();
|
||||||
|
|
||||||
int grabFrame(Image<ColorRgb> & image, bool forceUpdate = false);
|
int grabFrame(Image<ColorRgb> & image, bool forceUpdate = false);
|
||||||
int updateScreenDimensions(bool force = false);
|
int updateScreenDimensions(bool force = false);
|
||||||
void setVideoMode(VideoMode mode) override;
|
void setVideoMode(VideoMode mode) override;
|
||||||
bool setWidthHeight(int width, int height) override { return true; }
|
bool setWidthHeight(int width, int height) override { return true; }
|
||||||
void setPixelDecimation(int pixelDecimation) override;
|
bool setPixelDecimation(int pixelDecimation) override;
|
||||||
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover XCB screens available (for configuration).
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonObject discover(const QJsonObject& params);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
||||||
@ -52,8 +68,7 @@ private:
|
|||||||
xcb_render_transform_t _transform;
|
xcb_render_transform_t _transform;
|
||||||
xcb_shm_seg_t _shminfo;
|
xcb_shm_seg_t _shminfo;
|
||||||
|
|
||||||
int _pixelDecimation;
|
int _screen_num;
|
||||||
|
|
||||||
unsigned _screenWidth;
|
unsigned _screenWidth;
|
||||||
unsigned _screenHeight;
|
unsigned _screenHeight;
|
||||||
unsigned _src_x;
|
unsigned _src_x;
|
||||||
@ -63,6 +78,8 @@ private:
|
|||||||
bool _XcbRandRAvailable;
|
bool _XcbRandRAvailable;
|
||||||
bool _XcbShmAvailable;
|
bool _XcbShmAvailable;
|
||||||
bool _XcbShmPixmapAvailable;
|
bool _XcbShmPixmapAvailable;
|
||||||
|
bool _isWayland;
|
||||||
|
|
||||||
Logger * _logger;
|
Logger * _logger;
|
||||||
|
|
||||||
uint8_t * _shmData;
|
uint8_t * _shmData;
|
||||||
|
@ -11,7 +11,12 @@
|
|||||||
class XcbWrapper: public GrabberWrapper
|
class XcbWrapper: public GrabberWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XcbWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz);
|
XcbWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
|
||||||
|
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
|
||||||
|
int cropLeft=0, int cropRight=0,
|
||||||
|
int cropTop=0, int cropBottom=0
|
||||||
|
);
|
||||||
|
|
||||||
~XcbWrapper() override;
|
~XcbWrapper() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -6,23 +6,21 @@
|
|||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <utils/Image.h>
|
#include <utils/Image.h>
|
||||||
#include <utils/VideoMode.h>
|
#include <utils/VideoMode.h>
|
||||||
#include <grabber/VideoStandard.h>
|
#include <utils/VideoStandard.h>
|
||||||
#include <utils/ImageResampler.h>
|
#include <utils/ImageResampler.h>
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
|
||||||
#include <QMultiMap>
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief The Grabber class is responsible to apply image resizes (with or without ImageResampler)
|
/// @brief The Grabber class is responsible to apply image resizes (with or without ImageResampler)
|
||||||
/// Overwrite the videoMode with setVideoMode()
|
|
||||||
/// Overwrite setCropping()
|
|
||||||
class Grabber : public QObject
|
class Grabber : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Grabber(const QString& grabberName = "", int width=0, int height=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
|
||||||
|
Grabber(const QString& grabberName = "", int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the video mode (2D/3D)
|
/// Set the video mode (2D/3D)
|
||||||
@ -31,12 +29,18 @@ public:
|
|||||||
virtual void setVideoMode(VideoMode mode);
|
virtual void setVideoMode(VideoMode mode);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new crop values, on errors reject the values
|
/// Apply new flip mode (vertical/horizontal/both)
|
||||||
|
/// @param[in] mode The new flip mode
|
||||||
///
|
///
|
||||||
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
|
virtual void setFlipMode(FlipMode mode);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new video input (used from v4l)
|
/// @brief Apply new crop values, on errors reject the values
|
||||||
|
///
|
||||||
|
virtual void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Apply new video input (used from v4l2/MediaFoundation)
|
||||||
/// @param input device input
|
/// @param input device input
|
||||||
///
|
///
|
||||||
virtual bool setInput(int input);
|
virtual bool setInput(int input);
|
||||||
@ -48,108 +52,80 @@ public:
|
|||||||
virtual bool setWidthHeight(int width, int height);
|
virtual bool setWidthHeight(int width, int height);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new framerate (used from v4l)
|
/// @brief Apply new capture framerate in Hz
|
||||||
/// @param fps framesPerSecond
|
/// @param fps framesPerSecond
|
||||||
///
|
///
|
||||||
virtual bool setFramerate(int fps);
|
virtual bool setFramerate(int fps);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new pixelDecimation (used from x11, xcb and qt)
|
/// @brief Apply new framerate software decimation (used from v4l2/MediaFoundation)
|
||||||
|
/// @param decimation how many frames per second to omit
|
||||||
///
|
///
|
||||||
virtual void setPixelDecimation(int pixelDecimation) {}
|
virtual void setFpsSoftwareDecimation(int decimation);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply new signalThreshold (used from v4l)
|
/// @brief Apply videoStandard (used from v4l2)
|
||||||
///
|
///
|
||||||
virtual void setSignalThreshold(
|
virtual void setVideoStandard(VideoStandard videoStandard);
|
||||||
double redSignalThreshold,
|
|
||||||
double greenSignalThreshold,
|
|
||||||
double blueSignalThreshold,
|
|
||||||
int noSignalCounterThreshold = 50) {}
|
|
||||||
///
|
|
||||||
/// @brief Apply new SignalDetectionOffset (used from v4l)
|
|
||||||
///
|
|
||||||
virtual void setSignalDetectionOffset(
|
|
||||||
double verticalMin,
|
|
||||||
double horizontalMin,
|
|
||||||
double verticalMax,
|
|
||||||
double horizontalMax) {}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply SignalDetectionEnable (used from v4l)
|
/// @brief Apply new pixelDecimation
|
||||||
///
|
///
|
||||||
virtual void setSignalDetectionEnable(bool enable) {}
|
virtual bool setPixelDecimation(int pixelDecimation);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Apply CecDetectionEnable (used from v4l)
|
|
||||||
///
|
|
||||||
virtual void setCecDetectionEnable(bool enable) {}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Apply device and videoStanded (used from v4l)
|
|
||||||
///
|
|
||||||
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Apply display index (used from qt)
|
/// @brief Apply display index (used from qt)
|
||||||
///
|
///
|
||||||
virtual void setDisplayIndex(int index) {}
|
virtual bool setDisplayIndex(int /*index*/) { return true; }
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Apply path for device (used from framebuffer)
|
|
||||||
///
|
|
||||||
virtual void setDevicePath(const QString& path) {}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief get current resulting height of image (after crop)
|
|
||||||
///
|
|
||||||
virtual int getImageWidth() { return _width; }
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief get current resulting width of image (after crop)
|
|
||||||
///
|
|
||||||
virtual int getImageHeight() { return _height; }
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Prevent the real capture implementation from capturing if disabled
|
/// @brief Prevent the real capture implementation from capturing if disabled
|
||||||
///
|
///
|
||||||
void setEnabled(bool enable);
|
virtual void setEnabled(bool enable);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get a list of all available V4L devices
|
/// @brief get current resulting height of image (after crop)
|
||||||
/// @return List of all available V4L devices on success else empty List
|
|
||||||
///
|
///
|
||||||
virtual QStringList getV4L2devices() const { return QStringList(); }
|
int getImageWidth() const { return _width; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the V4L device name
|
/// @brief get current resulting width of image (after crop)
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return The name of the V4L device on success else empty String
|
|
||||||
///
|
///
|
||||||
virtual QString getV4L2deviceName(const QString& /*devicePath*/) const { return QString(); }
|
int getImageHeight() const { return _height; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get a name/index pair of supported device inputs
|
/// @brief Get current capture framerate in Hz
|
||||||
/// @param devicePath The device path
|
/// @param fps framesPerSecond
|
||||||
/// @return multi pair of name/index on success else empty pair
|
|
||||||
///
|
///
|
||||||
virtual QMultiMap<QString, int> getV4L2deviceInputs(const QString& /*devicePath*/) const { return QMultiMap<QString, int>(); }
|
int getFramerate() const { return _fps; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get a list of supported device resolutions
|
/// @brief Get capture interval in ms
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return List of resolutions on success else empty List
|
|
||||||
///
|
///
|
||||||
virtual QStringList getResolutions(const QString& /*devicePath*/) const { return QStringList(); }
|
int getUpdateInterval() const { return 1000/_fps; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get a list of supported device framerates
|
/// @brief Get pixelDecimation
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return List of framerates on success else empty List
|
|
||||||
///
|
///
|
||||||
virtual QStringList getFramerates(const QString& devicePath) const { return QStringList(); }
|
int getPixelDecimation() const { return _pixelDecimation; }
|
||||||
|
|
||||||
|
QString getGrabberName() const { return _grabberName; }
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
///
|
||||||
|
/// @brief Set device in error state
|
||||||
|
///
|
||||||
|
/// @param[in] errorMsg The error message to be logged
|
||||||
|
///
|
||||||
|
virtual void setInError( const QString& errorMsg);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
QString _grabberName;
|
||||||
|
|
||||||
|
/// logger instance
|
||||||
|
Logger * _log;
|
||||||
|
|
||||||
ImageResampler _imageResampler;
|
ImageResampler _imageResampler;
|
||||||
|
|
||||||
bool _useImageResampler;
|
bool _useImageResampler;
|
||||||
@ -157,6 +133,15 @@ protected:
|
|||||||
/// the selected VideoMode
|
/// the selected VideoMode
|
||||||
VideoMode _videoMode;
|
VideoMode _videoMode;
|
||||||
|
|
||||||
|
/// the used video standard
|
||||||
|
VideoStandard _videoStandard;
|
||||||
|
|
||||||
|
/// Image size decimation
|
||||||
|
int _pixelDecimation;
|
||||||
|
|
||||||
|
/// the used Flip Mode
|
||||||
|
FlipMode _flipMode;
|
||||||
|
|
||||||
/// With of the captured snapshot [pixels]
|
/// With of the captured snapshot [pixels]
|
||||||
int _width;
|
int _width;
|
||||||
|
|
||||||
@ -166,15 +151,21 @@ protected:
|
|||||||
/// frame per second
|
/// frame per second
|
||||||
int _fps;
|
int _fps;
|
||||||
|
|
||||||
|
/// fps software decimation
|
||||||
|
int _fpsSoftwareDecimation;
|
||||||
|
|
||||||
/// device input
|
/// device input
|
||||||
int _input;
|
int _input;
|
||||||
|
|
||||||
/// number of pixels to crop after capturing
|
/// number of pixels to crop after capturing
|
||||||
int _cropLeft, _cropRight, _cropTop, _cropBottom;
|
int _cropLeft, _cropRight, _cropTop, _cropBottom;
|
||||||
|
|
||||||
bool _enabled;
|
// Device states
|
||||||
|
|
||||||
/// logger instance
|
/// Is the device enabled?
|
||||||
Logger * _log;
|
bool _isEnabled;
|
||||||
|
|
||||||
|
/// Is the device in error state and stopped?
|
||||||
|
bool _isDeviceInError;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -12,30 +12,38 @@
|
|||||||
#include <utils/Image.h>
|
#include <utils/Image.h>
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <utils/VideoMode.h>
|
#include <utils/VideoMode.h>
|
||||||
|
#include <utils/PixelFormat.h>
|
||||||
#include <utils/settings.h>
|
#include <utils/settings.h>
|
||||||
|
#include <utils/VideoStandard.h>
|
||||||
|
|
||||||
class Grabber;
|
class Grabber;
|
||||||
class GlobalSignals;
|
class GlobalSignals;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
/// List of Hyperion instances that requested screen capt
|
|
||||||
static QList<int> GRABBER_SYS_CLIENTS;
|
|
||||||
static QList<int> GRABBER_V4L_CLIENTS;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// This class will be inherted by FramebufferWrapper and others which contains the real capture interface
|
/// This class will be inherited by GrabberWrappers which contains the real capture interface
|
||||||
///
|
///
|
||||||
class GrabberWrapper : public QObject
|
class GrabberWrapper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GrabberWrapper(const QString& grabberName, Grabber * ggrabber, unsigned width, unsigned height, unsigned updateRate_Hz = 0);
|
GrabberWrapper(const QString& grabberName, Grabber * ggrabber,int updateRate_Hz = DEFAULT_RATE_HZ);
|
||||||
|
|
||||||
~GrabberWrapper() override;
|
~GrabberWrapper() override;
|
||||||
|
|
||||||
static GrabberWrapper* instance;
|
static GrabberWrapper* instance;
|
||||||
static GrabberWrapper* getInstance(){ return instance; }
|
static GrabberWrapper* getInstance(){ return instance; }
|
||||||
|
|
||||||
|
static const int DEFAULT_RATE_HZ;
|
||||||
|
static const int DEFAULT_MIN_GRAB_RATE_HZ;
|
||||||
|
static const int DEFAULT_MAX_GRAB_RATE_HZ;
|
||||||
|
static const int DEFAULT_PIXELDECIMATION;
|
||||||
|
|
||||||
|
static QMap<int, QString> GRABBER_SYS_CLIENTS;
|
||||||
|
static QMap<int, QString> GRABBER_V4L_CLIENTS;
|
||||||
|
static bool GLOBAL_GRABBER_SYS_ENABLE;
|
||||||
|
static bool GLOBAL_GRABBER_V4L_ENABLE;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Starts the grabber which produces led values with the specified update rate
|
/// Starts the grabber which produces led values with the specified update rate
|
||||||
///
|
///
|
||||||
@ -56,45 +64,17 @@ public:
|
|||||||
///
|
///
|
||||||
virtual bool isActive() const;
|
virtual bool isActive() const;
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get a list of all available V4L devices
|
|
||||||
/// @return List of all available V4L devices on success else empty List
|
|
||||||
///
|
|
||||||
virtual QStringList getV4L2devices() const;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get the V4L device name
|
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return The name of the V4L device on success else empty String
|
|
||||||
///
|
|
||||||
virtual QString getV4L2deviceName(const QString& devicePath) const;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get a name/index pair of supported device inputs
|
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return multi pair of name/index on success else empty pair
|
|
||||||
///
|
|
||||||
virtual QMultiMap<QString, int> getV4L2deviceInputs(const QString& devicePath) const;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get a list of supported device resolutions
|
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return List of resolutions on success else empty List
|
|
||||||
///
|
|
||||||
virtual QStringList getResolutions(const QString& devicePath) const;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get a list of supported device framerates
|
|
||||||
/// @param devicePath The device path
|
|
||||||
/// @return List of framerates on success else empty List
|
|
||||||
///
|
|
||||||
virtual QStringList getFramerates(const QString& devicePath) const;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get active grabber name
|
/// @brief Get active grabber name
|
||||||
/// @return Active grabber name
|
/// @param hyperionInd The instance index
|
||||||
|
/// @return Active grabbers
|
||||||
///
|
///
|
||||||
virtual QString getActive() const;
|
virtual QStringList getActive(int inst) const;
|
||||||
|
|
||||||
|
bool getSysGrabberState() const { return GLOBAL_GRABBER_SYS_ENABLE; }
|
||||||
|
void setSysGrabberState(bool sysGrabberState){ GLOBAL_GRABBER_SYS_ENABLE = sysGrabberState; }
|
||||||
|
bool getV4lGrabberState() const { return GLOBAL_GRABBER_V4L_ENABLE; }
|
||||||
|
void setV4lGrabberState(bool v4lGrabberState){ GLOBAL_GRABBER_V4L_ENABLE = v4lGrabberState; }
|
||||||
|
|
||||||
static QStringList availableGrabbers();
|
static QStringList availableGrabbers();
|
||||||
|
|
||||||
@ -130,6 +110,12 @@ public slots:
|
|||||||
///
|
///
|
||||||
virtual void setVideoMode(VideoMode videoMode);
|
virtual void setVideoMode(VideoMode videoMode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the Flip mode
|
||||||
|
/// @param flipMode The new flip mode
|
||||||
|
///
|
||||||
|
virtual void setFlipMode(const QString &flipMode);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the crop values
|
/// Set the crop values
|
||||||
/// @param cropLeft Left pixel crop
|
/// @param cropLeft Left pixel crop
|
||||||
@ -137,11 +123,11 @@ public slots:
|
|||||||
/// @param cropTop Top pixel crop
|
/// @param cropTop Top pixel crop
|
||||||
/// @param cropBottom Bottom pixel crop
|
/// @param cropBottom Bottom pixel crop
|
||||||
///
|
///
|
||||||
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
|
virtual void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Handle settings update from HyperionDaemon Settingsmanager emit
|
/// @brief Handle settings update from HyperionDaemon Settingsmanager emit
|
||||||
/// @param type settingyType from enum
|
/// @param type settingsType from enum
|
||||||
/// @param config configuration object
|
/// @param config configuration object
|
||||||
///
|
///
|
||||||
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
|
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
|
||||||
@ -159,22 +145,38 @@ private slots:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Update Update capture rate
|
/// @brief Update Update capture rate
|
||||||
/// @param type interval between frames in millisecons
|
/// @param type interval between frames in milliseconds
|
||||||
///
|
///
|
||||||
void updateTimer(int interval);
|
void updateTimer(int interval);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the input device.
|
||||||
|
///
|
||||||
|
/// @return True, on success (i.e. device is ready)
|
||||||
|
///
|
||||||
|
virtual bool open() { return true; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Closes the input device.
|
||||||
|
///
|
||||||
|
/// @return True on success (i.e. device is closed)
|
||||||
|
///
|
||||||
|
virtual bool close() { return true; }
|
||||||
|
|
||||||
|
|
||||||
QString _grabberName;
|
QString _grabberName;
|
||||||
|
|
||||||
|
/// The Logger instance
|
||||||
|
Logger * _log;
|
||||||
|
|
||||||
/// The timer for generating events with the specified update rate
|
/// The timer for generating events with the specified update rate
|
||||||
QTimer* _timer;
|
QTimer* _timer;
|
||||||
|
|
||||||
/// The calced update rate [ms]
|
/// The calculated update rate [ms]
|
||||||
int _updateInterval_ms;
|
int _updateInterval_ms;
|
||||||
|
|
||||||
/// The Logger instance
|
|
||||||
Logger * _log;
|
|
||||||
|
|
||||||
Grabber *_ggrabber;
|
Grabber *_ggrabber;
|
||||||
|
|
||||||
/// The image used for grabbing frames
|
/// The image used for grabbing frames
|
||||||
|
@ -99,7 +99,7 @@ public:
|
|||||||
///
|
///
|
||||||
QString getActiveDeviceType() const;
|
QString getActiveDeviceType() const;
|
||||||
|
|
||||||
bool getReadOnlyMode() {return _readOnlyMode; };
|
bool getReadOnlyMode() {return _readOnlyMode; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ public slots:
|
|||||||
bool clear(int priority, bool forceClearAll=false);
|
bool clear(int priority, bool forceClearAll=false);
|
||||||
|
|
||||||
/// #############
|
/// #############
|
||||||
// EFFECTENGINE
|
/// EFFECTENGINE
|
||||||
///
|
///
|
||||||
/// @brief Get a pointer to the effect engine
|
/// @brief Get a pointer to the effect engine
|
||||||
/// @return EffectEngine instance pointer
|
/// @return EffectEngine instance pointer
|
||||||
|
@ -57,8 +57,11 @@ public:
|
|||||||
//Foreground and Background priorities
|
//Foreground and Background priorities
|
||||||
const static int FG_PRIORITY;
|
const static int FG_PRIORITY;
|
||||||
const static int BG_PRIORITY;
|
const static int BG_PRIORITY;
|
||||||
|
const static int MANUAL_SELECTED_PRIORITY;
|
||||||
/// The lowest possible priority, which is used when no priority channels are active
|
/// The lowest possible priority, which is used when no priority channels are active
|
||||||
const static int LOWEST_PRIORITY;
|
const static int LOWEST_PRIORITY;
|
||||||
|
/// Timeout used to identify a non active priority
|
||||||
|
const static int TIMEOUT_NOT_ACTIVE_PRIO;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Constructs the PriorityMuxer for the given number of LEDs (used to switch to black when
|
/// Constructs the PriorityMuxer for the given number of LEDs (used to switch to black when
|
||||||
@ -84,7 +87,7 @@ public:
|
|||||||
/// @param update True to update _currentPriority - INTERNAL usage.
|
/// @param update True to update _currentPriority - INTERNAL usage.
|
||||||
/// @return True if changed has been applied, false if the state is unchanged
|
/// @return True if changed has been applied, false if the state is unchanged
|
||||||
///
|
///
|
||||||
bool setSourceAutoSelectEnabled(bool enabel, bool update = true);
|
bool setSourceAutoSelectEnabled(bool enable, bool update = true);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the state of source auto selection
|
/// @brief Get the state of source auto selection
|
||||||
|
@ -9,12 +9,13 @@ class ImageResampler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageResampler();
|
ImageResampler();
|
||||||
~ImageResampler();
|
~ImageResampler() {}
|
||||||
|
|
||||||
void setHorizontalPixelDecimation(int decimator);
|
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
|
||||||
void setVerticalPixelDecimation(int decimator);
|
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
|
||||||
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
void setVideoMode(VideoMode mode);
|
void setVideoMode(VideoMode mode) { _videoMode = mode; }
|
||||||
|
void setFlipMode(FlipMode mode) { _flipMode = mode; }
|
||||||
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
|
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -25,5 +26,6 @@ private:
|
|||||||
int _cropTop;
|
int _cropTop;
|
||||||
int _cropBottom;
|
int _cropBottom;
|
||||||
VideoMode _videoMode;
|
VideoMode _videoMode;
|
||||||
|
FlipMode _flipMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ enum class PixelFormat {
|
|||||||
BGR24,
|
BGR24,
|
||||||
RGB32,
|
RGB32,
|
||||||
BGR32,
|
BGR32,
|
||||||
#ifdef HAVE_JPEG_DECODER
|
NV12,
|
||||||
|
I420,
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
MJPEG,
|
MJPEG,
|
||||||
#endif
|
#endif
|
||||||
NO_CHANGE
|
NO_CHANGE
|
||||||
@ -23,32 +25,40 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
|
|||||||
// convert to lower case
|
// convert to lower case
|
||||||
QString format = pixelFormat.toLower();
|
QString format = pixelFormat.toLower();
|
||||||
|
|
||||||
if (format.compare("yuyv") )
|
if (format.compare("yuyv") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::YUYV;
|
return PixelFormat::YUYV;
|
||||||
}
|
}
|
||||||
else if (format.compare("uyvy") )
|
else if (format.compare("uyvy") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::UYVY;
|
return PixelFormat::UYVY;
|
||||||
}
|
}
|
||||||
else if (format.compare("bgr16") )
|
else if (format.compare("bgr16") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::BGR16;
|
return PixelFormat::BGR16;
|
||||||
}
|
}
|
||||||
else if (format.compare("bgr24") )
|
else if (format.compare("bgr24") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::BGR24;
|
return PixelFormat::BGR24;
|
||||||
}
|
}
|
||||||
else if (format.compare("rgb32") )
|
else if (format.compare("rgb32") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::RGB32;
|
return PixelFormat::RGB32;
|
||||||
}
|
}
|
||||||
else if (format.compare("bgr32") )
|
else if (format.compare("bgr32") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::BGR32;
|
return PixelFormat::BGR32;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_JPEG_DECODER
|
else if (format.compare("i420") == 0)
|
||||||
else if (format.compare("mjpeg") )
|
{
|
||||||
|
return PixelFormat::I420;
|
||||||
|
}
|
||||||
|
else if (format.compare("nv12") == 0)
|
||||||
|
{
|
||||||
|
return PixelFormat::NV12;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
else if (format.compare("mjpeg") == 0)
|
||||||
{
|
{
|
||||||
return PixelFormat::MJPEG;
|
return PixelFormat::MJPEG;
|
||||||
}
|
}
|
||||||
@ -57,3 +67,102 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
|
|||||||
// return the default NO_CHANGE
|
// return the default NO_CHANGE
|
||||||
return PixelFormat::NO_CHANGE;
|
return PixelFormat::NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QString pixelFormatToString(const PixelFormat& pixelFormat)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( pixelFormat == PixelFormat::YUYV)
|
||||||
|
{
|
||||||
|
return "YUYV";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::UYVY)
|
||||||
|
{
|
||||||
|
return "UYVY";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::BGR16)
|
||||||
|
{
|
||||||
|
return "BGR16";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::BGR24)
|
||||||
|
{
|
||||||
|
return "BGR24";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::RGB32)
|
||||||
|
{
|
||||||
|
return "RGB32";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::BGR32)
|
||||||
|
{
|
||||||
|
return "BGR32";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::I420)
|
||||||
|
{
|
||||||
|
return "I420";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::NV12)
|
||||||
|
{
|
||||||
|
return "NV12";
|
||||||
|
}
|
||||||
|
#ifdef HAVE_TURBO_JPEG
|
||||||
|
else if (pixelFormat == PixelFormat::MJPEG)
|
||||||
|
{
|
||||||
|
return "MJPEG";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// return the default NO_CHANGE
|
||||||
|
return "NO_CHANGE";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of the possible flip modes
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum class FlipMode
|
||||||
|
{
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL,
|
||||||
|
BOTH,
|
||||||
|
NO_CHANGE
|
||||||
|
};
|
||||||
|
|
||||||
|
inline FlipMode parseFlipMode(const QString& flipMode)
|
||||||
|
{
|
||||||
|
// convert to lower case
|
||||||
|
QString mode = flipMode.toLower();
|
||||||
|
|
||||||
|
if (mode.compare("horizontal") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::HORIZONTAL;
|
||||||
|
}
|
||||||
|
else if (mode.compare("vertical") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::VERTICAL;
|
||||||
|
}
|
||||||
|
else if (mode.compare("both") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the default NO_CHANGE
|
||||||
|
return FlipMode::NO_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString flipModeToString(const FlipMode& flipMode)
|
||||||
|
{
|
||||||
|
if ( flipMode == FlipMode::HORIZONTAL)
|
||||||
|
{
|
||||||
|
return "horizontal";
|
||||||
|
}
|
||||||
|
else if (flipMode == FlipMode::VERTICAL)
|
||||||
|
{
|
||||||
|
return "vertical";
|
||||||
|
}
|
||||||
|
else if (flipMode == FlipMode::BOTH)
|
||||||
|
{
|
||||||
|
return "both";
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the default NO_CHANGE
|
||||||
|
return "NO_CHANGE";
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of the possible video standards the grabber can be set to
|
* Enumeration of the possible video standards the grabber can be set to
|
||||||
*/
|
*/
|
||||||
@ -13,17 +15,17 @@ enum class VideoStandard {
|
|||||||
inline VideoStandard parseVideoStandard(const QString& videoStandard)
|
inline VideoStandard parseVideoStandard(const QString& videoStandard)
|
||||||
{
|
{
|
||||||
// convert to lower case
|
// convert to lower case
|
||||||
QString standard = videoStandard.toLower();
|
QString standard = videoStandard.toUpper();
|
||||||
|
|
||||||
if (standard == "pal")
|
if (standard == "PAL")
|
||||||
{
|
{
|
||||||
return VideoStandard::PAL;
|
return VideoStandard::PAL;
|
||||||
}
|
}
|
||||||
else if (standard == "ntsc")
|
else if (standard == "NTSC")
|
||||||
{
|
{
|
||||||
return VideoStandard::NTSC;
|
return VideoStandard::NTSC;
|
||||||
}
|
}
|
||||||
else if (standard == "secam")
|
else if (standard == "SECAM")
|
||||||
{
|
{
|
||||||
return VideoStandard::SECAM;
|
return VideoStandard::SECAM;
|
||||||
}
|
}
|
||||||
@ -31,3 +33,14 @@ inline VideoStandard parseVideoStandard(const QString& videoStandard)
|
|||||||
// return the default NO_CHANGE
|
// return the default NO_CHANGE
|
||||||
return VideoStandard::NO_CHANGE;
|
return VideoStandard::NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QString VideoStandard2String(VideoStandard videoStandard)
|
||||||
|
{
|
||||||
|
switch (videoStandard)
|
||||||
|
{
|
||||||
|
case VideoStandard::PAL: return "PAL";
|
||||||
|
case VideoStandard::NTSC: return "NTSC";
|
||||||
|
case VideoStandard::SECAM: return "SECAM";
|
||||||
|
default: return "NO_CHANGE";
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
|
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
|
||||||
|
typedef QList< int > QIntList;
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
// fg effect
|
// fg effect
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
#include <hyperion/PriorityMuxer.h>
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
#include <effectengine/Effect.h>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Provide utility methods for Hyperion class
|
/// @brief Provide utility methods for Hyperion class
|
||||||
@ -17,7 +18,6 @@ namespace hyperion {
|
|||||||
void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
|
void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
|
||||||
{
|
{
|
||||||
#define FGCONFIG_ARRAY fgColorConfig.toArray()
|
#define FGCONFIG_ARRAY fgColorConfig.toArray()
|
||||||
const int DURATION_INFINITY = 0;
|
|
||||||
|
|
||||||
// initial foreground effect/color
|
// initial foreground effect/color
|
||||||
if (FGEffectConfig["enable"].toBool(true))
|
if (FGEffectConfig["enable"].toBool(true))
|
||||||
@ -27,7 +27,7 @@ namespace hyperion {
|
|||||||
const QJsonValue fgColorConfig = FGEffectConfig["color"];
|
const QJsonValue fgColorConfig = FGEffectConfig["color"];
|
||||||
int default_fg_duration_ms = 3000;
|
int default_fg_duration_ms = 3000;
|
||||||
int fg_duration_ms = FGEffectConfig["duration_ms"].toInt(default_fg_duration_ms);
|
int fg_duration_ms = FGEffectConfig["duration_ms"].toInt(default_fg_duration_ms);
|
||||||
if (fg_duration_ms == DURATION_INFINITY)
|
if (fg_duration_ms <= Effect::ENDLESS)
|
||||||
{
|
{
|
||||||
fg_duration_ms = default_fg_duration_ms;
|
fg_duration_ms = default_fg_duration_ms;
|
||||||
Warning(Logger::getInstance("HYPERION"), "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
|
Warning(Logger::getInstance("HYPERION"), "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
# Find the BCM-package (VC control)
|
||||||
|
IF ( "${PLATFORM}" MATCHES rpi)
|
||||||
|
find_package(BCM REQUIRED)
|
||||||
|
include_directories(${BCM_INCLUDE_DIRS})
|
||||||
|
ELSE()
|
||||||
|
SET(BCM_INCLUDE_DIRS "")
|
||||||
|
SET(BCM_LIBRARIES "")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
# Define the current source locations
|
# Define the current source locations
|
||||||
|
|
||||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/api)
|
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/api)
|
||||||
@ -12,6 +21,11 @@ add_library(hyperion-api
|
|||||||
${Api_RESOURCES}
|
${Api_RESOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ENABLE_DX)
|
||||||
|
include_directories(${DIRECTX9_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(hyperion-api ${DIRECTX9_LIBRARIES})
|
||||||
|
endif(ENABLE_DX)
|
||||||
|
|
||||||
target_link_libraries(hyperion-api
|
target_link_libraries(hyperion-api
|
||||||
hyperion
|
hyperion
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
|
28
libsrc/api/JSONRPC_schema/schema-inputsource.json
Normal file
28
libsrc/api/JSONRPC_schema/schema-inputsource.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"enum": [ "inputsource" ]
|
||||||
|
},
|
||||||
|
"tan": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"subcommand": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"enum": [ "discover", "getProperties" ]
|
||||||
|
},
|
||||||
|
"sourceType": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"type": "object",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"command": {
|
"command": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "transform", "correction" , "temperature"]
|
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "transform", "correction", "temperature" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
<file alias="schema-authorize">JSONRPC_schema/schema-authorize.json</file>
|
<file alias="schema-authorize">JSONRPC_schema/schema-authorize.json</file>
|
||||||
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
|
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
|
||||||
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
||||||
|
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
|
||||||
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
||||||
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
|
@ -16,7 +16,45 @@
|
|||||||
#include <leddevice/LedDevice.h>
|
#include <leddevice/LedDevice.h>
|
||||||
#include <leddevice/LedDeviceFactory.h>
|
#include <leddevice/LedDeviceFactory.h>
|
||||||
|
|
||||||
|
#include <HyperionConfig.h> // Required to determine the cmake options
|
||||||
|
|
||||||
#include <hyperion/GrabberWrapper.h>
|
#include <hyperion/GrabberWrapper.h>
|
||||||
|
#include <grabber/QtGrabber.h>
|
||||||
|
|
||||||
|
#if defined(ENABLE_MF)
|
||||||
|
#include <grabber/MFGrabber.h>
|
||||||
|
#elif defined(ENABLE_V4L2)
|
||||||
|
#include <grabber/V4L2Grabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_X11)
|
||||||
|
#include <grabber/X11Grabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_XCB)
|
||||||
|
#include <grabber/XcbGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_DX)
|
||||||
|
#include <grabber/DirectXGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_FB)
|
||||||
|
#include <grabber/FramebufferFrameGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_DISPMANX)
|
||||||
|
#include <grabber/DispmanxFrameGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_AMLOGIC)
|
||||||
|
#include <grabber/AmlogicGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_OSX)
|
||||||
|
#include <grabber/OsxFrameGrabber.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <utils/jsonschema/QJsonFactory.h>
|
#include <utils/jsonschema/QJsonFactory.h>
|
||||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||||
#include <HyperionConfig.h>
|
#include <HyperionConfig.h>
|
||||||
@ -41,7 +79,10 @@
|
|||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
|
|
||||||
JsonAPI::JsonAPI(QString peerAddress, Logger* log, bool localConnection, QObject* parent, bool noListener)
|
// Constants
|
||||||
|
namespace { const bool verbose = false; }
|
||||||
|
|
||||||
|
JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject *parent, bool noListener)
|
||||||
: API(log, localConnection, parent)
|
: API(log, localConnection, parent)
|
||||||
{
|
{
|
||||||
_noListener = noListener;
|
_noListener = noListener;
|
||||||
@ -86,7 +127,7 @@ bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleMessage(const QString& messageString, const QString& httpAuthHeader)
|
void JsonAPI::handleMessage(const QString &messageString, const QString &httpAuthHeader)
|
||||||
{
|
{
|
||||||
const QString ident = "JsonRpc@" + _peerAddress;
|
const QString ident = "JsonRpc@" + _peerAddress;
|
||||||
QJsonObject message;
|
QJsonObject message;
|
||||||
@ -174,6 +215,8 @@ proceed:
|
|||||||
handleInstanceCommand(message, command, tan);
|
handleInstanceCommand(message, command, tan);
|
||||||
else if (command == "leddevice")
|
else if (command == "leddevice")
|
||||||
handleLedDeviceCommand(message, command, tan);
|
handleLedDeviceCommand(message, command, tan);
|
||||||
|
else if (command == "inputsource")
|
||||||
|
handleInputSourceCommand(message, command, tan);
|
||||||
|
|
||||||
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
||||||
else if (command == "clearall")
|
else if (command == "clearall")
|
||||||
@ -187,17 +230,17 @@ proceed:
|
|||||||
handleNotImplemented(command, tan);
|
handleNotImplemented(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleColorCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleColorCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
int priority = message["priority"].toInt();
|
int priority = message["priority"].toInt();
|
||||||
int duration = message["duration"].toInt(-1);
|
int duration = message["duration"].toInt(-1);
|
||||||
const QString origin = message["origin"].toString("JsonRpc") + "@" + _peerAddress;
|
const QString origin = message["origin"].toString("JsonRpc") + "@" + _peerAddress;
|
||||||
|
|
||||||
const QJsonArray& jsonColor = message["color"].toArray();
|
const QJsonArray &jsonColor = message["color"].toArray();
|
||||||
std::vector<uint8_t> colors;
|
std::vector<uint8_t> colors;
|
||||||
// TODO faster copy
|
// TODO faster copy
|
||||||
for (const auto& entry : jsonColor)
|
for (const auto &entry : jsonColor)
|
||||||
{
|
{
|
||||||
colors.emplace_back(uint8_t(entry.toInt()));
|
colors.emplace_back(uint8_t(entry.toInt()));
|
||||||
}
|
}
|
||||||
@ -206,7 +249,7 @@ void JsonAPI::handleColorCommand(const QJsonObject& message, const QString& comm
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleImageCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleImageCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
|
|
||||||
@ -230,7 +273,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, int tan)
|
void JsonAPI::handleEffectCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
|
|
||||||
@ -249,19 +292,19 @@ void JsonAPI::handleEffectCommand(const QJsonObject& message, const QString& com
|
|||||||
sendErrorReply("Effect '" + dat.effectName + "' not found", command, tan);
|
sendErrorReply("Effect '" + dat.effectName + "' not found", command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleCreateEffectCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QString resultMsg = API::saveEffect(message);
|
const QString resultMsg = API::saveEffect(message);
|
||||||
resultMsg.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(resultMsg, command, tan);
|
resultMsg.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(resultMsg, command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleDeleteEffectCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QString res = API::deleteEffect(message["name"].toString());
|
const QString res = API::deleteEffect(message["name"].toString());
|
||||||
res.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(res, command, tan);
|
res.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(res, command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleSysInfoCommand(const QJsonObject&, const QString& command, int tan)
|
void JsonAPI::handleSysInfoCommand(const QJsonObject &, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create result
|
// create result
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
@ -304,7 +347,7 @@ void JsonAPI::handleSysInfoCommand(const QJsonObject&, const QString& command, i
|
|||||||
emit callbackMessage(result);
|
emit callbackMessage(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
QJsonObject info;
|
QJsonObject info;
|
||||||
|
|
||||||
@ -315,9 +358,9 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
activePriorities.removeAll(255);
|
activePriorities.removeAll(255);
|
||||||
int currentPriority = _hyperion->getCurrentPriority();
|
int currentPriority = _hyperion->getCurrentPriority();
|
||||||
|
|
||||||
for (int priority : activePriorities)
|
for(int priority : activePriorities)
|
||||||
{
|
{
|
||||||
const Hyperion::InputInfo& priorityInfo = _hyperion->getPriorityInfo(priority);
|
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||||
QJsonObject item;
|
QJsonObject item;
|
||||||
item["priority"] = priority;
|
item["priority"] = priority;
|
||||||
if (priorityInfo.timeoutTime_ms > 0)
|
if (priorityInfo.timeoutTime_ms > 0)
|
||||||
@ -371,9 +414,9 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
// collect adjustment information
|
// collect adjustment information
|
||||||
QJsonArray adjustmentArray;
|
QJsonArray adjustmentArray;
|
||||||
for (const QString& adjustmentId : _hyperion->getAdjustmentIds())
|
for (const QString &adjustmentId : _hyperion->getAdjustmentIds())
|
||||||
{
|
{
|
||||||
const ColorAdjustment* colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
const ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
||||||
if (colorAdjustment == nullptr)
|
if (colorAdjustment == nullptr)
|
||||||
{
|
{
|
||||||
Error(_log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId));
|
Error(_log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId));
|
||||||
@ -440,8 +483,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
// collect effect info
|
// collect effect info
|
||||||
QJsonArray effects;
|
QJsonArray effects;
|
||||||
const std::list<EffectDefinition>& effectsDefinitions = _hyperion->getEffects();
|
const std::list<EffectDefinition> &effectsDefinitions = _hyperion->getEffects();
|
||||||
for (const EffectDefinition& effectDefinition : effectsDefinitions)
|
for (const EffectDefinition &effectDefinition : effectsDefinitions)
|
||||||
{
|
{
|
||||||
QJsonObject effect;
|
QJsonObject effect;
|
||||||
effect["name"] = effectDefinition.name;
|
effect["name"] = effectDefinition.name;
|
||||||
@ -467,11 +510,18 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
QJsonObject grabbers;
|
QJsonObject grabbers;
|
||||||
QJsonArray availableGrabbers;
|
QJsonArray availableGrabbers;
|
||||||
|
|
||||||
#if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11) || defined(ENABLE_XCB) || defined(ENABLE_QT)
|
#if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_MF) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11) || defined(ENABLE_XCB) || defined(ENABLE_QT)
|
||||||
|
|
||||||
if (GrabberWrapper::getInstance() != nullptr)
|
if ( GrabberWrapper::getInstance() != nullptr )
|
||||||
{
|
{
|
||||||
grabbers["active"] = GrabberWrapper::getInstance()->getActive();
|
QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(_hyperion->getInstanceIndex());
|
||||||
|
QJsonArray activeGrabberNames;
|
||||||
|
for (auto grabberName : activeGrabbers)
|
||||||
|
{
|
||||||
|
activeGrabberNames.append(grabberName);
|
||||||
|
}
|
||||||
|
|
||||||
|
grabbers["active"] = activeGrabberNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get available grabbers
|
// get available grabbers
|
||||||
@ -480,55 +530,20 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
availableGrabbers.append(grabber);
|
availableGrabbers.append(grabber);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ENABLE_V4L2)
|
|
||||||
|
|
||||||
QJsonArray availableV4L2devices;
|
|
||||||
for (const auto& devicePath : GrabberWrapper::getInstance()->getV4L2devices())
|
|
||||||
{
|
|
||||||
QJsonObject device;
|
|
||||||
device["device"] = devicePath;
|
|
||||||
device["name"] = GrabberWrapper::getInstance()->getV4L2deviceName(devicePath);
|
|
||||||
|
|
||||||
QJsonArray availableInputs;
|
|
||||||
QMultiMap<QString, int> inputs = GrabberWrapper::getInstance()->getV4L2deviceInputs(devicePath);
|
|
||||||
for (auto input = inputs.begin(); input != inputs.end(); input++)
|
|
||||||
{
|
|
||||||
QJsonObject availableInput;
|
|
||||||
availableInput["inputName"] = input.key();
|
|
||||||
availableInput["inputIndex"] = input.value();
|
|
||||||
availableInputs.append(availableInput);
|
|
||||||
}
|
|
||||||
device.insert("inputs", availableInputs);
|
|
||||||
|
|
||||||
QJsonArray availableResolutions;
|
|
||||||
QStringList resolutions = GrabberWrapper::getInstance()->getResolutions(devicePath);
|
|
||||||
for (auto resolution : resolutions)
|
|
||||||
{
|
|
||||||
availableResolutions.append(resolution);
|
|
||||||
}
|
|
||||||
device.insert("resolutions", availableResolutions);
|
|
||||||
|
|
||||||
QJsonArray availableFramerates;
|
|
||||||
QStringList framerates = GrabberWrapper::getInstance()->getFramerates(devicePath);
|
|
||||||
for (auto framerate : framerates)
|
|
||||||
{
|
|
||||||
availableFramerates.append(framerate);
|
|
||||||
}
|
|
||||||
device.insert("framerates", availableFramerates);
|
|
||||||
|
|
||||||
availableV4L2devices.append(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
grabbers["v4l2_properties"] = availableV4L2devices;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grabbers["available"] = availableGrabbers;
|
grabbers["available"] = availableGrabbers;
|
||||||
info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
|
info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
|
||||||
info["grabbers"] = grabbers;
|
info["grabbers"] = grabbers;
|
||||||
|
|
||||||
|
QJsonObject cecInfo;
|
||||||
|
#if defined(ENABLE_CEC)
|
||||||
|
cecInfo["enabled"] = true;
|
||||||
|
#else
|
||||||
|
cecInfo["enabled"] = false;
|
||||||
|
#endif
|
||||||
|
info["cec"] = cecInfo;
|
||||||
|
|
||||||
// get available components
|
// get available components
|
||||||
QJsonArray component;
|
QJsonArray component;
|
||||||
std::map<hyperion::Components, bool> components = _hyperion->getComponentRegister().getRegister();
|
std::map<hyperion::Components, bool> components = _hyperion->getComponentRegister().getRegister();
|
||||||
@ -547,7 +562,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
// add sessions
|
// add sessions
|
||||||
QJsonArray sessions;
|
QJsonArray sessions;
|
||||||
#ifdef ENABLE_AVAHI
|
#ifdef ENABLE_AVAHI
|
||||||
for (auto session : BonjourBrowserWrapper::getInstance()->getAllServices())
|
for (auto session: BonjourBrowserWrapper::getInstance()->getAllServices())
|
||||||
{
|
{
|
||||||
if (session.port < 0)
|
if (session.port < 0)
|
||||||
continue;
|
continue;
|
||||||
@ -564,7 +579,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
#endif
|
#endif
|
||||||
// add instance info
|
// add instance info
|
||||||
QJsonArray instanceInfo;
|
QJsonArray instanceInfo;
|
||||||
for (const auto& entry : API::getAllInstanceData())
|
for (const auto &entry : API::getAllInstanceData())
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj.insert("friendly_name", entry["friendly_name"].toString());
|
obj.insert("friendly_name", entry["friendly_name"].toString());
|
||||||
@ -586,7 +601,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
// TRANSFORM INFORMATION (DEFAULT VALUES)
|
// TRANSFORM INFORMATION (DEFAULT VALUES)
|
||||||
QJsonArray transformArray;
|
QJsonArray transformArray;
|
||||||
for (const QString& transformId : _hyperion->getAdjustmentIds())
|
for (const QString &transformId : _hyperion->getAdjustmentIds())
|
||||||
{
|
{
|
||||||
QJsonObject transform;
|
QJsonObject transform;
|
||||||
QJsonArray blacklevel, whitelevel, gamma, threshold;
|
QJsonArray blacklevel, whitelevel, gamma, threshold;
|
||||||
@ -617,7 +632,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
// ACTIVE EFFECT INFO
|
// ACTIVE EFFECT INFO
|
||||||
QJsonArray activeEffects;
|
QJsonArray activeEffects;
|
||||||
for (const ActiveEffectDefinition& activeEffectDefinition : _hyperion->getActiveEffects())
|
for (const ActiveEffectDefinition &activeEffectDefinition : _hyperion->getActiveEffects())
|
||||||
{
|
{
|
||||||
if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1)
|
if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1)
|
||||||
{
|
{
|
||||||
@ -634,7 +649,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
// ACTIVE STATIC LED COLOR
|
// ACTIVE STATIC LED COLOR
|
||||||
QJsonArray activeLedColors;
|
QJsonArray activeLedColors;
|
||||||
const Hyperion::InputInfo& priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority());
|
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority());
|
||||||
if (priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty())
|
if (priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty())
|
||||||
{
|
{
|
||||||
QJsonObject LEDcolor;
|
QJsonObject LEDcolor;
|
||||||
@ -706,7 +721,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleClearCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleClearCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
int priority = message["priority"].toInt();
|
int priority = message["priority"].toInt();
|
||||||
@ -720,7 +735,7 @@ void JsonAPI::handleClearCommand(const QJsonObject& message, const QString& comm
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleClearallCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleClearallCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
emit forwardJsonMessage(message);
|
emit forwardJsonMessage(message);
|
||||||
QString replyMsg;
|
QString replyMsg;
|
||||||
@ -728,12 +743,12 @@ void JsonAPI::handleClearallCommand(const QJsonObject& message, const QString& c
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleAdjustmentCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QJsonObject& adjustment = message["adjustment"].toObject();
|
const QJsonObject &adjustment = message["adjustment"].toObject();
|
||||||
|
|
||||||
const QString adjustmentId = adjustment["id"].toString(_hyperion->getAdjustmentIds().first());
|
const QString adjustmentId = adjustment["id"].toString(_hyperion->getAdjustmentIds().first());
|
||||||
ColorAdjustment* colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
||||||
if (colorAdjustment == nullptr)
|
if (colorAdjustment == nullptr)
|
||||||
{
|
{
|
||||||
Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str());
|
Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str());
|
||||||
@ -742,39 +757,39 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject& message, const QString&
|
|||||||
|
|
||||||
if (adjustment.contains("red"))
|
if (adjustment.contains("red"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["red"].toArray();
|
const QJsonArray &values = adjustment["red"].toArray();
|
||||||
colorAdjustment->_rgbRedAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbRedAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adjustment.contains("green"))
|
if (adjustment.contains("green"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["green"].toArray();
|
const QJsonArray &values = adjustment["green"].toArray();
|
||||||
colorAdjustment->_rgbGreenAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbGreenAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adjustment.contains("blue"))
|
if (adjustment.contains("blue"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["blue"].toArray();
|
const QJsonArray &values = adjustment["blue"].toArray();
|
||||||
colorAdjustment->_rgbBlueAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbBlueAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
if (adjustment.contains("cyan"))
|
if (adjustment.contains("cyan"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["cyan"].toArray();
|
const QJsonArray &values = adjustment["cyan"].toArray();
|
||||||
colorAdjustment->_rgbCyanAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbCyanAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
if (adjustment.contains("magenta"))
|
if (adjustment.contains("magenta"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["magenta"].toArray();
|
const QJsonArray &values = adjustment["magenta"].toArray();
|
||||||
colorAdjustment->_rgbMagentaAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbMagentaAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
if (adjustment.contains("yellow"))
|
if (adjustment.contains("yellow"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["yellow"].toArray();
|
const QJsonArray &values = adjustment["yellow"].toArray();
|
||||||
colorAdjustment->_rgbYellowAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbYellowAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
if (adjustment.contains("white"))
|
if (adjustment.contains("white"))
|
||||||
{
|
{
|
||||||
const QJsonArray& values = adjustment["white"].toArray();
|
const QJsonArray &values = adjustment["white"].toArray();
|
||||||
colorAdjustment->_rgbWhiteAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
colorAdjustment->_rgbWhiteAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,7 +829,7 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject& message, const QString&
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleSourceSelectCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
if (message.contains("auto"))
|
if (message.contains("auto"))
|
||||||
{
|
{
|
||||||
@ -832,7 +847,7 @@ void JsonAPI::handleSourceSelectCommand(const QJsonObject& message, const QStrin
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleConfigCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleConfigCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
QString subcommand = message["subcommand"].toString("");
|
QString subcommand = message["subcommand"].toString("");
|
||||||
QString full_command = command + "-" + subcommand;
|
QString full_command = command + "-" + subcommand;
|
||||||
@ -876,14 +891,14 @@ void JsonAPI::handleConfigCommand(const QJsonObject& message, const QString& com
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleConfigSetCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
if (message.contains("config"))
|
if (message.contains("config"))
|
||||||
{
|
{
|
||||||
QJsonObject config = message["config"].toObject();
|
QJsonObject config = message["config"].toObject();
|
||||||
if (API::isHyperionEnabled())
|
if (API::isHyperionEnabled())
|
||||||
{
|
{
|
||||||
if (API::saveSettings(config))
|
if ( API::saveSettings(config) )
|
||||||
{
|
{
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
@ -897,7 +912,7 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject& message, const QString&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleSchemaGetCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleSchemaGetCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create result
|
// create result
|
||||||
QJsonObject schemaJson, alldevices, properties;
|
QJsonObject schemaJson, alldevices, properties;
|
||||||
@ -912,7 +927,7 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& message, const QString&
|
|||||||
{
|
{
|
||||||
schemaJson = QJsonFactory::readSchema(schemaFile);
|
schemaJson = QJsonFactory::readSchema(schemaFile);
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error& error)
|
catch (const std::runtime_error &error)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(error.what());
|
throw std::runtime_error(error.what());
|
||||||
}
|
}
|
||||||
@ -949,9 +964,9 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& message, const QString&
|
|||||||
sendSuccessDataReply(QJsonDocument(schemaJson), command, tan);
|
sendSuccessDataReply(QJsonDocument(schemaJson), command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleComponentStateCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QJsonObject& componentState = message["componentstate"].toObject();
|
const QJsonObject &componentState = message["componentstate"].toObject();
|
||||||
QString comp = componentState["component"].toString("invalid");
|
QString comp = componentState["component"].toString("invalid");
|
||||||
bool compState = componentState["state"].toBool(true);
|
bool compState = componentState["state"].toBool(true);
|
||||||
QString replyMsg;
|
QString replyMsg;
|
||||||
@ -964,7 +979,7 @@ void JsonAPI::handleComponentStateCommand(const QJsonObject& message, const QStr
|
|||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleLedColorsCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create result
|
// create result
|
||||||
QString subcommand = message["subcommand"].toString("");
|
QString subcommand = message["subcommand"].toString("");
|
||||||
@ -978,7 +993,7 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString&
|
|||||||
_streaming_leds_reply["command"] = command + "-ledstream-update";
|
_streaming_leds_reply["command"] = command + "-ledstream-update";
|
||||||
_streaming_leds_reply["tan"] = tan;
|
_streaming_leds_reply["tan"] = tan;
|
||||||
|
|
||||||
connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector<ColorRgb>& ledValues) {
|
connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector<ColorRgb> &ledValues) {
|
||||||
_currentLedValues = ledValues;
|
_currentLedValues = ledValues;
|
||||||
|
|
||||||
// necessary because Qt::UniqueConnection for lambdas does not work until 5.9
|
// necessary because Qt::UniqueConnection for lambdas does not work until 5.9
|
||||||
@ -1023,7 +1038,7 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString&
|
|||||||
sendSuccessReply(command + "-" + subcommand, tan);
|
sendSuccessReply(command + "-" + subcommand, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleLoggingCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleLoggingCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create result
|
// create result
|
||||||
QString subcommand = message["subcommand"].toString("");
|
QString subcommand = message["subcommand"].toString("");
|
||||||
@ -1065,25 +1080,25 @@ void JsonAPI::handleLoggingCommand(const QJsonObject& message, const QString& co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleProcessingCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleProcessingCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
API::setLedMappingType(ImageProcessor::mappingTypeToInt(message["mappingType"].toString("multicolor_mean")));
|
API::setLedMappingType(ImageProcessor::mappingTypeToInt(message["mappingType"].toString("multicolor_mean")));
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleVideoModeCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
API::setVideoMode(parse3DMode(message["videoMode"].toString("2D")));
|
API::setVideoMode(parse3DMode(message["videoMode"].toString("2D")));
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QString& subc = message["subcommand"].toString().trimmed();
|
const QString &subc = message["subcommand"].toString().trimmed();
|
||||||
const QString& id = message["id"].toString().trimmed();
|
const QString &id = message["id"].toString().trimmed();
|
||||||
const QString& password = message["password"].toString().trimmed();
|
const QString &password = message["password"].toString().trimmed();
|
||||||
const QString& newPassword = message["newPassword"].toString().trimmed();
|
const QString &newPassword = message["newPassword"].toString().trimmed();
|
||||||
const QString& comment = message["comment"].toString().trimmed();
|
const QString &comment = message["comment"].toString().trimmed();
|
||||||
|
|
||||||
// catch test if auth is required
|
// catch test if auth is required
|
||||||
if (subc == "tokenRequired")
|
if (subc == "tokenRequired")
|
||||||
@ -1194,8 +1209,8 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
if (subc == "requestToken")
|
if (subc == "requestToken")
|
||||||
{
|
{
|
||||||
// use id/comment
|
// use id/comment
|
||||||
const QString& comment = message["comment"].toString().trimmed();
|
const QString &comment = message["comment"].toString().trimmed();
|
||||||
const bool& acc = message["accept"].toBool(true);
|
const bool &acc = message["accept"].toBool(true);
|
||||||
if (acc)
|
if (acc)
|
||||||
API::setNewTokenRequest(comment, id, tan);
|
API::setNewTokenRequest(comment, id, tan);
|
||||||
else
|
else
|
||||||
@ -1211,7 +1226,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
if (API::getPendingTokenRequests(vec))
|
if (API::getPendingTokenRequests(vec))
|
||||||
{
|
{
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
for (const auto& entry : vec)
|
for (const auto &entry : vec)
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj["comment"] = entry.comment;
|
obj["comment"] = entry.comment;
|
||||||
@ -1233,7 +1248,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
if (subc == "answerRequest")
|
if (subc == "answerRequest")
|
||||||
{
|
{
|
||||||
// use id
|
// use id
|
||||||
const bool& accept = message["accept"].toBool(false);
|
const bool &accept = message["accept"].toBool(false);
|
||||||
if (!API::handlePendingTokenRequest(id, accept))
|
if (!API::handlePendingTokenRequest(id, accept))
|
||||||
sendErrorReply("No Authorization", command + "-" + subc, tan);
|
sendErrorReply("No Authorization", command + "-" + subc, tan);
|
||||||
return;
|
return;
|
||||||
@ -1246,7 +1261,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
if (API::getTokenList(defVect))
|
if (API::getTokenList(defVect))
|
||||||
{
|
{
|
||||||
QJsonArray tArr;
|
QJsonArray tArr;
|
||||||
for (const auto& entry : defVect)
|
for (const auto &entry : defVect)
|
||||||
{
|
{
|
||||||
QJsonObject subO;
|
QJsonObject subO;
|
||||||
subO["comment"] = entry.comment;
|
subO["comment"] = entry.comment;
|
||||||
@ -1265,7 +1280,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
// login
|
// login
|
||||||
if (subc == "login")
|
if (subc == "login")
|
||||||
{
|
{
|
||||||
const QString& token = message["token"].toString().trimmed();
|
const QString &token = message["token"].toString().trimmed();
|
||||||
|
|
||||||
// catch token
|
// catch token
|
||||||
if (!token.isEmpty())
|
if (!token.isEmpty())
|
||||||
@ -1313,11 +1328,11 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleInstanceCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleInstanceCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
const QString& subc = message["subcommand"].toString();
|
const QString &subc = message["subcommand"].toString();
|
||||||
const quint8& inst = message["instance"].toInt();
|
const quint8 &inst = message["instance"].toInt();
|
||||||
const QString& name = message["name"].toString();
|
const QString &name = message["name"].toString();
|
||||||
|
|
||||||
if (subc == "switchTo")
|
if (subc == "switchTo")
|
||||||
{
|
{
|
||||||
@ -1334,7 +1349,7 @@ void JsonAPI::handleInstanceCommand(const QJsonObject& message, const QString& c
|
|||||||
|
|
||||||
if (subc == "startInstance")
|
if (subc == "startInstance")
|
||||||
{
|
{
|
||||||
connect(this, &API::onStartInstanceResponse, [=](const int& tan) { sendSuccessReply(command + "-" + subc, tan); });
|
connect(this, &API::onStartInstanceResponse, [=] (const int &tan) { sendSuccessReply(command + "-" + subc, tan); });
|
||||||
if (!API::startInstance(inst, tan))
|
if (!API::startInstance(inst, tan))
|
||||||
sendErrorReply("Can't start Hyperion instance index " + QString::number(inst), command + "-" + subc, tan);
|
sendErrorReply("Can't start Hyperion instance index " + QString::number(inst), command + "-" + subc, tan);
|
||||||
|
|
||||||
@ -1384,12 +1399,12 @@ void JsonAPI::handleInstanceCommand(const QJsonObject& message, const QString& c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleLedDeviceCommand(const QJsonObject& message, const QString& command, int tan)
|
void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
|
||||||
const QString& subc = message["subcommand"].toString().trimmed();
|
const QString &subc = message["subcommand"].toString().trimmed();
|
||||||
const QString& devType = message["ledDeviceType"].toString().trimmed();
|
const QString &devType = message["ledDeviceType"].toString().trimmed();
|
||||||
|
|
||||||
QString full_command = command + "-" + subc;
|
QString full_command = command + "-" + subc;
|
||||||
|
|
||||||
@ -1407,27 +1422,27 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject& message, const QString&
|
|||||||
if (subc == "discover")
|
if (subc == "discover")
|
||||||
{
|
{
|
||||||
ledDevice = LedDeviceFactory::construct(config);
|
ledDevice = LedDeviceFactory::construct(config);
|
||||||
const QJsonObject& params = message["params"].toObject();
|
const QJsonObject ¶ms = message["params"].toObject();
|
||||||
const QJsonObject devicesDiscovered = ledDevice->discover(params);
|
const QJsonObject devicesDiscovered = ledDevice->discover(params);
|
||||||
|
|
||||||
Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
|
||||||
sendSuccessDataReply(QJsonDocument(devicesDiscovered), full_command, tan);
|
sendSuccessDataReply(QJsonDocument(devicesDiscovered), full_command, tan);
|
||||||
}
|
}
|
||||||
else if (subc == "getProperties")
|
else if (subc == "getProperties")
|
||||||
{
|
{
|
||||||
ledDevice = LedDeviceFactory::construct(config);
|
ledDevice = LedDeviceFactory::construct(config);
|
||||||
const QJsonObject& params = message["params"].toObject();
|
const QJsonObject ¶ms = message["params"].toObject();
|
||||||
const QJsonObject deviceProperties = ledDevice->getProperties(params);
|
const QJsonObject deviceProperties = ledDevice->getProperties(params);
|
||||||
|
|
||||||
Debug(_log, "response: [%s]", QString(QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
Debug(_log, "response: [%s]", QString(QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
|
||||||
sendSuccessDataReply(QJsonDocument(deviceProperties), full_command, tan);
|
sendSuccessDataReply(QJsonDocument(deviceProperties), full_command, tan);
|
||||||
}
|
}
|
||||||
else if (subc == "identify")
|
else if (subc == "identify")
|
||||||
{
|
{
|
||||||
ledDevice = LedDeviceFactory::construct(config);
|
ledDevice = LedDeviceFactory::construct(config);
|
||||||
const QJsonObject& params = message["params"].toObject();
|
const QJsonObject ¶ms = message["params"].toObject();
|
||||||
ledDevice->identify(params);
|
ledDevice->identify(params);
|
||||||
|
|
||||||
sendSuccessReply(full_command, tan);
|
sendSuccessReply(full_command, tan);
|
||||||
@ -1441,12 +1456,152 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject& message, const QString&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleNotImplemented(const QString& command, int tan)
|
void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
const QString& subc = message["subcommand"].toString().trimmed();
|
||||||
|
const QString& sourceType = message["sourceType"].toString().trimmed();
|
||||||
|
|
||||||
|
QString full_command = command + "-" + subc;
|
||||||
|
|
||||||
|
// TODO: Validate that source type is a valid one
|
||||||
|
/* if ( ! valid type )
|
||||||
|
{
|
||||||
|
sendErrorReply("Unknown device", full_command, tan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*/ {
|
||||||
|
if (subc == "discover")
|
||||||
|
{
|
||||||
|
QJsonObject inputSourcesDiscovered;
|
||||||
|
inputSourcesDiscovered.insert("sourceType", sourceType);
|
||||||
|
QJsonArray videoInputs;
|
||||||
|
|
||||||
|
#if defined(ENABLE_V4L2) || defined(ENABLE_MF)
|
||||||
|
|
||||||
|
if (sourceType == "video" )
|
||||||
|
{
|
||||||
|
#if defined(ENABLE_MF)
|
||||||
|
MFGrabber* grabber = new MFGrabber();
|
||||||
|
#elif defined(ENABLE_V4L2)
|
||||||
|
V4L2Grabber* grabber = new V4L2Grabber();
|
||||||
|
#endif
|
||||||
|
QJsonObject params;
|
||||||
|
videoInputs = grabber->discover(params);
|
||||||
|
delete grabber;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "sourceType: [%s]", QSTRING_CSTR(sourceType));
|
||||||
|
|
||||||
|
if (sourceType == "screen")
|
||||||
|
{
|
||||||
|
QJsonObject params;
|
||||||
|
|
||||||
|
QJsonObject device;
|
||||||
|
#ifdef ENABLE_QT
|
||||||
|
QtGrabber* qtgrabber = new QtGrabber();
|
||||||
|
device = qtgrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete qtgrabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_DX
|
||||||
|
DirectXGrabber* dxgrabber = new DirectXGrabber();
|
||||||
|
device = dxgrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete dxgrabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_X11
|
||||||
|
X11Grabber* x11Grabber = new X11Grabber();
|
||||||
|
device = x11Grabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete x11Grabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_XCB
|
||||||
|
XcbGrabber* xcbGrabber = new XcbGrabber();
|
||||||
|
device = xcbGrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete xcbGrabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_FB
|
||||||
|
FramebufferFrameGrabber* fbGrabber = new FramebufferFrameGrabber();
|
||||||
|
device = fbGrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete fbGrabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_DISPMANX)
|
||||||
|
DispmanxFrameGrabber* dispmanx = new DispmanxFrameGrabber();
|
||||||
|
device = dispmanx->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete dispmanx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_AMLOGIC)
|
||||||
|
AmlogicGrabber* amlGrabber = new AmlogicGrabber();
|
||||||
|
device = amlGrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete amlGrabber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_OSX)
|
||||||
|
OsxFrameGrabber* osxGrabber = new OsxFrameGrabber();
|
||||||
|
device = osxGrabber->discover(params);
|
||||||
|
if (!device.isEmpty() )
|
||||||
|
{
|
||||||
|
videoInputs.append(device);
|
||||||
|
}
|
||||||
|
delete osxGrabber;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
inputSourcesDiscovered["video_sources"] = videoInputs;
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "response: [%s]", QString(QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
sendSuccessDataReply(QJsonDocument(inputSourcesDiscovered), full_command, tan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonAPI::handleNotImplemented(const QString &command, int tan)
|
||||||
{
|
{
|
||||||
sendErrorReply("Command not implemented", command, tan);
|
sendErrorReply("Command not implemented", command, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::sendSuccessReply(const QString& command, int tan)
|
void JsonAPI::sendSuccessReply(const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create reply
|
// create reply
|
||||||
QJsonObject reply;
|
QJsonObject reply;
|
||||||
@ -1458,7 +1613,7 @@ void JsonAPI::sendSuccessReply(const QString& command, int tan)
|
|||||||
emit callbackMessage(reply);
|
emit callbackMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::sendSuccessDataReply(const QJsonDocument& doc, const QString& command, int tan)
|
void JsonAPI::sendSuccessDataReply(const QJsonDocument &doc, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
QJsonObject reply;
|
QJsonObject reply;
|
||||||
reply["success"] = true;
|
reply["success"] = true;
|
||||||
@ -1472,7 +1627,7 @@ void JsonAPI::sendSuccessDataReply(const QJsonDocument& doc, const QString& comm
|
|||||||
emit callbackMessage(reply);
|
emit callbackMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::sendErrorReply(const QString& error, const QString& command, int tan)
|
void JsonAPI::sendErrorReply(const QString &error, const QString &command, int tan)
|
||||||
{
|
{
|
||||||
// create reply
|
// create reply
|
||||||
QJsonObject reply;
|
QJsonObject reply;
|
||||||
@ -1485,12 +1640,12 @@ void JsonAPI::sendErrorReply(const QString& error, const QString& command, int t
|
|||||||
emit callbackMessage(reply);
|
emit callbackMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb> &ledColors)
|
||||||
{
|
{
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray leds;
|
QJsonArray leds;
|
||||||
|
|
||||||
for (const auto& color : ledColors)
|
for (const auto &color : ledColors)
|
||||||
{
|
{
|
||||||
leds << QJsonValue(color.red) << QJsonValue(color.green) << QJsonValue(color.blue);
|
leds << QJsonValue(color.red) << QJsonValue(color.green) << QJsonValue(color.blue);
|
||||||
}
|
}
|
||||||
@ -1502,9 +1657,9 @@ void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
|||||||
emit callbackMessage(_streaming_leds_reply);
|
emit callbackMessage(_streaming_leds_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::setImage(const Image<ColorRgb>& image)
|
void JsonAPI::setImage(const Image<ColorRgb> &image)
|
||||||
{
|
{
|
||||||
QImage jpgImage((const uint8_t*)image.memptr(), image.width(), image.height(), 3 * image.width(), QImage::Format_RGB888);
|
QImage jpgImage((const uint8_t *)image.memptr(), image.width(), image.height(), 3 * image.width(), QImage::Format_RGB888);
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
QBuffer buffer(&ba);
|
QBuffer buffer(&ba);
|
||||||
buffer.open(QIODevice::WriteOnly);
|
buffer.open(QIODevice::WriteOnly);
|
||||||
@ -1516,7 +1671,7 @@ void JsonAPI::setImage(const Image<ColorRgb>& image)
|
|||||||
emit callbackMessage(_streaming_image_reply);
|
emit callbackMessage(_streaming_image_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE& msg)
|
void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg)
|
||||||
{
|
{
|
||||||
QJsonObject result, message;
|
QJsonObject result, message;
|
||||||
QJsonArray messageArray;
|
QJsonArray messageArray;
|
||||||
@ -1524,7 +1679,7 @@ void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE& msg)
|
|||||||
if (!_streaming_logging_activated)
|
if (!_streaming_logging_activated)
|
||||||
{
|
{
|
||||||
_streaming_logging_activated = true;
|
_streaming_logging_activated = true;
|
||||||
const QList<Logger::T_LOG_MESSAGE>* logBuffer = LoggerManager::getInstance()->getLogMessageBuffer();
|
const QList<Logger::T_LOG_MESSAGE> *logBuffer = LoggerManager::getInstance()->getLogMessageBuffer();
|
||||||
for (int i = 0; i < logBuffer->length(); i++)
|
for (int i = 0; i < logBuffer->length(); i++)
|
||||||
{
|
{
|
||||||
message["appName"] = logBuffer->at(i).appName;
|
message["appName"] = logBuffer->at(i).appName;
|
||||||
@ -1560,7 +1715,7 @@ void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE& msg)
|
|||||||
emit callbackMessage(_streaming_logging_reply);
|
emit callbackMessage(_streaming_logging_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::newPendingTokenRequest(const QString& id, const QString& comment)
|
void JsonAPI::newPendingTokenRequest(const QString &id, const QString &comment)
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj["comment"] = comment;
|
obj["comment"] = comment;
|
||||||
@ -1570,7 +1725,7 @@ void JsonAPI::newPendingTokenRequest(const QString& id, const QString& comment)
|
|||||||
sendSuccessDataReply(QJsonDocument(obj), "authorize-tokenRequest", 1);
|
sendSuccessDataReply(QJsonDocument(obj), "authorize-tokenRequest", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleTokenResponse(bool success, const QString& token, const QString& comment, const QString& id, const int& tan)
|
void JsonAPI::handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan)
|
||||||
{
|
{
|
||||||
const QString cmd = "authorize-requestToken";
|
const QString cmd = "authorize-requestToken";
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
@ -1584,7 +1739,7 @@ void JsonAPI::handleTokenResponse(bool success, const QString& token, const QStr
|
|||||||
sendErrorReply("Token request timeout or denied", cmd, tan);
|
sendErrorReply("Token request timeout or denied", cmd, tan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString& name)
|
void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString &name)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &scr
|
|||||||
, _hyperion(hyperion)
|
, _hyperion(hyperion)
|
||||||
, _priority(priority)
|
, _priority(priority)
|
||||||
, _timeout(timeout)
|
, _timeout(timeout)
|
||||||
|
, _isEndless(timeout <= ENDLESS)
|
||||||
, _script(script)
|
, _script(script)
|
||||||
, _name(name)
|
, _name(name)
|
||||||
, _args(args)
|
, _args(args)
|
||||||
@ -51,7 +52,7 @@ Effect::~Effect()
|
|||||||
|
|
||||||
bool Effect::isInterruptionRequested()
|
bool Effect::isInterruptionRequested()
|
||||||
{
|
{
|
||||||
return _interupt || getRemaining() < ENDLESS;
|
return _interupt || (!_isEndless && getRemaining() <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Effect::getRemaining() const
|
int Effect::getRemaining() const
|
||||||
@ -59,12 +60,11 @@ int Effect::getRemaining() const
|
|||||||
// determine the timeout
|
// determine the timeout
|
||||||
int timeout = _timeout;
|
int timeout = _timeout;
|
||||||
|
|
||||||
if (timeout > 0)
|
if (timeout >= 0)
|
||||||
{
|
{
|
||||||
timeout = static_cast<int>( _endTime - QDateTime::currentMSecsSinceEpoch());
|
timeout = static_cast<int>( _endTime - QDateTime::currentMSecsSinceEpoch());
|
||||||
return timeout;
|
|
||||||
}
|
}
|
||||||
return ENDLESS;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::setModuleParameters()
|
void Effect::setModuleParameters()
|
||||||
|
@ -12,24 +12,24 @@ endif (ENABLE_FB)
|
|||||||
|
|
||||||
if (ENABLE_OSX)
|
if (ENABLE_OSX)
|
||||||
add_subdirectory(osx)
|
add_subdirectory(osx)
|
||||||
endif()
|
endif(ENABLE_OSX)
|
||||||
|
|
||||||
if (ENABLE_V4L2)
|
if (ENABLE_V4L2 OR ENABLE_MF)
|
||||||
add_subdirectory(v4l2)
|
add_subdirectory(video)
|
||||||
endif (ENABLE_V4L2)
|
endif ()
|
||||||
|
|
||||||
if (ENABLE_X11)
|
if (ENABLE_X11)
|
||||||
add_subdirectory(x11)
|
add_subdirectory(x11)
|
||||||
endif()
|
endif(ENABLE_X11)
|
||||||
|
|
||||||
if (ENABLE_XCB)
|
if (ENABLE_XCB)
|
||||||
add_subdirectory(xcb)
|
add_subdirectory(xcb)
|
||||||
endif()
|
endif(ENABLE_XCB)
|
||||||
|
|
||||||
if (ENABLE_QT)
|
if (ENABLE_QT)
|
||||||
add_subdirectory(qt)
|
add_subdirectory(qt)
|
||||||
endif()
|
endif(ENABLE_QT)
|
||||||
|
|
||||||
if (ENABLE_DX)
|
if (ENABLE_DX)
|
||||||
add_subdirectory(directx)
|
add_subdirectory(directx)
|
||||||
endif()
|
endif(ENABLE_DX)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
// Linux includes
|
// Linux includes
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -12,62 +11,92 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
// qt
|
||||||
|
#include <QFile>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
#include <grabber/AmlogicGrabber.h>
|
#include <grabber/AmlogicGrabber.h>
|
||||||
#include "Amvideocap.h"
|
#include "Amvideocap.h"
|
||||||
|
|
||||||
#define VIDEO_DEVICE "/dev/amvideo"
|
// Constants
|
||||||
#define CAPTURE_DEVICE "/dev/amvideocap0"
|
namespace {
|
||||||
|
const bool verbose = false;
|
||||||
|
|
||||||
AmlogicGrabber::AmlogicGrabber(unsigned width, unsigned height)
|
const char DEFAULT_FB_DEVICE[] = "/dev/fb0";
|
||||||
: Grabber("AMLOGICGRABBER", qMax(160u, width), qMax(160u, height)) // Minimum required width or height is 160
|
const char DEFAULT_VIDEO_DEVICE[] = "/dev/amvideo";
|
||||||
|
const char DEFAULT_CAPTURE_DEVICE[] = "/dev/amvideocap0";
|
||||||
|
|
||||||
|
const int AMVIDEOCAP_WAIT_MAX_MS = 50;
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
|
AmlogicGrabber::AmlogicGrabber()
|
||||||
|
: Grabber("AMLOGICGRABBER") // Minimum required width or height is 160
|
||||||
, _captureDev(-1)
|
, _captureDev(-1)
|
||||||
, _videoDev(-1)
|
, _videoDev(-1)
|
||||||
, _lastError(0)
|
, _lastError(0)
|
||||||
, _fbGrabber("/dev/fb0",width,height)
|
, _fbGrabber(DEFAULT_FB_DEVICE)
|
||||||
, _grabbingModeNotification(0)
|
, _grabbingModeNotification(0)
|
||||||
{
|
{
|
||||||
Debug(_log, "constructed(%d x %d), grabber device: %s",_width,_height, CAPTURE_DEVICE);
|
|
||||||
|
|
||||||
_image_bgr.resize(_width, _height);
|
|
||||||
_bytesToRead = _image_bgr.size();
|
|
||||||
_image_ptr = _image_bgr.memptr();
|
_image_ptr = _image_bgr.memptr();
|
||||||
|
|
||||||
|
_useImageResampler = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmlogicGrabber::~AmlogicGrabber()
|
AmlogicGrabber::~AmlogicGrabber()
|
||||||
{
|
{
|
||||||
closeDev(_captureDev);
|
closeDevice(_captureDev);
|
||||||
closeDev(_videoDev);
|
closeDevice(_videoDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AmlogicGrabber::openDev(int &fd, const char* dev)
|
bool AmlogicGrabber::setupScreen()
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
|
||||||
|
QSize screenSize = _fbGrabber.getScreenSize(DEFAULT_FB_DEVICE);
|
||||||
|
if ( !screenSize.isEmpty() )
|
||||||
|
{
|
||||||
|
if (setWidthHeight(screenSize.width(), screenSize.height()))
|
||||||
|
{
|
||||||
|
rc = _fbGrabber.setupScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AmlogicGrabber::openDevice(int &fd, const char* dev)
|
||||||
{
|
{
|
||||||
if (fd<0)
|
if (fd<0)
|
||||||
{
|
{
|
||||||
fd = open(dev, O_RDWR);
|
fd = ::open(dev, O_RDWR);
|
||||||
}
|
}
|
||||||
return fd >= 0;
|
return fd >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmlogicGrabber::closeDev(int &fd)
|
void AmlogicGrabber::closeDevice(int &fd)
|
||||||
{
|
{
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
close(fd);
|
::close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AmlogicGrabber::isVideoPlaying()
|
bool AmlogicGrabber::isVideoPlaying()
|
||||||
{
|
{
|
||||||
if(!QFile::exists(VIDEO_DEVICE)) return false;
|
bool rc = false;
|
||||||
|
if(QFile::exists(DEFAULT_VIDEO_DEVICE))
|
||||||
|
{
|
||||||
|
|
||||||
int videoDisabled = 1;
|
int videoDisabled = 1;
|
||||||
if (!openDev(_videoDev, VIDEO_DEVICE))
|
if (!openDevice(_videoDev, DEFAULT_VIDEO_DEVICE))
|
||||||
{
|
{
|
||||||
Error(_log, "Failed to open video device(%s): %d - %s", VIDEO_DEVICE, errno, strerror(errno));
|
Error(_log, "Failed to open video device(%s): %d - %s", DEFAULT_VIDEO_DEVICE, errno, strerror(errno));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -75,93 +104,230 @@ bool AmlogicGrabber::isVideoPlaying()
|
|||||||
if(ioctl(_videoDev, AMSTREAM_IOC_GET_VIDEO_DISABLE, &videoDisabled) < 0)
|
if(ioctl(_videoDev, AMSTREAM_IOC_GET_VIDEO_DISABLE, &videoDisabled) < 0)
|
||||||
{
|
{
|
||||||
Error(_log, "Failed to retrieve video state from device: %d - %s", errno, strerror(errno));
|
Error(_log, "Failed to retrieve video state from device: %d - %s", errno, strerror(errno));
|
||||||
closeDev(_videoDev);
|
closeDevice(_videoDev);
|
||||||
return false;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( videoDisabled == 0 )
|
||||||
|
{
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return videoDisabled == 0;
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AmlogicGrabber::grabFrame(Image<ColorRgb> & image)
|
int AmlogicGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled) return 0;
|
int rc = 0;
|
||||||
|
if (_isEnabled && !_isDeviceInError)
|
||||||
|
{
|
||||||
// Make sure video is playing, else there is nothing to grab
|
// Make sure video is playing, else there is nothing to grab
|
||||||
if (isVideoPlaying())
|
if (isVideoPlaying())
|
||||||
{
|
{
|
||||||
if (_grabbingModeNotification!=1)
|
if (_grabbingModeNotification!=1)
|
||||||
{
|
{
|
||||||
Info(_log, "VPU mode");
|
Info(_log, "Switch to VPU capture mode");
|
||||||
_grabbingModeNotification = 1;
|
_grabbingModeNotification = 1;
|
||||||
_lastError = 0;
|
_lastError = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grabFrame_amvideocap(image) < 0)
|
if (grabFrame_amvideocap(image) < 0) {
|
||||||
closeDev(_captureDev);
|
closeDevice(_captureDev);
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_grabbingModeNotification!=2)
|
if (_grabbingModeNotification!=2)
|
||||||
{
|
{
|
||||||
Info( _log, "FB mode");
|
Info( _log, "Switch to Framebuffer capture mode");
|
||||||
_grabbingModeNotification = 2;
|
_grabbingModeNotification = 2;
|
||||||
_lastError = 0;
|
_lastError = 0;
|
||||||
}
|
}
|
||||||
_fbGrabber.grabFrame(image);
|
rc = _fbGrabber.grabFrame(image);
|
||||||
|
|
||||||
usleep(50 * 1000);
|
//usleep(50 * 1000);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int AmlogicGrabber::grabFrame_amvideocap(Image<ColorRgb> & image)
|
int AmlogicGrabber::grabFrame_amvideocap(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
// If the device is not open, attempt to open it
|
// If the device is not open, attempt to open it
|
||||||
if (_captureDev < 0)
|
if (_captureDev < 0)
|
||||||
{
|
{
|
||||||
if (! openDev(_captureDev, CAPTURE_DEVICE))
|
if (! openDevice(_captureDev, DEFAULT_CAPTURE_DEVICE))
|
||||||
{
|
{
|
||||||
ErrorIf( _lastError != 1, _log,"Failed to open the AMLOGIC device (%d - %s):", errno, strerror(errno));
|
ErrorIf( _lastError != 1, _log,"Failed to open the AMLOGIC device (%d - %s):", errno, strerror(errno));
|
||||||
_lastError = 1;
|
_lastError = 1;
|
||||||
return -1;
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long r1 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, _width);
|
long r1 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, _width);
|
||||||
long r2 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, _height);
|
long r2 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, _height);
|
||||||
long r3 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS, CAP_FLAG_AT_END);
|
long r3 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS, CAP_FLAG_AT_END);
|
||||||
long r4 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS, 500);
|
long r4 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS, AMVIDEOCAP_WAIT_MAX_MS);
|
||||||
|
|
||||||
if (r1<0 || r2<0 || r3<0 || r4<0 || _height==0 || _width==0)
|
if (r1<0 || r2<0 || r3<0 || r4<0 || _height==0 || _width==0)
|
||||||
{
|
{
|
||||||
ErrorIf(_lastError != 2,_log,"Failed to configure capture device (%d - %s)", errno, strerror(errno));
|
ErrorIf(_lastError != 2,_log,"Failed to configure capture device (%d - %s)", errno, strerror(errno));
|
||||||
_lastError = 2;
|
_lastError = 2;
|
||||||
return -1;
|
rc = -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int linelen = ((_width + 31) & ~31) * 3;
|
||||||
|
size_t _bytesToRead = linelen * _height;
|
||||||
|
|
||||||
// Read the snapshot into the memory
|
// Read the snapshot into the memory
|
||||||
ssize_t bytesRead = pread(_captureDev, _image_ptr, _bytesToRead, 0);
|
ssize_t bytesRead = pread(_captureDev, _image_ptr, _bytesToRead, 0);
|
||||||
|
|
||||||
if (bytesRead < 0)
|
if (bytesRead < 0)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
ioctl(_captureDev, AMVIDEOCAP_IOR_GET_STATE, &state);
|
||||||
|
if (state == AMVIDEOCAP_STATE_ON_CAPTURE)
|
||||||
|
{
|
||||||
|
DebugIf(_lastError != 5, _log,"Video playback has been paused");
|
||||||
|
_lastError = 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ErrorIf(_lastError != 3, _log,"Read of device failed: %d - %s", errno, strerror(errno));
|
ErrorIf(_lastError != 3, _log,"Read of device failed: %d - %s", errno, strerror(errno));
|
||||||
_lastError = 3;
|
_lastError = 3;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
else if (_bytesToRead != bytesRead)
|
rc = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (static_cast<ssize_t>(_bytesToRead) != bytesRead)
|
||||||
{
|
{
|
||||||
// Read of snapshot failed
|
// Read of snapshot failed
|
||||||
ErrorIf(_lastError != 4, _log,"Capture failed to grab entire image [bytesToRead(%d) != bytesRead(%d)]", _bytesToRead, bytesRead);
|
ErrorIf(_lastError != 4, _log,"Capture failed to grab entire image [bytesToRead(%d) != bytesRead(%d)]", _bytesToRead, bytesRead);
|
||||||
_lastError = 4;
|
_lastError = 4;
|
||||||
return -1;
|
rc = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_imageResampler.processImage(static_cast<uint8_t*>(_image_ptr),
|
||||||
|
_width,
|
||||||
|
_height,
|
||||||
|
linelen,
|
||||||
|
PixelFormat::BGR24, image);
|
||||||
|
_lastError = 0;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject AmlogicGrabber::discover(const QJsonObject& params)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
QJsonObject inputsDiscovered;
|
||||||
|
|
||||||
|
if(QFile::exists(DEFAULT_VIDEO_DEVICE) && QFile::exists(DEFAULT_CAPTURE_DEVICE) )
|
||||||
|
{
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
|
||||||
|
QSize screenSize = _fbGrabber.getScreenSize();
|
||||||
|
if ( !screenSize.isEmpty() )
|
||||||
|
{
|
||||||
|
int fbIdx = _fbGrabber.getPath().rightRef(1).toInt();
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "FB device [%s] found with resolution: %dx%d", QSTRING_CSTR(_fbGrabber.getPath()), screenSize.width(), screenSize.height());
|
||||||
|
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
|
||||||
|
|
||||||
|
QJsonObject in;
|
||||||
|
|
||||||
|
QString displayName;
|
||||||
|
displayName = QString("Display%1").arg(fbIdx);
|
||||||
|
|
||||||
|
in["name"] = displayName;
|
||||||
|
in["inputIdx"] = fbIdx;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
resolution["width"] = screenSize.width();
|
||||||
|
resolution["height"] = screenSize.height();
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
_useImageResampler = true;
|
if (!video_inputs.isEmpty())
|
||||||
_imageResampler.processImage((const uint8_t*)_image_ptr, _width, _height, (_width << 1) + _width, PixelFormat::BGR24, image);
|
{
|
||||||
_lastError = 0;
|
inputsDiscovered["device"] = "amlogic";
|
||||||
|
inputsDiscovered["device_name"] = "AmLogic";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (inputsDiscovered.isEmpty())
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmlogicGrabber::setVideoMode(VideoMode mode)
|
||||||
|
{
|
||||||
|
Grabber::setVideoMode(mode);
|
||||||
|
_fbGrabber.setVideoMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AmlogicGrabber::setPixelDecimation(int pixelDecimation)
|
||||||
|
{
|
||||||
|
return ( Grabber::setPixelDecimation( pixelDecimation) &&
|
||||||
|
_fbGrabber.setPixelDecimation( pixelDecimation));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AmlogicGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
|
{
|
||||||
|
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
|
_fbGrabber.setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AmlogicGrabber::setWidthHeight(int width, int height)
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
if ( Grabber::setWidthHeight(width, height) )
|
||||||
|
{
|
||||||
|
_image_bgr.resize(static_cast<unsigned>(width), static_cast<unsigned>(height));
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
_bytesToRead = _image_bgr.size();
|
||||||
|
_image_ptr = _image_bgr.memptr();
|
||||||
|
rc = _fbGrabber.setWidthHeight(width, height);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AmlogicGrabber::setFramerate(int fps)
|
||||||
|
{
|
||||||
|
return (Grabber::setFramerate(fps) &&
|
||||||
|
_fbGrabber.setFramerate(fps));
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#include <grabber/AmlogicWrapper.h>
|
#include <grabber/AmlogicWrapper.h>
|
||||||
|
|
||||||
AmlogicWrapper::AmlogicWrapper(unsigned grabWidth, unsigned grabHeight)
|
AmlogicWrapper::AmlogicWrapper(int pixelDecimation, int updateRate_Hz)
|
||||||
: GrabberWrapper("AmLogic", &_grabber, grabWidth, grabHeight)
|
: GrabberWrapper("Amlogic", &_grabber, updateRate_Hz)
|
||||||
, _grabber(grabWidth, grabHeight)
|
, _grabber()
|
||||||
{}
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
void AmlogicWrapper::action()
|
void AmlogicWrapper::action()
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,35 @@
|
|||||||
#define CAP_FLAG_AT_TIME_WINDOW 1
|
#define CAP_FLAG_AT_TIME_WINDOW 1
|
||||||
#define CAP_FLAG_AT_END 2
|
#define CAP_FLAG_AT_END 2
|
||||||
|
|
||||||
// #define AMVIDEOCAP_IOW_SET_WANTFRAME_FORMAT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x01, int)
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_FORMAT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x01, int)
|
||||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int)
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int)
|
||||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int)
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int)
|
||||||
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_TIMESTAMP_MS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x04, unsigned long long)
|
||||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x05, unsigned long long)
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x05, unsigned long long)
|
||||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x06, int)
|
#define AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x06, int)
|
||||||
|
|
||||||
|
#define AMVIDEOCAP_IOR_GET_FRAME_FORMAT _IOR(AMVIDEOCAP_IOC_MAGIC, 0x10, int)
|
||||||
|
#define AMVIDEOCAP_IOR_GET_FRAME_WIDTH _IOR(AMVIDEOCAP_IOC_MAGIC, 0x11, int)
|
||||||
|
#define AMVIDEOCAP_IOR_GET_FRAME_HEIGHT _IOR(AMVIDEOCAP_IOC_MAGIC, 0x12, int)
|
||||||
|
#define AMVIDEOCAP_IOR_GET_FRAME_TIMESTAMP_MS _IOR(AMVIDEOCAP_IOC_MAGIC, 0x13, int)
|
||||||
|
|
||||||
|
#define AMVIDEOCAP_IOR_GET_SRCFRAME_FORMAT _IOR(AMVIDEOCAP_IOC_MAGIC, 0x20, int)
|
||||||
|
#define AMVIDEOCAP_IOR_GET_SRCFRAME_WIDTH _IOR(AMVIDEOCAP_IOC_MAGIC, 0x21, int)
|
||||||
|
#define AMVIDEOCAP_IOR_GET_SRCFRAME_HEIGHT _IOR(AMVIDEOCAP_IOC_MAGIC, 0x22, int)
|
||||||
|
|
||||||
|
#define AMVIDEOCAP_IOR_GET_STATE _IOR(AMVIDEOCAP_IOC_MAGIC, 0x31, int)
|
||||||
|
#define AMVIDEOCAP_IOW_SET_START_CAPTURE _IOW(AMVIDEOCAP_IOC_MAGIC, 0x32, int)
|
||||||
|
#define AMVIDEOCAP_IOW_SET_CANCEL_CAPTURE _IOW(AMVIDEOCAP_IOC_MAGIC, 0x33, int)
|
||||||
|
|
||||||
#define _A_M 'S'
|
#define _A_M 'S'
|
||||||
#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR((_A_M), 0x48, int)
|
#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR((_A_M), 0x48, int)
|
||||||
|
|
||||||
|
#define AMVIDEOCAP_IOC_MAGIC 'V'
|
||||||
|
#define AMVIDEOCAP_IOW_SET_START_CAPTURE _IOW(AMVIDEOCAP_IOC_MAGIC, 0x32, int)
|
||||||
|
|
||||||
|
enum amvideocap_state{
|
||||||
|
AMVIDEOCAP_STATE_INIT=0,
|
||||||
|
AMVIDEOCAP_STATE_ON_CAPTURE=200,
|
||||||
|
AMVIDEOCAP_STATE_FINISHED_CAPTURE=300,
|
||||||
|
AMVIDEOCAP_STATE_ERROR=0xffff,
|
||||||
|
};
|
||||||
|
@ -4,9 +4,13 @@
|
|||||||
#pragma comment(lib, "d3d9.lib")
|
#pragma comment(lib, "d3d9.lib")
|
||||||
#pragma comment(lib,"d3dx9.lib")
|
#pragma comment(lib,"d3dx9.lib")
|
||||||
|
|
||||||
DirectXGrabber::DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display)
|
// Constants
|
||||||
: Grabber("DXGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
namespace {
|
||||||
, _pixelDecimation(pixelDecimation)
|
const bool verbose = true;
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
|
DirectXGrabber::DirectXGrabber(int display, int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
|
: Grabber("DXGRABBER", cropLeft, cropRight, cropTop, cropBottom)
|
||||||
, _display(unsigned(display))
|
, _display(unsigned(display))
|
||||||
, _displayWidth(0)
|
, _displayWidth(0)
|
||||||
, _displayHeight(0)
|
, _displayHeight(0)
|
||||||
@ -15,8 +19,6 @@ DirectXGrabber::DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cro
|
|||||||
, _device(nullptr)
|
, _device(nullptr)
|
||||||
, _surface(nullptr)
|
, _surface(nullptr)
|
||||||
{
|
{
|
||||||
// init
|
|
||||||
setupDisplay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectXGrabber::~DirectXGrabber()
|
DirectXGrabber::~DirectXGrabber()
|
||||||
@ -140,15 +142,24 @@ bool DirectXGrabber::setupDisplay()
|
|||||||
|
|
||||||
int DirectXGrabber::grabFrame(Image<ColorRgb> & image)
|
int DirectXGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled)
|
if (!_isEnabled)
|
||||||
|
{
|
||||||
|
qDebug() << "AUS";
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_device == nullptr)
|
||||||
|
{
|
||||||
|
// reinit, this will disable capture on failure
|
||||||
|
bool result = setupDisplay();
|
||||||
|
setEnabled(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (FAILED(_device->GetFrontBufferData(0, _surface)))
|
if (FAILED(_device->GetFrontBufferData(0, _surface)))
|
||||||
{
|
{
|
||||||
// reinit, this will disable capture on failure
|
|
||||||
Error(_log, "Unable to get Buffer Surface Data");
|
Error(_log, "Unable to get Buffer Surface Data");
|
||||||
setEnabled(setupDisplay());
|
return 0;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DXLoadSurfaceFromSurface(_surfaceDest, nullptr, nullptr, _surface, nullptr, _srcRect, D3DX_DEFAULT, 0);
|
D3DXLoadSurfaceFromSurface(_surfaceDest, nullptr, nullptr, _surface, nullptr, _srcRect, D3DX_DEFAULT, 0);
|
||||||
@ -181,22 +192,91 @@ void DirectXGrabber::setVideoMode(VideoMode mode)
|
|||||||
setupDisplay();
|
setupDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectXGrabber::setPixelDecimation(int pixelDecimation)
|
bool DirectXGrabber::setPixelDecimation(int pixelDecimation)
|
||||||
{
|
{
|
||||||
_pixelDecimation = pixelDecimation;
|
if(Grabber::setPixelDecimation(pixelDecimation))
|
||||||
|
return setupDisplay();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectXGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
|
void DirectXGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
{
|
{
|
||||||
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
setupDisplay();
|
setupDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectXGrabber::setDisplayIndex(int index)
|
bool DirectXGrabber::setDisplayIndex(int index)
|
||||||
{
|
{
|
||||||
|
bool rc (true);
|
||||||
if(_display != unsigned(index))
|
if(_display != unsigned(index))
|
||||||
{
|
{
|
||||||
_display = unsigned(index);
|
_display = unsigned(index);
|
||||||
setupDisplay();
|
rc = setupDisplay();
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject DirectXGrabber::discover(const QJsonObject& params)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
QJsonObject inputsDiscovered;
|
||||||
|
if ((_d3d9 = Direct3DCreate9(D3D_SDK_VERSION)) != nullptr)
|
||||||
|
{
|
||||||
|
int adapterCount = (int)_d3d9->GetAdapterCount();
|
||||||
|
if(adapterCount > 0)
|
||||||
|
{
|
||||||
|
inputsDiscovered["device"] = "dx";
|
||||||
|
inputsDiscovered["device_name"] = "DX";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
|
||||||
|
|
||||||
|
for(int adapter = 0; adapter < adapterCount; adapter++)
|
||||||
|
{
|
||||||
|
QJsonObject in;
|
||||||
|
in["inputIdx"] = adapter;
|
||||||
|
|
||||||
|
D3DADAPTER_IDENTIFIER9 identifier;
|
||||||
|
_d3d9->GetAdapterIdentifier(adapter, D3DENUM_WHQL_LEVEL, &identifier);
|
||||||
|
|
||||||
|
QString name = identifier.DeviceName;
|
||||||
|
int pos = name.lastIndexOf('\\');
|
||||||
|
if (pos != -1)
|
||||||
|
name = name.right(name.length()-pos-1);
|
||||||
|
|
||||||
|
in["name"] = name;
|
||||||
|
|
||||||
|
D3DDISPLAYMODE ddm;
|
||||||
|
_d3d9->GetAdapterDisplayMode(adapter, &ddm);
|
||||||
|
|
||||||
|
QJsonArray formats, resolutionArray;
|
||||||
|
QJsonObject format, resolution;
|
||||||
|
|
||||||
|
resolution["width"] = (int)ddm.Width;
|
||||||
|
resolution["height"] = (int)ddm.Height;
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
#include <grabber/DirectXWrapper.h>
|
#include <grabber/DirectXWrapper.h>
|
||||||
|
|
||||||
DirectXWrapper::DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz)
|
DirectXWrapper::DirectXWrapper( int updateRate_Hz,
|
||||||
: GrabberWrapper("DirectX", &_grabber, 0, 0, updateRate_Hz)
|
int display,
|
||||||
, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
int pixelDecimation,
|
||||||
{}
|
int cropLeft, int cropRight, int cropTop, int cropBottom
|
||||||
|
)
|
||||||
|
: GrabberWrapper("DirectX", &_grabber, updateRate_Hz)
|
||||||
|
, _grabber(display, cropLeft, cropRight, cropTop, cropBottom)
|
||||||
|
|
||||||
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
void DirectXWrapper::action()
|
void DirectXWrapper::action()
|
||||||
{
|
{
|
||||||
|
@ -3,48 +3,34 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
//Qt
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
const bool verbose = false;
|
||||||
|
const int DEFAULT_DEVICE = 0;
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include "grabber/DispmanxFrameGrabber.h"
|
#include "grabber/DispmanxFrameGrabber.h"
|
||||||
|
|
||||||
DispmanxFrameGrabber::DispmanxFrameGrabber(unsigned width, unsigned height)
|
DispmanxFrameGrabber::DispmanxFrameGrabber()
|
||||||
: Grabber("DISPMANXGRABBER", 0, 0)
|
: Grabber("DISPMANXGRABBER")
|
||||||
, _vc_display(0)
|
, _vc_display(0)
|
||||||
, _vc_resource(0)
|
, _vc_resource(0)
|
||||||
, _vc_flags(0)
|
, _vc_flags(DISPMANX_TRANSFORM_T(0))
|
||||||
, _captureBuffer(new ColorRgba[0])
|
, _captureBuffer(new ColorRgba[0])
|
||||||
, _captureBufferSize(0)
|
, _captureBufferSize(0)
|
||||||
, _image_rgba(width, height)
|
, _image_rgba()
|
||||||
{
|
{
|
||||||
_useImageResampler = false;
|
_useImageResampler = true;
|
||||||
|
// Initialise BCM
|
||||||
// Initiase BCM
|
|
||||||
bcm_host_init();
|
bcm_host_init();
|
||||||
|
|
||||||
// Check if the display can be opened and display the current resolution
|
|
||||||
// Open the connection to the display
|
|
||||||
_vc_display = vc_dispmanx_display_open(0);
|
|
||||||
assert(_vc_display > 0);
|
|
||||||
|
|
||||||
// Obtain the display information
|
|
||||||
DISPMANX_MODEINFO_T vc_info;
|
|
||||||
int result = vc_dispmanx_display_get_info(_vc_display, &vc_info);
|
|
||||||
// Keep compiler happy in 'release' mode
|
|
||||||
(void)result;
|
|
||||||
|
|
||||||
// Close the display
|
|
||||||
vc_dispmanx_display_close(_vc_display);
|
|
||||||
|
|
||||||
if(result != 0)
|
|
||||||
{
|
|
||||||
Error(_log, "Failed to open display! Probably no permissions to access the capture interface");
|
|
||||||
setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Info(_log, "Display opened with resolution: %dx%d", vc_info.width, vc_info.height);
|
|
||||||
|
|
||||||
// init the resource and capture rectangle
|
|
||||||
setWidthHeight(width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DispmanxFrameGrabber::~DispmanxFrameGrabber()
|
DispmanxFrameGrabber::~DispmanxFrameGrabber()
|
||||||
@ -55,6 +41,28 @@ DispmanxFrameGrabber::~DispmanxFrameGrabber()
|
|||||||
bcm_host_deinit();
|
bcm_host_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DispmanxFrameGrabber::setupScreen()
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
|
||||||
|
int deviceIdx (DEFAULT_DEVICE);
|
||||||
|
|
||||||
|
QSize screenSize = getScreenSize(deviceIdx);
|
||||||
|
if ( screenSize.isEmpty() )
|
||||||
|
{
|
||||||
|
Error(_log, "Failed to open display [%d]! Probably no permissions to access the capture interface", deviceIdx);
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setWidthHeight(screenSize.width(), screenSize.height());
|
||||||
|
Info(_log, "Display [%d] opened with resolution: %dx%d", deviceIdx, screenSize.width(), screenSize.height());
|
||||||
|
setEnabled(true);
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void DispmanxFrameGrabber::freeResources()
|
void DispmanxFrameGrabber::freeResources()
|
||||||
{
|
{
|
||||||
delete[] _captureBuffer;
|
delete[] _captureBuffer;
|
||||||
@ -64,11 +72,14 @@ void DispmanxFrameGrabber::freeResources()
|
|||||||
|
|
||||||
bool DispmanxFrameGrabber::setWidthHeight(int width, int height)
|
bool DispmanxFrameGrabber::setWidthHeight(int width, int height)
|
||||||
{
|
{
|
||||||
|
bool rc = false;
|
||||||
if(Grabber::setWidthHeight(width, height))
|
if(Grabber::setWidthHeight(width, height))
|
||||||
{
|
{
|
||||||
if(_vc_resource != 0)
|
if(_vc_resource != 0) {
|
||||||
vc_dispmanx_resource_delete(_vc_resource);
|
vc_dispmanx_resource_delete(_vc_resource);
|
||||||
// Create the resources for capturing image
|
}
|
||||||
|
|
||||||
|
Debug(_log,"Create the resources for capturing image");
|
||||||
uint32_t vc_nativeImageHandle;
|
uint32_t vc_nativeImageHandle;
|
||||||
_vc_resource = vc_dispmanx_resource_create(
|
_vc_resource = vc_dispmanx_resource_create(
|
||||||
VC_IMAGE_RGBA32,
|
VC_IMAGE_RGBA32,
|
||||||
@ -77,55 +88,42 @@ bool DispmanxFrameGrabber::setWidthHeight(int width, int height)
|
|||||||
&vc_nativeImageHandle);
|
&vc_nativeImageHandle);
|
||||||
assert(_vc_resource);
|
assert(_vc_resource);
|
||||||
|
|
||||||
// Define the capture rectangle with the same size
|
if (_vc_resource != 0)
|
||||||
|
{
|
||||||
|
Debug(_log,"Define the capture rectangle with the same size");
|
||||||
vc_dispmanx_rect_set(&_rectangle, 0, 0, width, height);
|
vc_dispmanx_rect_set(&_rectangle, 0, 0, width, height);
|
||||||
return true;
|
rc = true;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispmanxFrameGrabber::setFlags(int vc_flags)
|
void DispmanxFrameGrabber::setFlags(DISPMANX_TRANSFORM_T vc_flags)
|
||||||
{
|
{
|
||||||
_vc_flags = vc_flags;
|
_vc_flags = vc_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled) return 0;
|
int rc = 0;
|
||||||
|
if (_isEnabled && !_isDeviceInError)
|
||||||
int ret;
|
{
|
||||||
|
|
||||||
// vc_dispmanx_resource_read_data doesn't seem to work well
|
// vc_dispmanx_resource_read_data doesn't seem to work well
|
||||||
// with arbitrary positions so we have to handle cropping by ourselves
|
// with arbitrary positions so we have to handle cropping by ourselves
|
||||||
unsigned cropLeft = _cropLeft;
|
int cropLeft = _cropLeft;
|
||||||
unsigned cropRight = _cropRight;
|
int cropRight = _cropRight;
|
||||||
unsigned cropTop = _cropTop;
|
int cropTop = _cropTop;
|
||||||
unsigned cropBottom = _cropBottom;
|
int cropBottom = _cropBottom;
|
||||||
|
|
||||||
if (_vc_flags & DISPMANX_SNAPSHOT_FILL)
|
if (_vc_flags & DISPMANX_SNAPSHOT_FILL)
|
||||||
{
|
{
|
||||||
// disable cropping, we are capturing the video overlay window
|
// disable cropping, we are capturing the video overlay window
|
||||||
|
Debug(_log,"Disable cropping, as the video overlay window is captured");
|
||||||
cropLeft = cropRight = cropTop = cropBottom = 0;
|
cropLeft = cropRight = cropTop = cropBottom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned imageWidth = _width - cropLeft - cropRight;
|
unsigned imageWidth = static_cast<unsigned>(_width - cropLeft - cropRight);
|
||||||
unsigned imageHeight = _height - cropTop - cropBottom;
|
unsigned imageHeight = static_cast<unsigned>(_height - cropTop - cropBottom);
|
||||||
|
|
||||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
|
||||||
switch (_videoMode)
|
|
||||||
{
|
|
||||||
case VideoMode::VIDEO_3DSBS:
|
|
||||||
imageWidth /= 2;
|
|
||||||
cropLeft /= 2;
|
|
||||||
break;
|
|
||||||
case VideoMode::VIDEO_3DTAB:
|
|
||||||
imageHeight /= 2;
|
|
||||||
cropTop /= 2;
|
|
||||||
break;
|
|
||||||
case VideoMode::VIDEO_2D:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// resize the given image if needed
|
// resize the given image if needed
|
||||||
if (image.width() != imageWidth || image.height() != imageHeight)
|
if (image.width() != imageWidth || image.height() != imageHeight)
|
||||||
@ -139,22 +137,23 @@ int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open the connection to the display
|
// Open the connection to the display
|
||||||
_vc_display = vc_dispmanx_display_open(0);
|
_vc_display = vc_dispmanx_display_open(DEFAULT_DEVICE);
|
||||||
if (_vc_display < 0)
|
if (_vc_display < 0)
|
||||||
{
|
{
|
||||||
Error(_log, "Cannot open display: %d", _vc_display);
|
Error(_log, "Cannot open display: %d", DEFAULT_DEVICE);
|
||||||
return -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
// Create the snapshot (incl down-scaling)
|
// Create the snapshot (incl down-scaling)
|
||||||
ret = vc_dispmanx_snapshot(_vc_display, _vc_resource, (DISPMANX_TRANSFORM_T) _vc_flags);
|
int ret = vc_dispmanx_snapshot(_vc_display, _vc_resource, _vc_flags);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
Error(_log, "Snapshot failed: %d", ret);
|
Error(_log, "Snapshot failed: %d", ret);
|
||||||
vc_dispmanx_display_close(_vc_display);
|
rc = ret;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Read the snapshot into the memory
|
// Read the snapshot into the memory
|
||||||
void* imagePtr = _image_rgba.memptr();
|
void* imagePtr = _image_rgba.memptr();
|
||||||
void* capturePtr = imagePtr;
|
void* capturePtr = imagePtr;
|
||||||
@ -166,11 +165,11 @@ int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
|
|
||||||
// grab to temp buffer if image pitch isn't valid or if we are cropping
|
// grab to temp buffer if image pitch isn't valid or if we are cropping
|
||||||
if (imagePitch != capturePitch
|
if (imagePitch != capturePitch
|
||||||
|| (unsigned)_rectangle.width != imageWidth
|
|| static_cast<unsigned>(_rectangle.width) != imageWidth
|
||||||
|| (unsigned)_rectangle.height != imageHeight)
|
|| static_cast<unsigned>(_rectangle.height) != imageHeight)
|
||||||
{
|
{
|
||||||
// check if we need to resize the capture buffer
|
// check if we need to resize the capture buffer
|
||||||
unsigned captureSize = capturePitch * _rectangle.height / sizeof(ColorRgba);
|
unsigned captureSize = capturePitch * static_cast<unsigned>(_rectangle.height) / sizeof(ColorRgba);
|
||||||
if (_captureBufferSize != captureSize)
|
if (_captureBufferSize != captureSize)
|
||||||
{
|
{
|
||||||
delete[] _captureBuffer;
|
delete[] _captureBuffer;
|
||||||
@ -185,31 +184,107 @@ int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
Error(_log, "vc_dispmanx_resource_read_data failed: %d", ret);
|
Error(_log, "vc_dispmanx_resource_read_data failed: %d", ret);
|
||||||
vc_dispmanx_display_close(_vc_display);
|
rc = ret;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// copy capture data to image if we captured to temp buffer
|
|
||||||
if (imagePtr != capturePtr)
|
|
||||||
{
|
{
|
||||||
// adjust source pointer to top/left cropping
|
_imageResampler.processImage(static_cast<uint8_t*>(capturePtr),
|
||||||
uint8_t* src_ptr = (uint8_t*) capturePtr
|
_width,
|
||||||
+ cropLeft * sizeof(ColorRgba)
|
_height,
|
||||||
+ cropTop * capturePitch;
|
static_cast<int>(capturePitch),
|
||||||
|
PixelFormat::RGB32,
|
||||||
for (unsigned y = 0; y < imageHeight; y++)
|
image);
|
||||||
{
|
|
||||||
memcpy((uint8_t*)imagePtr + y * imagePitch,
|
|
||||||
src_ptr + y * capturePitch,
|
|
||||||
imagePitch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the displaye
|
|
||||||
vc_dispmanx_display_close(_vc_display);
|
vc_dispmanx_display_close(_vc_display);
|
||||||
|
}
|
||||||
// image to output image
|
}
|
||||||
_image_rgba.toRgb(image);
|
return rc;
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
|
QSize DispmanxFrameGrabber::getScreenSize(int device) const
|
||||||
|
{
|
||||||
|
int width (0);
|
||||||
|
int height(0);
|
||||||
|
|
||||||
|
DISPMANX_DISPLAY_HANDLE_T vc_display = vc_dispmanx_display_open(device);
|
||||||
|
if ( vc_display > 0)
|
||||||
|
{
|
||||||
|
// Obtain the display information
|
||||||
|
DISPMANX_MODEINFO_T vc_info;
|
||||||
|
int result = vc_dispmanx_display_get_info(vc_display, &vc_info);
|
||||||
|
(void)result;
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
width = vc_info.width;
|
||||||
|
height = vc_info.height;
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "Display found with resolution: %dx%d", width, height);
|
||||||
|
}
|
||||||
|
// Close the display
|
||||||
|
vc_dispmanx_display_close(vc_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject DispmanxFrameGrabber::discover(const QJsonObject& params)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
QJsonObject inputsDiscovered;
|
||||||
|
|
||||||
|
int deviceIdx (DEFAULT_DEVICE);
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
|
||||||
|
QSize screenSize = getScreenSize(deviceIdx);
|
||||||
|
if ( !screenSize.isEmpty() )
|
||||||
|
{
|
||||||
|
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
|
||||||
|
|
||||||
|
QJsonObject in;
|
||||||
|
|
||||||
|
QString displayName;
|
||||||
|
displayName = QString("Screen:%1").arg(deviceIdx);
|
||||||
|
|
||||||
|
in["name"] = displayName;
|
||||||
|
in["inputIdx"] = deviceIdx;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
resolution["width"] = screenSize.width();
|
||||||
|
resolution["height"] = screenSize.height();
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!video_inputs.isEmpty())
|
||||||
|
{
|
||||||
|
inputsDiscovered["device"] = "dispmanx";
|
||||||
|
inputsDiscovered["device_name"] = "DispmanX";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputsDiscovered.isEmpty())
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
unsigned __bcm_frame_counter = 0;
|
unsigned __bcm_frame_counter = 0;
|
||||||
const int __screenWidth = 800;
|
const int __screenWidth = 800;
|
||||||
const int __screenHeight = 600;
|
const int __screenHeight = 600;
|
||||||
|
const int __display_num = 0;
|
||||||
|
|
||||||
void bcm_host_init()
|
void bcm_host_init()
|
||||||
{
|
{
|
||||||
@ -27,6 +28,7 @@ int vc_dispmanx_display_get_info(int, DISPMANX_MODEINFO_T *vc_info)
|
|||||||
{
|
{
|
||||||
vc_info->width = __screenWidth;
|
vc_info->width = __screenWidth;
|
||||||
vc_info->height = __screenHeight;
|
vc_info->height = __screenHeight;
|
||||||
|
vc_info->display_num = __display_num;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, in
|
|||||||
rectangle->top = top;
|
rectangle->top = top;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags)
|
int vc_dispmanx_snapshot(DISPMANX_DISPLAY_HANDLE_T /*display*/, DISPMANX_RESOURCE_HANDLE_T resource, DISPMANX_TRANSFORM_T /*vc_flags*/)
|
||||||
{
|
{
|
||||||
__bcm_frame_counter++;
|
__bcm_frame_counter++;
|
||||||
if (__bcm_frame_counter > 100)
|
if (__bcm_frame_counter > 100)
|
||||||
@ -66,7 +68,7 @@ int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags)
|
|||||||
if (__bcm_frame_counter < 25)
|
if (__bcm_frame_counter < 25)
|
||||||
{
|
{
|
||||||
color[0] = ColorRgba::WHITE;
|
color[0] = ColorRgba::WHITE;
|
||||||
0 color[1] = ColorRgba::RED;
|
color[1] = ColorRgba::RED;
|
||||||
color[2] = ColorRgba::BLUE;
|
color[2] = ColorRgba::BLUE;
|
||||||
color[3] = ColorRgba::GREEN;
|
color[3] = ColorRgba::GREEN;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <grabber/DispmanxWrapper.h>
|
#include <grabber/DispmanxWrapper.h>
|
||||||
|
|
||||||
DispmanxWrapper::DispmanxWrapper(unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
DispmanxWrapper::DispmanxWrapper( int updateRate_Hz,
|
||||||
: GrabberWrapper("Dispmanx", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
int pixelDecimation
|
||||||
, _grabber(grabWidth, grabHeight)
|
)
|
||||||
|
: GrabberWrapper("Dispmanx", &_grabber, updateRate_Hz)
|
||||||
|
, _grabber()
|
||||||
{
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispmanxWrapper::action()
|
void DispmanxWrapper::action()
|
||||||
|
@ -10,102 +10,261 @@
|
|||||||
// STL includes
|
// STL includes
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
//Qt
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
const bool verbose = false;
|
||||||
|
|
||||||
|
// fb discovery service
|
||||||
|
const char DISCOVERY_DIRECTORY[] = "/dev/";
|
||||||
|
const char DISCOVERY_FILEPATTERN[] = "fb?";
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
// Local includes
|
// Local includes
|
||||||
#include <grabber/FramebufferFrameGrabber.h>
|
#include <grabber/FramebufferFrameGrabber.h>
|
||||||
|
|
||||||
FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device, unsigned width, unsigned height)
|
FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device)
|
||||||
: Grabber("FRAMEBUFFERGRABBER", width, height)
|
: Grabber("FRAMEBUFFERGRABBER")
|
||||||
, _fbDevice()
|
, _fbDevice(device)
|
||||||
|
, _fbfd (-1)
|
||||||
{
|
{
|
||||||
setDevicePath(device);
|
_useImageResampler = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FramebufferFrameGrabber::~FramebufferFrameGrabber()
|
||||||
|
{
|
||||||
|
closeDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FramebufferFrameGrabber::setupScreen()
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
|
||||||
|
if ( _fbfd >= 0 )
|
||||||
|
{
|
||||||
|
closeDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = getScreenInfo();
|
||||||
|
setEnabled(rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FramebufferFrameGrabber::setWidthHeight(int width, int height)
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
if(Grabber::setWidthHeight(width, height))
|
||||||
|
{
|
||||||
|
rc = setupScreen();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
int FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled) return 0;
|
int rc = 0;
|
||||||
|
|
||||||
struct fb_var_screeninfo vinfo;
|
if (_isEnabled && !_isDeviceInError)
|
||||||
unsigned capSize, bytesPerPixel;
|
{
|
||||||
PixelFormat pixelFormat;
|
if ( getScreenInfo() )
|
||||||
|
{
|
||||||
|
/* map the device to memory */
|
||||||
|
uint8_t * fbp = static_cast<uint8_t*>(mmap(nullptr, _fixInfo.smem_len, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, _fbfd, 0));
|
||||||
|
if (fbp == MAP_FAILED) {
|
||||||
|
|
||||||
|
QString errorReason = QString ("Error mapping %1, [%2] %3").arg(_fbDevice).arg(errno).arg(std::strerror(errno));
|
||||||
|
this->setInError ( errorReason );
|
||||||
|
closeDevice();
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_imageResampler.processImage(fbp,
|
||||||
|
static_cast<int>(_varInfo.xres),
|
||||||
|
static_cast<int>(_varInfo.yres),
|
||||||
|
static_cast<int>(_fixInfo.line_length),
|
||||||
|
_pixelFormat,
|
||||||
|
image);
|
||||||
|
munmap(fbp, _fixInfo.smem_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeDevice();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FramebufferFrameGrabber::openDevice()
|
||||||
|
{
|
||||||
|
bool rc = true;
|
||||||
|
|
||||||
/* Open the framebuffer device */
|
/* Open the framebuffer device */
|
||||||
int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
_fbfd = ::open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
||||||
if (fbfd == -1)
|
if (_fbfd < 0)
|
||||||
{
|
{
|
||||||
Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
|
QString errorReason = QString ("Error opening %1, [%2] %3").arg(_fbDevice).arg(errno).arg(std::strerror(errno));
|
||||||
return -1;
|
this->setInError ( errorReason );
|
||||||
|
rc = false;
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* get variable screen information */
|
bool FramebufferFrameGrabber::closeDevice()
|
||||||
ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
{
|
||||||
|
bool rc = false;
|
||||||
bytesPerPixel = vinfo.bits_per_pixel / 8;
|
if (_fbfd >= 0)
|
||||||
capSize = vinfo.xres * vinfo.yres * bytesPerPixel;
|
|
||||||
|
|
||||||
switch (vinfo.bits_per_pixel)
|
|
||||||
{
|
{
|
||||||
case 16: pixelFormat = PixelFormat::BGR16; break;
|
if( ::close(_fbfd) == 0) {
|
||||||
case 24: pixelFormat = PixelFormat::BGR24; break;
|
rc = true;
|
||||||
|
}
|
||||||
|
_fbfd = -1;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize FramebufferFrameGrabber::getScreenSize() const
|
||||||
|
{
|
||||||
|
return getScreenSize(_fbDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize FramebufferFrameGrabber::getScreenSize(const QString& device) const
|
||||||
|
{
|
||||||
|
int width (0);
|
||||||
|
int height(0);
|
||||||
|
|
||||||
|
int fbfd = ::open(QSTRING_CSTR(device), O_RDONLY);
|
||||||
|
if (fbfd != -1)
|
||||||
|
{
|
||||||
|
struct fb_var_screeninfo vinfo;
|
||||||
|
int result = ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
width = static_cast<int>(vinfo.xres);
|
||||||
|
height = static_cast<int>(vinfo.yres);
|
||||||
|
DebugIf(verbose, _log, "FB device [%s] found with resolution: %dx%d", QSTRING_CSTR(device), width, height);
|
||||||
|
}
|
||||||
|
::close(fbfd);
|
||||||
|
}
|
||||||
|
return QSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FramebufferFrameGrabber::getScreenInfo()
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
|
||||||
|
if ( openDevice() )
|
||||||
|
{
|
||||||
|
if (ioctl(_fbfd, FBIOGET_FSCREENINFO, &_fixInfo) < 0 || ioctl (_fbfd, FBIOGET_VSCREENINFO, &_varInfo) < 0)
|
||||||
|
{
|
||||||
|
QString errorReason = QString ("Error getting screen information for %1, [%2] %3").arg(_fbDevice).arg(errno).arg(std::strerror(errno));
|
||||||
|
this->setInError ( errorReason );
|
||||||
|
closeDevice();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = true;
|
||||||
|
switch (_varInfo.bits_per_pixel)
|
||||||
|
{
|
||||||
|
case 16: _pixelFormat = PixelFormat::BGR16;
|
||||||
|
break;
|
||||||
|
case 24: _pixelFormat = PixelFormat::BGR24;
|
||||||
|
break;
|
||||||
#ifdef ENABLE_AMLOGIC
|
#ifdef ENABLE_AMLOGIC
|
||||||
case 32: pixelFormat = PixelFormat::PIXELFORMAT_RGB32; break;
|
case 32: _pixelFormat = PixelFormat::PIXELFORMAT_RGB32;
|
||||||
|
break;
|
||||||
#else
|
#else
|
||||||
case 32: pixelFormat = PixelFormat::BGR32; break;
|
case 32: _pixelFormat = PixelFormat::BGR32;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
Error(_log, "Unknown pixel format: %d bits per pixel", vinfo.bits_per_pixel);
|
rc= false;
|
||||||
close(fbfd);
|
QString errorReason = QString ("Unknown pixel format: %1 bits per pixel").arg(static_cast<int>(_varInfo.bits_per_pixel));
|
||||||
return -1;
|
this->setInError ( errorReason );
|
||||||
|
closeDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map the device to memory */
|
|
||||||
unsigned char * fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fbfd, 0);
|
|
||||||
if (fbp == MAP_FAILED) {
|
|
||||||
Error(_log, "Error mapping %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_imageResampler.setHorizontalPixelDecimation(vinfo.xres/_width);
|
return rc;
|
||||||
_imageResampler.setVerticalPixelDecimation(vinfo.yres/_height);
|
|
||||||
_imageResampler.processImage(fbp,
|
|
||||||
vinfo.xres,
|
|
||||||
vinfo.yres,
|
|
||||||
vinfo.xres * bytesPerPixel,
|
|
||||||
pixelFormat,
|
|
||||||
image);
|
|
||||||
|
|
||||||
munmap(fbp, capSize);
|
|
||||||
close(fbfd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferFrameGrabber::setDevicePath(const QString& path)
|
QJsonObject FramebufferFrameGrabber::discover(const QJsonObject& params)
|
||||||
{
|
{
|
||||||
if(_fbDevice != path)
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
{
|
|
||||||
_fbDevice = path;
|
|
||||||
int result;
|
|
||||||
struct fb_var_screeninfo vinfo;
|
|
||||||
|
|
||||||
// Check if the framebuffer device can be opened and display the current resolution
|
QJsonObject inputsDiscovered;
|
||||||
int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
|
||||||
if (fbfd == -1)
|
//Find framebuffer devices 0-9
|
||||||
|
QDir deviceDirectory (DISCOVERY_DIRECTORY);
|
||||||
|
QStringList deviceFilter(DISCOVERY_FILEPATTERN);
|
||||||
|
deviceDirectory.setNameFilters(deviceFilter);
|
||||||
|
deviceDirectory.setSorting(QDir::Name);
|
||||||
|
QFileInfoList deviceFiles = deviceDirectory.entryInfoList(QDir::System);
|
||||||
|
|
||||||
|
int fbIdx (0);
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
|
||||||
|
QFileInfoList::const_iterator deviceFileIterator;
|
||||||
|
for (deviceFileIterator = deviceFiles.constBegin(); deviceFileIterator != deviceFiles.constEnd(); ++deviceFileIterator)
|
||||||
{
|
{
|
||||||
Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
|
fbIdx = (*deviceFileIterator).fileName().rightRef(1).toInt();
|
||||||
}
|
QString device = (*deviceFileIterator).absoluteFilePath();
|
||||||
else
|
DebugIf(verbose, _log, "FB device [%s] found", QSTRING_CSTR(device));
|
||||||
|
|
||||||
|
QSize screenSize = getScreenSize(device);
|
||||||
|
if ( !screenSize.isEmpty() )
|
||||||
{
|
{
|
||||||
// get variable screen information
|
QJsonArray fps = { "1", "5", "10", "15", "20", "25", "30", "40", "50", "60" };
|
||||||
result = ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
|
||||||
if (result != 0)
|
QJsonObject in;
|
||||||
|
|
||||||
|
QString displayName;
|
||||||
|
displayName = QString("FB%1").arg(fbIdx);
|
||||||
|
|
||||||
|
in["name"] = displayName;
|
||||||
|
in["inputIdx"] = fbIdx;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
resolution["width"] = screenSize.width();
|
||||||
|
resolution["height"] = screenSize.height();
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!video_inputs.isEmpty())
|
||||||
{
|
{
|
||||||
Error(_log, "Could not get screen information, %s", std::strerror(errno));
|
inputsDiscovered["device"] = "framebuffer";
|
||||||
|
inputsDiscovered["device_name"] = "Framebuffer";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (inputsDiscovered.isEmpty())
|
||||||
{
|
{
|
||||||
Info(_log, "Display opened with resolution: %dx%d@%dbit", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
}
|
|
||||||
close(fbfd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
#include <grabber/FramebufferWrapper.h>
|
#include <grabber/FramebufferWrapper.h>
|
||||||
|
|
||||||
FramebufferWrapper::FramebufferWrapper(const QString & device, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
FramebufferWrapper::FramebufferWrapper( int updateRate_Hz,
|
||||||
: GrabberWrapper("FrameBuffer", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
const QString & device,
|
||||||
, _grabber(device, grabWidth, grabHeight)
|
int pixelDecimation)
|
||||||
{}
|
: GrabberWrapper("FrameBuffer", &_grabber, updateRate_Hz)
|
||||||
|
, _grabber(device)
|
||||||
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
void FramebufferWrapper::action()
|
void FramebufferWrapper::action()
|
||||||
{
|
{
|
||||||
|
@ -5,35 +5,57 @@
|
|||||||
// Local includes
|
// Local includes
|
||||||
#include <grabber/OsxFrameGrabber.h>
|
#include <grabber/OsxFrameGrabber.h>
|
||||||
|
|
||||||
OsxFrameGrabber::OsxFrameGrabber(unsigned display, unsigned width, unsigned height)
|
//Qt
|
||||||
: Grabber("OSXGRABBER", width, height)
|
#include <QJsonObject>
|
||||||
, _screenIndex(100)
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
const bool verbose = false;
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
|
OsxFrameGrabber::OsxFrameGrabber(int display)
|
||||||
|
: Grabber("OSXGRABBER")
|
||||||
|
, _screenIndex(display)
|
||||||
{
|
{
|
||||||
// check if display is available
|
_isEnabled = false;
|
||||||
setDisplayIndex(display);
|
_useImageResampler = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OsxFrameGrabber::~OsxFrameGrabber()
|
OsxFrameGrabber::~OsxFrameGrabber()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OsxFrameGrabber::setupDisplay()
|
||||||
|
{
|
||||||
|
bool rc (false);
|
||||||
|
|
||||||
|
rc = setDisplayIndex(_screenIndex);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled) return 0;
|
int rc = 0;
|
||||||
|
if (_isEnabled && !_isDeviceInError)
|
||||||
|
{
|
||||||
|
|
||||||
CGImageRef dispImage;
|
CGImageRef dispImage;
|
||||||
CFDataRef imgData;
|
CFDataRef imgData;
|
||||||
unsigned char * pImgData;
|
unsigned char * pImgData;
|
||||||
unsigned dspWidth, dspHeight;
|
unsigned dspWidth;
|
||||||
|
unsigned dspHeight;
|
||||||
|
|
||||||
dispImage = CGDisplayCreateImage(_display);
|
dispImage = CGDisplayCreateImage(_display);
|
||||||
|
|
||||||
// display lost, use main
|
// display lost, use main
|
||||||
if (dispImage == NULL && _display)
|
if (dispImage == nullptr && _display != 0)
|
||||||
{
|
{
|
||||||
dispImage = CGDisplayCreateImage(kCGDirectMainDisplay);
|
dispImage = CGDisplayCreateImage(kCGDirectMainDisplay);
|
||||||
// no displays connected, return
|
// no displays connected, return
|
||||||
if (dispImage == NULL)
|
if (dispImage == nullptr)
|
||||||
{
|
{
|
||||||
Error(_log, "No display connected...");
|
Error(_log, "No display connected...");
|
||||||
return -1;
|
return -1;
|
||||||
@ -44,55 +66,143 @@ int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
dspWidth = CGImageGetWidth(dispImage);
|
dspWidth = CGImageGetWidth(dispImage);
|
||||||
dspHeight = CGImageGetHeight(dispImage);
|
dspHeight = CGImageGetHeight(dispImage);
|
||||||
|
|
||||||
_imageResampler.setHorizontalPixelDecimation(dspWidth/_width);
|
|
||||||
_imageResampler.setVerticalPixelDecimation(dspHeight/_height);
|
|
||||||
_imageResampler.processImage( pImgData,
|
_imageResampler.processImage( pImgData,
|
||||||
dspWidth,
|
static_cast<int>(dspWidth),
|
||||||
dspHeight,
|
static_cast<int>(dspHeight),
|
||||||
CGImageGetBytesPerRow(dispImage),
|
static_cast<int>(CGImageGetBytesPerRow(dispImage)),
|
||||||
PixelFormat::BGR32,
|
PixelFormat::BGR32,
|
||||||
image);
|
image);
|
||||||
|
|
||||||
CFRelease(imgData);
|
CFRelease(imgData);
|
||||||
CGImageRelease(dispImage);
|
CGImageRelease(dispImage);
|
||||||
|
|
||||||
return 0;
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsxFrameGrabber::setDisplayIndex(int index)
|
bool OsxFrameGrabber::setDisplayIndex(int index)
|
||||||
{
|
{
|
||||||
if(_screenIndex != index)
|
bool rc (true);
|
||||||
|
if(_screenIndex != index || !_isEnabled)
|
||||||
{
|
{
|
||||||
_screenIndex = index;
|
_screenIndex = index;
|
||||||
|
|
||||||
CGImageRef image;
|
|
||||||
CGDisplayCount displayCount;
|
|
||||||
CGDirectDisplayID displays[8];
|
|
||||||
|
|
||||||
// get list of displays
|
// get list of displays
|
||||||
CGGetActiveDisplayList(8, displays, &displayCount);
|
CGDisplayCount dspyCnt = 0 ;
|
||||||
if (_screenIndex + 1 > displayCount)
|
CGDisplayErr err;
|
||||||
|
err = CGGetActiveDisplayList(0, nullptr, &dspyCnt);
|
||||||
|
if (err == kCGErrorSuccess && dspyCnt > 0)
|
||||||
{
|
{
|
||||||
Error(_log, "Display with index %d is not available. Using main display", _screenIndex);
|
CGDirectDisplayID *activeDspys = new CGDirectDisplayID [dspyCnt] ;
|
||||||
_display = kCGDirectMainDisplay;
|
err = CGGetActiveDisplayList(dspyCnt, activeDspys, &dspyCnt) ;
|
||||||
|
if (err == kCGErrorSuccess)
|
||||||
|
{
|
||||||
|
CGImageRef image;
|
||||||
|
|
||||||
|
if (_screenIndex + 1 > static_cast<int>(dspyCnt))
|
||||||
|
{
|
||||||
|
Error(_log, "Display with index %d is not available.", _screenIndex);
|
||||||
|
rc = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_display = displays[_screenIndex];
|
_display = activeDspys[_screenIndex];
|
||||||
}
|
|
||||||
|
|
||||||
image = CGDisplayCreateImage(_display);
|
image = CGDisplayCreateImage(_display);
|
||||||
if(image == NULL)
|
if(image == nullptr)
|
||||||
{
|
{
|
||||||
Error(_log, "Failed to open main display, disable capture interface");
|
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
return;
|
Error(_log, "Failed to open main display, disable capture interface");
|
||||||
|
rc = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
setEnabled(true);
|
setEnabled(true);
|
||||||
|
rc = true;
|
||||||
Info(_log, "Display opened with resolution: %dx%d@%dbit", CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerPixel(image));
|
Info(_log, "Display [%u] opened with resolution: %ux%u@%ubit", _display, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerPixel(image));
|
||||||
|
}
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject OsxFrameGrabber::discover(const QJsonObject& params)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
QJsonObject inputsDiscovered;
|
||||||
|
|
||||||
|
// get list of displays
|
||||||
|
CGDisplayCount dspyCnt = 0 ;
|
||||||
|
CGDisplayErr err;
|
||||||
|
err = CGGetActiveDisplayList(0, nullptr, &dspyCnt);
|
||||||
|
if (err == kCGErrorSuccess && dspyCnt > 0)
|
||||||
|
{
|
||||||
|
CGDirectDisplayID *activeDspys = new CGDirectDisplayID [dspyCnt] ;
|
||||||
|
err = CGGetActiveDisplayList(dspyCnt, activeDspys, &dspyCnt) ;
|
||||||
|
if (err == kCGErrorSuccess)
|
||||||
|
{
|
||||||
|
inputsDiscovered["device"] = "osx";
|
||||||
|
inputsDiscovered["device_name"] = "OSX";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
|
||||||
|
|
||||||
|
for (int i = 0; i < static_cast<int>(dspyCnt); ++i)
|
||||||
|
{
|
||||||
|
QJsonObject in;
|
||||||
|
|
||||||
|
CGDirectDisplayID did = activeDspys[i];
|
||||||
|
|
||||||
|
QString displayName;
|
||||||
|
displayName = QString("Display:%1").arg(did);
|
||||||
|
|
||||||
|
in["name"] = displayName;
|
||||||
|
in["inputIdx"] = i;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
|
||||||
|
CGDisplayModeRef dispMode = CGDisplayCopyDisplayMode(did);
|
||||||
|
CGRect rect = CGDisplayBounds(did);
|
||||||
|
resolution["width"] = static_cast<int>(rect.size.width);
|
||||||
|
resolution["height"] = static_cast<int>(rect.size.height);
|
||||||
|
CGDisplayModeRelease(dispMode);
|
||||||
|
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
|
}
|
||||||
|
delete [] activeDspys;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputsDiscovered.isEmpty())
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
|
}
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,33 @@ unsigned __osx_frame_counter = 0;
|
|||||||
const int __screenWidth = 800;
|
const int __screenWidth = 800;
|
||||||
const int __screenHeight = 600;
|
const int __screenHeight = 600;
|
||||||
|
|
||||||
void CGGetActiveDisplayList(int max, CGDirectDisplayID *displays, CGDisplayCount *displayCount)
|
CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount)
|
||||||
{
|
{
|
||||||
*displayCount = 1;
|
if (maxDisplays == 0 || activeDisplays == nullptr)
|
||||||
displays[0] = 1;
|
{
|
||||||
|
*displayCount = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
displayCount = &maxDisplays;
|
||||||
|
if (activeDisplays != nullptr)
|
||||||
|
{
|
||||||
|
for (CGDirectDisplayID i = 0; i < maxDisplays; ++i)
|
||||||
|
{
|
||||||
|
activeDisplays[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return kCGErrorFailure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kCGErrorSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display)
|
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display)
|
||||||
{
|
{
|
||||||
CGImageRef image = new CGImage(__screenWidth, __screenHeight);
|
CGImageRef image = new CGImage(__screenWidth / (display+1), __screenHeight / (display+1));
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
@ -123,4 +141,19 @@ void CFRelease(CFDataRef imgData)
|
|||||||
delete imgData;
|
delete imgData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
CGRect CGDisplayBounds(CGDirectDisplayID display)
|
||||||
|
{
|
||||||
|
CGRect rect;
|
||||||
|
rect.size.width = __screenWidth / (display+1);
|
||||||
|
rect.size.height = __screenHeight / (display+1);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
void CGDisplayModeRelease(CGDisplayModeRef mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
#include <grabber/OsxWrapper.h>
|
#include <grabber/OsxWrapper.h>
|
||||||
|
|
||||||
OsxWrapper::OsxWrapper(unsigned display, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
OsxWrapper::OsxWrapper( int updateRate_Hz,
|
||||||
: GrabberWrapper("OSX FrameGrabber", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
int display,
|
||||||
, _grabber(display, grabWidth, grabHeight)
|
int pixelDecimation
|
||||||
{}
|
)
|
||||||
|
: GrabberWrapper("OSX", &_grabber, updateRate_Hz)
|
||||||
|
, _grabber(display)
|
||||||
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
void OsxWrapper::action()
|
void OsxWrapper::action()
|
||||||
{
|
{
|
||||||
|
@ -7,23 +7,30 @@
|
|||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
QtGrabber::QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display)
|
// Constants
|
||||||
: Grabber("QTGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
namespace {
|
||||||
, _display(unsigned(display))
|
const bool verbose = false;
|
||||||
, _pixelDecimation(pixelDecimation)
|
} //End of constants
|
||||||
, _screenWidth(0)
|
|
||||||
, _screenHeight(0)
|
QtGrabber::QtGrabber(int display, int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
|
: Grabber("QTGRABBER", cropLeft, cropRight, cropTop, cropBottom)
|
||||||
|
, _display(display)
|
||||||
|
, _calculatedWidth(0)
|
||||||
|
, _calculatedHeight(0)
|
||||||
, _src_x(0)
|
, _src_x(0)
|
||||||
, _src_y(0)
|
, _src_y(0)
|
||||||
, _src_x_max(0)
|
, _src_x_max(0)
|
||||||
, _src_y_max(0)
|
, _src_y_max(0)
|
||||||
|
, _isWayland(false)
|
||||||
, _screen(nullptr)
|
, _screen(nullptr)
|
||||||
|
, _isVirtual(false)
|
||||||
{
|
{
|
||||||
|
_logger = Logger::getInstance("Qt");
|
||||||
_useImageResampler = false;
|
_useImageResampler = false;
|
||||||
|
|
||||||
// init
|
|
||||||
setupDisplay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QtGrabber::~QtGrabber()
|
QtGrabber::~QtGrabber()
|
||||||
@ -36,10 +43,38 @@ void QtGrabber::freeResources()
|
|||||||
// Qt seems to hold the ownership of the QScreen pointers
|
// Qt seems to hold the ownership of the QScreen pointers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QtGrabber::open()
|
||||||
|
{
|
||||||
|
bool rc = false;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (getenv("WAYLAND_DISPLAY") != nullptr)
|
||||||
|
{
|
||||||
|
_isWayland = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
bool QtGrabber::setupDisplay()
|
bool QtGrabber::setupDisplay()
|
||||||
{
|
{
|
||||||
|
bool result = false;
|
||||||
|
if ( ! open() )
|
||||||
|
{
|
||||||
|
if ( _isWayland )
|
||||||
|
{
|
||||||
|
Error(_log, "Grabber does not work under Wayland!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// cleanup last screen
|
// cleanup last screen
|
||||||
freeResources();
|
freeResources();
|
||||||
|
_numberOfSDisplays = 0;
|
||||||
|
|
||||||
QScreen* primary = QGuiApplication::primaryScreen();
|
QScreen* primary = QGuiApplication::primaryScreen();
|
||||||
QList<QScreen *> screens = QGuiApplication::screens();
|
QList<QScreen *> screens = QGuiApplication::screens();
|
||||||
@ -49,38 +84,70 @@ bool QtGrabber::setupDisplay()
|
|||||||
screens.prepend(primary);
|
screens.prepend(primary);
|
||||||
// remove last main screen if twice in list
|
// remove last main screen if twice in list
|
||||||
if(screens.lastIndexOf(primary) > 0)
|
if(screens.lastIndexOf(primary) > 0)
|
||||||
|
{
|
||||||
screens.removeAt(screens.lastIndexOf(primary));
|
screens.removeAt(screens.lastIndexOf(primary));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(screens.isEmpty())
|
if(screens.isEmpty())
|
||||||
{
|
{
|
||||||
Error(_log, "No displays found to capture from!");
|
Error(_log, "No displays found to capture from!");
|
||||||
return false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_numberOfSDisplays = screens.size();
|
||||||
|
|
||||||
Info(_log,"Available Displays:");
|
Info(_log,"Available Displays:");
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for(auto screen : screens)
|
for(auto * screen : qAsConst(screens))
|
||||||
{
|
{
|
||||||
const QRect geo = screen->geometry();
|
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());
|
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++;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
||||||
|
{
|
||||||
|
const QRect vgeo = screens.at(0)->virtualGeometry();
|
||||||
|
Info(_log,"Display %d: Name: %s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.left(), vgeo.top() ,vgeo.right(), vgeo.bottom(), screens.at(0)->depth());
|
||||||
|
}
|
||||||
|
|
||||||
|
_isVirtual = false;
|
||||||
// be sure the index is available
|
// be sure the index is available
|
||||||
if(_display > unsigned(screens.size()-1))
|
if (_display > _numberOfSDisplays - 1 )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((screens.at(0)->size() != screens.at(0)->virtualSize()) && (_display == _numberOfSDisplays))
|
||||||
|
{
|
||||||
|
_isVirtual = true;
|
||||||
|
_display = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Info(_log, "The requested display index '%d' is not available, falling back to display 0", _display);
|
Info(_log, "The requested display index '%d' is not available, falling back to display 0", _display);
|
||||||
_display = 0;
|
_display = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// init the requested display
|
// init the requested display
|
||||||
_screen = screens.at(_display);
|
_screen = screens.at(_display);
|
||||||
connect(_screen, &QScreen::geometryChanged, this, &QtGrabber::geometryChanged);
|
connect(_screen, &QScreen::geometryChanged, this, &QtGrabber::geometryChanged);
|
||||||
updateScreenDimensions(true);
|
updateScreenDimensions(true);
|
||||||
|
|
||||||
|
if (_isVirtual)
|
||||||
|
{
|
||||||
|
Info(_log, "Using virtual display across all screens");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Info(_log,"Initialized display %d", _display);
|
Info(_log,"Initialized display %d", _display);
|
||||||
return true;
|
}
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtGrabber::geometryChanged(const QRect &geo)
|
void QtGrabber::geometryChanged(const QRect &geo)
|
||||||
@ -91,90 +158,109 @@ void QtGrabber::geometryChanged(const QRect &geo)
|
|||||||
|
|
||||||
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if (!_enabled) return 0;
|
int rc = 0;
|
||||||
|
if (_isEnabled && !_isDeviceInError)
|
||||||
|
{
|
||||||
if(_screen == nullptr)
|
if(_screen == nullptr)
|
||||||
{
|
{
|
||||||
// reinit, this will disable capture on failure
|
// reinit, this will disable capture on failure
|
||||||
setEnabled(setupDisplay());
|
bool result = setupDisplay();
|
||||||
return -1;
|
setEnabled(result);
|
||||||
}
|
}
|
||||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
|
||||||
QPixmap resizedPixmap = originalPixmap.scaled(_width,_height);
|
|
||||||
QImage imageFrame = resizedPixmap.toImage().convertToFormat( QImage::Format_RGB888);
|
|
||||||
image.resize(imageFrame.width(), imageFrame.height());
|
|
||||||
|
|
||||||
for (int y=0; y<imageFrame.height(); ++y)
|
if (_isEnabled)
|
||||||
for (int x=0; x<imageFrame.width(); ++x)
|
|
||||||
{
|
{
|
||||||
QColor inPixel(imageFrame.pixel(x,y));
|
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||||
ColorRgb & outPixel = image(x,y);
|
if (originalPixmap.isNull())
|
||||||
outPixel.red = inPixel.red();
|
{
|
||||||
outPixel.green = inPixel.green();
|
rc = -1;
|
||||||
outPixel.blue = inPixel.blue();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat( QImage::Format_RGB888);
|
||||||
|
image.resize(static_cast<uint>(_calculatedWidth), static_cast<uint>(_calculatedHeight));
|
||||||
|
|
||||||
return 0;
|
for (int y = 0; y < imageFrame.height(); y++)
|
||||||
|
{
|
||||||
|
memcpy((unsigned char*)image.memptr() + y * image.width() * 3, static_cast<unsigned char*>(imageFrame.scanLine(y)), imageFrame.width() * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QtGrabber::updateScreenDimensions(bool force)
|
int QtGrabber::updateScreenDimensions(bool force)
|
||||||
{
|
{
|
||||||
if(!_screen)
|
if(_screen == nullptr)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const QRect& geo = _screen->geometry();
|
QRect geo;
|
||||||
if (!force && _screenWidth == unsigned(geo.right()) && _screenHeight == unsigned(geo.bottom()))
|
|
||||||
|
if (_isVirtual)
|
||||||
|
{
|
||||||
|
geo = _screen->virtualGeometry();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
geo = _screen->geometry();
|
||||||
|
}
|
||||||
|
if (!force && _width == geo.width() && _height == geo.height())
|
||||||
{
|
{
|
||||||
// No update required
|
// No update required
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _screenWidth, _screenHeight, geo.right(), geo.bottom());
|
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.width(), geo.height());
|
||||||
_screenWidth = geo.right() - geo.left();
|
_width = geo.width();
|
||||||
_screenHeight = geo.bottom() - geo.top();
|
_height = geo.height();
|
||||||
|
|
||||||
int width=0, height=0;
|
int width=0;
|
||||||
|
int height=0;
|
||||||
|
|
||||||
// Image scaling is performed by Qt
|
// Image scaling is performed by Qt
|
||||||
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
|
width = (_width > (_cropLeft + _cropRight))
|
||||||
? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
|
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
||||||
: (_screenWidth / _pixelDecimation);
|
: (_width / _pixelDecimation);
|
||||||
|
|
||||||
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
|
height = (_height > (_cropTop + _cropBottom))
|
||||||
? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
|
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||||
: (_screenHeight / _pixelDecimation);
|
: (_height / _pixelDecimation);
|
||||||
|
|
||||||
|
|
||||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||||
switch (_videoMode)
|
switch (_videoMode)
|
||||||
{
|
{
|
||||||
case VideoMode::VIDEO_3DSBS:
|
case VideoMode::VIDEO_3DSBS:
|
||||||
_width = width /2;
|
_calculatedWidth = width /2;
|
||||||
_height = height;
|
_calculatedHeight = height;
|
||||||
_src_x = _cropLeft / 2;
|
_src_x = _cropLeft / 2;
|
||||||
_src_y = _cropTop;
|
_src_y = _cropTop;
|
||||||
_src_x_max = (_screenWidth / 2) - _cropRight;
|
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||||
_src_y_max = _screenHeight - _cropBottom;
|
_src_y_max = _height - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
case VideoMode::VIDEO_3DTAB:
|
case VideoMode::VIDEO_3DTAB:
|
||||||
_width = width;
|
_calculatedWidth = width;
|
||||||
_height = height / 2;
|
_calculatedHeight = height / 2;
|
||||||
_src_x = _cropLeft;
|
_src_x = _cropLeft;
|
||||||
_src_y = _cropTop / 2;
|
_src_y = _cropTop / 2;
|
||||||
_src_x_max = _screenWidth - _cropRight;
|
_src_x_max = _width - _cropRight - _cropLeft;
|
||||||
_src_y_max = (_screenHeight / 2) - _cropBottom;
|
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
case VideoMode::VIDEO_2D:
|
case VideoMode::VIDEO_2D:
|
||||||
default:
|
default:
|
||||||
_width = width;
|
_calculatedWidth = width;
|
||||||
_height = height;
|
_calculatedHeight = height;
|
||||||
_src_x = _cropLeft;
|
_src_x = _cropLeft;
|
||||||
_src_y = _cropTop;
|
_src_y = _cropTop;
|
||||||
_src_x_max = _screenWidth - _cropRight;
|
_src_x_max = _width - _cropRight - _cropLeft;
|
||||||
_src_y_max = _screenHeight - _cropBottom;
|
_src_y_max = _height - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(_log, "Update output image resolution to [%dx%d]", _width, _height);
|
Info(_log, "Update output image resolution to [%dx%d]", _calculatedWidth, _calculatedHeight);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,22 +270,129 @@ void QtGrabber::setVideoMode(VideoMode mode)
|
|||||||
updateScreenDimensions(true);
|
updateScreenDimensions(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtGrabber::setPixelDecimation(int pixelDecimation)
|
bool QtGrabber::setPixelDecimation(int pixelDecimation)
|
||||||
{
|
{
|
||||||
_pixelDecimation = pixelDecimation;
|
bool rc (true);
|
||||||
|
if(Grabber::setPixelDecimation(pixelDecimation))
|
||||||
|
{
|
||||||
|
if ( updateScreenDimensions(true) < 0)
|
||||||
|
{
|
||||||
|
rc = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
|
void QtGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
{
|
{
|
||||||
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
updateScreenDimensions(true);
|
updateScreenDimensions(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtGrabber::setDisplayIndex(int index)
|
bool QtGrabber::setDisplayIndex(int index)
|
||||||
{
|
{
|
||||||
if(_display != unsigned(index))
|
bool rc (true);
|
||||||
|
if (_display != index)
|
||||||
{
|
{
|
||||||
_display = unsigned(index);
|
if (index <= _numberOfSDisplays)
|
||||||
setupDisplay();
|
{
|
||||||
|
_display = index;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
_display = 0;
|
||||||
|
}
|
||||||
|
rc = setupDisplay();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
QJsonObject inputsDiscovered;
|
||||||
|
if ( open() )
|
||||||
|
{
|
||||||
|
QList<QScreen*> screens = QGuiApplication::screens();
|
||||||
|
if (!screens.isEmpty())
|
||||||
|
{
|
||||||
|
inputsDiscovered["device"] = "qt";
|
||||||
|
inputsDiscovered["device_name"] = "QT";
|
||||||
|
inputsDiscovered["type"] = "screen";
|
||||||
|
|
||||||
|
QJsonArray video_inputs;
|
||||||
|
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
|
||||||
|
|
||||||
|
for (int i = 0; i < screens.size(); ++i)
|
||||||
|
{
|
||||||
|
QJsonObject in;
|
||||||
|
|
||||||
|
QString name = screens.at(i)->name();
|
||||||
|
int pos = name.lastIndexOf('\\');
|
||||||
|
if (pos != -1)
|
||||||
|
{
|
||||||
|
name = name.right(name.length()-pos-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
in["name"] = name;
|
||||||
|
in["inputIdx"] = i;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
resolution["width"] = screens.at(i)->size().width();
|
||||||
|
resolution["height"] = screens.at(i)->size().height();
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
||||||
|
{
|
||||||
|
QJsonObject in;
|
||||||
|
in["name"] = "All Displays";
|
||||||
|
in["inputIdx"] = screens.size();
|
||||||
|
in["virtual"] = true;
|
||||||
|
|
||||||
|
QJsonArray formats;
|
||||||
|
QJsonObject format;
|
||||||
|
|
||||||
|
QJsonArray resolutionArray;
|
||||||
|
|
||||||
|
QJsonObject resolution;
|
||||||
|
|
||||||
|
resolution["width"] = screens.at(0)->virtualSize().width();
|
||||||
|
resolution["height"] = screens.at(0)->virtualSize().height();
|
||||||
|
resolution["fps"] = fps;
|
||||||
|
|
||||||
|
resolutionArray.append(resolution);
|
||||||
|
|
||||||
|
format["resolutions"] = resolutionArray;
|
||||||
|
formats.append(format);
|
||||||
|
|
||||||
|
in["formats"] = formats;
|
||||||
|
video_inputs.append(in);
|
||||||
|
}
|
||||||
|
inputsDiscovered["video_inputs"] = video_inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputsDiscovered.isEmpty())
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
return inputsDiscovered;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
#include <grabber/QtWrapper.h>
|
#include <grabber/QtWrapper.h>
|
||||||
|
|
||||||
QtWrapper::QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, unsigned updateRate_Hz)
|
QtWrapper::QtWrapper( int updateRate_Hz,
|
||||||
: GrabberWrapper("Qt", &_grabber, 0, 0, updateRate_Hz)
|
int display,
|
||||||
, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
int pixelDecimation,
|
||||||
{}
|
int cropLeft, int cropRight, int cropTop, int cropBottom
|
||||||
|
)
|
||||||
|
: GrabberWrapper("Qt", &_grabber, updateRate_Hz)
|
||||||
|
, _grabber(display, cropLeft, cropRight, cropTop, cropBottom)
|
||||||
|
{
|
||||||
|
_grabber.setPixelDecimation(pixelDecimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtWrapper::open()
|
||||||
|
{
|
||||||
|
return _grabber.open();
|
||||||
|
}
|
||||||
|
|
||||||
void QtWrapper::action()
|
void QtWrapper::action()
|
||||||
{
|
{
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
# Define the current source locations
|
|
||||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
|
|
||||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/v4l2)
|
|
||||||
|
|
||||||
FILE ( GLOB V4L2_SOURCES "${CURRENT_HEADER_DIR}/V4L2*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" )
|
|
||||||
|
|
||||||
add_library(v4l2-grabber ${V4L2_SOURCES} )
|
|
||||||
|
|
||||||
target_link_libraries(v4l2-grabber
|
|
||||||
hyperion
|
|
||||||
${QT_LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(TURBOJPEG_FOUND)
|
|
||||||
target_link_libraries(v4l2-grabber ${TurboJPEG_LIBRARY})
|
|
||||||
elseif (JPEG_FOUND)
|
|
||||||
target_link_libraries(v4l2-grabber ${JPEG_LIBRARY})
|
|
||||||
endif(TURBOJPEG_FOUND)
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user