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 5b0ce3c0f2
.
* 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
|
||||
|
||||
# detect CI
|
||||
if [ "$SYSTEM_COLLECTIONID" != "" ]; then
|
||||
# Azure Pipelines
|
||||
echo "Azure detected"
|
||||
CI_NAME="$(echo "$AGENT_OS" | tr '[:upper:]' '[:lower:]')"
|
||||
CI_BUILD_DIR="$BUILD_SOURCESDIRECTORY"
|
||||
elif [ "$HOME" != "" ]; then
|
||||
if [ "$HOME" != "" ]; then
|
||||
# GitHub Actions
|
||||
echo "Github Actions detected"
|
||||
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
||||
else
|
||||
|
@ -1,11 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# detect CI
|
||||
if [ "$SYSTEM_COLLECTIONID" != "" ]; then
|
||||
# Azure Pipelines
|
||||
CI_NAME="$(echo "$AGENT_OS" | tr '[:upper:]' '[:lower:]')"
|
||||
CI_BUILD_DIR="$BUILD_SOURCESDIRECTORY"
|
||||
elif [ "$HOME" != "" ]; then
|
||||
if [ "$HOME" != "" ]; then
|
||||
# GitHub Actions
|
||||
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
shell: cmd
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -27,5 +27,11 @@ libsrc/flatbufserver/hyperion_request_generated.h
|
||||
*.kdev*
|
||||
|
||||
# Visual Studio 2015/2017/2019 cache/options directory
|
||||
.vs/
|
||||
# Ignore
|
||||
.vs/*
|
||||
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",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/bin/Debug/hyperiond.exe",
|
||||
"program": "${command:cmake.launchTargetDirectory}/hyperiond",
|
||||
"args": ["-d"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false
|
||||
"console": "internalConsole"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -4,10 +4,15 @@ message( STATUS "CMake Version: ${CMAKE_VERSION}" )
|
||||
|
||||
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)
|
||||
file (STRINGS "version" 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.
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
@ -50,6 +55,7 @@ SET ( DEFAULT_USE_SYSTEM_PROTO_LIBS OFF )
|
||||
SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF )
|
||||
SET ( DEFAULT_TESTS OFF )
|
||||
SET ( DEFAULT_EXPERIMENTAL OFF )
|
||||
SET ( DEFAULT_MF OFF )
|
||||
SET ( DEFAULT_DEPLOY_DEPENDENCIES ON )
|
||||
|
||||
IF ( ${CMAKE_SYSTEM} MATCHES "Linux" )
|
||||
@ -60,7 +66,8 @@ IF ( ${CMAKE_SYSTEM} MATCHES "Linux" )
|
||||
SET ( DEFAULT_USB_HID ON )
|
||||
SET ( DEFAULT_CEC ON )
|
||||
ELSEIF ( WIN32 )
|
||||
SET ( DEFAULT_DX OFF )
|
||||
SET ( DEFAULT_DX ON )
|
||||
SET ( DEFAULT_MF ON )
|
||||
ELSE()
|
||||
SET ( DEFAULT_V4L2 OFF )
|
||||
SET ( DEFAULT_FB OFF )
|
||||
@ -122,6 +129,11 @@ elseif ( "${PLATFORM}" MATCHES "rpi" )
|
||||
SET ( DEFAULT_WS281XPWM ON )
|
||||
elseif ( "${PLATFORM}" STREQUAL "amlogic" )
|
||||
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" )
|
||||
SET ( DEFAULT_AMLOGIC ON )
|
||||
elseif ( "${PLATFORM}" MATCHES "x11" )
|
||||
@ -150,17 +162,18 @@ ADD_DEFINITIONS( ${PLATFORM_DEFINE} )
|
||||
option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_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)
|
||||
SET(ENABLE_FB ON)
|
||||
else()
|
||||
option(ENABLE_FB "Enable the framebuffer grabber" ${DEFAULT_FB} )
|
||||
endif()
|
||||
|
||||
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}")
|
||||
|
||||
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})
|
||||
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} )
|
||||
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})
|
||||
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}")
|
||||
|
||||
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
|
||||
FILE ( GLOB_RECURSE HYPERION_SCHEMAS RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc/*schema*.json )
|
||||
SET( JSON_FILES
|
||||
config/hyperion.config.json.default
|
||||
${HYPERION_SCHEMAS}
|
||||
)
|
||||
SET( JSON_FILES ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default ${HYPERION_SCHEMAS})
|
||||
|
||||
EXECUTE_PROCESS (
|
||||
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')
|
||||
IF (NOT WIN32)
|
||||
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}
|
||||
RESULT_VARIABLE CHECK_CONFIG_FAILED
|
||||
)
|
||||
@ -399,31 +412,6 @@ find_package(libusb-1.0 REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
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)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
|
||||
endif()
|
||||
|
@ -1,48 +1,51 @@
|
||||
// Generated config file
|
||||
|
||||
// Define to enable the dispmanx grabber
|
||||
// Define to enable the DispmanX grabber
|
||||
#cmakedefine ENABLE_DISPMANX
|
||||
|
||||
// Define to enable the v4l2 grabber
|
||||
// Define to enable the V4L2 grabber
|
||||
#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
|
||||
|
||||
// Define to enable the amlogic grabber
|
||||
// Define to enable the AMLogic grabber
|
||||
#cmakedefine ENABLE_AMLOGIC
|
||||
|
||||
// Define to enable the osx grabber
|
||||
// Define to enable the OSX grabber
|
||||
#cmakedefine ENABLE_OSX
|
||||
|
||||
// Define to enable the x11 grabber
|
||||
// Define to enable the X11 grabber
|
||||
#cmakedefine ENABLE_X11
|
||||
|
||||
// Define to enable the xcb grabber
|
||||
// Define to enable the XCB grabber
|
||||
#cmakedefine ENABLE_XCB
|
||||
|
||||
// Define to enable the qt grabber
|
||||
// Define to enable the Qt grabber
|
||||
#cmakedefine ENABLE_QT
|
||||
|
||||
// Define to enable the DirectX grabber
|
||||
#cmakedefine ENABLE_DX
|
||||
|
||||
// Define to enable the spi-device
|
||||
// Define to enable the SPI-Device
|
||||
#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
|
||||
|
||||
// Define to enable the tinkerforge device
|
||||
// Define to enable the Tinkerforge device
|
||||
#cmakedefine ENABLE_TINKERFORGE
|
||||
|
||||
// Define to enable avahi
|
||||
// Define to enable AVAHI
|
||||
#cmakedefine ENABLE_AVAHI
|
||||
|
||||
// Define to enable cec
|
||||
// Define to enable CEC
|
||||
#cmakedefine ENABLE_CEC
|
||||
|
||||
// Define to enable the usb / hid devices
|
||||
// Define to enable the USB / HID devices
|
||||
#cmakedefine ENABLE_USB_HID
|
||||
|
||||
// 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 id="btn_wiz_holder"></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 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>
|
||||
</button>
|
||||
<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>
|
||||
</div>
|
||||
<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">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -29,22 +57,34 @@
|
||||
<tr>
|
||||
<td></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>
|
||||
<td></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>
|
||||
<td></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>
|
||||
<td></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>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -61,17 +101,17 @@
|
||||
<tr>
|
||||
<td></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>
|
||||
<td></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>
|
||||
<td></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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -8,6 +8,7 @@
|
||||
<div class="panel-body">
|
||||
<form>
|
||||
<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="show_pw" type="checkbox" id="show_pw" /><label for="show_pw">Show/Hide Password</label>
|
||||
</div>
|
||||
|
@ -24,14 +24,34 @@ body{
|
||||
*/
|
||||
/* fixed brand icon */
|
||||
@media (min-width: 768px){
|
||||
.navbar-brand{position:fixed}
|
||||
#main-nav{position:absolute !important;}
|
||||
#wrapper{
|
||||
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*/
|
||||
@media (max-width: 768px){
|
||||
.navbar-toggle{position:fixed;right:0px;}
|
||||
#main-nav{position:fixed;right:-200px;}
|
||||
#wrapper{
|
||||
padding: 0px;
|
||||
}
|
||||
.navbar-toggle{
|
||||
position:fixed;right:0px;
|
||||
}
|
||||
#main-nav{
|
||||
position:fixed;right:-200px;
|
||||
}
|
||||
}
|
||||
.navbar-toggle .icon-bar {
|
||||
background-color:#4c4c4c !important;
|
||||
@ -72,23 +92,25 @@ table.input-group{width:100%}
|
||||
@media (max-width: 767px) {.ltd{white-space:normal;}}
|
||||
|
||||
/*icon spacing*/
|
||||
.fa-fw,.mdi-24px{margin-right:5px;}
|
||||
.fa-fw, .mdi-24px{margin-right:5px;}
|
||||
|
||||
/*table*/
|
||||
table.borderless td,table.borderless th{border: none !important;}
|
||||
table.borderless td:first-child{width: 25px !important;}
|
||||
.borderless {margin-bottom:0px}
|
||||
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{width: 25px !important;}
|
||||
|
||||
/*Header*/
|
||||
.navbar-brand{padding-top:4px;padding-bottom:0px;padding-left:2;}
|
||||
.sidebar{margin-top:65px;}
|
||||
.navbar-brand{top:0px;left:17px;padding-top:0;}
|
||||
.sidebar{margin-top:85px;}
|
||||
.dropdown{font-size:18px;}
|
||||
@media (max-width: 767px) {.sidebar{margin-top:0px;padding-top:0px !important;}}
|
||||
.page-header{margin-top:0px;}
|
||||
|
||||
.navbar-top-links li a {
|
||||
min-height: 64px;
|
||||
min-height: 84px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@ -216,6 +238,7 @@ table.first_cell_borderless td:first-child,table.first_cell_borderless th:first-
|
||||
.btn-transparent {
|
||||
background-color: transparent;
|
||||
border-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/*general instance management button*/
|
||||
|
@ -274,6 +274,9 @@
|
||||
"edt_conf_enum_NTSC": "NTSC",
|
||||
"edt_conf_enum_PAL": "PAL",
|
||||
"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_bbclassic": "Klassisch",
|
||||
"edt_conf_enum_bbdefault": "Standard",
|
||||
@ -442,6 +445,8 @@
|
||||
"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_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_title": "Zertifikats-Pfad",
|
||||
"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_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_lang_text": "If you don't like the result of the automatic language detection you could overwrite it here.",
|
||||
"InfoDialog_lang_title": "Language setting",
|
||||
"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_nostorage_title": "Cannot store settings",
|
||||
"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_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_error": "We had trouble collecting 3rd party licenses information from web. <br />Please follow this link to the GitHub Resource.",
|
||||
"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_label_title": "General settings",
|
||||
"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_option": "Option",
|
||||
"conf_leds_config_error": "Error in LED/LED layout configuration",
|
||||
@ -127,10 +130,12 @@
|
||||
"conf_leds_optgroup_RPiGPIO": "RPi GPIO",
|
||||
"conf_leds_optgroup_RPiPWM": "RPi PWM",
|
||||
"conf_leds_optgroup_RPiSPI": "RPi SPI",
|
||||
"conf_leds_optgroup_debug": "Debug",
|
||||
"conf_leds_optgroup_network": "Network",
|
||||
"conf_leds_optgroup_other": "Other",
|
||||
"conf_leds_optgroup_usb": "USB/Serial",
|
||||
"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_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.",
|
||||
@ -274,6 +279,9 @@
|
||||
"edt_conf_enum_NTSC": "NTSC",
|
||||
"edt_conf_enum_PAL": "PAL",
|
||||
"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_bbclassic": "Classic",
|
||||
"edt_conf_enum_bbdefault": "Default",
|
||||
@ -358,11 +366,20 @@
|
||||
"edt_conf_general_port_title": "Port",
|
||||
"edt_conf_general_priority_expl": "The priority of this component",
|
||||
"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_v4lEnable_expl": "Enables the USB capture for this LED hardware instance",
|
||||
"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_log_heading_title": "Logging",
|
||||
"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_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_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_title": "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_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_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_title": "Certificate path",
|
||||
"edt_conf_webc_docroot_expl": "Local webinterface root path (just for webui developer)",
|
||||
@ -607,6 +644,7 @@
|
||||
"edt_eff_height": "Height",
|
||||
"edt_eff_huechange": "Color change",
|
||||
"edt_eff_image": "Image file",
|
||||
"edt_eff_initial_blink" : "Flash for attention",
|
||||
"edt_eff_interval": "Interval",
|
||||
"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.",
|
||||
@ -644,6 +682,7 @@
|
||||
"edt_eff_reversedirection": "Reverse direction",
|
||||
"edt_eff_rotationtime": "Rotation time",
|
||||
"edt_eff_saturation": "Saturation",
|
||||
"edt_eff_set_post_color" : "Set post color after alam",
|
||||
"edt_eff_showseconds": "Show seconds",
|
||||
"edt_eff_sleeptime": "Sleep time",
|
||||
"edt_eff_smooth_custom": "Enable smoothing",
|
||||
@ -748,11 +787,11 @@
|
||||
"general_comp_BOBLIGHTSERVER": "Boblight Server",
|
||||
"general_comp_FLATBUFSERVER": "Flatbuffers Server",
|
||||
"general_comp_FORWARDER": "Forwarder",
|
||||
"general_comp_GRABBER": "Screen Capture",
|
||||
"general_comp_LEDDEVICE": "LED device",
|
||||
"general_comp_GRABBER": "Capture Screen",
|
||||
"general_comp_LEDDEVICE": "LED Output",
|
||||
"general_comp_PROTOSERVER": "Protocol Buffers Server",
|
||||
"general_comp_SMOOTHING": "Smoothing",
|
||||
"general_comp_V4L": "USB Capture",
|
||||
"general_comp_V4L": "Capture USB-Input",
|
||||
"general_country_cn": "China",
|
||||
"general_country_de": "Germany",
|
||||
"general_country_es": "Spain",
|
||||
@ -812,6 +851,7 @@
|
||||
"main_ledsim_btn_togglelednumber": "LED numbers",
|
||||
"main_ledsim_btn_toggleleds": "Show LEDs",
|
||||
"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_title": "LED Visualization",
|
||||
"main_menu_about_token": "About Hyperion",
|
||||
@ -823,7 +863,8 @@
|
||||
"main_menu_general_conf_token": "General",
|
||||
"main_menu_grabber_conf_token": "Capturing Hardware",
|
||||
"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_network_conf_token": "Network Services",
|
||||
"main_menu_remotecontrol_token": "Remote Control",
|
||||
@ -956,6 +997,7 @@
|
||||
"wiz_hue_title": "Philips Hue Wizard",
|
||||
"wiz_hue_username": "User ID:",
|
||||
"wiz_identify": "Identify",
|
||||
"wiz_identify_tip": "Identify configured device by lighting it up",
|
||||
"wiz_identify_light": "Identify $1",
|
||||
"wiz_ids_disabled": "Deactivated",
|
||||
"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>
|
||||
<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';
|
||||
}
|
||||
</script>
|
||||
@ -52,6 +51,8 @@
|
||||
<script src="js/lib/jquery.i18n/jquery.i18n.language.js"></script>
|
||||
<script src="js/lib/jquery.i18n/CLDRPluralRuleParser.js"></script>
|
||||
|
||||
<script src="js/languages.js"></script>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<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>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<div style="color:red;margin: 40px 0;text-align:center">
|
||||
<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>
|
||||
</div>
|
||||
<style type="text/css"> #loading_overlay, #wrapper{ display: none } </style>
|
||||
<style type="text/css">
|
||||
#loading_overlay, #wrapper {
|
||||
display: none
|
||||
}
|
||||
</style>
|
||||
</noscript>
|
||||
|
||||
<div id="loading_overlay" class="overlay"></div>
|
||||
<div id="wrapper">
|
||||
|
||||
<!-- 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">
|
||||
<button type="button" class="navbar-toggle closed" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
@ -105,7 +109,7 @@
|
||||
<span class="icon-bar middle-bar"></span>
|
||||
<span class="icon-bar bottom-bar"></span>
|
||||
</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>
|
||||
<!-- /.navbar-header -->
|
||||
@ -166,8 +170,8 @@
|
||||
<li id="btn_setlang">
|
||||
<a>
|
||||
<div>
|
||||
<i class="fa fa-globe"></i>
|
||||
<select id="language-select" class="selectpicker" data-width="fit" data-style="btn-transparent" > </select>
|
||||
<i class="fa fa-globe fa-fw"></i>
|
||||
<select id="language-select" class="selectpicker" data-width="fit" data-style="btn-transparent"> </select>
|
||||
</div>
|
||||
</a>
|
||||
</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="#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"><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">
|
||||
<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_colors"><i class="fa fa-photo fa-fw"></i><span data-i18n="main_menu_colors_conf_token">Image Processing</span></a> </li>
|
||||
</ul>
|
||||
</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" 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="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" 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="#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"><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">
|
||||
<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" 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>
|
||||
@ -285,7 +290,7 @@
|
||||
<div id="wizp1">
|
||||
<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">
|
||||
<div id="wizp1_body" ></div>
|
||||
<div id="wizp1_body"></div>
|
||||
</div>
|
||||
<div id="wizp1_footer" class="modal-footer" style="text-align:center"></div>
|
||||
</div>
|
||||
@ -320,6 +325,7 @@
|
||||
<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-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>
|
||||
</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 += '</div></div>';
|
||||
|
||||
|
||||
instances_html += '<div class="panel-body">';
|
||||
instances_html += '<table class="table borderless">';
|
||||
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 += '<span>' + $.i18n('dashboard_infobox_label_title') + '</span>';
|
||||
instances_html += '</th></tr></thead>';
|
||||
instances_html += '<tbody><tr><td></td>';
|
||||
instances_html += '<td>' + $.i18n('conf_leds_contr_label_contrtype') + '</td>';
|
||||
instances_html += '<td style="text-align:right">' + window.serverConfig.device.type + '</td>';
|
||||
instances_html += '</tr><tr></tbody></table>';
|
||||
instances_html += '<tbody>';
|
||||
instances_html += '<tr><td></td><td>' + $.i18n('conf_leds_contr_label_contrtype') + '</td>';
|
||||
instances_html += '<td style="text-align:right; padding-right:0">';
|
||||
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 += '<thead><tr><th colspan="3">';
|
||||
@ -50,12 +52,18 @@ $(document).ready(function () {
|
||||
instances_html += '<span>' + $.i18n('dashboard_componentbox_label_title') + '</span>';
|
||||
instances_html += '</th></tr></thead>';
|
||||
|
||||
var tab_components = "";
|
||||
var componentBtn = "";
|
||||
var instance_components = "";
|
||||
for (var idx = 0; idx < components.length; idx++) {
|
||||
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" : "";
|
||||
const general_comp = "general_comp_" + components[idx].name;
|
||||
var componentBtn = '<input ' +
|
||||
componentBtn = '<input ' +
|
||||
'id="' + general_comp + '" ' + comp_enabled +
|
||||
' type="checkbox" ' +
|
||||
'data-toggle="toggle" ' +
|
||||
@ -64,14 +72,15 @@ $(document).ready(function () {
|
||||
'data-on="' + $.i18n('general_btn_on') + '" ' +
|
||||
'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').prepend(instances_html);
|
||||
|
||||
updateUiOnInstance(window.currentHyperionInstance);
|
||||
updateHyperionInstanceListing();
|
||||
|
||||
@ -83,7 +92,7 @@ $(document).ready(function () {
|
||||
for (var idx = 0; idx < components.length; idx++) {
|
||||
if (components[idx].name != "ALL") {
|
||||
$("#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 => {
|
||||
requestSetComponentState(e.currentTarget.id.split('_')[2], e.currentTarget.checked);
|
||||
});
|
||||
@ -92,6 +101,12 @@ $(document).ready(function () {
|
||||
}
|
||||
|
||||
// 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');
|
||||
$('#dash_fbPort').html(fbPort);
|
||||
var pbPort = window.serverConfig.protoServer.enable ? window.serverConfig.protoServer.port : $.i18n('general_disabled');
|
||||
|
@ -1,4 +1,4 @@
|
||||
$(document).ready( function() {
|
||||
$(document).ready(function () {
|
||||
performTranslation();
|
||||
|
||||
var importedConf;
|
||||
@ -6,8 +6,7 @@ $(document).ready( function() {
|
||||
var conf_editor = null;
|
||||
|
||||
$('#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")));
|
||||
}
|
||||
else
|
||||
@ -17,19 +16,19 @@ $(document).ready( function() {
|
||||
general: window.schema.general
|
||||
}, 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);
|
||||
});
|
||||
|
||||
$('#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());
|
||||
});
|
||||
|
||||
// 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_ma_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||
});
|
||||
@ -37,52 +36,48 @@ $(document).ready( function() {
|
||||
var inst = e.currentTarget.id.split("_")[1];
|
||||
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())
|
||||
});
|
||||
|
||||
$('#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);
|
||||
});
|
||||
}
|
||||
|
||||
function handleInstanceDelete(e)
|
||||
{
|
||||
function handleInstanceDelete(e) {
|
||||
var inst = e.currentTarget.id.split("_")[1];
|
||||
showInfoDialog('delInst',$.i18n('conf_general_inst_delreq_h'),$.i18n('conf_general_inst_delreq_t',getInstanceNameByIndex(inst)));
|
||||
$("#id_btn_yes").off().on('click', function(){
|
||||
showInfoDialog('delInst', $.i18n('conf_general_inst_delreq_h'), $.i18n('conf_general_inst_delreq_t', getInstanceNameByIndex(inst)));
|
||||
$("#id_btn_yes").off().on('click', function () {
|
||||
requestInstanceDelete(inst)
|
||||
});
|
||||
}
|
||||
|
||||
function buildInstanceList()
|
||||
{
|
||||
function buildInstanceList() {
|
||||
var inst = serverInfo.instance
|
||||
$('.itbody').html("");
|
||||
for(var key in inst)
|
||||
{
|
||||
for (var key in inst) {
|
||||
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 delBtn = "";
|
||||
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>';
|
||||
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')+'">';
|
||||
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>';
|
||||
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));
|
||||
$('#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).change(e => {
|
||||
$('#inst_' + inst[key].instance).bootstrapToggle();
|
||||
$('#inst_' + inst[key].instance).change(e => {
|
||||
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 ? $('#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 ? $('#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 ? $('#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));
|
||||
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);
|
||||
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'))
|
||||
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'))
|
||||
else
|
||||
$('#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());
|
||||
$('#inst_name').val("");
|
||||
$('#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()
|
||||
});
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
function readFile(evt)
|
||||
{
|
||||
function readFile(evt) {
|
||||
var f = evt.target.files[0];
|
||||
|
||||
if (f)
|
||||
{
|
||||
if (f) {
|
||||
var r = new FileReader();
|
||||
r.onload = function(e)
|
||||
{
|
||||
r.onload = function (e) {
|
||||
var content = e.target.result.replace(/[^:]?\/\/.*/g, ''); //remove Comments
|
||||
|
||||
//check file is json
|
||||
var check = isJsonString(content);
|
||||
if(check.length != 0)
|
||||
{
|
||||
if (check.length != 0) {
|
||||
showInfoDialog('error', "", $.i18n('infoDialog_import_jsonerror_text', f.name, JSON.stringify(check)));
|
||||
dis_imp_btn(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
content = JSON.parse(content);
|
||||
//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));
|
||||
dis_imp_btn(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
dis_imp_btn(false);
|
||||
importedConf = content;
|
||||
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));
|
||||
|
||||
$('#id_btn_import').off().on('click', function(){
|
||||
$('#id_btn_import').off().on('click', function () {
|
||||
requestWriteConfig(importedConf, true);
|
||||
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)
|
||||
readFile(e);
|
||||
else
|
||||
@ -170,23 +157,22 @@ $(document).ready( function() {
|
||||
});
|
||||
|
||||
//export
|
||||
$('#btn_export_conf').off().on('click', function(){
|
||||
$('#btn_export_conf').off().on('click', function () {
|
||||
var name = window.serverConfig.general.name;
|
||||
|
||||
var d = new Date();
|
||||
var month = d.getMonth()+1;
|
||||
var month = d.getMonth() + 1;
|
||||
var day = d.getDate();
|
||||
|
||||
var timestamp = d.getFullYear() + '.' +
|
||||
(month<10 ? '0' : '') + month + '.' +
|
||||
(day<10 ? '0' : '') + day;
|
||||
(month < 10 ? '0' : '') + month + '.' +
|
||||
(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
|
||||
if(window.showOptHelp)
|
||||
{
|
||||
if (window.showOptHelp) {
|
||||
createHint("intro", $.i18n('conf_general_intro'), "editor_container");
|
||||
createHint("intro", $.i18n('conf_general_tok_desc'), "tok_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).scroll(function(){
|
||||
$(window).scroll(function() {
|
||||
if ($(window).scrollTop() > 65)
|
||||
$("#navbar_brand_logo").css("display", "none");
|
||||
else
|
||||
$("#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() {
|
||||
@ -349,7 +354,7 @@ $("#btn_darkmode").off().on("click", function (e) {
|
||||
});
|
||||
|
||||
// Menuitem toggle;
|
||||
function SwitchToMenuItem(target) {
|
||||
function SwitchToMenuItem(target, item) {
|
||||
document.getElementById(target).click(); // Get <a href menu item;
|
||||
let sidebar = $('#side-menu'); // Get sidebar menu;
|
||||
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).addClass('active'); // Add active state by classname;
|
||||
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 colorOrderDefault = "rgb";
|
||||
|
||||
$('#btn_test_controller').hide();
|
||||
|
||||
switch (ledType) {
|
||||
case "cololight":
|
||||
case "wled":
|
||||
@ -769,11 +771,38 @@ $(document).ready(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 canSave = false;
|
||||
|
||||
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 "wled":
|
||||
var hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
|
||||
@ -797,48 +826,20 @@ $(document).ready(function () {
|
||||
}
|
||||
}
|
||||
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:
|
||||
canIdentify = false;
|
||||
canSave = true;
|
||||
}
|
||||
|
||||
if (!conf_editor.validate().length) {
|
||||
if (canIdentify) {
|
||||
$("#btn_test_controller").removeClass('hidden');
|
||||
$("#btn_test_controller").show();
|
||||
$('#btn_test_controller').attr('disabled', false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#btn_test_controller').hide();
|
||||
$('#btn_test_controller').attr('disabled', true);
|
||||
}
|
||||
|
||||
var hardwareLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
|
||||
if (hardwareLedCount < 1) {
|
||||
} else {
|
||||
canSave = false;
|
||||
}
|
||||
|
||||
@ -886,9 +887,9 @@ $(document).ready(function () {
|
||||
conf_editor.getEditor(specOptPath + "host").setValue(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
showAllDeviceInputOptions("hostList", showOptions);
|
||||
}
|
||||
});
|
||||
|
||||
conf_editor.watch('root.specificOptions.host', () => {
|
||||
@ -900,8 +901,10 @@ $(document).ready(function () {
|
||||
else {
|
||||
let params = {};
|
||||
switch (ledType) {
|
||||
|
||||
case "cololight":
|
||||
params = { host: host };
|
||||
getProperties_device(ledType, host, params);
|
||||
break;
|
||||
|
||||
case "nanoleaf":
|
||||
@ -910,33 +913,70 @@ $(document).ready(function () {
|
||||
return;
|
||||
}
|
||||
params = { host: host, token: token };
|
||||
getProperties_device(ledType, host, params);
|
||||
break;
|
||||
|
||||
case "wled":
|
||||
params = { host: host, filter: "info" };
|
||||
getProperties_device(ledType, host, params);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
getProperties_device(ledType, host, params);
|
||||
}
|
||||
});
|
||||
|
||||
conf_editor.watch('root.specificOptions.output', () => {
|
||||
var output = conf_editor.getEditor("root.specificOptions.output").getValue();
|
||||
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);
|
||||
showAllDeviceInputOptions("output", false);
|
||||
}
|
||||
else {
|
||||
showAllDeviceInputOptions("output", true);
|
||||
let params = {};
|
||||
var canIdentify = false;
|
||||
switch (ledType) {
|
||||
case "adalight":
|
||||
canIdentify = true;
|
||||
break;
|
||||
case "atmo":
|
||||
case "karate":
|
||||
params = { serialPort: output };
|
||||
getProperties_device(ledType, output, params);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Rewrite whole LED & Layout configuration, in case changes were done accross tabs and no default layout
|
||||
if (genDefLayout !== true) {
|
||||
result.ledConfig = getLedConfig();
|
||||
@ -1269,8 +1311,6 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
||||
ledTypeGroup = "devRPiGPIO";
|
||||
}
|
||||
|
||||
var specOpt = conf_editor.getEditor('root.specificOptions'); // get specificOptions of the editor
|
||||
|
||||
switch (ledTypeGroup) {
|
||||
case "devNET":
|
||||
key = "hostList";
|
||||
@ -1434,11 +1474,14 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
$('#btn_submit_controller').attr('disabled', true);
|
||||
|
||||
const result = await requestLedDeviceDiscovery(ledType, params);
|
||||
|
||||
var discoveryResult;
|
||||
@ -1479,6 +1522,7 @@ async function getProperties_device(ledType, key, params) {
|
||||
}
|
||||
else {
|
||||
$('#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.ledCount.length > 0) {
|
||||
var configuredLedCount = window.serverConfig.device.hardwareLedCount;
|
||||
var generalOpt = conf_editor.getEditor('root.generalOptions');
|
||||
updateJsonEditorSelection(generalOpt, "hardwareLedCount", {}, ledProperties.ledCount, [], configuredLedCount);
|
||||
updateJsonEditorSelection(conf_editor, 'root.generalOptions', "hardwareLedCount", {}, ledProperties.ledCount, [], configuredLedCount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -25,7 +25,7 @@ $(document).ready(function () {
|
||||
$('#btn_submit').off().on('click', function () {
|
||||
|
||||
var displayedLogLevel = conf_editor.getEditor("root.logger.level").getValue();
|
||||
var newLogLevel = {logger:{}};
|
||||
var newLogLevel = { logger: {} };
|
||||
newLogLevel.logger.level = displayedLogLevel;
|
||||
|
||||
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 () {
|
||||
const temp = document.createElement('textarea');
|
||||
|
@ -7,7 +7,7 @@ $(document).ready(function () {
|
||||
var oldEffects = [];
|
||||
var cpcolor = '#B500FF';
|
||||
var mappingList = window.serverSchema.properties.color.properties.imageToLedMappingType.enum;
|
||||
var duration = 0;
|
||||
var duration = ENDLESS;
|
||||
var rgb = { r: 255, g: 0, b: 0 };
|
||||
var lastImgData = "";
|
||||
var lastFileName = "";
|
||||
@ -201,7 +201,9 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
const enable_style = (comp.enabled ? "checked" : "");
|
||||
|
@ -33,6 +33,8 @@ window.comps = [];
|
||||
window.defaultPasswordIsSet = null;
|
||||
tokenList = {};
|
||||
|
||||
const ENDLESS = -1;
|
||||
|
||||
function initRestart()
|
||||
{
|
||||
$(window.hyperion).off();
|
||||
@ -470,8 +472,14 @@ async function requestLedDeviceProperties(type, params)
|
||||
|
||||
function requestLedDeviceIdentification(type, params)
|
||||
{
|
||||
//sendToHyperion("leddevice", "identify", '"ledDeviceType": "'+type+'","params": '+JSON.stringify(params)+'');
|
||||
let data = { ledDeviceType: type, params: params };
|
||||
|
||||
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 ledsim_width = 540;
|
||||
var ledsim_height = 489;
|
||||
var dialog;
|
||||
var leds;
|
||||
var grabberConfig;
|
||||
var lC = false;
|
||||
var imageCanvasNodeCtx;
|
||||
var ledsCanvasNodeCtx;
|
||||
var canvas_height;
|
||||
var canvas_width;
|
||||
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
|
||||
CanvasRenderingContext2D.prototype.clear = function(){
|
||||
CanvasRenderingContext2D.prototype.clear = function () {
|
||||
this.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||
};
|
||||
|
||||
function create2dPaths(){
|
||||
function create2dPaths() {
|
||||
twoDPaths = [];
|
||||
for(var idx=0; idx<leds.length; idx++)
|
||||
{
|
||||
for (var idx = 0; idx < leds.length; 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) {
|
||||
if (typeof radius == 'number') {
|
||||
radius = {tl: radius, tr: radius, br: radius, bl: radius};
|
||||
radius = { tl: radius, tr: radius, br: radius, bl: radius };
|
||||
} 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) {
|
||||
radius[side] = radius[side] || defaultRadius[side];
|
||||
}
|
||||
@ -67,18 +74,17 @@ $(document).ready(function() {
|
||||
return path;
|
||||
}
|
||||
|
||||
$(window.hyperion).one("ready",function(){
|
||||
$(window.hyperion).one("ready", function () {
|
||||
leds = window.serverConfig.leds;
|
||||
grabberConfig = window.serverConfig.grabberV4L2;
|
||||
|
||||
if(window.showOptHelp)
|
||||
{
|
||||
if (window.showOptHelp) {
|
||||
createHint('intro', $.i18n('main_ledsim_text'), 'ledsim_text');
|
||||
$('#ledsim_text').css({'margin':'10px 15px 0px 15px'});
|
||||
$('#ledsim_text .bs-callout').css("margin","0px")
|
||||
$('#ledsim_text').css({ 'margin': '10px 15px 0px 15px' });
|
||||
$('#ledsim_text .bs-callout').css("margin", "0px")
|
||||
}
|
||||
|
||||
if(getStorage('ledsim_width') != null)
|
||||
{
|
||||
if (getStorage('ledsim_width') != null) {
|
||||
ledsim_width = getStorage('ledsim_width');
|
||||
ledsim_height = getStorage('ledsim_height');
|
||||
}
|
||||
@ -98,8 +104,7 @@ $(document).ready(function() {
|
||||
updateLedLayout();
|
||||
},
|
||||
opened: function (e) {
|
||||
if(!lC)
|
||||
{
|
||||
if (!lC) {
|
||||
updateLedLayout();
|
||||
lC = true;
|
||||
}
|
||||
@ -107,11 +112,12 @@ $(document).ready(function() {
|
||||
requestLedColorsStart();
|
||||
|
||||
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();
|
||||
},
|
||||
closed: function (e) {
|
||||
modalOpened = false;
|
||||
lC = false;
|
||||
},
|
||||
resizeStop: function (e) {
|
||||
setStorage("ledsim_width", $("#ledsim_dialog").outerWidth());
|
||||
@ -119,48 +125,58 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
// apply new serverinfos
|
||||
$(window.hyperion).on("cmd-config-getconfig",function(event){
|
||||
$(window.hyperion).on("cmd-config-getconfig", function (event) {
|
||||
leds = event.response.info.leds;
|
||||
grabberConfig = event.response.info.grabberV4L2;
|
||||
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
|
||||
if(toggleLeds)
|
||||
if (toggleLeds)
|
||||
return;
|
||||
|
||||
var useColor = false;
|
||||
var cPos = 0;
|
||||
ledsCanvasNodeCtx.clear();
|
||||
if(typeof colors != "undefined")
|
||||
if (typeof colors != "undefined")
|
||||
useColor = true;
|
||||
|
||||
// check size of ledcolors with leds length
|
||||
if(colors && colors.length/3 < leds.length)
|
||||
if (colors && colors.length / 3 < leds.length)
|
||||
return;
|
||||
|
||||
for(var idx=0; idx<leds.length; idx++)
|
||||
{
|
||||
for (var idx = 0; idx < leds.length; idx++) {
|
||||
var led = leds[idx];
|
||||
// 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])
|
||||
//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.strokeStyle = '#323232';
|
||||
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
|
||||
|
||||
if(toggleLedsNum)
|
||||
{
|
||||
if (toggleLedsNum) {
|
||||
//ledsCanvasNodeCtx.shadowOffsetX = 1;
|
||||
//ledsCanvasNodeCtx.shadowOffsetY = 1;
|
||||
//ledsCanvasNodeCtx.shadowColor = "black";
|
||||
//ledsCanvasNodeCtx.shadowBlur = 4;
|
||||
ledsCanvasNodeCtx.fillStyle = "white";
|
||||
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
|
||||
@ -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
|
||||
canvas_height = $('#ledsim_dialog').outerHeight()-$('#ledsim_text').outerHeight()-$('[data-role=footer]').outerHeight()-$('[data-role=header]').outerHeight()-40;
|
||||
canvas_width = $('#ledsim_dialog').outerWidth()-30;
|
||||
canvas_height = $('#ledsim_dialog').outerHeight() - $('#ledsim_text').outerHeight() - $('[data-role=footer]').outerHeight() - $('[data-role=header]').outerHeight() - 40;
|
||||
canvas_width = $('#ledsim_dialog').outerWidth() - 30;
|
||||
|
||||
$('#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>';
|
||||
leds_html += '<canvas id="leds_preview_canv" width="'+canvas_width+'" height="'+canvas_height+'" style="position: absolute; left: 0; top: 0; z-index: 99999;"></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="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);
|
||||
|
||||
imageCanvasNodeCtx = document.getElementById("image_preview_canv").getContext("2d");
|
||||
ledsCanvasNodeCtx = document.getElementById("leds_preview_canv").getContext("2d");
|
||||
sigDetectAreaCanvasNodeCtx = document.getElementById("grab_preview_canv").getContext("2d");
|
||||
create2dPaths();
|
||||
printLedsToCanvas();
|
||||
resetImage();
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
$('#leds_toggle_num').off().on("click", function() {
|
||||
$('#leds_toggle_num').off().on("click", function () {
|
||||
toggleLedsNum = !toggleLedsNum
|
||||
toggleClass('#leds_toggle_num', "btn-danger", "btn-success");
|
||||
});
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$('#leds_toggle').off().on("click", function() {
|
||||
$('#leds_toggle').off().on("click", function () {
|
||||
toggleLeds = !toggleLeds
|
||||
ledsCanvasNodeCtx.clear();
|
||||
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() {
|
||||
setClassByBool('#leds_toggle_live_video',window.imageStreamActive,"btn-success","btn-danger");
|
||||
if ( window.imageStreamActive )
|
||||
{
|
||||
$('#leds_toggle_live_video').off().on("click", function () {
|
||||
setClassByBool('#leds_toggle_live_video', window.imageStreamActive, "btn-success", "btn-danger");
|
||||
if (window.imageStreamActive) {
|
||||
requestLedImageStop();
|
||||
resetImage();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
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){
|
||||
if (!modalOpened)
|
||||
{
|
||||
$(window.hyperion).on("cmd-ledcolors-ledstream-update", function (event) {
|
||||
if (!modalOpened) {
|
||||
requestLedColorsStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
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");
|
||||
if (!modalOpened)
|
||||
{
|
||||
if (!modalOpened) {
|
||||
if ($('#leds_prev_toggle_live_video').length > 0)
|
||||
return;
|
||||
requestLedImageStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
var imageData = (event.response.result.image);
|
||||
|
||||
var image = new Image();
|
||||
image.onload = function() {
|
||||
image.onload = function () {
|
||||
imageCanvasNodeCtx.drawImage(image, 0, 0, canvas_width, canvas_height);
|
||||
};
|
||||
image.src = imageData;
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn_open_ledsim").off().on("click", function(event) {
|
||||
$("#btn_open_ledsim").off().on("click", function (event) {
|
||||
dialog.open();
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
$(window.hyperion).on("cmd-settings-update",function(event){
|
||||
$(window.hyperion).on("cmd-settings-update", function (event) {
|
||||
|
||||
var obj = event.response.data
|
||||
if ( obj.leds) {
|
||||
console.log("ledsim: cmd-settings-update", event.response.data);
|
||||
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
|
||||
if (obj.leds || obj.grabberV4L2) {
|
||||
//console.log("ledsim: cmd-settings-update", event.response.data);
|
||||
Object.getOwnPropertyNames(obj).forEach(function (val, idx, array) {
|
||||
window.serverInfo[val] = obj[val];
|
||||
});
|
||||
leds = window.serverConfig.leds
|
||||
leds = window.serverConfig.leds;
|
||||
grabberConfig = window.serverConfig.grabberV4L2;
|
||||
updateLedLayout();
|
||||
}
|
||||
});
|
||||
|
||||
function resetImage(){
|
||||
if (getStorage("darkMode", false) == "on") {
|
||||
imageCanvasNodeCtx.clear();
|
||||
} else {
|
||||
imageCanvasNodeCtx.fillStyle = "rgb(225,225,225)"
|
||||
imageCanvasNodeCtx.fillRect(0, 0, canvas_width, canvas_height);
|
||||
$(window.hyperion).on("cmd-priorities-update", function (event) {
|
||||
//console.log("cmd-priorities-update", event.response.data);
|
||||
|
||||
var prios = event.response.data.priorities;
|
||||
if (prios.length > 0)
|
||||
{
|
||||
//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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1839,7 +1839,14 @@ JSONEditor.AbstractEditor = Class.extend({
|
||||
this.parent = null;
|
||||
},
|
||||
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];
|
||||
|
||||
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'];
|
||||
|
||||
//$.i18n.debug = true;
|
||||
var storedAccess;
|
||||
|
||||
//Change Password
|
||||
function changePassword(){
|
||||
@ -26,48 +21,11 @@ function changePassword(){
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready( function() {
|
||||
$(document).ready(function () {
|
||||
|
||||
//i18n
|
||||
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
|
||||
{
|
||||
if (!storageComp()) {
|
||||
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');
|
||||
storedLang = 'auto';
|
||||
storedAccess = "default";
|
||||
$('#btn_setlang').attr("disabled", true);
|
||||
$('#language-select').attr("disabled", true);
|
||||
$('#btn_setaccess').attr("disabled", true);
|
||||
}
|
||||
|
||||
@ -75,10 +33,14 @@ $(document).ready( function() {
|
||||
|
||||
//access
|
||||
storedAccess = getStorage("accesslevel");
|
||||
if (storedAccess == null)
|
||||
{
|
||||
setStorage("accesslevel", "default");
|
||||
if (storedAccess == null) {
|
||||
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() {
|
||||
|
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) {
|
||||
if (typeof d === "undefined" || d < 0)
|
||||
return 0;
|
||||
return ENDLESS;
|
||||
else
|
||||
return d *= 1000;
|
||||
}
|
||||
@ -162,25 +162,22 @@ function initLanguageSelection() {
|
||||
|
||||
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
|
||||
var langIdx = availLang.indexOf(langLocale);
|
||||
if (langIdx > -1) {
|
||||
langText = availLangText[langIdx];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// If language is not supported by hyperion, try fallback language
|
||||
langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
|
||||
langIdx = availLang.indexOf(langLocale);
|
||||
if (langIdx > -1) {
|
||||
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);
|
||||
$('#active_instance_dropdown').prop('disabled', false);
|
||||
$('#active_instance_dropdown').css('cursor', 'pointer');
|
||||
$("#active_instance_dropdown").css("pointer-events", "auto");
|
||||
} else {
|
||||
$('#btn_hypinstanceswitch').toggle(false);
|
||||
$('#active_instance_dropdown').prop('disabled', true);
|
||||
$("#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") {
|
||||
$('#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('<input class="form-control" id="oldPw" placeholder="Old" type="text"> <br />');
|
||||
$('#id_body_rename').append('<input class="form-control" id="newPw" placeholder="New" type="password">');
|
||||
$('#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('<h4>' + header + '</h4><br>');
|
||||
$('#id_body_rename').append('<div class="row"><div class="col-md-3"><p class="text-left">' + $.i18n('infoDialog_password_current_text') +
|
||||
'</p></div><div class="col-md-8"><input class="form-control" id="oldPw" placeholder="Old" type="password"></div></div><br>');
|
||||
$('#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>');
|
||||
}
|
||||
else if (type == "checklist") {
|
||||
@ -461,7 +462,8 @@ function createJsonEditor(container, schema, setconfig, usePanel, arrayre) {
|
||||
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 newSchema = [];
|
||||
@ -536,13 +538,15 @@ function updateJsonEditorSelection(editor, key, addElements, newEnumVals, newTit
|
||||
|
||||
editor.original_schema.properties[key] = orginalProperties;
|
||||
editor.schema.properties[key] = newSchema[key];
|
||||
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||
|
||||
editor.removeObjectProperty(key);
|
||||
delete editor.cached_editors[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 newSchema = [];
|
||||
@ -593,36 +597,55 @@ function updateJsonEditorMultiSelection(editor, key, addElements, newEnumVals, n
|
||||
|
||||
editor.original_schema.properties[key] = orginalProperties;
|
||||
editor.schema.properties[key] = newSchema[key];
|
||||
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||
|
||||
editor.removeObjectProperty(key);
|
||||
delete editor.cached_editors[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 newSchema = [];
|
||||
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;
|
||||
}
|
||||
if (maximum) {
|
||||
if (typeof maximum !== "undefined") {
|
||||
newSchema[key]["maximum"] = maximum;
|
||||
}
|
||||
if (defaultValue) {
|
||||
if (typeof defaultValue !== "undefined") {
|
||||
newSchema[key]["default"] = defaultValue;
|
||||
currentValue = defaultValue;
|
||||
}
|
||||
if (step) {
|
||||
|
||||
if (typeof step !== "undefined") {
|
||||
newSchema[key]["step"] = step;
|
||||
}
|
||||
|
||||
editor.original_schema.properties[key] = orginalProperties;
|
||||
editor.schema.properties[key] = newSchema[key];
|
||||
rootEditor.validator.schema.properties[editor.key].properties[key] = newSchema[key];
|
||||
|
||||
editor.removeObjectProperty(key);
|
||||
delete editor.cached_editors[key];
|
||||
editor.addObjectProperty(key);
|
||||
|
||||
// Restore current (new default) value for new range
|
||||
rootEditor.getEditor(path + "." + key).setValue(currentValue);
|
||||
}
|
||||
|
||||
function buildWL(link, linkt, cl) {
|
||||
@ -807,14 +830,15 @@ function createRow(id) {
|
||||
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;
|
||||
|
||||
var pfooter = document.createElement('button');
|
||||
pfooter.className = "btn btn-primary";
|
||||
pfooter.setAttribute("id", footerid);
|
||||
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') {
|
||||
@ -1141,14 +1165,34 @@ function isAccessLevelCompliant(accessLevel) {
|
||||
|
||||
function showInputOptions(path, elements, state) {
|
||||
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 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) {
|
||||
if (showForKey !== key) {
|
||||
if ($.inArray(key, keysToshow) === -1) {
|
||||
var accessLevel = editor.schema.properties[item].properties[key].access;
|
||||
|
||||
//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-compat-libdnssd-dev \
|
||||
libssl-dev \
|
||||
libjpeg-dev \
|
||||
libqt5sql5-sqlite \
|
||||
libqt5svg5-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
|
||||
# packages string inserted to cmake cmd
|
||||
PACKAGES=""
|
||||
# platform string inserted to cmake cmd
|
||||
BUILD_PLATFORM=""
|
||||
#Run build using GitHub code files
|
||||
BUILD_LOCAL=0
|
||||
#Build from scratch
|
||||
@ -73,6 +75,7 @@ echo "########################################################
|
||||
# docker-compile.sh -p true # If true, build packages with CPack
|
||||
# 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 -f x11 # cmake PLATFORM parameter
|
||||
# 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"
|
||||
|
||||
while getopts i:t:b:p:lcvh option
|
||||
while getopts i:t:b:p:f:lcvh option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
@ -92,6 +95,7 @@ do
|
||||
t) BUILD_TAG=${OPTARG};;
|
||||
b) BUILD_TYPE=${OPTARG};;
|
||||
p) BUILD_PACKAGES=${OPTARG};;
|
||||
f) BUILD_PLATFORM=${OPTARG,,};;
|
||||
l) BUILD_LOCAL=1;;
|
||||
c) BUILD_INCREMENTAL=1;;
|
||||
v) _VERBOSE=1;;
|
||||
@ -104,7 +108,12 @@ if [ ${BUILD_PACKAGES} == "true" ]; then
|
||||
PACKAGES="package"
|
||||
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}"
|
||||
CODE_PATH=${BASE_PATH};
|
||||
@ -155,7 +164,7 @@ $DOCKER run --rm \
|
||||
-v "${CODE_PATH}/:/source:rw" \
|
||||
${REGISTRY_URL}/${BUILD_IMAGE}:${BUILD_TAG} \
|
||||
/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 || : &&
|
||||
exit 0;
|
||||
exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 4; }
|
||||
@ -164,7 +173,6 @@ DOCKERRC=${?}
|
||||
|
||||
# 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}) ${DEPLOY_PATH}
|
||||
|
||||
if [ ${DOCKERRC} == 0 ]; then
|
||||
if [ ${BUILD_LOCAL} == 1 ]; then
|
||||
@ -175,6 +183,7 @@ if [ ${DOCKERRC} == 0 ]; then
|
||||
echo "---> Copying packages to host folder: ${DEPLOY_PATH}" &&
|
||||
cp -v ${BUILD_PATH}/Hyperion-* ${DEPLOY_PATH} 2>/dev/null
|
||||
echo "---> Find deployment packages in: ${DEPLOY_PATH}"
|
||||
sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${DEPLOY_PATH}
|
||||
fi
|
||||
fi
|
||||
echo "---> Script finished [${DOCKERRC}]"
|
||||
|
@ -241,7 +241,7 @@ macro(DeployWindows TARGET)
|
||||
list(REMOVE_AT DEPENDENCIES 0 1)
|
||||
endwhile()
|
||||
|
||||
# Copy OpenSSL Libs
|
||||
# Copy libssl/libcrypto to 'hyperion'
|
||||
if (OPENSSL_FOUND)
|
||||
string(REGEX MATCHALL "[0-9]+" openssl_versions "${OPENSSL_VERSION}")
|
||||
list(GET openssl_versions 0 openssl_version_major)
|
||||
@ -271,6 +271,27 @@ macro(DeployWindows TARGET)
|
||||
)
|
||||
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
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/qt.conf" "[Paths]\nPlugins=../lib/\n")
|
||||
install(
|
||||
@ -318,6 +339,30 @@ macro(DeployWindows TARGET)
|
||||
)
|
||||
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()
|
||||
# Run CMake after target was built
|
||||
add_custom_command(
|
||||
|
@ -3,15 +3,31 @@
|
||||
# TurboJPEG_INCLUDE_DIRS
|
||||
# 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
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
)
|
||||
|
||||
find_library(TurboJPEG_LIBRARY
|
||||
find_library(TurboJPEG_LIBRARY
|
||||
NAMES turbojpeg turbojpeg-static
|
||||
PATH_SUFFIXES bin lib
|
||||
)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
||||
include(CheckCSourceCompiles)
|
||||
@ -26,7 +42,7 @@ if(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARY)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(TurboJpeg
|
||||
find_package_handle_standard_args(TurboJPEG
|
||||
FOUND_VAR TURBOJPEG_FOUND
|
||||
REQUIRED_VARS TurboJPEG_LIBRARY TurboJPEG_INCLUDE_DIRS TURBOJPEG_WORKS
|
||||
TurboJPEG_INCLUDE_DIRS TurboJPEG_LIBRARY
|
||||
|
@ -16,7 +16,7 @@ install_file()
|
||||
}
|
||||
|
||||
|
||||
echo "---Hyperion ambient light postinstall ---"
|
||||
echo "--- Hyperion ambient light postinstall ---"
|
||||
|
||||
#check system
|
||||
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:
|
||||
|
||||
; 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
|
||||
|
||||
|
@ -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" :
|
||||
{
|
||||
"name" : "My Hyperion Config",
|
||||
"configVersion": "configVersionValue",
|
||||
"previousVersion": "previousVersionValue",
|
||||
"watchedVersionBranch" : "Stable",
|
||||
"showOptHelp" : true
|
||||
},
|
||||
@ -62,40 +64,49 @@
|
||||
|
||||
"grabberV4L2" :
|
||||
{
|
||||
"device" : "auto",
|
||||
"enable" : false,
|
||||
"device" : "none",
|
||||
"input" : 0,
|
||||
"encoding" : "NO_CHANGE",
|
||||
"width" : 0,
|
||||
"height" : 0,
|
||||
"fps" : 15,
|
||||
"standard" : "NO_CHANGE",
|
||||
"flip" : "NO_CHANGE",
|
||||
"fpsSoftwareDecimation" : 0,
|
||||
"sizeDecimation" : 8,
|
||||
"cropLeft" : 0,
|
||||
"cropRight" : 0,
|
||||
"cropTop" : 0,
|
||||
"cropBottom" : 0,
|
||||
"redSignalThreshold" : 5,
|
||||
"greenSignalThreshold" : 5,
|
||||
"blueSignalThreshold" : 5,
|
||||
"redSignalThreshold" : 0,
|
||||
"greenSignalThreshold" : 100,
|
||||
"blueSignalThreshold" : 0,
|
||||
"signalDetection" : false,
|
||||
"noSignalCounterThreshold" : 200,
|
||||
"cecDetection" : false,
|
||||
"sDVOffsetMin" : 0.25,
|
||||
"sDHOffsetMin" : 0.25,
|
||||
"sDVOffsetMax" : 0.75,
|
||||
"sDHOffsetMax" : 0.75
|
||||
"sDVOffsetMin" : 0.1,
|
||||
"sDVOffsetMax" : 0.9,
|
||||
"sDHOffsetMin" : 0.4,
|
||||
"sDHOffsetMax" : 0.46,
|
||||
"hardware_brightness" : 0,
|
||||
"hardware_contrast" : 0,
|
||||
"hardware_saturation" : 0,
|
||||
"hardware_hue" : 0
|
||||
},
|
||||
|
||||
"framegrabber" :
|
||||
{
|
||||
"type" : "auto",
|
||||
"enable" : false,
|
||||
"device" : "auto",
|
||||
"input" : 0,
|
||||
"width" : 80,
|
||||
"height" : 45,
|
||||
"frequency_Hz" : 10,
|
||||
"fps" : 10,
|
||||
"pixelDecimation" : 8,
|
||||
"cropLeft" : 0,
|
||||
"cropRight" : 0,
|
||||
"cropTop" : 0,
|
||||
"cropBottom" : 0,
|
||||
"display" : 0
|
||||
"cropBottom" : 0
|
||||
},
|
||||
|
||||
"blackborderdetector" :
|
||||
@ -177,9 +188,11 @@
|
||||
|
||||
"instCapture" :
|
||||
{
|
||||
"systemEnable" : true,
|
||||
"systemEnable" : false,
|
||||
"systemGrabberDevice" : "NONE",
|
||||
"systemPriority" : 250,
|
||||
"v4lEnable" : false,
|
||||
"v4lGrabberDevice" : "NONE",
|
||||
"v4lPriority" : 240
|
||||
},
|
||||
|
||||
|
@ -11,7 +11,7 @@ Note: call the script with `./docker-compile.sh -h` for more options.
|
||||
```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
|
||||
```
|
||||
**Raspbian Buster**
|
||||
**Raspbian Buster/Raspberry Pi OS**
|
||||
```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
|
||||
```
|
||||
@ -58,7 +58,7 @@ cd $HYPERION_HOME
|
||||
|
||||
```console
|
||||
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**
|
||||
@ -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.
|
||||
```console
|
||||
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..).
|
||||
|
||||
@ -98,18 +98,20 @@ brew install qt5 python3 cmake libusb doxygen zlib
|
||||
## Windows (WIP)
|
||||
We assume a 64bit Windows 10. Install the following;
|
||||
- [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))
|
||||
- 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.
|
||||
- [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)
|
||||
- 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`
|
||||
- [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:
|
||||
- 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:
|
||||
- [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);
|
||||
|
||||
/// 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
|
||||
///
|
||||
|
@ -67,6 +67,7 @@ public:
|
||||
QString getName() const { return _name; }
|
||||
|
||||
int getTimeout() const {return _timeout; }
|
||||
bool isEndless() const { return _isEndless; }
|
||||
|
||||
QJsonObject getArgs() const { return _args; }
|
||||
|
||||
@ -83,6 +84,7 @@ private:
|
||||
const int _priority;
|
||||
|
||||
const int _timeout;
|
||||
bool _isEndless;
|
||||
|
||||
const QString _script;
|
||||
const QString _name;
|
||||
|
@ -14,12 +14,16 @@ public:
|
||||
///
|
||||
/// Construct a AmlogicGrabber that will capture snapshots with specified dimensions.
|
||||
///
|
||||
/// @param[in] width The width of the captured screenshot
|
||||
/// @param[in] height The heigth of the captured screenshot
|
||||
///
|
||||
AmlogicGrabber(unsigned width, unsigned height);
|
||||
AmlogicGrabber();
|
||||
~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
|
||||
/// provided image should have the same dimensions as the configured values (_width and
|
||||
@ -31,14 +35,51 @@ public:
|
||||
///
|
||||
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:
|
||||
/**
|
||||
* Returns true if video is playing over the amlogic chip
|
||||
* @return True if video is playing else false
|
||||
*/
|
||||
bool isVideoPlaying();
|
||||
void closeDev(int &fd);
|
||||
bool openDev(int &fd, const char* dev);
|
||||
void closeDevice(int &fd);
|
||||
bool openDevice(int &fd, const char* dev);
|
||||
|
||||
int grabFrame_amvideocap(Image<ColorRgb> & image);
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <grabber/AmlogicGrabber.h>
|
||||
|
||||
///
|
||||
/// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the
|
||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
||||
/// 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 committed to the
|
||||
/// attached Hyperion.
|
||||
///
|
||||
class AmlogicWrapper : public GrabberWrapper
|
||||
@ -13,12 +13,14 @@ class AmlogicWrapper : public GrabberWrapper
|
||||
Q_OBJECT
|
||||
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] 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:
|
||||
///
|
||||
|
@ -8,8 +8,14 @@
|
||||
|
||||
// Hyperion-utils includes
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <hyperion/GrabberWrapper.h>
|
||||
#include <hyperion/Grabber.h>
|
||||
|
||||
// qt includes
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
///
|
||||
/// @brief The DirectX9 capture implementation
|
||||
///
|
||||
@ -17,33 +23,32 @@ class DirectXGrabber : public Grabber
|
||||
{
|
||||
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();
|
||||
|
||||
///
|
||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||
/// provided image should have the same dimensions as the configured values (_width and
|
||||
/// _height)
|
||||
/// provided image should have the same dimensions as the configured values (_width and _height)
|
||||
///
|
||||
/// @param[out] image The snapped screenshot
|
||||
///
|
||||
virtual int grabFrame(Image<ColorRgb> & image);
|
||||
int grabFrame(Image<ColorRgb> & image);
|
||||
|
||||
///
|
||||
/// @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
|
||||
///
|
||||
virtual bool setWidthHeight(int width, int height) { return true; };
|
||||
bool setWidthHeight(int /* width */, int /*height*/) override { return true; }
|
||||
|
||||
///
|
||||
/// @brief Apply new pixelDecimation
|
||||
///
|
||||
virtual void setPixelDecimation(int pixelDecimation);
|
||||
bool setPixelDecimation(int pixelDecimation) override;
|
||||
|
||||
///
|
||||
/// Set the crop values
|
||||
@ -52,12 +57,20 @@ public:
|
||||
/// @param cropTop Top 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
|
||||
///
|
||||
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:
|
||||
///
|
||||
@ -72,7 +85,6 @@ private:
|
||||
void freeResources();
|
||||
|
||||
private:
|
||||
int _pixelDecimation;
|
||||
unsigned _display;
|
||||
unsigned _displayWidth;
|
||||
unsigned _displayHeight;
|
||||
|
@ -9,15 +9,21 @@ public:
|
||||
///
|
||||
/// 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] cropRight Remove from right [pixels]
|
||||
/// @param[in] cropTop Remove from top [pixels]
|
||||
/// @param[in] cropBottom Remove from bottom [pixels]
|
||||
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||
/// @param[in] 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.
|
||||
|
@ -14,8 +14,7 @@
|
||||
#include <hyperion/Grabber.h>
|
||||
|
||||
///
|
||||
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a
|
||||
/// downsized and scaled resolution.
|
||||
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a downsized and scaled resolution.
|
||||
///
|
||||
class DispmanxFrameGrabber : public Grabber
|
||||
{
|
||||
@ -23,12 +22,16 @@ public:
|
||||
///
|
||||
/// Construct a DispmanxFrameGrabber 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
|
||||
///
|
||||
DispmanxFrameGrabber(unsigned width, unsigned height);
|
||||
DispmanxFrameGrabber();
|
||||
~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
|
||||
@ -44,13 +47,24 @@ public:
|
||||
///@brief Set new width and height for dispmanx, overwrite Grabber.h impl
|
||||
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:
|
||||
///
|
||||
/// Updates the frame-grab flags as used by the VC library for frame grabbing
|
||||
///
|
||||
/// @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
|
||||
@ -63,11 +77,11 @@ private:
|
||||
/// Handle to the resource for storing the captured snapshot
|
||||
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;
|
||||
|
||||
/// Flags (transforms) for creating snapshots
|
||||
int _vc_flags;
|
||||
DISPMANX_TRANSFORM_T _vc_flags;
|
||||
|
||||
// temp buffer when capturing with unsupported pitch size or
|
||||
// when we need to crop the image
|
||||
@ -78,5 +92,4 @@ private:
|
||||
|
||||
// rgba output buffer
|
||||
Image<ColorRgba> _image_rgba;
|
||||
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ typedef int DISPMANX_TRANSFORM_T;
|
||||
struct DISPMANX_MODEINFO_T {
|
||||
int width;
|
||||
int height;
|
||||
uint32_t display_num;
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
@ -16,11 +16,14 @@ public:
|
||||
///
|
||||
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
|
||||
///
|
||||
/// @param[in] grabWidth The width of the grabbed image [pixels]
|
||||
/// @param[in] grabHeight The height of the grabbed images [pixels]
|
||||
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||
/// @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:
|
||||
///
|
||||
|
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
|
||||
|
||||
#include <linux/fb.h>
|
||||
|
||||
// Utils includes
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <hyperion/Grabber.h>
|
||||
@ -14,10 +16,10 @@ public:
|
||||
/// Construct a FramebufferFrameGrabber that will capture snapshots with specified dimensions.
|
||||
///
|
||||
/// @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
|
||||
@ -30,11 +32,42 @@ public:
|
||||
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:
|
||||
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
bool getScreenInfo();
|
||||
|
||||
/// Framebuffer device e.g. /dev/fb0
|
||||
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
|
||||
/// 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.
|
||||
///
|
||||
class FramebufferWrapper: public GrabberWrapper
|
||||
@ -15,12 +15,14 @@ public:
|
||||
///
|
||||
/// 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] 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:
|
||||
///
|
||||
|
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.
|
||||
///
|
||||
/// @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;
|
||||
|
||||
///
|
||||
/// @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
|
||||
/// provided image should have the same dimensions as the configured values (_width and
|
||||
@ -40,12 +45,21 @@ public:
|
||||
///
|
||||
/// @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:
|
||||
/// display
|
||||
unsigned _screenIndex;
|
||||
int _screenIndex;
|
||||
|
||||
/// Reference to the captured diaplay
|
||||
/// Reference to the captured display
|
||||
CGDirectDisplayID _display;
|
||||
};
|
||||
|
@ -5,21 +5,79 @@
|
||||
* 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.
|
||||
*
|
||||
* 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/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 CGImage* CGImageRef;
|
||||
typedef unsigned char CFData;
|
||||
typedef CFData* CFDataRef;
|
||||
typedef unsigned CGDisplayCount;
|
||||
|
||||
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);
|
||||
void CGImageRelease(CGImageRef image);
|
||||
CGImageRef CGImageGetDataProvider(CGImageRef image);
|
||||
@ -31,4 +89,5 @@ unsigned CGImageGetBitsPerPixel(CGImageRef image);
|
||||
unsigned CGImageGetBytesPerRow(CGImageRef image);
|
||||
void CFRelease(CFDataRef imgData);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -4,9 +4,8 @@
|
||||
#include <grabber/OsxFrameGrabber.h>
|
||||
|
||||
///
|
||||
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the
|
||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
||||
/// attached Hyperion.
|
||||
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the displayed content.
|
||||
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
|
||||
///
|
||||
class OsxWrapper: public GrabberWrapper
|
||||
{
|
||||
@ -15,12 +14,14 @@ public:
|
||||
///
|
||||
/// 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] 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:
|
||||
///
|
||||
|
@ -15,14 +15,13 @@ class QtGrabber : public Grabber
|
||||
{
|
||||
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;
|
||||
|
||||
///
|
||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||
/// provided image should have the same dimensions as the configured values (_width and
|
||||
/// _height)
|
||||
/// provided image should have the same dimensions as the configured values (_width and _height)
|
||||
///
|
||||
/// @param[out] image The snapped screenshot (should be initialized with correct width and
|
||||
/// height)
|
||||
@ -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
|
||||
///
|
||||
bool setWidthHeight(int width, int height) override { return true; }
|
||||
bool setWidthHeight(int /*width*/, int /*height*/) override { return true; }
|
||||
|
||||
///
|
||||
/// @brief Apply new pixelDecimation
|
||||
///
|
||||
void setPixelDecimation(int pixelDecimation) override;
|
||||
bool setPixelDecimation(int pixelDecimation) override;
|
||||
|
||||
///
|
||||
/// Set the crop values
|
||||
@ -51,14 +50,37 @@ public:
|
||||
/// @param cropTop Top 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
|
||||
///
|
||||
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:
|
||||
|
||||
///
|
||||
/// @brief is called whenever the current _screen changes it's geometry
|
||||
/// @param geo The new geometry
|
||||
@ -66,11 +88,6 @@ private slots:
|
||||
void geometryChanged(const QRect &geo);
|
||||
|
||||
private:
|
||||
///
|
||||
/// @brief Setup a new capture display, will free the previous one
|
||||
/// @return True on success, false if no display is found
|
||||
///
|
||||
bool setupDisplay();
|
||||
|
||||
///
|
||||
/// @brief Is called whenever we need new screen dimension calculations based on window geometry
|
||||
@ -84,13 +101,19 @@ private:
|
||||
|
||||
private:
|
||||
|
||||
unsigned _display;
|
||||
int _pixelDecimation;
|
||||
unsigned _screenWidth;
|
||||
unsigned _screenHeight;
|
||||
unsigned _src_x;
|
||||
unsigned _src_y;
|
||||
unsigned _src_x_max;
|
||||
unsigned _src_y_max;
|
||||
int _display;
|
||||
int _numberOfSDisplays;
|
||||
|
||||
int _calculatedWidth;
|
||||
int _calculatedHeight;
|
||||
int _src_x;
|
||||
int _src_y;
|
||||
int _src_x_max;
|
||||
int _src_y_max;
|
||||
bool _isWayland;
|
||||
|
||||
QScreen* _screen;
|
||||
bool _isVirtual;
|
||||
|
||||
Logger * _logger;
|
||||
};
|
||||
|
@ -10,16 +10,28 @@ class QtWrapper: public GrabberWrapper
|
||||
{
|
||||
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] cropRight Remove from right [pixels]
|
||||
/// @param[in] cropTop Remove from top [pixels]
|
||||
/// @param[in] cropBottom Remove from bottom [pixels]
|
||||
/// @param[in] pixelDecimation Decimation factor for image [pixels]
|
||||
/// @param[in] updateRate_Hz The image grab rate [Hz]
|
||||
|
||||
///
|
||||
QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, 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:
|
||||
///
|
||||
|
@ -14,30 +14,24 @@
|
||||
// util includes
|
||||
#include <utils/PixelFormat.h>
|
||||
#include <hyperion/Grabber.h>
|
||||
#include <grabber/VideoStandard.h>
|
||||
#include <hyperion/GrabberWrapper.h>
|
||||
#include <utils/VideoStandard.h>
|
||||
#include <utils/Components.h>
|
||||
#include <cec/CECEvent.h>
|
||||
|
||||
// general JPEG decoder includes
|
||||
#ifdef HAVE_JPEG_DECODER
|
||||
#include <QImage>
|
||||
#include <QColor>
|
||||
#endif
|
||||
|
||||
// System JPEG decoder
|
||||
#ifdef HAVE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <csetjmp>
|
||||
#endif
|
||||
|
||||
// TurboJPEG decoder
|
||||
#ifdef HAVE_TURBO_JPEG
|
||||
#include <turbojpeg.h>
|
||||
// decoder thread includes
|
||||
#include <grabber/EncoderThread.h>
|
||||
|
||||
// Determine the cmake options
|
||||
#include <HyperionConfig.h>
|
||||
|
||||
#if defined(ENABLE_CEC)
|
||||
#include <cec/CECEvent.h>
|
||||
#endif
|
||||
|
||||
///
|
||||
/// Capture class for V4L2 devices
|
||||
///
|
||||
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
|
||||
|
||||
class V4L2Grabber : public Grabber
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -46,117 +40,66 @@ public:
|
||||
struct DeviceProperties
|
||||
{
|
||||
QString name = QString();
|
||||
QMultiMap<QString, int> inputs = QMultiMap<QString, int>();
|
||||
QStringList resolutions = QStringList();
|
||||
QStringList framerates = QStringList();
|
||||
struct InputProperties
|
||||
{
|
||||
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,
|
||||
const unsigned width,
|
||||
const unsigned height,
|
||||
const unsigned fps,
|
||||
const unsigned input,
|
||||
VideoStandard videoStandard,
|
||||
PixelFormat pixelFormat,
|
||||
int pixelDecimation
|
||||
);
|
||||
struct DeviceControls
|
||||
{
|
||||
QString property = QString();
|
||||
int minValue = 0;
|
||||
int maxValue = 0;
|
||||
int step = 0;
|
||||
int defaultValue = 0;
|
||||
int currentValue = 0;
|
||||
};
|
||||
|
||||
V4L2Grabber();
|
||||
~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> &);
|
||||
|
||||
///
|
||||
/// @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
|
||||
///
|
||||
void setDevice(const QString& devicePath, const QString& deviceName);
|
||||
bool setInput(int input) override;
|
||||
|
||||
///
|
||||
/// @brief overwrite Grabber.h implementation
|
||||
///
|
||||
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;
|
||||
|
||||
///
|
||||
/// @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;
|
||||
QJsonArray discover(const QJsonObject& params);
|
||||
|
||||
public slots:
|
||||
|
||||
bool prepare();
|
||||
bool start();
|
||||
|
||||
void stop();
|
||||
void newThreadFrame(Image<ColorRgb> image);
|
||||
|
||||
#if defined(ENABLE_CEC)
|
||||
void handleCecEvent(CECEvent event);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void newFrame(const Image<ColorRgb> & image);
|
||||
@ -166,36 +109,19 @@ private slots:
|
||||
int read_frame();
|
||||
|
||||
private:
|
||||
void getV4Ldevices();
|
||||
|
||||
bool init();
|
||||
|
||||
void uninit();
|
||||
|
||||
bool open_device();
|
||||
|
||||
void close_device();
|
||||
|
||||
void init_read(unsigned int buffer_size);
|
||||
|
||||
void init_mmap();
|
||||
|
||||
void init_userp(unsigned int buffer_size);
|
||||
|
||||
void init_device(VideoStandard videoStandard);
|
||||
|
||||
void uninit_device();
|
||||
|
||||
void start_capturing();
|
||||
|
||||
void stop_capturing();
|
||||
|
||||
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 fileDescriptor, int request, void *arg);
|
||||
|
||||
void throw_exception(const QString & error)
|
||||
@ -222,56 +148,28 @@ private:
|
||||
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:
|
||||
QString _deviceName;
|
||||
std::map<QString, QString> _v4lDevices;
|
||||
QString _currentDevicePath, _currentDeviceName;
|
||||
EncoderThreadManager* _threadManager;
|
||||
QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
|
||||
QMap<QString, QList<DeviceControls>> _deviceControls;
|
||||
|
||||
VideoStandard _videoStandard;
|
||||
io_method _ioMethod;
|
||||
int _fileDescriptor;
|
||||
std::vector<buffer> _buffers;
|
||||
|
||||
PixelFormat _pixelFormat;
|
||||
int _pixelDecimation;
|
||||
PixelFormat _pixelFormat, _pixelFormatConfig;
|
||||
int _lineLength;
|
||||
int _frameByteSize;
|
||||
|
||||
QAtomicInt _currentFrame;
|
||||
|
||||
// signal detection
|
||||
int _noSignalCounterThreshold;
|
||||
ColorRgb _noSignalThresholdColor;
|
||||
bool _signalDetectionEnabled;
|
||||
bool _cecDetectionEnabled;
|
||||
bool _cecStandbyActivated;
|
||||
bool _noSignalDetected;
|
||||
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected;
|
||||
int _noSignalCounter;
|
||||
int _brightness, _contrast, _saturation, _hue;
|
||||
double _x_frac_min;
|
||||
double _y_frac_min;
|
||||
double _x_frac_max;
|
||||
@ -279,9 +177,9 @@ private:
|
||||
|
||||
QSocketNotifier *_streamNotifier;
|
||||
|
||||
bool _initialized;
|
||||
bool _deviceAutoDiscoverEnabled;
|
||||
bool _initialized, _reload;
|
||||
|
||||
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 <QAbstractNativeEventFilter>
|
||||
#include <QCoreApplication>
|
||||
|
||||
// QT includes
|
||||
#include <QObject>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
|
||||
// Hyperion-utils includes
|
||||
#include <utils/ColorRgb.h>
|
||||
@ -20,11 +26,13 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter
|
||||
{
|
||||
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;
|
||||
|
||||
bool Setup();
|
||||
bool open();
|
||||
|
||||
bool setupDisplay();
|
||||
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
void setPixelDecimation(int pixelDecimation) override;
|
||||
bool setPixelDecimation(int pixelDecimation) override;
|
||||
|
||||
///
|
||||
/// Set the crop values
|
||||
@ -59,22 +67,33 @@ public:
|
||||
/// @param cropTop Top 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:
|
||||
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
||||
|
||||
private:
|
||||
bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable, _XRandRAvailable;
|
||||
|
||||
XImage* _xImage;
|
||||
XShmSegmentInfo _shminfo;
|
||||
void freeResources();
|
||||
void setupResources();
|
||||
|
||||
/// Reference to the X11 display (nullptr if not opened)
|
||||
Display* _x11Display;
|
||||
Window _window;
|
||||
XWindowAttributes _windowAttr;
|
||||
|
||||
XImage* _xImage;
|
||||
XShmSegmentInfo _shminfo;
|
||||
|
||||
Pixmap _pixmap;
|
||||
XRenderPictFormat* _srcFormat;
|
||||
XRenderPictFormat* _dstFormat;
|
||||
@ -85,15 +104,19 @@ private:
|
||||
int _XRandREventBase;
|
||||
|
||||
XTransform _transform;
|
||||
int _pixelDecimation;
|
||||
|
||||
unsigned _screenWidth;
|
||||
unsigned _screenHeight;
|
||||
unsigned _calculatedWidth;
|
||||
unsigned _calculatedHeight;
|
||||
unsigned _src_x;
|
||||
unsigned _src_y;
|
||||
|
||||
Image<ColorRgb> _image;
|
||||
bool _XShmAvailable;
|
||||
bool _XShmPixmapAvailable;
|
||||
bool _XRenderAvailable;
|
||||
bool _XRandRAvailable;
|
||||
bool _isWayland;
|
||||
|
||||
void freeResources();
|
||||
void setupResources();
|
||||
Logger * _logger;
|
||||
|
||||
Image<ColorRgb> _image;
|
||||
};
|
||||
|
@ -9,25 +9,26 @@
|
||||
|
||||
|
||||
///
|
||||
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the
|
||||
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
|
||||
/// attached Hyperion.
|
||||
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the displayed content.
|
||||
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
|
||||
///
|
||||
class X11Wrapper: public GrabberWrapper
|
||||
{
|
||||
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] 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;
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractNativeEventFilter>
|
||||
// QT includes
|
||||
#include <QObject>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <hyperion/Grabber.h>
|
||||
@ -21,16 +25,28 @@ class XcbGrabber : public Grabber, public QAbstractNativeEventFilter
|
||||
Q_OBJECT
|
||||
|
||||
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;
|
||||
|
||||
bool Setup();
|
||||
bool open();
|
||||
bool setupDisplay();
|
||||
|
||||
int grabFrame(Image<ColorRgb> & image, bool forceUpdate = false);
|
||||
int updateScreenDimensions(bool force = false);
|
||||
void setVideoMode(VideoMode mode) override;
|
||||
bool setWidthHeight(int width, int height) override { return true; }
|
||||
void setPixelDecimation(int pixelDecimation) override;
|
||||
void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) override;
|
||||
bool setPixelDecimation(int pixelDecimation) 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:
|
||||
bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
|
||||
@ -52,8 +68,7 @@ private:
|
||||
xcb_render_transform_t _transform;
|
||||
xcb_shm_seg_t _shminfo;
|
||||
|
||||
int _pixelDecimation;
|
||||
|
||||
int _screen_num;
|
||||
unsigned _screenWidth;
|
||||
unsigned _screenHeight;
|
||||
unsigned _src_x;
|
||||
@ -63,6 +78,8 @@ private:
|
||||
bool _XcbRandRAvailable;
|
||||
bool _XcbShmAvailable;
|
||||
bool _XcbShmPixmapAvailable;
|
||||
bool _isWayland;
|
||||
|
||||
Logger * _logger;
|
||||
|
||||
uint8_t * _shmData;
|
||||
|
@ -11,7 +11,12 @@
|
||||
class XcbWrapper: public GrabberWrapper
|
||||
{
|
||||
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;
|
||||
|
||||
public slots:
|
||||
|
@ -6,23 +6,21 @@
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <utils/Image.h>
|
||||
#include <utils/VideoMode.h>
|
||||
#include <grabber/VideoStandard.h>
|
||||
#include <utils/VideoStandard.h>
|
||||
#include <utils/ImageResampler.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Components.h>
|
||||
|
||||
#include <QMultiMap>
|
||||
|
||||
///
|
||||
/// @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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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)
|
||||
@ -31,12 +29,18 @@ public:
|
||||
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
|
||||
///
|
||||
virtual bool setInput(int input);
|
||||
@ -48,108 +52,80 @@ public:
|
||||
virtual bool setWidthHeight(int width, int height);
|
||||
|
||||
///
|
||||
/// @brief Apply new framerate (used from v4l)
|
||||
/// @brief Apply new capture framerate in Hz
|
||||
/// @param fps framesPerSecond
|
||||
///
|
||||
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(
|
||||
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) {}
|
||||
virtual void setVideoStandard(VideoStandard videoStandard);
|
||||
|
||||
///
|
||||
/// @brief Apply SignalDetectionEnable (used from v4l)
|
||||
/// @brief Apply new pixelDecimation
|
||||
///
|
||||
virtual void setSignalDetectionEnable(bool enable) {}
|
||||
|
||||
///
|
||||
/// @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) {}
|
||||
virtual bool setPixelDecimation(int pixelDecimation);
|
||||
|
||||
///
|
||||
/// @brief Apply display index (used from qt)
|
||||
///
|
||||
virtual void setDisplayIndex(int index) {}
|
||||
|
||||
///
|
||||
/// @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; }
|
||||
virtual bool setDisplayIndex(int /*index*/) { return true; }
|
||||
|
||||
///
|
||||
/// @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
|
||||
/// @return List of all available V4L devices on success else empty List
|
||||
/// @brief get current resulting height of image (after crop)
|
||||
///
|
||||
virtual QStringList getV4L2devices() const { return QStringList(); }
|
||||
int getImageWidth() const { return _width; }
|
||||
|
||||
///
|
||||
/// @brief Get the V4L device name
|
||||
/// @param devicePath The device path
|
||||
/// @return The name of the V4L device on success else empty String
|
||||
/// @brief get current resulting width of image (after crop)
|
||||
///
|
||||
virtual QString getV4L2deviceName(const QString& /*devicePath*/) const { return QString(); }
|
||||
int getImageHeight() const { return _height; }
|
||||
|
||||
///
|
||||
/// @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
|
||||
/// @brief Get current capture framerate in Hz
|
||||
/// @param fps framesPerSecond
|
||||
///
|
||||
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
|
||||
/// @param devicePath The device path
|
||||
/// @return List of resolutions on success else empty List
|
||||
/// @brief Get capture interval in ms
|
||||
///
|
||||
virtual QStringList getResolutions(const QString& /*devicePath*/) const { return QStringList(); }
|
||||
int getUpdateInterval() const { return 1000/_fps; }
|
||||
|
||||
///
|
||||
/// @brief Get a list of supported device framerates
|
||||
/// @param devicePath The device path
|
||||
/// @return List of framerates on success else empty List
|
||||
/// @brief Get pixelDecimation
|
||||
///
|
||||
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:
|
||||
|
||||
QString _grabberName;
|
||||
|
||||
/// logger instance
|
||||
Logger * _log;
|
||||
|
||||
ImageResampler _imageResampler;
|
||||
|
||||
bool _useImageResampler;
|
||||
@ -157,6 +133,15 @@ protected:
|
||||
/// the selected 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]
|
||||
int _width;
|
||||
|
||||
@ -166,15 +151,21 @@ protected:
|
||||
/// frame per second
|
||||
int _fps;
|
||||
|
||||
/// fps software decimation
|
||||
int _fpsSoftwareDecimation;
|
||||
|
||||
/// device input
|
||||
int _input;
|
||||
|
||||
/// number of pixels to crop after capturing
|
||||
int _cropLeft, _cropRight, _cropTop, _cropBottom;
|
||||
|
||||
bool _enabled;
|
||||
// Device states
|
||||
|
||||
/// logger instance
|
||||
Logger * _log;
|
||||
/// Is the device enabled?
|
||||
bool _isEnabled;
|
||||
|
||||
/// Is the device in error state and stopped?
|
||||
bool _isDeviceInError;
|
||||
|
||||
};
|
||||
|
@ -12,30 +12,38 @@
|
||||
#include <utils/Image.h>
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <utils/VideoMode.h>
|
||||
#include <utils/PixelFormat.h>
|
||||
#include <utils/settings.h>
|
||||
#include <utils/VideoStandard.h>
|
||||
|
||||
class Grabber;
|
||||
class GlobalSignals;
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
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;
|
||||
|
||||
static GrabberWrapper* 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
|
||||
///
|
||||
@ -56,45 +64,17 @@ public:
|
||||
///
|
||||
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
|
||||
/// @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();
|
||||
|
||||
@ -130,6 +110,12 @@ public slots:
|
||||
///
|
||||
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
|
||||
/// @param cropLeft Left pixel crop
|
||||
@ -137,11 +123,11 @@ public slots:
|
||||
/// @param cropTop Top 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
|
||||
/// @param type settingyType from enum
|
||||
/// @param type settingsType from enum
|
||||
/// @param config configuration object
|
||||
///
|
||||
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
|
||||
@ -159,22 +145,38 @@ private slots:
|
||||
|
||||
///
|
||||
/// @brief Update Update capture rate
|
||||
/// @param type interval between frames in millisecons
|
||||
/// @param type interval between frames in milliseconds
|
||||
///
|
||||
void updateTimer(int interval);
|
||||
|
||||
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;
|
||||
|
||||
/// The Logger instance
|
||||
Logger * _log;
|
||||
|
||||
/// The timer for generating events with the specified update rate
|
||||
QTimer* _timer;
|
||||
|
||||
/// The calced update rate [ms]
|
||||
/// The calculated update rate [ms]
|
||||
int _updateInterval_ms;
|
||||
|
||||
/// The Logger instance
|
||||
Logger * _log;
|
||||
|
||||
Grabber *_ggrabber;
|
||||
|
||||
/// The image used for grabbing frames
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
///
|
||||
QString getActiveDeviceType() const;
|
||||
|
||||
bool getReadOnlyMode() {return _readOnlyMode; };
|
||||
bool getReadOnlyMode() {return _readOnlyMode; }
|
||||
|
||||
public slots:
|
||||
|
||||
@ -193,7 +193,7 @@ public slots:
|
||||
bool clear(int priority, bool forceClearAll=false);
|
||||
|
||||
/// #############
|
||||
// EFFECTENGINE
|
||||
/// EFFECTENGINE
|
||||
///
|
||||
/// @brief Get a pointer to the effect engine
|
||||
/// @return EffectEngine instance pointer
|
||||
|
@ -57,8 +57,11 @@ public:
|
||||
//Foreground and Background priorities
|
||||
const static int FG_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
|
||||
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
|
||||
@ -84,7 +87,7 @@ public:
|
||||
/// @param update True to update _currentPriority - INTERNAL usage.
|
||||
/// @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
|
||||
|
@ -9,12 +9,13 @@ class ImageResampler
|
||||
{
|
||||
public:
|
||||
ImageResampler();
|
||||
~ImageResampler();
|
||||
~ImageResampler() {}
|
||||
|
||||
void setHorizontalPixelDecimation(int decimator);
|
||||
void setVerticalPixelDecimation(int decimator);
|
||||
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
|
||||
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
|
||||
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;
|
||||
|
||||
private:
|
||||
@ -25,5 +26,6 @@ private:
|
||||
int _cropTop;
|
||||
int _cropBottom;
|
||||
VideoMode _videoMode;
|
||||
FlipMode _flipMode;
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,9 @@ enum class PixelFormat {
|
||||
BGR24,
|
||||
RGB32,
|
||||
BGR32,
|
||||
#ifdef HAVE_JPEG_DECODER
|
||||
NV12,
|
||||
I420,
|
||||
#ifdef HAVE_TURBO_JPEG
|
||||
MJPEG,
|
||||
#endif
|
||||
NO_CHANGE
|
||||
@ -23,32 +25,40 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
|
||||
// convert to lower case
|
||||
QString format = pixelFormat.toLower();
|
||||
|
||||
if (format.compare("yuyv") )
|
||||
if (format.compare("yuyv") == 0)
|
||||
{
|
||||
return PixelFormat::YUYV;
|
||||
}
|
||||
else if (format.compare("uyvy") )
|
||||
else if (format.compare("uyvy") == 0)
|
||||
{
|
||||
return PixelFormat::UYVY;
|
||||
}
|
||||
else if (format.compare("bgr16") )
|
||||
else if (format.compare("bgr16") == 0)
|
||||
{
|
||||
return PixelFormat::BGR16;
|
||||
}
|
||||
else if (format.compare("bgr24") )
|
||||
else if (format.compare("bgr24") == 0)
|
||||
{
|
||||
return PixelFormat::BGR24;
|
||||
}
|
||||
else if (format.compare("rgb32") )
|
||||
else if (format.compare("rgb32") == 0)
|
||||
{
|
||||
return PixelFormat::RGB32;
|
||||
}
|
||||
else if (format.compare("bgr32") )
|
||||
else if (format.compare("bgr32") == 0)
|
||||
{
|
||||
return PixelFormat::BGR32;
|
||||
}
|
||||
#ifdef HAVE_JPEG_DECODER
|
||||
else if (format.compare("mjpeg") )
|
||||
else if (format.compare("i420") == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -57,3 +67,102 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
|
||||
// return the default 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
|
||||
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// convert to lower case
|
||||
QString standard = videoStandard.toLower();
|
||||
QString standard = videoStandard.toUpper();
|
||||
|
||||
if (standard == "pal")
|
||||
if (standard == "PAL")
|
||||
{
|
||||
return VideoStandard::PAL;
|
||||
}
|
||||
else if (standard == "ntsc")
|
||||
else if (standard == "NTSC")
|
||||
{
|
||||
return VideoStandard::NTSC;
|
||||
}
|
||||
else if (standard == "secam")
|
||||
else if (standard == "SECAM")
|
||||
{
|
||||
return VideoStandard::SECAM;
|
||||
}
|
||||
@ -31,3 +33,14 @@ inline VideoStandard parseVideoStandard(const QString& videoStandard)
|
||||
// return the default 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
|
||||
|
||||
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
|
||||
typedef QList< int > QIntList;
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
// fg effect
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include <hyperion/PriorityMuxer.h>
|
||||
#include <effectengine/Effect.h>
|
||||
|
||||
///
|
||||
/// @brief Provide utility methods for Hyperion class
|
||||
@ -17,7 +18,6 @@ namespace hyperion {
|
||||
void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
|
||||
{
|
||||
#define FGCONFIG_ARRAY fgColorConfig.toArray()
|
||||
const int DURATION_INFINITY = 0;
|
||||
|
||||
// initial foreground effect/color
|
||||
if (FGEffectConfig["enable"].toBool(true))
|
||||
@ -27,7 +27,7 @@ namespace hyperion {
|
||||
const QJsonValue fgColorConfig = FGEffectConfig["color"];
|
||||
int default_fg_duration_ms = 3000;
|
||||
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;
|
||||
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
|
||||
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/api)
|
||||
@ -12,6 +21,11 @@ add_library(hyperion-api
|
||||
${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
|
||||
hyperion
|
||||
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": {
|
||||
"type" : "string",
|
||||
"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-instance">JSONRPC_schema/schema-instance.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-->
|
||||
<file alias="schema-transform">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/LedDeviceFactory.h>
|
||||
|
||||
#include <HyperionConfig.h> // Required to determine the cmake options
|
||||
|
||||
#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/QJsonSchemaChecker.h>
|
||||
#include <HyperionConfig.h>
|
||||
@ -41,7 +79,10 @@
|
||||
|
||||
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)
|
||||
{
|
||||
_noListener = noListener;
|
||||
@ -86,7 +127,7 @@ bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
||||
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;
|
||||
QJsonObject message;
|
||||
@ -174,6 +215,8 @@ proceed:
|
||||
handleInstanceCommand(message, command, tan);
|
||||
else if (command == "leddevice")
|
||||
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
|
||||
else if (command == "clearall")
|
||||
@ -187,17 +230,17 @@ proceed:
|
||||
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);
|
||||
int priority = message["priority"].toInt();
|
||||
int duration = message["duration"].toInt(-1);
|
||||
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;
|
||||
// TODO faster copy
|
||||
for (const auto& entry : jsonColor)
|
||||
for (const auto &entry : jsonColor)
|
||||
{
|
||||
colors.emplace_back(uint8_t(entry.toInt()));
|
||||
}
|
||||
@ -206,7 +249,7 @@ void JsonAPI::handleColorCommand(const QJsonObject& message, const QString& comm
|
||||
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);
|
||||
|
||||
@ -230,7 +273,7 @@ void JsonAPI::handleImageCommand(const QJsonObject& message, const QString& comm
|
||||
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);
|
||||
|
||||
@ -249,19 +292,19 @@ void JsonAPI::handleEffectCommand(const QJsonObject& message, const QString& com
|
||||
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);
|
||||
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());
|
||||
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
|
||||
QJsonObject result;
|
||||
@ -304,7 +347,7 @@ void JsonAPI::handleSysInfoCommand(const QJsonObject&, const QString& command, i
|
||||
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;
|
||||
|
||||
@ -315,9 +358,9 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
activePriorities.removeAll(255);
|
||||
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;
|
||||
item["priority"] = priority;
|
||||
if (priorityInfo.timeoutTime_ms > 0)
|
||||
@ -371,9 +414,9 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
|
||||
// collect adjustment information
|
||||
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)
|
||||
{
|
||||
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
|
||||
QJsonArray effects;
|
||||
const std::list<EffectDefinition>& effectsDefinitions = _hyperion->getEffects();
|
||||
for (const EffectDefinition& effectDefinition : effectsDefinitions)
|
||||
const std::list<EffectDefinition> &effectsDefinitions = _hyperion->getEffects();
|
||||
for (const EffectDefinition &effectDefinition : effectsDefinitions)
|
||||
{
|
||||
QJsonObject effect;
|
||||
effect["name"] = effectDefinition.name;
|
||||
@ -467,11 +510,18 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
QJsonObject grabbers;
|
||||
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
|
||||
@ -480,55 +530,20 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
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
|
||||
|
||||
grabbers["available"] = availableGrabbers;
|
||||
info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
|
||||
info["grabbers"] = grabbers;
|
||||
|
||||
QJsonObject cecInfo;
|
||||
#if defined(ENABLE_CEC)
|
||||
cecInfo["enabled"] = true;
|
||||
#else
|
||||
cecInfo["enabled"] = false;
|
||||
#endif
|
||||
info["cec"] = cecInfo;
|
||||
|
||||
// get available components
|
||||
QJsonArray component;
|
||||
std::map<hyperion::Components, bool> components = _hyperion->getComponentRegister().getRegister();
|
||||
@ -547,7 +562,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
// add sessions
|
||||
QJsonArray sessions;
|
||||
#ifdef ENABLE_AVAHI
|
||||
for (auto session : BonjourBrowserWrapper::getInstance()->getAllServices())
|
||||
for (auto session: BonjourBrowserWrapper::getInstance()->getAllServices())
|
||||
{
|
||||
if (session.port < 0)
|
||||
continue;
|
||||
@ -564,7 +579,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
#endif
|
||||
// add instance info
|
||||
QJsonArray instanceInfo;
|
||||
for (const auto& entry : API::getAllInstanceData())
|
||||
for (const auto &entry : API::getAllInstanceData())
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert("friendly_name", entry["friendly_name"].toString());
|
||||
@ -586,7 +601,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
|
||||
// TRANSFORM INFORMATION (DEFAULT VALUES)
|
||||
QJsonArray transformArray;
|
||||
for (const QString& transformId : _hyperion->getAdjustmentIds())
|
||||
for (const QString &transformId : _hyperion->getAdjustmentIds())
|
||||
{
|
||||
QJsonObject transform;
|
||||
QJsonArray blacklevel, whitelevel, gamma, threshold;
|
||||
@ -617,7 +632,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
|
||||
// ACTIVE EFFECT INFO
|
||||
QJsonArray activeEffects;
|
||||
for (const ActiveEffectDefinition& activeEffectDefinition : _hyperion->getActiveEffects())
|
||||
for (const ActiveEffectDefinition &activeEffectDefinition : _hyperion->getActiveEffects())
|
||||
{
|
||||
if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1)
|
||||
{
|
||||
@ -634,7 +649,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
||||
|
||||
// ACTIVE STATIC LED COLOR
|
||||
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())
|
||||
{
|
||||
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);
|
||||
int priority = message["priority"].toInt();
|
||||
@ -720,7 +735,7 @@ void JsonAPI::handleClearCommand(const QJsonObject& message, const QString& comm
|
||||
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);
|
||||
QString replyMsg;
|
||||
@ -728,12 +743,12 @@ void JsonAPI::handleClearallCommand(const QJsonObject& message, const QString& c
|
||||
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());
|
||||
ColorAdjustment* colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
||||
ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId);
|
||||
if (colorAdjustment == nullptr)
|
||||
{
|
||||
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"))
|
||||
{
|
||||
const QJsonArray& values = adjustment["red"].toArray();
|
||||
const QJsonArray &values = adjustment["red"].toArray();
|
||||
colorAdjustment->_rgbRedAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
@ -814,7 +829,7 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject& message, const QString&
|
||||
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"))
|
||||
{
|
||||
@ -832,7 +847,7 @@ void JsonAPI::handleSourceSelectCommand(const QJsonObject& message, const QStrin
|
||||
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 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"))
|
||||
{
|
||||
QJsonObject config = message["config"].toObject();
|
||||
if (API::isHyperionEnabled())
|
||||
{
|
||||
if (API::saveSettings(config))
|
||||
if ( API::saveSettings(config) )
|
||||
{
|
||||
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
|
||||
QJsonObject schemaJson, alldevices, properties;
|
||||
@ -912,7 +927,7 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& message, const QString&
|
||||
{
|
||||
schemaJson = QJsonFactory::readSchema(schemaFile);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
catch (const std::runtime_error &error)
|
||||
{
|
||||
throw std::runtime_error(error.what());
|
||||
}
|
||||
@ -949,9 +964,9 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& message, const QString&
|
||||
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");
|
||||
bool compState = componentState["state"].toBool(true);
|
||||
QString replyMsg;
|
||||
@ -964,7 +979,7 @@ void JsonAPI::handleComponentStateCommand(const QJsonObject& message, const QStr
|
||||
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
|
||||
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["tan"] = tan;
|
||||
|
||||
connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector<ColorRgb>& ledValues) {
|
||||
connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector<ColorRgb> &ledValues) {
|
||||
_currentLedValues = ledValues;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void JsonAPI::handleLoggingCommand(const QJsonObject& message, const QString& command, int tan)
|
||||
void JsonAPI::handleLoggingCommand(const QJsonObject &message, const QString &command, int tan)
|
||||
{
|
||||
// create result
|
||||
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")));
|
||||
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")));
|
||||
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& id = message["id"].toString().trimmed();
|
||||
const QString& password = message["password"].toString().trimmed();
|
||||
const QString& newPassword = message["newPassword"].toString().trimmed();
|
||||
const QString& comment = message["comment"].toString().trimmed();
|
||||
const QString &subc = message["subcommand"].toString().trimmed();
|
||||
const QString &id = message["id"].toString().trimmed();
|
||||
const QString &password = message["password"].toString().trimmed();
|
||||
const QString &newPassword = message["newPassword"].toString().trimmed();
|
||||
const QString &comment = message["comment"].toString().trimmed();
|
||||
|
||||
// catch test if auth is required
|
||||
if (subc == "tokenRequired")
|
||||
@ -1194,8 +1209,8 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
||||
if (subc == "requestToken")
|
||||
{
|
||||
// use id/comment
|
||||
const QString& comment = message["comment"].toString().trimmed();
|
||||
const bool& acc = message["accept"].toBool(true);
|
||||
const QString &comment = message["comment"].toString().trimmed();
|
||||
const bool &acc = message["accept"].toBool(true);
|
||||
if (acc)
|
||||
API::setNewTokenRequest(comment, id, tan);
|
||||
else
|
||||
@ -1211,7 +1226,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
||||
if (API::getPendingTokenRequests(vec))
|
||||
{
|
||||
QJsonArray arr;
|
||||
for (const auto& entry : vec)
|
||||
for (const auto &entry : vec)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj["comment"] = entry.comment;
|
||||
@ -1233,7 +1248,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
||||
if (subc == "answerRequest")
|
||||
{
|
||||
// use id
|
||||
const bool& accept = message["accept"].toBool(false);
|
||||
const bool &accept = message["accept"].toBool(false);
|
||||
if (!API::handlePendingTokenRequest(id, accept))
|
||||
sendErrorReply("No Authorization", command + "-" + subc, tan);
|
||||
return;
|
||||
@ -1246,7 +1261,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
||||
if (API::getTokenList(defVect))
|
||||
{
|
||||
QJsonArray tArr;
|
||||
for (const auto& entry : defVect)
|
||||
for (const auto &entry : defVect)
|
||||
{
|
||||
QJsonObject subO;
|
||||
subO["comment"] = entry.comment;
|
||||
@ -1265,7 +1280,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString&
|
||||
// login
|
||||
if (subc == "login")
|
||||
{
|
||||
const QString& token = message["token"].toString().trimmed();
|
||||
const QString &token = message["token"].toString().trimmed();
|
||||
|
||||
// catch token
|
||||
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 quint8& inst = message["instance"].toInt();
|
||||
const QString& name = message["name"].toString();
|
||||
const QString &subc = message["subcommand"].toString();
|
||||
const quint8 &inst = message["instance"].toInt();
|
||||
const QString &name = message["name"].toString();
|
||||
|
||||
if (subc == "switchTo")
|
||||
{
|
||||
@ -1334,7 +1349,7 @@ void JsonAPI::handleInstanceCommand(const QJsonObject& message, const QString& c
|
||||
|
||||
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))
|
||||
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& devType = message["ledDeviceType"].toString().trimmed();
|
||||
const QString &subc = message["subcommand"].toString().trimmed();
|
||||
const QString &devType = message["ledDeviceType"].toString().trimmed();
|
||||
|
||||
QString full_command = command + "-" + subc;
|
||||
|
||||
@ -1407,27 +1422,27 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject& message, const QString&
|
||||
if (subc == "discover")
|
||||
{
|
||||
ledDevice = LedDeviceFactory::construct(config);
|
||||
const QJsonObject& params = message["params"].toObject();
|
||||
const QJsonObject ¶ms = message["params"].toObject();
|
||||
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);
|
||||
}
|
||||
else if (subc == "getProperties")
|
||||
{
|
||||
ledDevice = LedDeviceFactory::construct(config);
|
||||
const QJsonObject& params = message["params"].toObject();
|
||||
const QJsonObject ¶ms = message["params"].toObject();
|
||||
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);
|
||||
}
|
||||
else if (subc == "identify")
|
||||
{
|
||||
ledDevice = LedDeviceFactory::construct(config);
|
||||
const QJsonObject& params = message["params"].toObject();
|
||||
const QJsonObject ¶ms = message["params"].toObject();
|
||||
ledDevice->identify(params);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void JsonAPI::sendSuccessReply(const QString& command, int tan)
|
||||
void JsonAPI::sendSuccessReply(const QString &command, int tan)
|
||||
{
|
||||
// create reply
|
||||
QJsonObject reply;
|
||||
@ -1458,7 +1613,7 @@ void JsonAPI::sendSuccessReply(const QString& command, int tan)
|
||||
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;
|
||||
reply["success"] = true;
|
||||
@ -1472,7 +1627,7 @@ void JsonAPI::sendSuccessDataReply(const QJsonDocument& doc, const QString& comm
|
||||
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
|
||||
QJsonObject reply;
|
||||
@ -1485,12 +1640,12 @@ void JsonAPI::sendErrorReply(const QString& error, const QString& command, int t
|
||||
emit callbackMessage(reply);
|
||||
}
|
||||
|
||||
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
||||
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb> &ledColors)
|
||||
{
|
||||
QJsonObject result;
|
||||
QJsonArray leds;
|
||||
|
||||
for (const auto& color : ledColors)
|
||||
for (const auto &color : ledColors)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
@ -1516,7 +1671,7 @@ void JsonAPI::setImage(const Image<ColorRgb>& image)
|
||||
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;
|
||||
QJsonArray messageArray;
|
||||
@ -1524,7 +1679,7 @@ void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE& msg)
|
||||
if (!_streaming_logging_activated)
|
||||
{
|
||||
_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++)
|
||||
{
|
||||
message["appName"] = logBuffer->at(i).appName;
|
||||
@ -1560,7 +1715,7 @@ void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE& msg)
|
||||
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;
|
||||
obj["comment"] = comment;
|
||||
@ -1570,7 +1725,7 @@ void JsonAPI::newPendingTokenRequest(const QString& id, const QString& comment)
|
||||
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";
|
||||
QJsonObject result;
|
||||
@ -1584,7 +1739,7 @@ void JsonAPI::handleTokenResponse(bool success, const QString& token, const QStr
|
||||
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)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &scr
|
||||
, _hyperion(hyperion)
|
||||
, _priority(priority)
|
||||
, _timeout(timeout)
|
||||
, _isEndless(timeout <= ENDLESS)
|
||||
, _script(script)
|
||||
, _name(name)
|
||||
, _args(args)
|
||||
@ -51,7 +52,7 @@ Effect::~Effect()
|
||||
|
||||
bool Effect::isInterruptionRequested()
|
||||
{
|
||||
return _interupt || getRemaining() < ENDLESS;
|
||||
return _interupt || (!_isEndless && getRemaining() <= 0);
|
||||
}
|
||||
|
||||
int Effect::getRemaining() const
|
||||
@ -59,12 +60,11 @@ int Effect::getRemaining() const
|
||||
// determine the timeout
|
||||
int timeout = _timeout;
|
||||
|
||||
if (timeout > 0)
|
||||
if (timeout >= 0)
|
||||
{
|
||||
timeout = static_cast<int>( _endTime - QDateTime::currentMSecsSinceEpoch());
|
||||
return timeout;
|
||||
}
|
||||
return ENDLESS;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
void Effect::setModuleParameters()
|
||||
|
@ -12,24 +12,24 @@ endif (ENABLE_FB)
|
||||
|
||||
if (ENABLE_OSX)
|
||||
add_subdirectory(osx)
|
||||
endif()
|
||||
endif(ENABLE_OSX)
|
||||
|
||||
if (ENABLE_V4L2)
|
||||
add_subdirectory(v4l2)
|
||||
endif (ENABLE_V4L2)
|
||||
if (ENABLE_V4L2 OR ENABLE_MF)
|
||||
add_subdirectory(video)
|
||||
endif ()
|
||||
|
||||
if (ENABLE_X11)
|
||||
add_subdirectory(x11)
|
||||
endif()
|
||||
endif(ENABLE_X11)
|
||||
|
||||
if (ENABLE_XCB)
|
||||
add_subdirectory(xcb)
|
||||
endif()
|
||||
endif(ENABLE_XCB)
|
||||
|
||||
if (ENABLE_QT)
|
||||
add_subdirectory(qt)
|
||||
endif()
|
||||
endif(ENABLE_QT)
|
||||
|
||||
if (ENABLE_DX)
|
||||
add_subdirectory(directx)
|
||||
endif()
|
||||
endif(ENABLE_DX)
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <QFile>
|
||||
|
||||
// Linux includes
|
||||
#include <errno.h>
|
||||
@ -12,62 +11,92 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// qt
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QSize>
|
||||
|
||||
// Local includes
|
||||
#include <utils/Logger.h>
|
||||
#include <grabber/AmlogicGrabber.h>
|
||||
#include "Amvideocap.h"
|
||||
|
||||
#define VIDEO_DEVICE "/dev/amvideo"
|
||||
#define CAPTURE_DEVICE "/dev/amvideocap0"
|
||||
// Constants
|
||||
namespace {
|
||||
const bool verbose = false;
|
||||
|
||||
AmlogicGrabber::AmlogicGrabber(unsigned width, unsigned height)
|
||||
: Grabber("AMLOGICGRABBER", qMax(160u, width), qMax(160u, height)) // Minimum required width or height is 160
|
||||
const char DEFAULT_FB_DEVICE[] = "/dev/fb0";
|
||||
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)
|
||||
, _videoDev(-1)
|
||||
, _lastError(0)
|
||||
, _fbGrabber("/dev/fb0",width,height)
|
||||
, _fbGrabber(DEFAULT_FB_DEVICE)
|
||||
, _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();
|
||||
|
||||
_useImageResampler = true;
|
||||
}
|
||||
|
||||
AmlogicGrabber::~AmlogicGrabber()
|
||||
{
|
||||
closeDev(_captureDev);
|
||||
closeDev(_videoDev);
|
||||
closeDevice(_captureDev);
|
||||
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)
|
||||
{
|
||||
fd = open(dev, O_RDWR);
|
||||
fd = ::open(dev, O_RDWR);
|
||||
}
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
void AmlogicGrabber::closeDev(int &fd)
|
||||
void AmlogicGrabber::closeDevice(int &fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool AmlogicGrabber::isVideoPlaying()
|
||||
{
|
||||
if(!QFile::exists(VIDEO_DEVICE)) return false;
|
||||
bool rc = false;
|
||||
if(QFile::exists(DEFAULT_VIDEO_DEVICE))
|
||||
{
|
||||
|
||||
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));
|
||||
return false;
|
||||
Error(_log, "Failed to open video device(%s): %d - %s", DEFAULT_VIDEO_DEVICE, errno, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -75,93 +104,230 @@ bool AmlogicGrabber::isVideoPlaying()
|
||||
if(ioctl(_videoDev, AMSTREAM_IOC_GET_VIDEO_DISABLE, &videoDisabled) < 0)
|
||||
{
|
||||
Error(_log, "Failed to retrieve video state from device: %d - %s", errno, strerror(errno));
|
||||
closeDev(_videoDev);
|
||||
return false;
|
||||
closeDevice(_videoDev);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( videoDisabled == 0 )
|
||||
{
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return videoDisabled == 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
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
|
||||
if (isVideoPlaying())
|
||||
{
|
||||
if (_grabbingModeNotification!=1)
|
||||
{
|
||||
Info(_log, "VPU mode");
|
||||
Info(_log, "Switch to VPU capture mode");
|
||||
_grabbingModeNotification = 1;
|
||||
_lastError = 0;
|
||||
}
|
||||
|
||||
if (grabFrame_amvideocap(image) < 0)
|
||||
closeDev(_captureDev);
|
||||
if (grabFrame_amvideocap(image) < 0) {
|
||||
closeDevice(_captureDev);
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_grabbingModeNotification!=2)
|
||||
{
|
||||
Info( _log, "FB mode");
|
||||
Info( _log, "Switch to Framebuffer capture mode");
|
||||
_grabbingModeNotification = 2;
|
||||
_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 rc = 0;
|
||||
|
||||
// If the device is not open, attempt to open it
|
||||
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));
|
||||
_lastError = 1;
|
||||
return -1;
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
long r1 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, _width);
|
||||
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 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)
|
||||
{
|
||||
ErrorIf(_lastError != 2,_log,"Failed to configure capture device (%d - %s)", errno, strerror(errno));
|
||||
_lastError = 2;
|
||||
return -1;
|
||||
}
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int linelen = ((_width + 31) & ~31) * 3;
|
||||
size_t _bytesToRead = linelen * _height;
|
||||
|
||||
// Read the snapshot into the memory
|
||||
ssize_t bytesRead = pread(_captureDev, _image_ptr, _bytesToRead, 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));
|
||||
_lastError = 3;
|
||||
return -1;
|
||||
}
|
||||
else if (_bytesToRead != bytesRead)
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (static_cast<ssize_t>(_bytesToRead) != bytesRead)
|
||||
{
|
||||
// Read of snapshot failed
|
||||
ErrorIf(_lastError != 4, _log,"Capture failed to grab entire image [bytesToRead(%d) != bytesRead(%d)]", _bytesToRead, bytesRead);
|
||||
_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;
|
||||
_imageResampler.processImage((const uint8_t*)_image_ptr, _width, _height, (_width << 1) + _width, PixelFormat::BGR24, image);
|
||||
_lastError = 0;
|
||||
if (!video_inputs.isEmpty())
|
||||
{
|
||||
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>
|
||||
|
||||
AmlogicWrapper::AmlogicWrapper(unsigned grabWidth, unsigned grabHeight)
|
||||
: GrabberWrapper("AmLogic", &_grabber, grabWidth, grabHeight)
|
||||
, _grabber(grabWidth, grabHeight)
|
||||
{}
|
||||
AmlogicWrapper::AmlogicWrapper(int pixelDecimation, int updateRate_Hz)
|
||||
: GrabberWrapper("Amlogic", &_grabber, updateRate_Hz)
|
||||
, _grabber()
|
||||
{
|
||||
_grabber.setPixelDecimation(pixelDecimation);
|
||||
}
|
||||
|
||||
void AmlogicWrapper::action()
|
||||
{
|
||||
|
@ -11,11 +11,35 @@
|
||||
#define CAP_FLAG_AT_TIME_WINDOW 1
|
||||
#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_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_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 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,"d3dx9.lib")
|
||||
|
||||
DirectXGrabber::DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display)
|
||||
: Grabber("DXGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
||||
, _pixelDecimation(pixelDecimation)
|
||||
// Constants
|
||||
namespace {
|
||||
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))
|
||||
, _displayWidth(0)
|
||||
, _displayHeight(0)
|
||||
@ -15,8 +19,6 @@ DirectXGrabber::DirectXGrabber(int cropLeft, int cropRight, int cropTop, int cro
|
||||
, _device(nullptr)
|
||||
, _surface(nullptr)
|
||||
{
|
||||
// init
|
||||
setupDisplay();
|
||||
}
|
||||
|
||||
DirectXGrabber::~DirectXGrabber()
|
||||
@ -140,15 +142,24 @@ bool DirectXGrabber::setupDisplay()
|
||||
|
||||
int DirectXGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
{
|
||||
if (!_enabled)
|
||||
if (!_isEnabled)
|
||||
{
|
||||
qDebug() << "AUS";
|
||||
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)))
|
||||
{
|
||||
// reinit, this will disable capture on failure
|
||||
Error(_log, "Unable to get Buffer Surface Data");
|
||||
setEnabled(setupDisplay());
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
D3DXLoadSurfaceFromSurface(_surfaceDest, nullptr, nullptr, _surface, nullptr, _srcRect, D3DX_DEFAULT, 0);
|
||||
@ -181,22 +192,91 @@ void DirectXGrabber::setVideoMode(VideoMode mode)
|
||||
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);
|
||||
setupDisplay();
|
||||
}
|
||||
|
||||
void DirectXGrabber::setDisplayIndex(int index)
|
||||
bool DirectXGrabber::setDisplayIndex(int index)
|
||||
{
|
||||
bool rc (true);
|
||||
if(_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>
|
||||
|
||||
DirectXWrapper::DirectXWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz)
|
||||
: GrabberWrapper("DirectX", &_grabber, 0, 0, updateRate_Hz)
|
||||
, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
||||
{}
|
||||
DirectXWrapper::DirectXWrapper( int updateRate_Hz,
|
||||
int 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()
|
||||
{
|
||||
|
@ -3,48 +3,34 @@
|
||||
#include <cassert>
|
||||
#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
|
||||
#include "grabber/DispmanxFrameGrabber.h"
|
||||
|
||||
DispmanxFrameGrabber::DispmanxFrameGrabber(unsigned width, unsigned height)
|
||||
: Grabber("DISPMANXGRABBER", 0, 0)
|
||||
DispmanxFrameGrabber::DispmanxFrameGrabber()
|
||||
: Grabber("DISPMANXGRABBER")
|
||||
, _vc_display(0)
|
||||
, _vc_resource(0)
|
||||
, _vc_flags(0)
|
||||
, _vc_flags(DISPMANX_TRANSFORM_T(0))
|
||||
, _captureBuffer(new ColorRgba[0])
|
||||
, _captureBufferSize(0)
|
||||
, _image_rgba(width, height)
|
||||
, _image_rgba()
|
||||
{
|
||||
_useImageResampler = false;
|
||||
|
||||
// Initiase BCM
|
||||
_useImageResampler = true;
|
||||
// Initialise BCM
|
||||
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()
|
||||
@ -55,6 +41,28 @@ DispmanxFrameGrabber::~DispmanxFrameGrabber()
|
||||
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()
|
||||
{
|
||||
delete[] _captureBuffer;
|
||||
@ -64,11 +72,14 @@ void DispmanxFrameGrabber::freeResources()
|
||||
|
||||
bool DispmanxFrameGrabber::setWidthHeight(int width, int height)
|
||||
{
|
||||
bool rc = false;
|
||||
if(Grabber::setWidthHeight(width, height))
|
||||
{
|
||||
if(_vc_resource != 0)
|
||||
if(_vc_resource != 0) {
|
||||
vc_dispmanx_resource_delete(_vc_resource);
|
||||
// Create the resources for capturing image
|
||||
}
|
||||
|
||||
Debug(_log,"Create the resources for capturing image");
|
||||
uint32_t vc_nativeImageHandle;
|
||||
_vc_resource = vc_dispmanx_resource_create(
|
||||
VC_IMAGE_RGBA32,
|
||||
@ -77,55 +88,42 @@ bool DispmanxFrameGrabber::setWidthHeight(int width, int height)
|
||||
&vc_nativeImageHandle);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
{
|
||||
if (!_enabled) return 0;
|
||||
|
||||
int ret;
|
||||
|
||||
int rc = 0;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
// vc_dispmanx_resource_read_data doesn't seem to work well
|
||||
// with arbitrary positions so we have to handle cropping by ourselves
|
||||
unsigned cropLeft = _cropLeft;
|
||||
unsigned cropRight = _cropRight;
|
||||
unsigned cropTop = _cropTop;
|
||||
unsigned cropBottom = _cropBottom;
|
||||
int cropLeft = _cropLeft;
|
||||
int cropRight = _cropRight;
|
||||
int cropTop = _cropTop;
|
||||
int cropBottom = _cropBottom;
|
||||
|
||||
if (_vc_flags & DISPMANX_SNAPSHOT_FILL)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
unsigned imageWidth = _width - cropLeft - cropRight;
|
||||
unsigned imageHeight = _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;
|
||||
}
|
||||
unsigned imageWidth = static_cast<unsigned>(_width - cropLeft - cropRight);
|
||||
unsigned imageHeight = static_cast<unsigned>(_height - cropTop - cropBottom);
|
||||
|
||||
// resize the given image if needed
|
||||
if (image.width() != imageWidth || image.height() != imageHeight)
|
||||
@ -139,22 +137,23 @@ int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
Error(_log, "Cannot open display: %d", _vc_display);
|
||||
return -1;
|
||||
Error(_log, "Cannot open display: %d", DEFAULT_DEVICE);
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
|
||||
// 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)
|
||||
{
|
||||
Error(_log, "Snapshot failed: %d", ret);
|
||||
vc_dispmanx_display_close(_vc_display);
|
||||
return ret;
|
||||
rc = ret;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Read the snapshot into the memory
|
||||
void* imagePtr = _image_rgba.memptr();
|
||||
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
|
||||
if (imagePitch != capturePitch
|
||||
|| (unsigned)_rectangle.width != imageWidth
|
||||
|| (unsigned)_rectangle.height != imageHeight)
|
||||
|| static_cast<unsigned>(_rectangle.width) != imageWidth
|
||||
|| static_cast<unsigned>(_rectangle.height) != imageHeight)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
delete[] _captureBuffer;
|
||||
@ -185,31 +184,107 @@ int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
if (ret < 0)
|
||||
{
|
||||
Error(_log, "vc_dispmanx_resource_read_data failed: %d", ret);
|
||||
vc_dispmanx_display_close(_vc_display);
|
||||
return ret;
|
||||
rc = ret;
|
||||
}
|
||||
|
||||
// copy capture data to image if we captured to temp buffer
|
||||
if (imagePtr != capturePtr)
|
||||
else
|
||||
{
|
||||
// adjust source pointer to top/left cropping
|
||||
uint8_t* src_ptr = (uint8_t*) capturePtr
|
||||
+ cropLeft * sizeof(ColorRgba)
|
||||
+ cropTop * capturePitch;
|
||||
|
||||
for (unsigned y = 0; y < imageHeight; y++)
|
||||
{
|
||||
memcpy((uint8_t*)imagePtr + y * imagePitch,
|
||||
src_ptr + y * capturePitch,
|
||||
imagePitch);
|
||||
_imageResampler.processImage(static_cast<uint8_t*>(capturePtr),
|
||||
_width,
|
||||
_height,
|
||||
static_cast<int>(capturePitch),
|
||||
PixelFormat::RGB32,
|
||||
image);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the displaye
|
||||
vc_dispmanx_display_close(_vc_display);
|
||||
|
||||
// image to output image
|
||||
_image_rgba.toRgb(image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
const int __screenWidth = 800;
|
||||
const int __screenHeight = 600;
|
||||
const int __display_num = 0;
|
||||
|
||||
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->height = __screenHeight;
|
||||
vc_info->display_num = __display_num;
|
||||
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;
|
||||
}
|
||||
|
||||
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++;
|
||||
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)
|
||||
{
|
||||
color[0] = ColorRgba::WHITE;
|
||||
0 color[1] = ColorRgba::RED;
|
||||
color[1] = ColorRgba::RED;
|
||||
color[2] = ColorRgba::BLUE;
|
||||
color[3] = ColorRgba::GREEN;
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include <grabber/DispmanxWrapper.h>
|
||||
|
||||
DispmanxWrapper::DispmanxWrapper(unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
||||
: GrabberWrapper("Dispmanx", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
||||
, _grabber(grabWidth, grabHeight)
|
||||
DispmanxWrapper::DispmanxWrapper( int updateRate_Hz,
|
||||
int pixelDecimation
|
||||
)
|
||||
: GrabberWrapper("Dispmanx", &_grabber, updateRate_Hz)
|
||||
, _grabber()
|
||||
{
|
||||
|
||||
_grabber.setPixelDecimation(pixelDecimation);
|
||||
}
|
||||
|
||||
void DispmanxWrapper::action()
|
||||
|
@ -10,102 +10,261 @@
|
||||
// STL includes
|
||||
#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
|
||||
#include <grabber/FramebufferFrameGrabber.h>
|
||||
|
||||
FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device, unsigned width, unsigned height)
|
||||
: Grabber("FRAMEBUFFERGRABBER", width, height)
|
||||
, _fbDevice()
|
||||
FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device)
|
||||
: Grabber("FRAMEBUFFERGRABBER")
|
||||
, _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)
|
||||
{
|
||||
if (!_enabled) return 0;
|
||||
int rc = 0;
|
||||
|
||||
struct fb_var_screeninfo vinfo;
|
||||
unsigned capSize, bytesPerPixel;
|
||||
PixelFormat pixelFormat;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
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 */
|
||||
int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
||||
if (fbfd == -1)
|
||||
_fbfd = ::open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
||||
if (_fbfd < 0)
|
||||
{
|
||||
Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
|
||||
return -1;
|
||||
QString errorReason = QString ("Error opening %1, [%2] %3").arg(_fbDevice).arg(errno).arg(std::strerror(errno));
|
||||
this->setInError ( errorReason );
|
||||
rc = false;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* get variable screen information */
|
||||
ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
|
||||
bytesPerPixel = vinfo.bits_per_pixel / 8;
|
||||
capSize = vinfo.xres * vinfo.yres * bytesPerPixel;
|
||||
|
||||
switch (vinfo.bits_per_pixel)
|
||||
bool FramebufferFrameGrabber::closeDevice()
|
||||
{
|
||||
bool rc = false;
|
||||
if (_fbfd >= 0)
|
||||
{
|
||||
case 16: pixelFormat = PixelFormat::BGR16; break;
|
||||
case 24: pixelFormat = PixelFormat::BGR24; break;
|
||||
if( ::close(_fbfd) == 0) {
|
||||
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
|
||||
case 32: pixelFormat = PixelFormat::PIXELFORMAT_RGB32; break;
|
||||
case 32: _pixelFormat = PixelFormat::PIXELFORMAT_RGB32;
|
||||
break;
|
||||
#else
|
||||
case 32: pixelFormat = PixelFormat::BGR32; break;
|
||||
case 32: _pixelFormat = PixelFormat::BGR32;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Error(_log, "Unknown pixel format: %d bits per pixel", vinfo.bits_per_pixel);
|
||||
close(fbfd);
|
||||
return -1;
|
||||
rc= false;
|
||||
QString errorReason = QString ("Unknown pixel format: %1 bits per pixel").arg(static_cast<int>(_varInfo.bits_per_pixel));
|
||||
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);
|
||||
_imageResampler.setVerticalPixelDecimation(vinfo.yres/_height);
|
||||
_imageResampler.processImage(fbp,
|
||||
vinfo.xres,
|
||||
vinfo.yres,
|
||||
vinfo.xres * bytesPerPixel,
|
||||
pixelFormat,
|
||||
image);
|
||||
|
||||
munmap(fbp, capSize);
|
||||
close(fbfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void FramebufferFrameGrabber::setDevicePath(const QString& path)
|
||||
QJsonObject FramebufferFrameGrabber::discover(const QJsonObject& params)
|
||||
{
|
||||
if(_fbDevice != path)
|
||||
{
|
||||
_fbDevice = path;
|
||||
int result;
|
||||
struct fb_var_screeninfo vinfo;
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
// Check if the framebuffer device can be opened and display the current resolution
|
||||
int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
||||
if (fbfd == -1)
|
||||
QJsonObject inputsDiscovered;
|
||||
|
||||
//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));
|
||||
}
|
||||
else
|
||||
fbIdx = (*deviceFileIterator).fileName().rightRef(1).toInt();
|
||||
QString device = (*deviceFileIterator).absoluteFilePath();
|
||||
DebugIf(verbose, _log, "FB device [%s] found", QSTRING_CSTR(device));
|
||||
|
||||
QSize screenSize = getScreenSize(device);
|
||||
if ( !screenSize.isEmpty() )
|
||||
{
|
||||
// get variable screen information
|
||||
result = ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
if (result != 0)
|
||||
QJsonArray fps = { "1", "5", "10", "15", "20", "25", "30", "40", "50", "60" };
|
||||
|
||||
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);
|
||||
}
|
||||
close(fbfd);
|
||||
}
|
||||
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,13 @@
|
||||
#include <grabber/FramebufferWrapper.h>
|
||||
|
||||
FramebufferWrapper::FramebufferWrapper(const QString & device, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
||||
: GrabberWrapper("FrameBuffer", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
||||
, _grabber(device, grabWidth, grabHeight)
|
||||
{}
|
||||
FramebufferWrapper::FramebufferWrapper( int updateRate_Hz,
|
||||
const QString & device,
|
||||
int pixelDecimation)
|
||||
: GrabberWrapper("FrameBuffer", &_grabber, updateRate_Hz)
|
||||
, _grabber(device)
|
||||
{
|
||||
_grabber.setPixelDecimation(pixelDecimation);
|
||||
}
|
||||
|
||||
void FramebufferWrapper::action()
|
||||
{
|
||||
|
@ -5,35 +5,57 @@
|
||||
// Local includes
|
||||
#include <grabber/OsxFrameGrabber.h>
|
||||
|
||||
OsxFrameGrabber::OsxFrameGrabber(unsigned display, unsigned width, unsigned height)
|
||||
: Grabber("OSXGRABBER", width, height)
|
||||
, _screenIndex(100)
|
||||
//Qt
|
||||
#include <QJsonObject>
|
||||
#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
|
||||
setDisplayIndex(display);
|
||||
_isEnabled = false;
|
||||
_useImageResampler = true;
|
||||
}
|
||||
|
||||
OsxFrameGrabber::~OsxFrameGrabber()
|
||||
{
|
||||
}
|
||||
|
||||
bool OsxFrameGrabber::setupDisplay()
|
||||
{
|
||||
bool rc (false);
|
||||
|
||||
rc = setDisplayIndex(_screenIndex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
{
|
||||
if (!_enabled) return 0;
|
||||
int rc = 0;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
|
||||
CGImageRef dispImage;
|
||||
CFDataRef imgData;
|
||||
unsigned char * pImgData;
|
||||
unsigned dspWidth, dspHeight;
|
||||
unsigned dspWidth;
|
||||
unsigned dspHeight;
|
||||
|
||||
dispImage = CGDisplayCreateImage(_display);
|
||||
|
||||
// display lost, use main
|
||||
if (dispImage == NULL && _display)
|
||||
if (dispImage == nullptr && _display != 0)
|
||||
{
|
||||
dispImage = CGDisplayCreateImage(kCGDirectMainDisplay);
|
||||
// no displays connected, return
|
||||
if (dispImage == NULL)
|
||||
if (dispImage == nullptr)
|
||||
{
|
||||
Error(_log, "No display connected...");
|
||||
return -1;
|
||||
@ -44,55 +66,143 @@ int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
dspWidth = CGImageGetWidth(dispImage);
|
||||
dspHeight = CGImageGetHeight(dispImage);
|
||||
|
||||
_imageResampler.setHorizontalPixelDecimation(dspWidth/_width);
|
||||
_imageResampler.setVerticalPixelDecimation(dspHeight/_height);
|
||||
_imageResampler.processImage( pImgData,
|
||||
dspWidth,
|
||||
dspHeight,
|
||||
CGImageGetBytesPerRow(dispImage),
|
||||
static_cast<int>(dspWidth),
|
||||
static_cast<int>(dspHeight),
|
||||
static_cast<int>(CGImageGetBytesPerRow(dispImage)),
|
||||
PixelFormat::BGR32,
|
||||
image);
|
||||
|
||||
CFRelease(imgData);
|
||||
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;
|
||||
|
||||
CGImageRef image;
|
||||
CGDisplayCount displayCount;
|
||||
CGDirectDisplayID displays[8];
|
||||
|
||||
// get list of displays
|
||||
CGGetActiveDisplayList(8, displays, &displayCount);
|
||||
if (_screenIndex + 1 > displayCount)
|
||||
CGDisplayCount dspyCnt = 0 ;
|
||||
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);
|
||||
_display = kCGDirectMainDisplay;
|
||||
CGDirectDisplayID *activeDspys = new CGDirectDisplayID [dspyCnt] ;
|
||||
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
|
||||
{
|
||||
_display = displays[_screenIndex];
|
||||
}
|
||||
_display = activeDspys[_screenIndex];
|
||||
|
||||
image = CGDisplayCreateImage(_display);
|
||||
if(image == NULL)
|
||||
if(image == nullptr)
|
||||
{
|
||||
Error(_log, "Failed to open main display, disable capture interface");
|
||||
setEnabled(false);
|
||||
return;
|
||||
Error(_log, "Failed to open main display, disable capture interface");
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
setEnabled(true);
|
||||
|
||||
Info(_log, "Display opened with resolution: %dx%d@%dbit", CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerPixel(image));
|
||||
|
||||
rc = true;
|
||||
Info(_log, "Display [%u] opened with resolution: %ux%u@%ubit", _display, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerPixel(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 __screenHeight = 600;
|
||||
|
||||
void CGGetActiveDisplayList(int max, CGDirectDisplayID *displays, CGDisplayCount *displayCount)
|
||||
CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount)
|
||||
{
|
||||
*displayCount = 1;
|
||||
displays[0] = 1;
|
||||
if (maxDisplays == 0 || activeDisplays == nullptr)
|
||||
{
|
||||
*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 image = new CGImage(__screenWidth, __screenHeight);
|
||||
CGImageRef image = new CGImage(__screenWidth / (display+1), __screenHeight / (display+1));
|
||||
|
||||
return image;
|
||||
}
|
||||
@ -123,4 +141,19 @@ void CFRelease(CFDataRef 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
|
||||
|
@ -1,9 +1,14 @@
|
||||
#include <grabber/OsxWrapper.h>
|
||||
|
||||
OsxWrapper::OsxWrapper(unsigned display, unsigned grabWidth, unsigned grabHeight, unsigned updateRate_Hz)
|
||||
: GrabberWrapper("OSX FrameGrabber", &_grabber, grabWidth, grabHeight, updateRate_Hz)
|
||||
, _grabber(display, grabWidth, grabHeight)
|
||||
{}
|
||||
OsxWrapper::OsxWrapper( int updateRate_Hz,
|
||||
int display,
|
||||
int pixelDecimation
|
||||
)
|
||||
: GrabberWrapper("OSX", &_grabber, updateRate_Hz)
|
||||
, _grabber(display)
|
||||
{
|
||||
_grabber.setPixelDecimation(pixelDecimation);
|
||||
}
|
||||
|
||||
void OsxWrapper::action()
|
||||
{
|
||||
|
@ -7,23 +7,30 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QWidget>
|
||||
#include <QScreen>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
QtGrabber::QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display)
|
||||
: Grabber("QTGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
||||
, _display(unsigned(display))
|
||||
, _pixelDecimation(pixelDecimation)
|
||||
, _screenWidth(0)
|
||||
, _screenHeight(0)
|
||||
// Constants
|
||||
namespace {
|
||||
const bool verbose = false;
|
||||
} //End of constants
|
||||
|
||||
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_y(0)
|
||||
, _src_x_max(0)
|
||||
, _src_y_max(0)
|
||||
, _isWayland(false)
|
||||
, _screen(nullptr)
|
||||
, _isVirtual(false)
|
||||
{
|
||||
_logger = Logger::getInstance("Qt");
|
||||
_useImageResampler = false;
|
||||
|
||||
// init
|
||||
setupDisplay();
|
||||
}
|
||||
|
||||
QtGrabber::~QtGrabber()
|
||||
@ -36,10 +43,38 @@ void QtGrabber::freeResources()
|
||||
// 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 result = false;
|
||||
if ( ! open() )
|
||||
{
|
||||
if ( _isWayland )
|
||||
{
|
||||
Error(_log, "Grabber does not work under Wayland!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// cleanup last screen
|
||||
freeResources();
|
||||
_numberOfSDisplays = 0;
|
||||
|
||||
QScreen* primary = QGuiApplication::primaryScreen();
|
||||
QList<QScreen *> screens = QGuiApplication::screens();
|
||||
@ -49,38 +84,70 @@ bool QtGrabber::setupDisplay()
|
||||
screens.prepend(primary);
|
||||
// remove last main screen if twice in list
|
||||
if(screens.lastIndexOf(primary) > 0)
|
||||
{
|
||||
screens.removeAt(screens.lastIndexOf(primary));
|
||||
}
|
||||
}
|
||||
|
||||
if(screens.isEmpty())
|
||||
{
|
||||
Error(_log, "No displays found to capture from!");
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_numberOfSDisplays = screens.size();
|
||||
|
||||
Info(_log,"Available Displays:");
|
||||
int index = 0;
|
||||
for(auto screen : screens)
|
||||
for(auto * screen : qAsConst(screens))
|
||||
{
|
||||
const QRect geo = screen->geometry();
|
||||
Info(_log,"Display %d: Name:%s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.left(), geo.top() ,geo.right(), geo.bottom(), screen->depth());
|
||||
index++;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
_display = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// init the requested display
|
||||
_screen = screens.at(_display);
|
||||
connect(_screen, &QScreen::geometryChanged, this, &QtGrabber::geometryChanged);
|
||||
updateScreenDimensions(true);
|
||||
|
||||
if (_isVirtual)
|
||||
{
|
||||
Info(_log, "Using virtual display across all screens");
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Initialized display %d", _display);
|
||||
return true;
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtGrabber::geometryChanged(const QRect &geo)
|
||||
@ -91,90 +158,109 @@ void QtGrabber::geometryChanged(const QRect &geo)
|
||||
|
||||
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
{
|
||||
if (!_enabled) return 0;
|
||||
int rc = 0;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
if(_screen == nullptr)
|
||||
{
|
||||
// reinit, this will disable capture on failure
|
||||
setEnabled(setupDisplay());
|
||||
return -1;
|
||||
bool result = setupDisplay();
|
||||
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)
|
||||
for (int x=0; x<imageFrame.width(); ++x)
|
||||
if (_isEnabled)
|
||||
{
|
||||
QColor inPixel(imageFrame.pixel(x,y));
|
||||
ColorRgb & outPixel = image(x,y);
|
||||
outPixel.red = inPixel.red();
|
||||
outPixel.green = inPixel.green();
|
||||
outPixel.blue = inPixel.blue();
|
||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
if (originalPixmap.isNull())
|
||||
{
|
||||
rc = -1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if(!_screen)
|
||||
if(_screen == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const QRect& geo = _screen->geometry();
|
||||
if (!force && _screenWidth == unsigned(geo.right()) && _screenHeight == unsigned(geo.bottom()))
|
||||
QRect geo;
|
||||
|
||||
if (_isVirtual)
|
||||
{
|
||||
geo = _screen->virtualGeometry();
|
||||
}
|
||||
else
|
||||
{
|
||||
geo = _screen->geometry();
|
||||
}
|
||||
if (!force && _width == geo.width() && _height == geo.height())
|
||||
{
|
||||
// No update required
|
||||
return 0;
|
||||
}
|
||||
|
||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _screenWidth, _screenHeight, geo.right(), geo.bottom());
|
||||
_screenWidth = geo.right() - geo.left();
|
||||
_screenHeight = geo.bottom() - geo.top();
|
||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.width(), geo.height());
|
||||
_width = geo.width();
|
||||
_height = geo.height();
|
||||
|
||||
int width=0, height=0;
|
||||
int width=0;
|
||||
int height=0;
|
||||
|
||||
// Image scaling is performed by Qt
|
||||
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
|
||||
? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
|
||||
: (_screenWidth / _pixelDecimation);
|
||||
width = (_width > (_cropLeft + _cropRight))
|
||||
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
||||
: (_width / _pixelDecimation);
|
||||
|
||||
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
|
||||
? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_screenHeight / _pixelDecimation);
|
||||
height = (_height > (_cropTop + _cropBottom))
|
||||
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_height / _pixelDecimation);
|
||||
|
||||
|
||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||
switch (_videoMode)
|
||||
{
|
||||
case VideoMode::VIDEO_3DSBS:
|
||||
_width = width /2;
|
||||
_height = height;
|
||||
_calculatedWidth = width /2;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft / 2;
|
||||
_src_y = _cropTop;
|
||||
_src_x_max = (_screenWidth / 2) - _cropRight;
|
||||
_src_y_max = _screenHeight - _cropBottom;
|
||||
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_3DTAB:
|
||||
_width = width;
|
||||
_height = height / 2;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height / 2;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop / 2;
|
||||
_src_x_max = _screenWidth - _cropRight;
|
||||
_src_y_max = (_screenHeight / 2) - _cropBottom;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_2D:
|
||||
default:
|
||||
_width = width;
|
||||
_height = height;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop;
|
||||
_src_x_max = _screenWidth - _cropRight;
|
||||
_src_y_max = _screenHeight - _cropBottom;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -184,22 +270,129 @@ void QtGrabber::setVideoMode(VideoMode mode)
|
||||
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);
|
||||
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);
|
||||
setupDisplay();
|
||||
if (index <= _numberOfSDisplays)
|
||||
{
|
||||
_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>
|
||||
|
||||
QtWrapper::QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, unsigned updateRate_Hz)
|
||||
: GrabberWrapper("Qt", &_grabber, 0, 0, updateRate_Hz)
|
||||
, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation, display)
|
||||
{}
|
||||
QtWrapper::QtWrapper( int updateRate_Hz,
|
||||
int 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()
|
||||
{
|
||||
|
@ -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…
Reference in New Issue
Block a user