mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Feature/xcb grabber (#912)
* Add Xcb grabber * update compile instruction Signed-off-by: Paulchen Panther <Paulchen-Panter@protonmail.com> * Fix problem on resolution change + Make XCB default if X11 is not avaialable * Fix decimation problem Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com> Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
		| @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||||||
| ### Breaking | ### Breaking | ||||||
|  |  | ||||||
| ### Added | ### Added | ||||||
|  | - Add XCB grabber, a faster and safer alternative for X11 grabbing (#912) | ||||||
|  |  | ||||||
| ### Changed | ### Changed | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ SET ( DEFAULT_AMLOGIC                     OFF ) | |||||||
| SET ( DEFAULT_DISPMANX                    OFF ) | SET ( DEFAULT_DISPMANX                    OFF ) | ||||||
| SET ( DEFAULT_OSX                         OFF ) | SET ( DEFAULT_OSX                         OFF ) | ||||||
| SET ( DEFAULT_X11                         OFF ) | SET ( DEFAULT_X11                         OFF ) | ||||||
|  | SET ( DEFAULT_XCB                         OFF ) | ||||||
| SET ( DEFAULT_QT                          ON  ) | SET ( DEFAULT_QT                          ON  ) | ||||||
| SET ( DEFAULT_WS281XPWM                   OFF ) | SET ( DEFAULT_WS281XPWM                   OFF ) | ||||||
| SET ( DEFAULT_AVAHI                       ON  ) | SET ( DEFAULT_AVAHI                       ON  ) | ||||||
| @@ -122,6 +123,7 @@ elseif ( "${PLATFORM}" STREQUAL "amlogic64" ) | |||||||
| 	SET ( DEFAULT_AMLOGIC    ON ) | 	SET ( DEFAULT_AMLOGIC    ON ) | ||||||
| elseif ( "${PLATFORM}" MATCHES "x11" ) | elseif ( "${PLATFORM}" MATCHES "x11" ) | ||||||
| 	SET ( DEFAULT_X11        ON ) | 	SET ( DEFAULT_X11        ON ) | ||||||
|  | 	SET ( DEFAULT_XCB        ON ) | ||||||
| 	if ( "${PLATFORM}" STREQUAL "x11-dev" ) | 	if ( "${PLATFORM}" STREQUAL "x11-dev" ) | ||||||
| 		SET ( DEFAULT_AMLOGIC    ON) | 		SET ( DEFAULT_AMLOGIC    ON) | ||||||
| 		SET ( DEFAULT_WS281XPWM  ON ) | 		SET ( DEFAULT_WS281XPWM  ON ) | ||||||
| @@ -182,6 +184,9 @@ message(STATUS "ENABLE_CEC = ${ENABLE_CEC}") | |||||||
| option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11}) | option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11}) | ||||||
| message(STATUS "ENABLE_X11 = ${ENABLE_X11}") | message(STATUS "ENABLE_X11 = ${ENABLE_X11}") | ||||||
|  |  | ||||||
|  | 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}") | message(STATUS "ENABLE_QT = ${ENABLE_QT}") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/ | |||||||
|  |  | ||||||
| ``` | ``` | ||||||
| sudo apt-get update | sudo apt-get update | ||||||
| sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev | sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite 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 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| **on RPI you need the videocore IV headers** | **on RPI you need the videocore IV headers** | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ Update the Ubuntu environment to the latest stage and install required additiona | |||||||
| ``` | ``` | ||||||
| sudo apt-get update | sudo apt-get update | ||||||
| sudo apt-get upgrade | sudo apt-get upgrade | ||||||
| sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev | sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite 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 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment: | Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment: | ||||||
|   | |||||||
| @@ -18,6 +18,9 @@ | |||||||
| // Define to enable the x11 grabber | // Define to enable the x11 grabber | ||||||
| #cmakedefine ENABLE_X11 | #cmakedefine ENABLE_X11 | ||||||
|  |  | ||||||
|  | // Define to enable the xcb grabber | ||||||
|  | #cmakedefine ENABLE_XCB | ||||||
|  |  | ||||||
| // Define to enable the qt grabber | // Define to enable the qt grabber | ||||||
| #cmakedefine ENABLE_QT | #cmakedefine ENABLE_QT | ||||||
|  |  | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ $(document).ready( function() { | |||||||
|  |  | ||||||
| 	if(grabbers.indexOf('dispmanx') > -1) | 	if(grabbers.indexOf('dispmanx') > -1) | ||||||
| 		html += 'Raspberry Pi'; | 		html += 'Raspberry Pi'; | ||||||
| 	else if(grabbers.indexOf('x11') > -1) | 	else if(grabbers.indexOf('x11') > -1 || grabbers.indexOf('xcb') > -1) | ||||||
| 		html += 'X86'; | 		html += 'X86'; | ||||||
| 	else if(grabbers.indexOf('osx')  > -1) | 	else if(grabbers.indexOf('osx')  > -1) | ||||||
| 		html += 'OSX'; | 		html += 'OSX'; | ||||||
|   | |||||||
| @@ -323,7 +323,7 @@ $(document).ready( function() { | |||||||
|  |  | ||||||
|     if (grabbers.indexOf('dispmanx') > -1) |     if (grabbers.indexOf('dispmanx') > -1) | ||||||
|       hideEl(["device","pixelDecimation"]); |       hideEl(["device","pixelDecimation"]); | ||||||
|     else if (grabbers.indexOf('x11') > -1) |     else if (grabbers.indexOf('x11') > -1 || grabbers.indexOf('xcb') > -1) | ||||||
|       hideEl(["device","width","height"]); |       hideEl(["device","width","height"]); | ||||||
|     else if (grabbers.indexOf('osx')  > -1 ) |     else if (grabbers.indexOf('osx')  > -1 ) | ||||||
|       hideEl(["device","pixelDecimation"]); |       hideEl(["device","pixelDecimation"]); | ||||||
|   | |||||||
| @@ -236,6 +236,7 @@ else | |||||||
| 	ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2 | 	ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2 | ||||||
| 	ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | 	ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | ||||||
| 	ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | 	ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | ||||||
|  | 	ln -fs $BINSP/hyperion-xcb $BINTP/hyperion-xcb 2>/dev/null | ||||||
| 	ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | 	ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | ||||||
| fi | fi | ||||||
|  |  | ||||||
| @@ -260,6 +261,11 @@ elif [ $OS_OPENELEC -eq 1 ]; then | |||||||
| 		echo '---> Adding Hyperion-x11 to OpenELEC/LibreELEC autostart.sh' | 		echo '---> Adding Hyperion-x11 to OpenELEC/LibreELEC autostart.sh' | ||||||
| 		echo "DISPLAY=:0.0 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/storage/hyperion/bin /storage/hyperion/bin/hyperion-x11 </dev/null >/storage/logfiles/hyperion.log 2>&1 &" >> /storage/.config/autostart.sh		 | 		echo "DISPLAY=:0.0 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/storage/hyperion/bin /storage/hyperion/bin/hyperion-x11 </dev/null >/storage/logfiles/hyperion.log 2>&1 &" >> /storage/.config/autostart.sh		 | ||||||
| 	fi | 	fi | ||||||
|  | 	# only add hyperion-xcb to startup, if not found and x32x64 detected | ||||||
|  | 	if [ $CPU_X32X64 -eq 1 ] && [ `cat /storage/.config/autostart.sh 2>/dev/null | grep hyperion-xcb | wc -l` -eq 0 ]; then | ||||||
|  | 		echo '---> Adding Hyperion-xcb to OpenELEC/LibreELEC autostart.sh' | ||||||
|  | 		echo "DISPLAY=:0.0 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/storage/hyperion/bin /storage/hyperion/bin/hyperion-xcb </dev/null >/storage/logfiles/hyperion.log 2>&1 &" >> /storage/.config/autostart.sh | ||||||
|  | 	fi | ||||||
| elif [ $USE_SYSTEMD -eq 1 ]; then | elif [ $USE_SYSTEMD -eq 1 ]; then | ||||||
| 	echo '---> Installing systemd script' | 	echo '---> Installing systemd script' | ||||||
| 	#place startup script for systemd and activate | 	#place startup script for systemd and activate | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ elif [ $OS_OPENELEC -eq 1 ]; then | |||||||
| 	echo "---> Remove Hyperion from OpenELEC autostart.sh" | 	echo "---> Remove Hyperion from OpenELEC autostart.sh" | ||||||
| 	sed -i "/hyperiond/d" /storage/.config/autostart.sh 2>/dev/null | 	sed -i "/hyperiond/d" /storage/.config/autostart.sh 2>/dev/null | ||||||
| 	sed -i "/hyperion-x11/d" /storage/.config/autostart.sh 2>/dev/null | 	sed -i "/hyperion-x11/d" /storage/.config/autostart.sh 2>/dev/null | ||||||
|  | 	sed -i "/hyperion-xcb/d" /storage/.config/autostart.sh 2>/dev/null | ||||||
| elif [ $USE_SYSTEMD -eq 1 ]; then | elif [ $USE_SYSTEMD -eq 1 ]; then | ||||||
| 	# Delete and disable Hyperion systemd script | 	# Delete and disable Hyperion systemd script | ||||||
| 	echo '---> Delete and disable Hyperion systemd script' | 	echo '---> Delete and disable Hyperion systemd script' | ||||||
| @@ -105,6 +106,7 @@ else | |||||||
| 	rm -v /usr/bin/hyperion-v4l2 2>/dev/null | 	rm -v /usr/bin/hyperion-v4l2 2>/dev/null | ||||||
| 	rm -v /usr/bin/hyperion-dispmanx 2>/dev/null | 	rm -v /usr/bin/hyperion-dispmanx 2>/dev/null | ||||||
| 	rm -v /usr/bin/hyperion-x11 2>/dev/null | 	rm -v /usr/bin/hyperion-x11 2>/dev/null | ||||||
|  | 	rm -v /usr/bin/hyperion-xcb 2>/dev/null | ||||||
| 	rm -v /usr/bin/hyperion-aml 2>/dev/null | 	rm -v /usr/bin/hyperion-aml 2>/dev/null | ||||||
| 	rm -v /etc/hyperion.config.json 2>/dev/null | 	rm -v /etc/hyperion.config.json 2>/dev/null | ||||||
| 	echo "---> Remove binaries" | 	echo "---> Remove binaries" | ||||||
|   | |||||||
							
								
								
									
										278
									
								
								cmake/ECMFindModuleHelpers.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								cmake/ECMFindModuleHelpers.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | |||||||
|  | #.rst: | ||||||
|  | # ECMFindModuleHelpers | ||||||
|  | # -------------------- | ||||||
|  | # | ||||||
|  | # Helper macros for find modules: ecm_find_package_version_check(), | ||||||
|  | # ecm_find_package_parse_components() and | ||||||
|  | # ecm_find_package_handle_library_components(). | ||||||
|  | # | ||||||
|  | # :: | ||||||
|  | # | ||||||
|  | #   ecm_find_package_version_check(<name>) | ||||||
|  | # | ||||||
|  | # Prints warnings if the CMake version or the project's required CMake version | ||||||
|  | # is older than that required by extra-cmake-modules. | ||||||
|  | # | ||||||
|  | # :: | ||||||
|  | # | ||||||
|  | #   ecm_find_package_parse_components(<name> | ||||||
|  | #       RESULT_VAR <variable> | ||||||
|  | #       KNOWN_COMPONENTS <component1> [<component2> [...]] | ||||||
|  | #       [SKIP_DEPENDENCY_HANDLING]) | ||||||
|  | # | ||||||
|  | # This macro will populate <variable> with a list of components found in | ||||||
|  | # <name>_FIND_COMPONENTS, after checking that all those components are in the | ||||||
|  | # list of KNOWN_COMPONENTS; if there are any unknown components, it will print | ||||||
|  | # an error or warning (depending on the value of <name>_FIND_REQUIRED) and call | ||||||
|  | # return(). | ||||||
|  | # | ||||||
|  | # The order of components in <variable> is guaranteed to match the order they | ||||||
|  | # are listed in the KNOWN_COMPONENTS argument. | ||||||
|  | # | ||||||
|  | # If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable | ||||||
|  | # <name>_<component>_component_deps will be checked for dependent components. | ||||||
|  | # If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive) | ||||||
|  | # dependencies will also be added to <variable>. | ||||||
|  | # | ||||||
|  | # :: | ||||||
|  | # | ||||||
|  | #   ecm_find_package_handle_library_components(<name> | ||||||
|  | #       COMPONENTS <component> [<component> [...]] | ||||||
|  | #       [SKIP_DEPENDENCY_HANDLING]) | ||||||
|  | #       [SKIP_PKG_CONFIG]) | ||||||
|  | # | ||||||
|  | # Creates an imported library target for each component.  The operation of this | ||||||
|  | # macro depends on the presence of a number of CMake variables. | ||||||
|  | # | ||||||
|  | # The <name>_<component>_lib variable should contain the name of this library, | ||||||
|  | # and <name>_<component>_header variable should contain the name of a header | ||||||
|  | # file associated with it (whatever relative path is normally passed to | ||||||
|  | # '#include'). <name>_<component>_header_subdir variable can be used to specify | ||||||
|  | # which subdirectory of the include path the headers will be found in. | ||||||
|  | # ecm_find_package_components() will then search for the library | ||||||
|  | # and include directory (creating appropriate cache variables) and create an | ||||||
|  | # imported library target named <name>::<component>. | ||||||
|  | # | ||||||
|  | # Additional variables can be used to provide additional information: | ||||||
|  | # | ||||||
|  | # If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and | ||||||
|  | # pkg-config is found, the pkg-config module given by | ||||||
|  | # <name>_<component>_pkg_config will be searched for and used to help locate the | ||||||
|  | # library and header file.  It will also be used to set | ||||||
|  | # <name>_<component>_VERSION. | ||||||
|  | # | ||||||
|  | # Note that if version information is found via pkg-config, | ||||||
|  | # <name>_<component>_FIND_VERSION can be set to require a particular version | ||||||
|  | # for each component. | ||||||
|  | # | ||||||
|  | # If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property | ||||||
|  | # of the imported target for <component> will be set to contain the imported | ||||||
|  | # targets for the components listed in <name>_<component>_component_deps. | ||||||
|  | # <component>_FOUND will also be set to false if any of the compoments in | ||||||
|  | # <name>_<component>_component_deps are not found.  This requires the components | ||||||
|  | # in <name>_<component>_component_deps to be listed before <component> in the | ||||||
|  | # COMPONENTS argument. | ||||||
|  | # | ||||||
|  | # The following variables will be set: | ||||||
|  | # | ||||||
|  | # ``<name>_TARGETS`` | ||||||
|  | #   the imported targets | ||||||
|  | # ``<name>_LIBRARIES`` | ||||||
|  | #   the found libraries | ||||||
|  | # ``<name>_INCLUDE_DIRS`` | ||||||
|  | #   the combined required include directories for the components | ||||||
|  | # ``<name>_DEFINITIONS`` | ||||||
|  | #   the "other" CFLAGS provided by pkg-config, if any | ||||||
|  | # ``<name>_VERSION`` | ||||||
|  | #   the value of ``<name>_<component>_VERSION`` for the first component that | ||||||
|  | #   has this variable set (note that components are searched for in the order | ||||||
|  | #   they are passed to the macro), although if it is already set, it will not | ||||||
|  | #   be altered | ||||||
|  | # | ||||||
|  | # Note that these variables are never cleared, so if | ||||||
|  | # ecm_find_package_handle_library_components() is called multiple times with | ||||||
|  | # different components (typically because of multiple find_package() calls) then | ||||||
|  | # ``<name>_TARGETS``, for example, will contain all the targets found in any | ||||||
|  | # call (although no duplicates). | ||||||
|  | # | ||||||
|  | # Since pre-1.0.0. | ||||||
|  |  | ||||||
|  | #============================================================================= | ||||||
|  | # SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org> | ||||||
|  | # | ||||||
|  | # SPDX-License-Identifier: BSD-3-Clause | ||||||
|  |  | ||||||
|  | include(CMakeParseArguments) | ||||||
|  |  | ||||||
|  | macro(ecm_find_package_version_check module_name) | ||||||
|  |     if(CMAKE_VERSION VERSION_LESS 2.8.12) | ||||||
|  |         message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake") | ||||||
|  |     endif() | ||||||
|  |     if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) | ||||||
|  |         message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake") | ||||||
|  |     endif() | ||||||
|  | endmacro() | ||||||
|  |  | ||||||
|  | macro(ecm_find_package_parse_components module_name) | ||||||
|  |     set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING) | ||||||
|  |     set(ecm_fppc_oneValueArgs RESULT_VAR) | ||||||
|  |     set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS) | ||||||
|  |     cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN}) | ||||||
|  |  | ||||||
|  |     if(ECM_FPPC_UNPARSED_ARGUMENTS) | ||||||
|  |         message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}") | ||||||
|  |     endif() | ||||||
|  |     if(NOT ECM_FPPC_RESULT_VAR) | ||||||
|  |         message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components") | ||||||
|  |     endif() | ||||||
|  |     if(NOT ECM_FPPC_KNOWN_COMPONENTS) | ||||||
|  |         message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components") | ||||||
|  |     endif() | ||||||
|  |     if(NOT ECM_FPPC_DEFAULT_COMPONENTS) | ||||||
|  |         set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS}) | ||||||
|  |     endif() | ||||||
|  |  | ||||||
|  |     if(${module_name}_FIND_COMPONENTS) | ||||||
|  |         set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS}) | ||||||
|  |  | ||||||
|  |         if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING) | ||||||
|  |             # Make sure deps are included | ||||||
|  |             foreach(ecm_fppc_comp ${ecm_fppc_requestedComps}) | ||||||
|  |                 foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps}) | ||||||
|  |                     list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index) | ||||||
|  |                     if("${ecm_fppc_index}" STREQUAL "-1") | ||||||
|  |                         if(NOT ${module_name}_FIND_QUIETLY) | ||||||
|  |                             message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}") | ||||||
|  |                         endif() | ||||||
|  |                         list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}") | ||||||
|  |                     endif() | ||||||
|  |                 endforeach() | ||||||
|  |             endforeach() | ||||||
|  |         else() | ||||||
|  |             message(STATUS "Skipping dependency handling for ${module_name}") | ||||||
|  |         endif() | ||||||
|  |         list(REMOVE_DUPLICATES ecm_fppc_requestedComps) | ||||||
|  |  | ||||||
|  |         # This makes sure components are listed in the same order as | ||||||
|  |         # KNOWN_COMPONENTS (potentially important for inter-dependencies) | ||||||
|  |         set(${ECM_FPPC_RESULT_VAR}) | ||||||
|  |         foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS}) | ||||||
|  |             list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index) | ||||||
|  |             if(NOT "${ecm_fppc_index}" STREQUAL "-1") | ||||||
|  |                 list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}") | ||||||
|  |                 list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index}) | ||||||
|  |             endif() | ||||||
|  |         endforeach() | ||||||
|  |         # if there are any left, they are unknown components | ||||||
|  |         if(ecm_fppc_requestedComps) | ||||||
|  |             set(ecm_fppc_msgType STATUS) | ||||||
|  |             if(${module_name}_FIND_REQUIRED) | ||||||
|  |                 set(ecm_fppc_msgType FATAL_ERROR) | ||||||
|  |             endif() | ||||||
|  |             if(NOT ${module_name}_FIND_QUIETLY) | ||||||
|  |                 message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}") | ||||||
|  |             endif() | ||||||
|  |             return() | ||||||
|  |         endif() | ||||||
|  |     else() | ||||||
|  |         set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS}) | ||||||
|  |     endif() | ||||||
|  | endmacro() | ||||||
|  |  | ||||||
|  | macro(ecm_find_package_handle_library_components module_name) | ||||||
|  |     set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING) | ||||||
|  |     set(ecm_fpwc_oneValueArgs) | ||||||
|  |     set(ecm_fpwc_multiValueArgs COMPONENTS) | ||||||
|  |     cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN}) | ||||||
|  |  | ||||||
|  |     if(ECM_FPWC_UNPARSED_ARGUMENTS) | ||||||
|  |         message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}") | ||||||
|  |     endif() | ||||||
|  |     if(NOT ECM_FPWC_COMPONENTS) | ||||||
|  |         message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components") | ||||||
|  |     endif() | ||||||
|  |  | ||||||
|  |     include(FindPackageHandleStandardArgs) | ||||||
|  |     find_package(PkgConfig) | ||||||
|  |     foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS}) | ||||||
|  |         set(ecm_fpwc_dep_vars) | ||||||
|  |         set(ecm_fpwc_dep_targets) | ||||||
|  |         if(NOT SKIP_DEPENDENCY_HANDLING) | ||||||
|  |             foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps}) | ||||||
|  |                 list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND") | ||||||
|  |                 list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}") | ||||||
|  |             endforeach() | ||||||
|  |         endif() | ||||||
|  |  | ||||||
|  |         if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config) | ||||||
|  |             pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET | ||||||
|  |                               ${${module_name}_${ecm_fpwc_comp}_pkg_config}) | ||||||
|  |         endif() | ||||||
|  |  | ||||||
|  |         find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR | ||||||
|  |             NAMES ${${module_name}_${ecm_fpwc_comp}_header} | ||||||
|  |             HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS} | ||||||
|  |             PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir} | ||||||
|  |         ) | ||||||
|  |         find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY | ||||||
|  |             NAMES ${${module_name}_${ecm_fpwc_comp}_lib} | ||||||
|  |             HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS} | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}") | ||||||
|  |         if(NOT ${module_name}_VERSION) | ||||||
|  |             set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) | ||||||
|  |         endif() | ||||||
|  |  | ||||||
|  |         set(FPHSA_NAME_MISMATCHED 1) | ||||||
|  |         find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} | ||||||
|  |             FOUND_VAR | ||||||
|  |                 ${module_name}_${ecm_fpwc_comp}_FOUND | ||||||
|  |             REQUIRED_VARS | ||||||
|  |                 ${module_name}_${ecm_fpwc_comp}_LIBRARY | ||||||
|  |                 ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR | ||||||
|  |                 ${ecm_fpwc_dep_vars} | ||||||
|  |             VERSION_VAR | ||||||
|  |                 ${module_name}_${ecm_fpwc_comp}_VERSION | ||||||
|  |             ) | ||||||
|  |         unset(FPHSA_NAME_MISMATCHED) | ||||||
|  |  | ||||||
|  |         mark_as_advanced( | ||||||
|  |             ${module_name}_${ecm_fpwc_comp}_LIBRARY | ||||||
|  |             ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         if(${module_name}_${ecm_fpwc_comp}_FOUND) | ||||||
|  |             list(APPEND ${module_name}_LIBRARIES | ||||||
|  |                         "${${module_name}_${ecm_fpwc_comp}_LIBRARY}") | ||||||
|  |             list(APPEND ${module_name}_INCLUDE_DIRS | ||||||
|  |                         "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}") | ||||||
|  |             set(${module_name}_DEFINITIONS | ||||||
|  |                     ${${module_name}_DEFINITIONS} | ||||||
|  |                     ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}) | ||||||
|  |             if(NOT TARGET ${module_name}::${ecm_fpwc_comp}) | ||||||
|  |                 add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED) | ||||||
|  |                 set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES | ||||||
|  |                     IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}" | ||||||
|  |                     INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}" | ||||||
|  |                     INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}" | ||||||
|  |                     INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}" | ||||||
|  |                 ) | ||||||
|  |             endif() | ||||||
|  |             list(APPEND ${module_name}_TARGETS | ||||||
|  |                         "${module_name}::${ecm_fpwc_comp}") | ||||||
|  |         endif() | ||||||
|  |     endforeach() | ||||||
|  |     if(${module_name}_LIBRARIES) | ||||||
|  |         list(REMOVE_DUPLICATES ${module_name}_LIBRARIES) | ||||||
|  |     endif() | ||||||
|  |     if(${module_name}_INCLUDE_DIRS) | ||||||
|  |         list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS) | ||||||
|  |     endif() | ||||||
|  |     if(${module_name}_DEFINITIONS) | ||||||
|  |         list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS) | ||||||
|  |     endif() | ||||||
|  |     if(${module_name}_TARGETS) | ||||||
|  |         list(REMOVE_DUPLICATES ${module_name}_TARGETS) | ||||||
|  |     endif() | ||||||
|  | endmacro() | ||||||
							
								
								
									
										180
									
								
								cmake/FindXCB.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								cmake/FindXCB.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | |||||||
