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>
|
||||
|
@ -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;
|
||||
@ -76,19 +96,21 @@ table.input-group{width:100%}
|
||||
|
||||
/*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,6 +44,7 @@
|
||||
"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_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",
|
||||
@ -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,7 +170,7 @@
|
||||
<li id="btn_setlang">
|
||||
<a>
|
||||
<div>
|
||||
<i class="fa fa-globe"></i>
|
||||
<i class="fa fa-globe fa-fw"></i>
|
||||
<select id="language-select" class="selectpicker" data-width="fit" data-style="btn-transparent"> </select>
|
||||
</div>
|
||||
</a>
|
||||
@ -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>
|
||||
@ -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');
|
||||
|
@ -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
|
||||
@ -22,12 +21,12 @@ $(document).ready( 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 () {
|
||||
window.readOnlyMode ? $('#btn_cl_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
|
||||
@ -46,8 +45,7 @@ $(document).ready( function() {
|
||||
});
|
||||
}
|
||||
|
||||
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 () {
|
||||
@ -55,18 +53,15 @@ $(document).ready( function() {
|
||||
});
|
||||
}
|
||||
|
||||
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 startBtn = ""
|
||||
var delBtn = "";
|
||||
if(inst[key].instance > 0)
|
||||
{
|
||||
if (inst[key].instance > 0) {
|
||||
delBtn = '<button id="instdel_' + inst[key].instance + '" type="button" class="btn btn-danger"><i class="mdi mdi-delete-forever""></i></button>';
|
||||
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') + '">';
|
||||
|
||||
@ -109,40 +104,32 @@ $(document).ready( function() {
|
||||
});
|
||||
|
||||
//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;
|
||||
@ -185,8 +172,7 @@ $(document).ready( function() {
|
||||
});
|
||||
|
||||
//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
@ -313,6 +313,11 @@ $(document).ready(function () {
|
||||
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;
|
||||
|
@ -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);
|
@ -4,13 +4,21 @@ $(document).ready(function() {
|
||||
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 () {
|
||||
@ -19,8 +27,7 @@ $(document).ready(function() {
|
||||
|
||||
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));
|
||||
}
|
||||
@ -69,16 +76,15 @@ $(document).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")
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -112,6 +117,7 @@ $(document).ready(function() {
|
||||
},
|
||||
closed: function (e) {
|
||||
modalOpened = false;
|
||||
lC = false;
|
||||
},
|
||||
resizeStop: function (e) {
|
||||
setStorage("ledsim_width", $("#ledsim_dialog").outerWidth());
|
||||
@ -121,12 +127,23 @@ $(document).ready(function() {
|
||||
// apply new serverinfos
|
||||
$(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)
|
||||
return;
|
||||
@ -141,8 +158,7 @@ $(document).ready(function() {
|
||||
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])
|
||||
@ -150,10 +166,10 @@ $(document).ready(function() {
|
||||
|
||||
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";
|
||||
@ -168,8 +184,13 @@ $(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;
|
||||
@ -177,14 +198,17 @@ $(document).ready(function() {
|
||||
$('#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>';
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -198,45 +222,52 @@ $(document).ready(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 )
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!modalOpened) {
|
||||
requestLedColorsStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
printLedsToCanvas(event.response.result.leds)
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
$(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();
|
||||
@ -255,25 +286,44 @@ $(document).ready(function() {
|
||||
$(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);
|
||||
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(){
|
||||
@ -28,46 +23,9 @@ function changePassword(){
|
||||
|
||||
$(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,6 +3,21 @@
|
||||
# TurboJPEG_INCLUDE_DIRS
|
||||
# TurboJPEG_LIBRARY
|
||||
|
||||
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
|
||||
@ -12,6 +27,7 @@ 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
|
||||
|
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>
|
||||
|
||||
// decoder thread includes
|
||||
#include <grabber/EncoderThread.h>
|
||||
|
||||
// Determine the cmake options
|
||||
#include <HyperionConfig.h>
|
||||
|
||||
#if defined(ENABLE_CEC)
|
||||
#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>
|
||||
#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,6 +79,9 @@
|
||||
|
||||
using namespace hyperion;
|
||||
|
||||
// Constants
|
||||
namespace { const bool verbose = false; }
|
||||
|
||||
JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject *parent, bool noListener)
|
||||
: API(log, localConnection, parent)
|
||||
{
|
||||
@ -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")
|
||||
@ -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 )
|
||||
{
|
||||
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();
|
||||
@ -1441,6 +1456,146 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject& message, const QString&
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
_useImageResampler = true;
|
||||
_imageResampler.processImage((const uint8_t*)_image_ptr, _width, _height, (_width << 1) + _width, PixelFormat::BGR24, image);
|
||||
else {
|
||||
_imageResampler.processImage(static_cast<uint8_t*>(_image_ptr),
|
||||
_width,
|
||||
_height,
|
||||
linelen,
|
||||
PixelFormat::BGR24, image);
|
||||
_lastError = 0;
|
||||
|
||||
return 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);
|
||||
}
|
||||
|
||||
if (!video_inputs.isEmpty())
|
||||
{
|
||||
inputsDiscovered["device"] = "amlogic";
|
||||
inputsDiscovered["device_name"] = "AmLogic";
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
case 16: pixelFormat = PixelFormat::BGR16; break;
|
||||
case 24: pixelFormat = PixelFormat::BGR24; break;
|
||||
bool rc = false;
|
||||
if (_fbfd >= 0)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
QJsonObject FramebufferFrameGrabber::discover(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
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)
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
_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;
|
||||
if (!video_inputs.isEmpty())
|
||||
{
|
||||
inputsDiscovered["device"] = "framebuffer";
|
||||
inputsDiscovered["device_name"] = "Framebuffer";
|
||||
inputsDiscovered["type"] = "screen";
|
||||
inputsDiscovered["video_inputs"] = video_inputs;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferFrameGrabber::setDevicePath(const QString& path)
|
||||
if (inputsDiscovered.isEmpty())
|
||||
{
|
||||
if(_fbDevice != path)
|
||||
{
|
||||
_fbDevice = path;
|
||||
int result;
|
||||
struct fb_var_screeninfo vinfo;
|
||||
DebugIf(verbose, _log, "No displays found to capture from!");
|
||||
}
|
||||
|
||||
// Check if the framebuffer device can be opened and display the current resolution
|
||||
int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
|
||||
if (fbfd == -1)
|
||||
{
|
||||
Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
// get variable screen information
|
||||
result = ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
if (result != 0)
|
||||
{
|
||||
Error(_log, "Could not get screen information, %s", std::strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log, "Display opened with resolution: %dx%d@%dbit", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
|
||||
}
|
||||
close(fbfd);
|
||||
}
|
||||
}
|
||||
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
return inputsDiscovered;
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include <grabber/FramebufferWrapper.h>
|
||||
|
||||
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++;
|
||||
++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)
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user