|  | #.rst: | ||||||
|  | # FindXCB | ||||||
|  | # ------- | ||||||
|  | # | ||||||
|  | # Try to find XCB. | ||||||
|  | # | ||||||
|  | # This is a component-based find module, which makes use of the COMPONENTS and | ||||||
|  | # OPTIONAL_COMPONENTS arguments to find_module.  The following components are | ||||||
|  | # available:: | ||||||
|  | # | ||||||
|  | #   XCB | ||||||
|  | #   ATOM         AUX          COMPOSITE    CURSOR       DAMAGE | ||||||
|  | #   DPMS         DRI2         DRI3         EVENT        EWMH | ||||||
|  | #   GLX          ICCCM        IMAGE        KEYSYMS      PRESENT | ||||||
|  | #   RANDR        RECORD       RENDER       RENDERUTIL   RES | ||||||
|  | #   SCREENSAVER  SHAPE        SHM          SYNC         UTIL | ||||||
|  | #   XEVIE        XF86DRI      XFIXES       XINERAMA     XINPUT | ||||||
|  | #   XKB          XPRINT       XTEST        XV           XVMC | ||||||
|  | # | ||||||
|  | # If no components are specified, this module will act as though all components | ||||||
|  | # except XINPUT (which is considered unstable) were passed to | ||||||
|  | # OPTIONAL_COMPONENTS. | ||||||
|  | # | ||||||
|  | # This module will define the following variables, independently of the | ||||||
|  | # components searched for or found: | ||||||
|  | # | ||||||
|  | # ``XCB_FOUND`` | ||||||
|  | #     True if (the requestion version of) xcb is available | ||||||
|  | # ``XCB_VERSION`` | ||||||
|  | #     Found xcb version | ||||||
|  | # ``XCB_TARGETS`` | ||||||
|  | #     A list of all targets imported by this module (note that there may be more | ||||||
|  | #     than the components that were requested) | ||||||
|  | # ``XCB_LIBRARIES`` | ||||||
|  | #     This can be passed to target_link_libraries() instead of the imported | ||||||
|  | #     targets | ||||||
|  | # ``XCB_INCLUDE_DIRS`` | ||||||
|  | #     This should be passed to target_include_directories() if the targets are | ||||||
|  | #     not used for linking | ||||||
|  | # ``XCB_DEFINITIONS`` | ||||||
|  | #     This should be passed to target_compile_options() if the targets are not | ||||||
|  | #     used for linking | ||||||
|  | # | ||||||
|  | # For each searched-for components, ``XCB_<component>_FOUND`` will be set to | ||||||
|  | # true if the corresponding xcb library was found, and false otherwise.  If | ||||||
|  | # ``XCB_<component>_FOUND`` is true, the imported target ``XCB::<component>`` | ||||||
|  | # will be defined.  This module will also attempt to determine | ||||||
|  | # ``XCB_*_VERSION`` variables for each imported target, although | ||||||
|  | # ``XCB_VERSION`` should normally be sufficient. | ||||||
|  | # | ||||||
|  | # In general we recommend using the imported targets, as they are easier to use | ||||||
|  | # and provide more control.  Bear in mind, however, that if any target is in the | ||||||
|  | # link interface of an exported library, it must be made available by the | ||||||
|  | # package config file. | ||||||
|  | # | ||||||
|  | # Since pre-1.0.0. | ||||||
|  |  | ||||||
|  | #============================================================================= | ||||||
|  | # SPDX-FileCopyrightText: 2011 Fredrik Höglund <fredrik@kde.org> | ||||||
|  | # SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> | ||||||
|  | # SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org> | ||||||
|  | # | ||||||
|  | # SPDX-License-Identifier: BSD-3-Clause | ||||||
|  | #============================================================================= | ||||||
|  |  | ||||||
|  | include(${CMAKE_SOURCE_DIR}/cmake/ECMFindModuleHelpers.cmake) | ||||||
|  |  | ||||||
|  | ecm_find_package_version_check(XCB) | ||||||
|  |  | ||||||
|  | # Note that this list needs to be ordered such that any component | ||||||
|  | # appears after its dependencies | ||||||
|  | set(XCB_known_components | ||||||
|  |     XCB | ||||||
|  |     RENDER | ||||||
|  |     SHAPE | ||||||
|  |     XFIXES | ||||||
|  |     SHM | ||||||
|  |     ATOM | ||||||
|  |     AUX | ||||||
|  |     COMPOSITE | ||||||
|  |     CURSOR | ||||||
|  |     DAMAGE | ||||||
|  |     DPMS | ||||||
|  |     DRI2 | ||||||
|  |     DRI3 | ||||||
|  |     EVENT | ||||||
|  |     EWMH | ||||||
|  |     GLX | ||||||
|  |     ICCCM | ||||||
|  |     IMAGE | ||||||
|  |     KEYSYMS | ||||||
|  |     PRESENT | ||||||
|  |     RANDR | ||||||
|  |     RECORD | ||||||
|  |     RENDERUTIL | ||||||
|  |     RES | ||||||
|  |     SCREENSAVER | ||||||
|  |     SYNC | ||||||
|  |     UTIL | ||||||
|  |     XEVIE | ||||||
|  |     XF86DRI | ||||||
|  |     XINERAMA | ||||||
|  |     XINPUT | ||||||
|  |     XKB | ||||||
|  |     XPRINT | ||||||
|  |     XTEST | ||||||
|  |     XV | ||||||
|  |     XVMC | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # XINPUT is unstable; do not include it by default | ||||||
|  | set(XCB_default_components ${XCB_known_components}) | ||||||
|  | list(REMOVE_ITEM XCB_default_components "XINPUT") | ||||||
|  |  | ||||||
|  | # default component info: xcb components have fairly predictable | ||||||
|  | # header files, library names and pkg-config names | ||||||
|  | foreach(_comp ${XCB_known_components}) | ||||||
|  |     string(TOLOWER "${_comp}" _lc_comp) | ||||||
|  |     set(XCB_${_comp}_component_deps XCB) | ||||||
|  |     set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}") | ||||||
|  |     set(XCB_${_comp}_lib "xcb-${_lc_comp}") | ||||||
|  |     set(XCB_${_comp}_header "xcb/${_lc_comp}.h") | ||||||
|  | endforeach() | ||||||
|  | # exceptions | ||||||
|  | set(XCB_XCB_component_deps) | ||||||
|  | set(XCB_COMPOSITE_component_deps XCB XFIXES) | ||||||
|  | set(XCB_DAMAGE_component_deps XCB XFIXES) | ||||||
|  | set(XCB_IMAGE_component_deps XCB SHM) | ||||||
|  | set(XCB_RENDERUTIL_component_deps XCB RENDER) | ||||||
|  | set(XCB_XFIXES_component_deps XCB RENDER SHAPE) | ||||||
|  | set(XCB_XVMC_component_deps XCB XV) | ||||||
|  | set(XCB_XV_component_deps XCB SHM) | ||||||
|  | set(XCB_XCB_pkg_config "xcb") | ||||||
|  | set(XCB_XCB_lib "xcb") | ||||||
|  | set(XCB_ATOM_header "xcb/xcb_atom.h") | ||||||
|  | set(XCB_ATOM_lib "xcb-util") | ||||||
|  | set(XCB_AUX_header "xcb/xcb_aux.h") | ||||||
|  | set(XCB_AUX_lib "xcb-util") | ||||||
|  | set(XCB_CURSOR_header "xcb/xcb_cursor.h") | ||||||
|  | set(XCB_EVENT_header "xcb/xcb_event.h") | ||||||
|  | set(XCB_EVENT_lib "xcb-util") | ||||||
|  | set(XCB_EWMH_header "xcb/xcb_ewmh.h") | ||||||
|  | set(XCB_ICCCM_header "xcb/xcb_icccm.h") | ||||||
|  | set(XCB_IMAGE_header "xcb/xcb_image.h") | ||||||
|  | set(XCB_KEYSYMS_header "xcb/xcb_keysyms.h") | ||||||
|  | set(XCB_PIXEL_header "xcb/xcb_pixel.h") | ||||||
|  | set(XCB_RENDERUTIL_header "xcb/xcb_renderutil.h") | ||||||
|  | set(XCB_RENDERUTIL_lib "xcb-render-util") | ||||||
|  | set(XCB_UTIL_header "xcb/xcb_util.h") | ||||||
|  |  | ||||||
|  | ecm_find_package_parse_components(XCB | ||||||
|  |     RESULT_VAR XCB_components | ||||||
|  |     KNOWN_COMPONENTS ${XCB_known_components} | ||||||
|  |     DEFAULT_COMPONENTS ${XCB_default_components} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | list(FIND XCB_components "XINPUT" _XCB_XINPUT_index) | ||||||
|  | if (NOT _XCB_XINPUT_index EQUAL -1) | ||||||
|  |     message(AUTHOR_WARNING "XINPUT from XCB was requested: this is EXPERIMENTAL and is likely to unavailable on many systems!") | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | ecm_find_package_handle_library_components(XCB | ||||||
|  |     COMPONENTS ${XCB_components} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | find_package_handle_standard_args(XCB | ||||||
|  |     FOUND_VAR | ||||||
|  |         XCB_FOUND | ||||||
|  |     REQUIRED_VARS | ||||||
|  |         XCB_LIBRARIES | ||||||
|  |     VERSION_VAR | ||||||
|  |         XCB_VERSION | ||||||
|  |     HANDLE_COMPONENTS | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | include(FeatureSummary) | ||||||
|  | set_package_properties(XCB PROPERTIES | ||||||
|  |     URL "https://xcb.freedesktop.org/" | ||||||
|  |     DESCRIPTION "X protocol C-language Binding" | ||||||
|  | ) | ||||||
| @@ -88,6 +88,7 @@ ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2 | |||||||
| ln -fs $BINSP/hyperion-framebuffer $BINTP/hyperion-framebuffer 2>/dev/null | ln -fs $BINSP/hyperion-framebuffer $BINTP/hyperion-framebuffer 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | ||||||
|  | ln -fs $BINSP/hyperion-xcb $BINTP/hyperion-xcb 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-qt $BINTP/hyperion-qt 2>/dev/null | ln -fs $BINSP/hyperion-qt $BINTP/hyperion-qt 2>/dev/null | ||||||
|  |  | ||||||
|   | |||||||
| @@ -135,6 +135,9 @@ endif() | |||||||
| if(ENABLE_X11) | if(ENABLE_X11) | ||||||
| 	SET ( CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_x11" ) | 	SET ( CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_x11" ) | ||||||
| endif() | endif() | ||||||
|  | if(ENABLE_XCB) | ||||||
|  | 	SET ( CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_xcb" ) | ||||||
|  | endif() | ||||||
| if(ENABLE_DISPMANX) | if(ENABLE_DISPMANX) | ||||||
| 	SET ( CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_dispmanx" ) | 	SET ( CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_dispmanx" ) | ||||||
| endif() | endif() | ||||||
| @@ -211,6 +214,15 @@ if(ENABLE_X11) | |||||||
| 		DEPENDS Hyperion | 		DEPENDS Hyperion | ||||||
| 	) | 	) | ||||||
| endif() | endif() | ||||||
|  | if(ENABLE_X11) | ||||||
|  | 	cpack_add_component(hyperion_xcb | ||||||
|  | 		DISPLAY_NAME "XCB Standalone Screencap" | ||||||
|  | 		DESCRIPTION "XCB based standalone screen capture" | ||||||
|  | 		INSTALL_TYPES Full | ||||||
|  | 		GROUP Screencapture | ||||||
|  | 		DEPENDS Hyperion | ||||||
|  | 	) | ||||||
|  | endif() | ||||||
| if(ENABLE_DISPMANX) | if(ENABLE_DISPMANX) | ||||||
| 	cpack_add_component(hyperion_dispmanx | 	cpack_add_component(hyperion_dispmanx | ||||||
| 		DISPLAY_NAME "RPi dispmanx Standalone Screencap" | 		DISPLAY_NAME "RPi dispmanx Standalone Screencap" | ||||||
|   | |||||||
| @@ -88,6 +88,7 @@ ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2 | |||||||
| ln -fs $BINSP/hyperion-framebuffer $BINTP/hyperion-framebuffer 2>/dev/null | ln -fs $BINSP/hyperion-framebuffer $BINTP/hyperion-framebuffer 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null | ||||||
|  | ln -fs $BINSP/hyperion-xcb $BINTP/hyperion-xcb 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null | ||||||
| ln -fs $BINSP/hyperion-qt $BINTP/hyperion-qt 2>/dev/null | ln -fs $BINSP/hyperion-qt $BINTP/hyperion-qt 2>/dev/null | ||||||
|  |  | ||||||
|   | |||||||
| @@ -142,7 +142,7 @@ | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	///  The configuration for the frame-grabber, contains the following items: | 	///  The configuration for the frame-grabber, contains the following items: | ||||||
| 	///   * type         : type of grabber. (auto|osx|dispmanx|amlogic|x11|framebuffer|qt) [auto] | 	///   * type         : type of grabber. (auto|osx|dispmanx|amlogic|x11|xcb|framebuffer|qt) [auto] | ||||||
| 	///   * width        : The width of the grabbed frames [pixels] | 	///   * width        : The width of the grabbed frames [pixels] | ||||||
| 	///   * height       : The height of the grabbed frames [pixels] | 	///   * height       : The height of the grabbed frames [pixels] | ||||||
| 	///   * frequency_Hz : The frequency of the frame grab [Hz] | 	///   * frequency_Hz : The frequency of the frame grab [Hz] | ||||||
| @@ -161,7 +161,7 @@ | |||||||
| 		"width"        : 96, | 		"width"        : 96, | ||||||
| 		"height"       : 96, | 		"height"       : 96, | ||||||
|  |  | ||||||
| 		// valid for x11|qt | 		// valid for x11|xcb|qt | ||||||
| 		"pixelDecimation"           : 8, | 		"pixelDecimation"           : 8, | ||||||
|  |  | ||||||
| 		// valid for qt | 		// valid for qt | ||||||
|   | |||||||
							
								
								
									
										71
									
								
								include/grabber/XcbGrabber.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								include/grabber/XcbGrabber.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <QAbstractNativeEventFilter> | ||||||
|  | #include <QObject> | ||||||
|  |  | ||||||
|  | #include <utils/ColorRgb.h> | ||||||
|  | #include <hyperion/Grabber.h> | ||||||
|  |  | ||||||
|  | #include <sys/ipc.h> | ||||||
|  | #include <sys/shm.h> | ||||||
|  |  | ||||||
|  | #include <xcb/randr.h> | ||||||
|  | #include <xcb/shm.h> | ||||||
|  | #include <xcb/xcb.h> | ||||||
|  | #include <xcb/xcb_image.h> | ||||||
|  |  | ||||||
|  | class Logger; | ||||||
|  |  | ||||||
|  | class XcbGrabber : public Grabber, public QAbstractNativeEventFilter | ||||||
|  | { | ||||||
|  | 	Q_OBJECT | ||||||
|  |  | ||||||
|  | public: | ||||||
|  | 	XcbGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation); | ||||||
|  | 	~XcbGrabber() override; | ||||||
|  |  | ||||||
|  | 	bool Setup(); | ||||||
|  | 	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; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override; | ||||||
|  | 	void freeResources(); | ||||||
|  | 	void setupResources(); | ||||||
|  | 	void setupRender(); | ||||||
|  | 	void setupRandr(); | ||||||
|  | 	void setupShm(); | ||||||
|  | 	xcb_screen_t * getScreen(const xcb_setup_t *setup, int screen_num) const; | ||||||
|  | 	xcb_render_pictformat_t findFormatForVisual(xcb_visualid_t visual) const; | ||||||
|  |  | ||||||
|  | 	xcb_connection_t * _connection; | ||||||
|  | 	xcb_screen_t * _screen; | ||||||
|  | 	xcb_pixmap_t _pixmap; | ||||||
|  | 	xcb_render_pictformat_t _srcFormat; | ||||||
|  | 	xcb_render_pictformat_t _dstFormat; | ||||||
|  | 	xcb_render_picture_t _srcPicture; | ||||||
|  | 	xcb_render_picture_t _dstPicture; | ||||||
|  | 	xcb_render_transform_t _transform; | ||||||
|  | 	xcb_shm_seg_t  _shminfo; | ||||||
|  |  | ||||||
|  | 	int _pixelDecimation; | ||||||
|  |  | ||||||
|  | 	unsigned _screenWidth; | ||||||
|  | 	unsigned _screenHeight; | ||||||
|  | 	unsigned _src_x; | ||||||
|  | 	unsigned _src_y; | ||||||
|  |  | ||||||
|  | 	bool _XcbRenderAvailable; | ||||||
|  | 	bool _XcbRandRAvailable; | ||||||
|  | 	bool _XcbShmAvailable; | ||||||
|  | 	bool _XcbShmPixmapAvailable; | ||||||
|  | 	Logger * _logger; | ||||||
|  |  | ||||||
|  | 	uint8_t * _shmData; | ||||||
|  |  | ||||||
|  | 	int _XcbRandREventBase; | ||||||
|  | }; | ||||||
							
								
								
									
										24
									
								
								include/grabber/XcbWrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								include/grabber/XcbWrapper.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <hyperion/GrabberWrapper.h> | ||||||
|  | #include <grabber/XcbGrabber.h> | ||||||
|  |  | ||||||
|  | // some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions | ||||||
|  | #ifdef None | ||||||
|  | 	#undef None | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | class XcbWrapper: public GrabberWrapper | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	XcbWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz); | ||||||
|  | 	~XcbWrapper() override; | ||||||
|  |  | ||||||
|  | public slots: | ||||||
|  | 	virtual void action(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	XcbGrabber _grabber; | ||||||
|  |  | ||||||
|  | 	bool _init; | ||||||
|  | }; | ||||||
| @@ -54,7 +54,7 @@ public: | |||||||
| 	virtual bool setFramerate(int fps); | 	virtual bool setFramerate(int fps); | ||||||
|  |  | ||||||
| 	/// | 	/// | ||||||
| 	/// @brief Apply new pixelDecimation (used from x11 and qt) | 	/// @brief Apply new pixelDecimation (used from x11, xcb and qt) | ||||||
| 	/// | 	/// | ||||||
| 	virtual void setPixelDecimation(int pixelDecimation) {} | 	virtual void setPixelDecimation(int pixelDecimation) {} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -480,7 +480,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString | |||||||
| 	QJsonObject grabbers; | 	QJsonObject grabbers; | ||||||
| 	QJsonArray availableGrabbers; | 	QJsonArray availableGrabbers; | ||||||
|  |  | ||||||
| #if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11) || defined(ENABLE_QT) | #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) | ||||||
|  |  | ||||||
| 	// get available grabbers | 	// get available grabbers | ||||||
| 	//grabbers["active"] = ????; | 	//grabbers["active"] = ????; | ||||||
|   | |||||||
| @@ -22,6 +22,10 @@ if (ENABLE_X11) | |||||||
| 	add_subdirectory(x11) | 	add_subdirectory(x11) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | if (ENABLE_XCB) | ||||||
|  | 	add_subdirectory(xcb) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if (ENABLE_QT) | if (ENABLE_QT) | ||||||
| 	add_subdirectory(qt) | 	add_subdirectory(qt) | ||||||
| endif() | endif() | ||||||
|   | |||||||
| @@ -72,8 +72,13 @@ void X11Grabber::setupResources() | |||||||
| 		_shminfo.readOnly = False; | 		_shminfo.readOnly = False; | ||||||
| 		XShmAttach(_x11Display, &_shminfo); | 		XShmAttach(_x11Display, &_shminfo); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (_XRenderAvailable) | 	if (_XRenderAvailable) | ||||||
| 	{ | 	{ | ||||||
|  |         	_useImageResampler = false; | ||||||
|  | 		_imageResampler.setHorizontalPixelDecimation(1); | ||||||
|  | 		_imageResampler.setVerticalPixelDecimation(1); | ||||||
|  |  | ||||||
| 		if(_XShmPixmapAvailable) | 		if(_XShmPixmapAvailable) | ||||||
| 		{ | 		{ | ||||||
| 			_pixmap = XShmCreatePixmap(_x11Display, _window, _xImage->data, &_shminfo, _width, _height, _windowAttr.depth); | 			_pixmap = XShmCreatePixmap(_x11Display, _window, _xImage->data, &_shminfo, _width, _height, _windowAttr.depth); | ||||||
| @@ -86,8 +91,16 @@ void X11Grabber::setupResources() | |||||||
| 		_dstFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); | 		_dstFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); | ||||||
| 		_srcPicture = XRenderCreatePicture(_x11Display, _window, _srcFormat, CPRepeat, &_pictAttr); | 		_srcPicture = XRenderCreatePicture(_x11Display, _window, _srcFormat, CPRepeat, &_pictAttr); | ||||||
| 		_dstPicture = XRenderCreatePicture(_x11Display, _pixmap, _dstFormat, CPRepeat, &_pictAttr); | 		_dstPicture = XRenderCreatePicture(_x11Display, _pixmap, _dstFormat, CPRepeat, &_pictAttr); | ||||||
|  |  | ||||||
| 		XRenderSetPictureFilter(_x11Display, _srcPicture, FilterBilinear, NULL, 0); | 		XRenderSetPictureFilter(_x11Display, _srcPicture, FilterBilinear, NULL, 0); | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  |         	_useImageResampler = true; | ||||||
|  | 		_imageResampler.setHorizontalPixelDecimation(_pixelDecimation); | ||||||
|  | 		_imageResampler.setVerticalPixelDecimation(_pixelDecimation); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool X11Grabber::Setup() | bool X11Grabber::Setup() | ||||||
| @@ -117,10 +130,6 @@ bool X11Grabber::Setup() | |||||||
| 	XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported); | 	XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported); | ||||||
| 	_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap; | 	_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap; | ||||||
|  |  | ||||||
| 	// Image scaling is performed by XRender when available, otherwise by ImageResampler |  | ||||||
| 	_imageResampler.setHorizontalPixelDecimation(_XRenderAvailable ? 1 : _pixelDecimation); |  | ||||||
| 	_imageResampler.setVerticalPixelDecimation(_XRenderAvailable ? 1 : _pixelDecimation); |  | ||||||
|  |  | ||||||
| 	bool result = (updateScreenDimensions(true) >=0); | 	bool result = (updateScreenDimensions(true) >=0); | ||||||
| 	ErrorIf(!result, _log, "X11 Grabber start failed"); | 	ErrorIf(!result, _log, "X11 Grabber start failed"); | ||||||
| 	setEnabled(result); | 	setEnabled(result); | ||||||
|   | |||||||
| @@ -23,13 +23,17 @@ void X11Wrapper::action() | |||||||
| 		{ | 		{ | ||||||
| 			stop(); | 			stop(); | ||||||
| 		} | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (_grabber.updateScreenDimensions() < 0 ) | ||||||
|  | 			{ | ||||||
|  | 				stop(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (isActive()) | 	if (isActive()) | ||||||
| 	{ | 	{ | ||||||
| 		if (_grabber.updateScreenDimensions() >= 0 ) | 		transferFrame(_grabber); | ||||||
| 		{ |  | ||||||
| 			transferFrame(_grabber); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								libsrc/grabber/xcb/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libsrc/grabber/xcb/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | # Define the current source locations | ||||||
|  | SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) | ||||||
|  | SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb) | ||||||
|  |  | ||||||
|  | find_package(XCB COMPONENTS SHM IMAGE RENDER RANDR REQUIRED) | ||||||
|  | find_package(Qt5Widgets REQUIRED) | ||||||
|  | find_package(Qt5X11Extras REQUIRED) | ||||||
|  |  | ||||||
|  | include_directories(${XCB_INCLUDE_DIRS}) | ||||||
|  |  | ||||||
|  | FILE (GLOB XCB_SOURCES "${CURRENT_HEADER_DIR}/Xcb*.h"  "${CURRENT_SOURCE_DIR}/*.h"  "${CURRENT_SOURCE_DIR}/*.cpp" ) | ||||||
|  |  | ||||||
|  | add_library(xcb-grabber ${XCB_SOURCES}) | ||||||
|  |  | ||||||
|  | target_link_libraries(xcb-grabber | ||||||
|  | 	hyperion | ||||||
|  | 	Qt5::X11Extras | ||||||
|  | 	Qt5::Widgets | ||||||
|  | 	${XCB_LIBRARIES} | ||||||
|  | ) | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								libsrc/grabber/xcb/XcbCommandExecutor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libsrc/grabber/xcb/XcbCommandExecutor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
|  | #include <xcb/xcb.h> | ||||||
|  |  | ||||||
|  | template<class Request, class ...Args> | ||||||
|  | 	std::unique_ptr<typename Request::ResponseType, decltype(&free)> | ||||||
|  | 		query(xcb_connection_t * connection, Args&& ...args) | ||||||
|  | { | ||||||
|  | 	auto cookie = Request::RequestFunction(connection,args...); | ||||||
|  |  | ||||||
|  | 	xcb_generic_error_t * error = nullptr; | ||||||
|  | 	std::unique_ptr<typename Request::ResponseType, decltype(&free)> xcbResponse( | ||||||
|  | 		Request::ReplyFunction(connection, cookie, &error), free); | ||||||
|  |  | ||||||
|  | 	if (error) { | ||||||
|  | 		Logger * LOGGER = Logger::getInstance("XCB"); | ||||||
|  | 		Error(LOGGER, | ||||||
|  | 			"Cannot get the image data event_error: response_type:%u error_code:%u " | ||||||
|  | 			"sequence:%u resource_id:%u minor_code:%u major_code:%u.\n", | ||||||
|  | 			error->response_type, error->error_code, error->sequence, | ||||||
|  | 			error->resource_id, error->minor_code, error->major_code); | ||||||
|  |  | ||||||
|  | 		free(error); | ||||||
|  | 		return {nullptr, nullptr}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return xcbResponse; | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								libsrc/grabber/xcb/XcbCommands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								libsrc/grabber/xcb/XcbCommands.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <xcb/randr.h> | ||||||
|  | #include <xcb/shm.h> | ||||||
|  | #include <xcb/xcb.h> | ||||||
|  | #include <xcb/xcb_image.h> | ||||||
|  |  | ||||||
|  | struct GetImage | ||||||
|  | { | ||||||
|  | 	typedef xcb_get_image_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_get_image; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_get_image_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct GetGeometry | ||||||
|  | { | ||||||
|  | 	typedef xcb_get_geometry_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_get_geometry; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_get_geometry_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ShmQueryVersion | ||||||
|  | { | ||||||
|  | 	typedef xcb_shm_query_version_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_shm_query_version; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_shm_query_version_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct RenderQueryVersion | ||||||
|  | { | ||||||
|  | 	typedef xcb_render_query_version_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_render_query_version; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_render_query_version_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ShmGetImage | ||||||
|  | { | ||||||
|  | 	typedef xcb_shm_get_image_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_shm_get_image; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_shm_get_image_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct RenderQueryPictFormats | ||||||
|  | { | ||||||
|  | 	typedef xcb_render_query_pict_formats_reply_t ResponseType; | ||||||
|  |  | ||||||
|  | 	static constexpr auto RequestFunction = xcb_render_query_pict_formats; | ||||||
|  | 	static constexpr auto ReplyFunction = xcb_render_query_pict_formats_reply; | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										452
									
								
								libsrc/grabber/xcb/XcbGrabber.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								libsrc/grabber/xcb/XcbGrabber.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,452 @@ | |||||||
|  | #include <utils/Logger.h> | ||||||
|  | #include <grabber/XcbGrabber.h> | ||||||
|  |  | ||||||
|  | #include "XcbCommands.h" | ||||||
|  | #include "XcbCommandExecutor.h" | ||||||
|  |  | ||||||
|  | #include <xcb/xcb_event.h> | ||||||
|  |  | ||||||
|  | #include <QCoreApplication> | ||||||
|  | #include <QX11Info> | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
|  | #define DOUBLE_TO_FIXED(d) ((xcb_render_fixed_t) ((d) * 65536)) | ||||||
|  |  | ||||||
|  | XcbGrabber::XcbGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation) | ||||||
|  | 	: Grabber("XCBGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom) | ||||||
|  | 	, _connection{} | ||||||
|  | 	, _screen{} | ||||||
|  | 	, _pixmap{} | ||||||
|  | 	, _srcFormat{} | ||||||
|  | 	, _dstFormat{} | ||||||
|  | 	, _srcPicture{} | ||||||
|  | 	, _dstPicture{} | ||||||
|  | 	, _transform{} | ||||||
|  | 	, _shminfo{} | ||||||
|  | 	, _pixelDecimation(pixelDecimation) | ||||||
|  | 	, _screenWidth{} | ||||||
|  | 	, _screenHeight{} | ||||||
|  | 	, _src_x(cropLeft) | ||||||
|  | 	, _src_y(cropTop) | ||||||
|  | 	, _XcbRenderAvailable{} | ||||||
|  | 	, _XcbRandRAvailable{} | ||||||
|  | 	, _XcbShmAvailable{} | ||||||
|  | 	, _XcbShmPixmapAvailable{} | ||||||
|  | 	, _logger{} | ||||||
|  | 	, _shmData{} | ||||||
|  | 	, _XcbRandREventBase{-1} | ||||||
|  | { | ||||||
|  | 	_logger = Logger::getInstance("XCB"); | ||||||
|  |  | ||||||
|  | 	// cropping is performed by XcbRender, XcbShmGetImage or XcbGetImage | ||||||
|  | 	_useImageResampler = false; | ||||||
|  | 	_imageResampler.setCropping(0, 0, 0, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | XcbGrabber::~XcbGrabber() | ||||||
|  | { | ||||||
|  | 	if (_connection != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		freeResources(); | ||||||
|  | 		xcb_disconnect(_connection); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::freeResources() | ||||||
|  | { | ||||||
|  | 	if (_XcbRandRAvailable) | ||||||
|  | 	{ | ||||||
|  | 		qApp->removeNativeEventFilter(this); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if(_XcbShmAvailable) | ||||||
|  | 	{ | ||||||
|  | 		xcb_shm_detach(_connection, _shminfo); | ||||||
|  | 		shmdt(_shmData); | ||||||
|  | 		shmctl(_shminfo, IPC_RMID, 0); | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (_XcbRenderAvailable) | ||||||
|  | 	{ | ||||||
|  | 		xcb_free_pixmap(_connection, _pixmap); | ||||||
|  | 		xcb_render_free_picture(_connection, _srcPicture); | ||||||
|  | 		xcb_render_free_picture(_connection, _dstPicture); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setupResources() | ||||||
|  | { | ||||||
|  | 	if (_XcbRandRAvailable) | ||||||
|  | 	{ | ||||||
|  | 		qApp->installNativeEventFilter(this); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if(_XcbShmAvailable) | ||||||
|  | 	{ | ||||||
|  | 		_shminfo = xcb_generate_id(_connection); | ||||||
|  | 		int id = shmget(IPC_PRIVATE, _width * _height * 4, IPC_CREAT | 0777); | ||||||
|  | 		_shmData = static_cast<uint8_t*>(shmat(id, nullptr, 0)); | ||||||
|  | 		xcb_shm_attach(_connection, _shminfo, id, 0); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (_XcbRenderAvailable) | ||||||
|  | 	{ | ||||||
|  | 		_useImageResampler = false; | ||||||
|  | 		_imageResampler.setHorizontalPixelDecimation(1); | ||||||
|  | 		_imageResampler.setVerticalPixelDecimation(1); | ||||||
|  |  | ||||||
|  | 		if(_XcbShmPixmapAvailable) | ||||||
|  | 		{ | ||||||
|  | 			_pixmap = xcb_generate_id(_connection); | ||||||
|  | 			xcb_shm_create_pixmap( | ||||||
|  | 				_connection, _pixmap, _screen->root, _width, | ||||||
|  | 				_height, _screen->root_depth, _shminfo, 0); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			_pixmap = xcb_generate_id(_connection); | ||||||
|  | 			xcb_create_pixmap(_connection, _screen->root_depth, _pixmap, _screen->root, _width, _height); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		_srcFormat = findFormatForVisual(_screen->root_visual); | ||||||
|  | 		_dstFormat = findFormatForVisual(_screen->root_visual); | ||||||
|  |  | ||||||
|  | 		_srcPicture = xcb_generate_id(_connection); | ||||||
|  | 		_dstPicture = xcb_generate_id(_connection); | ||||||
|  |  | ||||||
|  | 		const uint32_t value_mask = XCB_RENDER_CP_REPEAT; | ||||||
|  | 		const uint32_t values[] = { XCB_RENDER_REPEAT_NONE }; | ||||||
|  |  | ||||||
|  | 		xcb_render_create_picture(_connection, _srcPicture, _screen->root, _srcFormat, value_mask, values); | ||||||
|  | 		xcb_render_create_picture(_connection, _dstPicture, _pixmap, _dstFormat, value_mask, values); | ||||||
|  |  | ||||||
|  | 		const std::string filter = "fast"; | ||||||
|  | 		xcb_render_set_picture_filter(_connection, _srcPicture, filter.size(), filter.c_str(), 0, nullptr); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		_useImageResampler = true; | ||||||
|  | 		_imageResampler.setHorizontalPixelDecimation(_pixelDecimation); | ||||||
|  | 		_imageResampler.setVerticalPixelDecimation(_pixelDecimation); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xcb_screen_t * XcbGrabber::getScreen(const xcb_setup_t *setup, int screen_num) const | ||||||
|  | { | ||||||
|  | 	xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup); | ||||||
|  | 	xcb_screen_t * screen    = nullptr; | ||||||
|  |  | ||||||
|  | 	for (; it.rem > 0; xcb_screen_next(&it)) | ||||||
|  | 	{ | ||||||
|  | 		if (!screen_num) | ||||||
|  | 		{ | ||||||
|  | 			screen = it.data; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		screen_num--; | ||||||
|  | 	} | ||||||
|  | 	return screen; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setupRandr() | ||||||
|  | { | ||||||
|  | 	auto randrQueryExtensionReply = xcb_get_extension_data(_connection, &xcb_randr_id); | ||||||
|  | 	_XcbRandRAvailable = randrQueryExtensionReply != nullptr; | ||||||
|  | 	_XcbRandREventBase = randrQueryExtensionReply ? randrQueryExtensionReply->first_event : -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setupRender() | ||||||
|  | { | ||||||
|  | 	auto renderQueryVersionReply = query<RenderQueryVersion>(_connection, 0, 0); | ||||||
|  |  | ||||||
|  | 	_XcbRenderAvailable = renderQueryVersionReply != nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setupShm() | ||||||
|  | { | ||||||
|  | 	auto shmQueryExtensionReply = xcb_get_extension_data(_connection, &xcb_render_id); | ||||||
|  | 	_XcbShmAvailable = shmQueryExtensionReply != nullptr; | ||||||
|  |  | ||||||
|  | 	_XcbShmPixmapAvailable = false; | ||||||
|  | 	if (_XcbShmAvailable) | ||||||
|  | 	{ | ||||||
|  | 		auto shmQueryVersionReply = query<ShmQueryVersion>(_connection); | ||||||
|  |  | ||||||
|  | 		_XcbShmPixmapAvailable = shmQueryVersionReply ? shmQueryVersionReply->shared_pixmaps : false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool XcbGrabber::Setup() | ||||||
|  | { | ||||||
|  | 	int screen_num; | ||||||
|  | 	_connection = xcb_connect(nullptr, &screen_num); | ||||||
|  |  | ||||||
|  | 	int ret = xcb_connection_has_error(_connection); | ||||||
|  | 	if (ret != 0) | ||||||
|  | 	{ | ||||||
|  | 		Error(_logger, "Cannot open display, error %d", ret); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const xcb_setup_t * setup = xcb_get_setup(_connection); | ||||||
|  | 	_screen = getScreen(setup, screen_num); | ||||||
|  |  | ||||||
|  | 	if (!_screen) | ||||||
|  | 	{ | ||||||
|  | 		Error(_log, "Unable to open display, screen %d does not exist", screen_num); | ||||||
|  |  | ||||||
|  | 		if (getenv("DISPLAY")) | ||||||
|  | 			Error(_log, "%s", getenv("DISPLAY")); | ||||||
|  | 		else | ||||||
|  | 			Error(_log, "DISPLAY environment variable not set"); | ||||||
|  |  | ||||||
|  | 		freeResources(); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	setupRandr(); | ||||||
|  | 	setupRender(); | ||||||
|  | 	setupShm(); | ||||||
|  |  | ||||||
|  | 	Info(_log, "XcbRandR : %s", _XcbRandRAvailable ? "available" : "unavailable"); | ||||||
|  | 	Info(_log, "XcbRender : %s", _XcbRenderAvailable ? "available" : "unavailable"); | ||||||
|  | 	Info(_log, "XcbShm : %s", _XcbShmAvailable ? "available" : "unavailable"); | ||||||
|  | 	Info(_log, "XcbPixmap : %s", _XcbShmPixmapAvailable ? "available" : "unavailable"); | ||||||
|  |  | ||||||
|  | 	bool result = (updateScreenDimensions(true) >=0); | ||||||
|  | 	ErrorIf(!result, _log, "XCB Grabber start failed"); | ||||||
|  | 	setEnabled(result); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int XcbGrabber::grabFrame(Image<ColorRgb> & image, bool forceUpdate) | ||||||
|  | { | ||||||
|  | 	if (!_enabled) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	if (forceUpdate) | ||||||
|  | 		updateScreenDimensions(forceUpdate); | ||||||
|  |  | ||||||
|  | 	if (_XcbRenderAvailable) | ||||||
|  | 	{ | ||||||
|  | 		double scale_x = static_cast<double>(_screenWidth / _pixelDecimation) / static_cast<double>(_screenWidth); | ||||||
|  | 		double scale_y = static_cast<double>(_screenHeight / _pixelDecimation) / static_cast<double>(_screenHeight); | ||||||
|  | 		double scale = qMin(scale_y, scale_x); | ||||||
|  |  | ||||||
|  | 		_transform = { | ||||||
|  | 			DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), | ||||||
|  | 			DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(1), DOUBLE_TO_FIXED(0), | ||||||
|  | 			DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(0), DOUBLE_TO_FIXED(scale) | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		xcb_render_set_picture_transform(_connection, _srcPicture, _transform); | ||||||
|  | 		xcb_render_composite(_connection, | ||||||
|  | 			XCB_RENDER_PICT_OP_SRC, _srcPicture, | ||||||
|  | 			XCB_RENDER_PICTURE_NONE, _dstPicture, | ||||||
|  | 			(_src_x/_pixelDecimation), | ||||||
|  | 			(_src_y/_pixelDecimation), | ||||||
|  | 			0, 0, 0, 0, _width, _height); | ||||||
|  |  | ||||||
|  | 		xcb_flush(_connection); | ||||||
|  |  | ||||||
|  | 		if (_XcbShmAvailable) | ||||||
|  | 		{ | ||||||
|  | 			query<ShmGetImage>(_connection, | ||||||
|  | 				_pixmap, 0, 0, _width, _height, | ||||||
|  | 				~0, XCB_IMAGE_FORMAT_Z_PIXMAP, _shminfo, 0); | ||||||
|  |  | ||||||
|  | 			_imageResampler.processImage( | ||||||
|  | 				reinterpret_cast<const uint8_t *>(_shmData), | ||||||
|  | 				_width, _height, _width * 4, PixelFormat::BGR32, image); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			auto result = query<GetImage>(_connection, | ||||||
|  | 				XCB_IMAGE_FORMAT_Z_PIXMAP, _pixmap, | ||||||
|  | 				0, 0, _width, _height, ~0); | ||||||
|  |  | ||||||
|  | 			auto buffer = xcb_get_image_data(result.get()); | ||||||
|  |  | ||||||
|  | 			_imageResampler.processImage( | ||||||
|  | 				reinterpret_cast<const uint8_t *>(buffer), | ||||||
|  | 				_width, _height, _width * 4, PixelFormat::BGR32, image); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | 	else if (_XcbShmAvailable) | ||||||
|  | 	{ | ||||||
|  | 		query<ShmGetImage>(_connection, | ||||||
|  | 			_screen->root, _src_x, _src_y, _width, _height, | ||||||
|  | 			~0, XCB_IMAGE_FORMAT_Z_PIXMAP, _shminfo, 0); | ||||||
|  |  | ||||||
|  | 		_imageResampler.processImage( | ||||||
|  | 			reinterpret_cast<const uint8_t *>(_shmData), | ||||||
|  | 			_width, _height, _width * 4, PixelFormat::BGR32, image); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		auto result = query<GetImage>(_connection, | ||||||
|  | 			XCB_IMAGE_FORMAT_Z_PIXMAP, _screen->root, | ||||||
|  | 			_src_x, _src_y, _width, _height, ~0); | ||||||
|  |  | ||||||
|  | 		auto buffer = xcb_get_image_data(result.get()); | ||||||
|  |  | ||||||
|  | 		_imageResampler.processImage( | ||||||
|  | 			reinterpret_cast<const uint8_t *>(buffer), | ||||||
|  | 			_width, _height, _width * 4, PixelFormat::BGR32, image); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int XcbGrabber::updateScreenDimensions(bool force) | ||||||
|  | { | ||||||
|  | 	auto geometry = query<GetGeometry>(_connection, _screen->root); | ||||||
|  | 	if (geometry == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		setEnabled(false); | ||||||
|  | 		Error(_log, "Failed to obtain screen geometry"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!_enabled) | ||||||
|  | 		setEnabled(true); | ||||||
|  |  | ||||||
|  | 	if (!force && _screenWidth == unsigned(geometry->width) && | ||||||
|  | 		_screenHeight == unsigned(geometry->height)) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	if (_screenWidth || _screenHeight) | ||||||
|  | 		freeResources(); | ||||||
|  |  | ||||||
|  | 	Info(_log, "Update of screen resolution: [%dx%d]  to [%dx%d]", _screenWidth, _screenHeight, geometry->width, geometry->height); | ||||||
|  |  | ||||||
|  | 	_screenWidth  = geometry->width; | ||||||
|  | 	_screenHeight = geometry->height; | ||||||
|  |  | ||||||
|  | 	int width = 0, height = 0; | ||||||
|  |  | ||||||
|  | 	// Image scaling is performed by XRender when available, otherwise by ImageResampler | ||||||
|  | 	if (_XcbRenderAvailable) | ||||||
|  | 	{ | ||||||
|  | 		width  =  (_screenWidth > unsigned(_cropLeft + _cropRight)) | ||||||
|  | 			? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation) | ||||||
|  | 			: _screenWidth / _pixelDecimation; | ||||||
|  |  | ||||||
|  | 		height =  (_screenHeight > unsigned(_cropTop + _cropBottom)) | ||||||
|  | 			? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation) | ||||||
|  | 			: _screenHeight / _pixelDecimation; | ||||||
|  |  | ||||||
|  | 		Info(_log, "Using XcbRender for grabbing [%dx%d]", width, height); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		width  =  (_screenWidth > unsigned(_cropLeft + _cropRight)) | ||||||
|  | 			? (_screenWidth - _cropLeft - _cropRight) | ||||||
|  | 			: _screenWidth; | ||||||
|  |  | ||||||
|  | 		height =  (_screenHeight > unsigned(_cropTop + _cropBottom)) | ||||||
|  | 			? (_screenHeight - _cropTop - _cropBottom) | ||||||
|  | 			: _screenHeight; | ||||||
|  |  | ||||||
|  | 		Info(_log, "Using XcbGetImage for grabbing [%dx%d]", width, height); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Calculate final image dimensions and adjust top/left cropping in 3D modes | ||||||
|  | 	switch (_videoMode) | ||||||
|  | 	{ | ||||||
|  | 	case VideoMode::VIDEO_3DSBS: | ||||||
|  | 		_width  = width /2; | ||||||
|  | 		_height = height; | ||||||
|  | 		_src_x  = _cropLeft / 2; | ||||||
|  | 		_src_y  = _cropTop; | ||||||
|  | 		break; | ||||||
|  | 	case VideoMode::VIDEO_3DTAB: | ||||||
|  | 		_width  = width; | ||||||
|  | 		_height = height / 2; | ||||||
|  | 		_src_x  = _cropLeft; | ||||||
|  | 		_src_y  = _cropTop / 2; | ||||||
|  | 		break; | ||||||
|  | 	case VideoMode::VIDEO_2D: | ||||||
|  | 	default: | ||||||
|  | 		_width  = width; | ||||||
|  | 		_height = height; | ||||||
|  | 		_src_x  = _cropLeft; | ||||||
|  | 		_src_y  = _cropTop; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	setupResources(); | ||||||
|  |  | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setVideoMode(VideoMode mode) | ||||||
|  | { | ||||||
|  | 	Grabber::setVideoMode(mode); | ||||||
|  | 	updateScreenDimensions(true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setPixelDecimation(int pixelDecimation) | ||||||
|  | { | ||||||
|  | 	if(_pixelDecimation != pixelDecimation) | ||||||
|  | 	{ | ||||||
|  | 		_pixelDecimation = pixelDecimation; | ||||||
|  | 		updateScreenDimensions(true); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) | ||||||
|  | { | ||||||
|  | 	Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom); | ||||||
|  | 	if(_connection != nullptr) | ||||||
|  | 		updateScreenDimensions(true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool XcbGrabber::nativeEventFilter(const QByteArray & eventType, void * message, long int * /*result*/) | ||||||
|  | { | ||||||
|  | 	if (!_XcbRandRAvailable || eventType != "xcb_generic_event_t" || _XcbRandREventBase == -1) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	xcb_generic_event_t *e = static_cast<xcb_generic_event_t*>(message); | ||||||
|  | 	const uint8_t xEventType = XCB_EVENT_RESPONSE_TYPE(e); | ||||||
|  |  | ||||||
|  | 	if (xEventType == _XcbRandREventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY) | ||||||
|  | 		updateScreenDimensions(true); | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xcb_render_pictformat_t XcbGrabber::findFormatForVisual(xcb_visualid_t visual) const | ||||||
|  | { | ||||||
|  | 	auto formats = query<RenderQueryPictFormats>(_connection); | ||||||
|  | 	if (formats == nullptr) | ||||||
|  | 		return {}; | ||||||
|  |  | ||||||
|  | 	int screen = QX11Info::appScreen(); | ||||||
|  | 	xcb_render_pictscreen_iterator_t sit = | ||||||
|  | 		xcb_render_query_pict_formats_screens_iterator(formats.get()); | ||||||
|  |  | ||||||
|  | 	for (; sit.rem; --screen, xcb_render_pictscreen_next(&sit)) { | ||||||
|  | 		if (screen != 0) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		xcb_render_pictdepth_iterator_t dit = | ||||||
|  | 			xcb_render_pictscreen_depths_iterator(sit.data); | ||||||
|  | 		for (; dit.rem; xcb_render_pictdepth_next(&dit)) | ||||||
|  | 		{ | ||||||
|  | 			xcb_render_pictvisual_iterator_t vit | ||||||
|  | 				= xcb_render_pictdepth_visuals_iterator(dit.data); | ||||||
|  | 			for (; vit.rem; xcb_render_pictvisual_next(&vit)) | ||||||
|  | 			{ | ||||||
|  | 				if (vit.data->visual == visual) | ||||||
|  | 				{ | ||||||
|  | 					return vit.data->format; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return {}; | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								libsrc/grabber/xcb/XcbWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								libsrc/grabber/xcb/XcbWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | #include <grabber/XcbWrapper.h> | ||||||
|  |  | ||||||
|  | XcbWrapper::XcbWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz) | ||||||
|  | 	: GrabberWrapper("Xcb", &_grabber, 0, 0, updateRate_Hz) | ||||||
|  | 	, _grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation) | ||||||
|  | 	, _init(false) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | XcbWrapper::~XcbWrapper() | ||||||
|  | { | ||||||
|  | 	if ( _init ) | ||||||
|  | 	{ | ||||||
|  | 		stop(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbWrapper::action() | ||||||
|  | { | ||||||
|  | 	if (! _init ) | ||||||
|  | 	{ | ||||||
|  | 		_init = true; | ||||||
|  | 		if ( ! _grabber.Setup() ) | ||||||
|  | 		{ | ||||||
|  | 			stop(); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (_grabber.updateScreenDimensions() < 0 ) | ||||||
|  | 			{ | ||||||
|  | 				stop(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (isActive()) | ||||||
|  | 	{ | ||||||
|  | 		transferFrame(_grabber); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -94,6 +94,10 @@ QStringList GrabberWrapper::availableGrabbers() | |||||||
| 	grabbers << "x11"; | 	grabbers << "x11"; | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
|  | 	#ifdef ENABLE_XCB | ||||||
|  | 	grabbers << "xcb"; | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
| 	#ifdef ENABLE_QT | 	#ifdef ENABLE_QT | ||||||
| 	grabbers << "qt"; | 	grabbers << "qt"; | ||||||
| 	#endif | 	#endif | ||||||
|   | |||||||
| @@ -7,10 +7,10 @@ | |||||||
| 		{ | 		{ | ||||||
| 			"type" : "string", | 			"type" : "string", | ||||||
| 			"title" : "edt_conf_fg_type_title", | 			"title" : "edt_conf_fg_type_title", | ||||||
| 			"enum"  : ["auto","dispmanx","amlogic","x11","framebuffer","qt"], | 			"enum"  : ["auto","dispmanx","amlogic","x11", "xcb", "framebuffer","qt"], | ||||||
| 			"options": | 			"options": | ||||||
| 			{ | 			{ | ||||||
| 				"enum_titles": ["edt_conf_enum_automatic","DispmanX","AMLogic","X11","Framebuffer","QT"] | 				"enum_titles": ["edt_conf_enum_automatic","DispmanX","AMLogic","X11", "XCB", "Framebuffer","QT"] | ||||||
| 			}, | 			}, | ||||||
| 			"default" : "auto", | 			"default" : "auto", | ||||||
| 			"propertyOrder" : 2 | 			"propertyOrder" : 2 | ||||||
|   | |||||||
| @@ -14,6 +14,10 @@ if(ENABLE_X11) | |||||||
| 	add_subdirectory(hyperion-x11) | 	add_subdirectory(hyperion-x11) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | if(ENABLE_XCB) | ||||||
|  | 	add_subdirectory(hyperion-xcb) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| if(ENABLE_DISPMANX) | if(ENABLE_DISPMANX) | ||||||
| 	add_subdirectory(hyperion-dispmanx) | 	add_subdirectory(hyperion-dispmanx) | ||||||
| endif() | endif() | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								src/hyperion-xcb/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/hyperion-xcb/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | cmake_minimum_required(VERSION 3.0.0) | ||||||
|  | project(hyperion-xcb) | ||||||
|  |  | ||||||
|  | include_directories( | ||||||
|  | 	${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver | ||||||
|  | 	${FLATBUFFERS_INCLUDE_DIRS} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | set(Hyperion_XCB_HEADERS | ||||||
|  | 	XcbWrapper.h | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | set(Hyperion_XCB_SOURCES | ||||||
|  | 	hyperion-xcb.cpp | ||||||
|  | 	XcbWrapper.cpp | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | add_executable(${PROJECT_NAME} | ||||||
|  | 	${Hyperion_XCB_HEADERS} | ||||||
|  | 	${Hyperion_XCB_SOURCES} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | target_link_libraries(${PROJECT_NAME} | ||||||
|  | 	commandline | ||||||
|  | 	hyperion-utils | ||||||
|  | 	flatbufserver | ||||||
|  | 	flatbuffers | ||||||
|  | 	xcb-grabber | ||||||
|  | 	ssdp | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_xcb") | ||||||
|  |  | ||||||
|  | if(CMAKE_HOST_UNIX) | ||||||
|  | 	install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_xcb" ) | ||||||
|  | 	install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_xcb" ) | ||||||
|  | 	install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_xcb" ) | ||||||
|  | endif(CMAKE_HOST_UNIX) | ||||||
							
								
								
									
										47
									
								
								src/hyperion-xcb/XcbWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/hyperion-xcb/XcbWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  |  | ||||||
|  | // Hyperion-Xcb includes | ||||||
|  | #include "XcbWrapper.h" | ||||||
|  |  | ||||||
|  | XcbWrapper::XcbWrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation) : | ||||||
|  | 	_timer(this), | ||||||
|  | 	_grabber(cropLeft, cropRight, cropTop, cropBottom, pixelDecimation) | ||||||
|  | { | ||||||
|  | 	_timer.setSingleShot(false); | ||||||
|  | 	_timer.setInterval(grabInterval); | ||||||
|  |  | ||||||
|  | 	// Connect capturing to the timeout signal of the timer | ||||||
|  | 	connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const Image<ColorRgb> & XcbWrapper::getScreenshot() | ||||||
|  | { | ||||||
|  | 	_grabber.grabFrame(_screenshot, true); | ||||||
|  | 	return _screenshot; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbWrapper::start() | ||||||
|  | { | ||||||
|  | 	_timer.start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbWrapper::stop() | ||||||
|  | { | ||||||
|  | 	_timer.stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool XcbWrapper::displayInit() | ||||||
|  | { | ||||||
|  | 	return _grabber.Setup(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbWrapper::capture() | ||||||
|  | { | ||||||
|  | 	_grabber.grabFrame(_screenshot, !_inited); | ||||||
|  | 	emit sig_screenshot(_screenshot); | ||||||
|  | 	_inited = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XcbWrapper::setVideoMode(const VideoMode mode) | ||||||
|  | { | ||||||
|  | 	_grabber.setVideoMode(mode); | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								src/hyperion-xcb/XcbWrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/hyperion-xcb/XcbWrapper.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // QT includes | ||||||
|  | #include <QTimer> | ||||||
|  |  | ||||||
|  | // Hyperion-Xcb includes | ||||||
|  | #include <grabber/XcbGrabber.h> | ||||||
|  |  | ||||||
|  | //Utils includes | ||||||
|  | #include <utils/VideoMode.h> | ||||||
|  |  | ||||||
|  | class XcbWrapper : public QObject | ||||||
|  | { | ||||||
|  | 	Q_OBJECT | ||||||
|  | public: | ||||||
|  | 	XcbWrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation); | ||||||
|  |  | ||||||
|  | 	const Image<ColorRgb> & getScreenshot(); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Starts the timed capturing of screenshots | ||||||
|  | 	/// | ||||||
|  | 	void start(); | ||||||
|  |  | ||||||
|  | 	void stop(); | ||||||
|  |  | ||||||
|  | 	bool displayInit(); | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  | 	void sig_screenshot(const Image<ColorRgb> & screenshot); | ||||||
|  |  | ||||||
|  | public slots: | ||||||
|  | 	/// | ||||||
|  | 	/// Set the video mode (2D/3D) | ||||||
|  | 	/// @param[in] mode The new video mode | ||||||
|  | 	/// | ||||||
|  | 	void setVideoMode(const VideoMode videoMode); | ||||||
|  |  | ||||||
|  | private slots: | ||||||
|  | 	/// | ||||||
|  | 	/// Performs a single screenshot capture and publishes the capture screenshot on the screenshot | ||||||
|  | 	/// signal. | ||||||
|  | 	/// | ||||||
|  | 	void capture(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	/// The QT timer to generate capture-publish events | ||||||
|  | 	QTimer _timer; | ||||||
|  |  | ||||||
|  | 	/// The grabber for creating screenshots | ||||||
|  | 	XcbGrabber _grabber; | ||||||
|  |  | ||||||
|  | 	Image<ColorRgb>  _screenshot; | ||||||
|  |  | ||||||
|  | 	// prevent cont dimension updates | ||||||
|  | 	bool _inited = false; | ||||||
|  | }; | ||||||
							
								
								
									
										115
									
								
								src/hyperion-xcb/hyperion-xcb.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/hyperion-xcb/hyperion-xcb.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | |||||||
|  |  | ||||||
|  | // QT includes | ||||||
|  | #include <QApplication> | ||||||
|  | #include <QImage> | ||||||
|  |  | ||||||
|  | #include <commandline/Parser.h> | ||||||
|  | #include <flatbufserver/FlatBufferConnection.h> | ||||||
|  | #include <utils/DefaultSignalHandler.h> | ||||||
|  | #include "XcbWrapper.h" | ||||||
|  | #include "HyperionConfig.h" | ||||||
|  |  | ||||||
|  | // ssdp discover | ||||||
|  | #include <ssdp/SSDPDiscover.h> | ||||||
|  |  | ||||||
|  | using namespace commandline; | ||||||
|  |  | ||||||
|  | // save the image as screenshot | ||||||
|  | void saveScreenshot(QString filename, const Image<ColorRgb> & image) | ||||||
|  | { | ||||||
|  | 	// store as PNG | ||||||
|  | 	QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); | ||||||
|  | 	pngImage.save(filename); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char ** argv) | ||||||
|  | { | ||||||
|  | 	 std::cout | ||||||
|  | 		<< "hyperion-xcb:" << std::endl | ||||||
|  | 		<< "\tVersion   : " << HYPERION_VERSION << " (" << HYPERION_BUILD_ID << ")" << std::endl | ||||||
|  | 		<< "\tbuild time: " << __DATE__ << " " << __TIME__ << std::endl; | ||||||
|  |  | ||||||
|  | 	DefaultSignalHandler::install(); | ||||||
|  |  | ||||||
|  | 	QApplication app(argc, argv); | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		// create the option parser and initialize all parameters | ||||||
|  | 		Parser parser("XCB capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used."); | ||||||
|  |  | ||||||
|  | 		IntOption           & argFps             = parser.add<IntOption>    ('f', "framerate", "Capture frame rate [default: %1]", "10"); | ||||||
|  | 		IntOption           & argCropWidth       = parser.add<IntOption>    (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: %1]", "0"); | ||||||
|  | 		IntOption           & argCropHeight      = parser.add<IntOption>    (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: %1]", "0"); | ||||||
|  | 		IntOption           & argCropLeft        = parser.add<IntOption>    (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)"); | ||||||
|  | 		IntOption           & argCropRight       = parser.add<IntOption>    (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)"); | ||||||
|  | 		IntOption           & argCropTop         = parser.add<IntOption>    (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)"); | ||||||
|  | 		IntOption           & argCropBottom      = parser.add<IntOption>    (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)"); | ||||||
|  | 		IntOption           & argSizeDecimation  = parser.add<IntOption>    ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "8", 1); | ||||||
|  | 		BooleanOption       & argScreenshot      = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit"); | ||||||
|  | 		Option              & argAddress         = parser.add<Option>       ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19400"); | ||||||
|  | 		IntOption           & argPriority        = parser.add<IntOption>    ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150"); | ||||||
|  | 		BooleanOption       & argSkipReply       = parser.add<BooleanOption>(0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); | ||||||
|  | 		BooleanOption       & argHelp            = parser.add<BooleanOption>('h', "help", "Show this help message and exit"); | ||||||
|  |  | ||||||
|  | 		// parse all options | ||||||
|  | 		parser.process(app); | ||||||
|  |  | ||||||
|  | 		// check if we need to display the usage. exit if we do. | ||||||
|  | 		if (parser.isSet(argHelp)) | ||||||
|  | 		{ | ||||||
|  | 			parser.showHelp(0); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create the XCB grabbing stuff | ||||||
|  | 		XcbWrapper xcbWrapper( | ||||||
|  | 					1000 / argFps.getInt(parser), | ||||||
|  | 					parser.isSet(argCropLeft) ? argCropLeft.getInt(parser) : argCropWidth.getInt(parser), | ||||||
|  | 					parser.isSet(argCropRight) ? argCropRight.getInt(parser) : argCropWidth.getInt(parser), | ||||||
|  | 					parser.isSet(argCropTop) ? argCropTop.getInt(parser) : argCropHeight.getInt(parser), | ||||||
|  | 					parser.isSet(argCropBottom) ? argCropBottom.getInt(parser) : argCropHeight.getInt(parser), | ||||||
|  | 					argSizeDecimation.getInt(parser)); // decimation | ||||||
|  |  | ||||||
|  | 		if (!xcbWrapper.displayInit()) | ||||||
|  | 			return -1; | ||||||
|  |  | ||||||
|  | 		if (parser.isSet(argScreenshot)) | ||||||
|  | 		{ | ||||||
|  | 			// Capture a single screenshot and finish | ||||||
|  | 			const Image<ColorRgb> & screenshot = xcbWrapper.getScreenshot(); | ||||||
|  | 			saveScreenshot("screenshot.png", screenshot); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			// server searching by ssdp | ||||||
|  | 			QString address = argAddress.value(parser); | ||||||
|  | 			if(argAddress.value(parser) == "127.0.0.1:19400") | ||||||
|  | 			{ | ||||||
|  | 				SSDPDiscover discover; | ||||||
|  | 				address = discover.getFirstService(searchType::STY_FLATBUFSERVER); | ||||||
|  | 				if(address.isEmpty()) | ||||||
|  | 				{ | ||||||
|  | 					address = argAddress.value(parser); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			// Create the Flatbuf-connection | ||||||
|  | 			FlatBufferConnection flatbuf("XCB Standalone", address, argPriority.getInt(parser), parser.isSet(argSkipReply)); | ||||||
|  |  | ||||||
|  | 			// Connect the screen capturing to flatbuf connection processing | ||||||
|  | 			QObject::connect(&xcbWrapper, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &flatbuf, SLOT(setImage(Image<ColorRgb>))); | ||||||
|  |  | ||||||
|  | 			// Start the capturing | ||||||
|  | 			xcbWrapper.start(); | ||||||
|  |  | ||||||
|  | 			// Start the application | ||||||
|  | 			app.exec(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	catch (const std::runtime_error & e) | ||||||
|  | 	{ | ||||||
|  | 		// An error occured. Display error and quit | ||||||
|  | 		Error(Logger::getInstance("XCBGRABBER"), "%s", e.what()); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
| @@ -95,6 +95,10 @@ if (ENABLE_X11) | |||||||
| 	target_link_libraries(hyperiond	x11-grabber) | 	target_link_libraries(hyperiond	x11-grabber) | ||||||
| endif () | endif () | ||||||
|  |  | ||||||
|  | if (ENABLE_XCB) | ||||||
|  | 	target_link_libraries(hyperiond	xcb-grabber) | ||||||
|  | endif () | ||||||
|  |  | ||||||
| if (ENABLE_QT) | if (ENABLE_QT) | ||||||
| 	target_link_libraries(hyperiond	qt-grabber) | 	target_link_libraries(hyperiond	qt-grabber) | ||||||
| endif () | endif () | ||||||
|   | |||||||
| @@ -75,6 +75,7 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, const bo | |||||||
| 		, _v4l2Grabber(nullptr) | 		, _v4l2Grabber(nullptr) | ||||||
| 		, _dispmanx(nullptr) | 		, _dispmanx(nullptr) | ||||||
| 		, _x11Grabber(nullptr) | 		, _x11Grabber(nullptr) | ||||||
|  | 		, _xcbGrabber(nullptr) | ||||||
| 		, _amlGrabber(nullptr) | 		, _amlGrabber(nullptr) | ||||||
| 		, _fbGrabber(nullptr) | 		, _fbGrabber(nullptr) | ||||||
| 		, _osxGrabber(nullptr) | 		, _osxGrabber(nullptr) | ||||||
| @@ -133,7 +134,7 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, const bo | |||||||
| 	connect(this, &HyperionDaemon::videoMode, _instanceManager, &HyperionIManager::newVideoMode); | 	connect(this, &HyperionDaemon::videoMode, _instanceManager, &HyperionIManager::newVideoMode); | ||||||
|  |  | ||||||
| // ---- grabber ----- | // ---- grabber ----- | ||||||
| #if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) | #if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_XCB) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) | ||||||
| 	Warning(_log, "No platform capture can be instantiated, because all grabbers have been left out from the build"); | 	Warning(_log, "No platform capture can be instantiated, because all grabbers have been left out from the build"); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -374,7 +375,13 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type &settingsType, co | |||||||
| 				QByteArray envDisplay = qgetenv("DISPLAY"); | 				QByteArray envDisplay = qgetenv("DISPLAY"); | ||||||
| 				if ( !envDisplay.isEmpty() ) | 				if ( !envDisplay.isEmpty() ) | ||||||
| 				{ | 				{ | ||||||
|  | 				#if defined(ENABLE_X11) | ||||||
| 					type = "x11"; | 					type = "x11"; | ||||||
|  | 				#elif defined(ENABLE_XCB) | ||||||
|  | 					type = "xcb"; | ||||||
|  | 				#else | ||||||
|  | 					type = "qt"; | ||||||
|  | 				#endif | ||||||
| 				} | 				} | ||||||
| 				// qt -> if nothing other applies | 				// qt -> if nothing other applies | ||||||
| 				else | 				else | ||||||
| @@ -429,6 +436,14 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type &settingsType, co | |||||||
| 				 _x11Grabber = nullptr; | 				 _x11Grabber = nullptr; | ||||||
| 			} | 			} | ||||||
| 			#endif | 			#endif | ||||||
|  | 			#ifdef ENABLE_XCB | ||||||
|  | 			if(_xcbGrabber != nullptr) | ||||||
|  | 			{ | ||||||
|  | 				 _xcbGrabber->stop(); | ||||||
|  | 				 delete _xcbGrabber; | ||||||
|  | 				 _xcbGrabber = nullptr; | ||||||
|  | 			} | ||||||
|  | 			#endif | ||||||
| 			#ifdef ENABLE_QT | 			#ifdef ENABLE_QT | ||||||
| 			if(_qtGrabber != nullptr) | 			if(_qtGrabber != nullptr) | ||||||
| 			{ | 			{ | ||||||
| @@ -479,6 +494,14 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type &settingsType, co | |||||||
| 				_x11Grabber->tryStart(); | 				_x11Grabber->tryStart(); | ||||||
| 				#endif | 				#endif | ||||||
| 			} | 			} | ||||||
|  | 			else if (type == "xcb") | ||||||
|  | 			{ | ||||||
|  | 				if (_xcbGrabber == nullptr) | ||||||
|  | 					createGrabberXcb(grabberConfig); | ||||||
|  | 				#ifdef ENABLE_XCB | ||||||
|  | 				_xcbGrabber->tryStart(); | ||||||
|  | 				#endif | ||||||
|  | 			} | ||||||
| 			else if (type == "qt") | 			else if (type == "qt") | ||||||
| 			{ | 			{ | ||||||
| 				if (_qtGrabber == nullptr) | 				if (_qtGrabber == nullptr) | ||||||
| @@ -603,6 +626,25 @@ void HyperionDaemon::createGrabberX11(const QJsonObject &grabberConfig) | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void HyperionDaemon::createGrabberXcb(const QJsonObject &grabberConfig) | ||||||
|  | { | ||||||
|  | #ifdef ENABLE_XCB | ||||||
|  | 	_xcbGrabber = new XcbWrapper( | ||||||
|  | 			_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, | ||||||
|  | 			grabberConfig["pixelDecimation"].toInt(8), | ||||||
|  | 			_grabber_frequency); | ||||||
|  | 	_xcbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); | ||||||
|  |  | ||||||
|  | 	// connect to HyperionDaemon signal | ||||||
|  | 	connect(this, &HyperionDaemon::videoMode, _xcbGrabber, &XcbWrapper::setVideoMode); | ||||||
|  | 	connect(this, &HyperionDaemon::settingsChanged, _xcbGrabber, &XcbWrapper::handleSettingsUpdate); | ||||||
|  |  | ||||||
|  | 	Info(_log, "XCB grabber created"); | ||||||
|  | #else | ||||||
|  | 	Error(_log, "The XCB grabber can not be instantiated, because it has been left out from the build"); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
| void HyperionDaemon::createGrabberQt(const QJsonObject &grabberConfig) | void HyperionDaemon::createGrabberQt(const QJsonObject &grabberConfig) | ||||||
| { | { | ||||||
| #ifdef ENABLE_QT | #ifdef ENABLE_QT | ||||||
|   | |||||||
| @@ -40,6 +40,12 @@ | |||||||
| 	typedef QObject X11Wrapper; | 	typedef QObject X11Wrapper; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef ENABLE_XCB | ||||||
|  | 	#include <grabber/XcbWrapper.h> | ||||||
|  | #else | ||||||
|  | 	typedef QObject XcbWrapper; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef ENABLE_QT | #ifdef ENABLE_QT | ||||||
| 	#include <grabber/QtWrapper.h> | 	#include <grabber/QtWrapper.h> | ||||||
| #else | #else | ||||||
| @@ -144,6 +150,7 @@ private: | |||||||
| 	void createGrabberFramebuffer(const QJsonObject & grabberConfig); | 	void createGrabberFramebuffer(const QJsonObject & grabberConfig); | ||||||
| 	void createGrabberOsx(const QJsonObject & grabberConfig); | 	void createGrabberOsx(const QJsonObject & grabberConfig); | ||||||
| 	void createGrabberX11(const QJsonObject & grabberConfig); | 	void createGrabberX11(const QJsonObject & grabberConfig); | ||||||
|  | 	void createGrabberXcb(const QJsonObject & grabberConfig); | ||||||
| 	void createGrabberQt(const QJsonObject & grabberConfig); | 	void createGrabberQt(const QJsonObject & grabberConfig); | ||||||
| 	void createCecHandler(); | 	void createCecHandler(); | ||||||
|  |  | ||||||
| @@ -159,6 +166,7 @@ private: | |||||||
| 	V4L2Wrapper*               _v4l2Grabber; | 	V4L2Wrapper*               _v4l2Grabber; | ||||||
| 	DispmanxWrapper*           _dispmanx; | 	DispmanxWrapper*           _dispmanx; | ||||||
| 	X11Wrapper*                _x11Grabber; | 	X11Wrapper*                _x11Grabber; | ||||||
|  | 	XcbWrapper*                _xcbGrabber; | ||||||
| 	AmlogicWrapper*            _amlGrabber; | 	AmlogicWrapper*            _amlGrabber; | ||||||
| 	FramebufferWrapper*        _fbGrabber; | 	FramebufferWrapper*        _fbGrabber; | ||||||
| 	OsxWrapper*                _osxGrabber; | 	OsxWrapper*                _osxGrabber; | ||||||
|   | |||||||
| @@ -105,13 +105,21 @@ QCoreApplication* createApplication(int &argc, char *argv[]) | |||||||
| 	if (!forceNoGui) | 	if (!forceNoGui) | ||||||
| 	{ | 	{ | ||||||
| 		// if x11, then test if xserver is available | 		// if x11, then test if xserver is available | ||||||
| 		#ifdef ENABLE_X11 | 		#if defined(ENABLE_X11) | ||||||
| 		Display* dpy = XOpenDisplay(NULL); | 		Display* dpy = XOpenDisplay(NULL); | ||||||
| 		if (dpy != NULL) | 		if (dpy != NULL) | ||||||
| 		{ | 		{ | ||||||
| 			XCloseDisplay(dpy); | 			XCloseDisplay(dpy); | ||||||
| 			isGuiApp = true; | 			isGuiApp = true; | ||||||
| 		} | 		} | ||||||
|  | 		#elif defined(ENABLE_XCB) | ||||||
|  | 			int screen_num; | ||||||
|  | 			xcb_connection_t * connection = xcb_connect(nullptr, &screen_num); | ||||||
|  | 			if (!xcb_connection_has_error(connection)) | ||||||
|  | 			{ | ||||||
|  | 				isGuiApp = true; | ||||||
|  | 			} | ||||||
|  | 			xcb_disconnect(connection); | ||||||
| 		#endif | 		#endif | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user