diff --git a/CMakeLists.txt b/CMakeLists.txt index c3a021ef929..c0e77e4ef5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ set(CMAKE_AUTORCC ON) set(CMAKE_INCLUDE_CURRENT_DIR OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# set(CMAKE_OPTIMIZE_DEPENDENCIES ON) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release") if(NOT CMAKE_BUILD_TYPE) @@ -106,6 +107,10 @@ endif() set(BUILD_SHARED_LIBS OFF) +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_definitions(QGC_INSTALL_RELEASE) +endif() + ####################################################### # Qt6 Configuration ####################################################### diff --git a/cmake/FindFFMPEG.cmake b/cmake/FindFFMPEG.cmake deleted file mode 100644 index f727ef2dddf..00000000000 --- a/cmake/FindFFMPEG.cmake +++ /dev/null @@ -1,195 +0,0 @@ -#[==[ -Provides the following variables: - - * `FFMPEG_INCLUDE_DIRS`: Include directories necessary to use FFMPEG. - * `FFMPEG_LIBRARIES`: Libraries necessary to use FFMPEG. Note that this only - includes libraries for the components requested. - * `FFMPEG_VERSION`: The version of FFMPEG found. - -The following components are supported: - - * `avcodec` - * `avdevice` - * `avfilter` - * `avformat` - * `avresample` - * `avutil` - * `swresample` - * `swscale` - -For each component, the following are provided: - - * `FFMPEG__FOUND`: Libraries for the component. - * `FFMPEG__INCLUDE_DIRS`: Include directories for - the component. - * `FFMPEG__LIBRARIES`: Libraries for the component. - * `FFMPEG::`: A target to use with `target_link_libraries`. - -Note that only components requested with `COMPONENTS` or `OPTIONAL_COMPONENTS` -are guaranteed to set these variables or provide targets. -#]==] - -function (_ffmpeg_find component headername) - find_path("FFMPEG_${component}_INCLUDE_DIR" - NAMES - "lib${component}/${headername}" - PATHS - "${FFMPEG_ROOT}/include" - ~/Library/Frameworks - /Library/Frameworks - /usr/local/include - /usr/include - /sw/include # Fink - /opt/local/include # DarwinPorts - /opt/csw/include # Blastwave - /opt/include - /usr/freeware/include - PATH_SUFFIXES - ffmpeg - DOC "FFMPEG's ${component} include directory") - mark_as_advanced("FFMPEG_${component}_INCLUDE_DIR") - - # On Windows, static FFMPEG is sometimes built as `lib.a`. - if (WIN32) - list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib") - list(APPEND CMAKE_FIND_LIBRARY_PREFIXES "" "lib") - endif () - - find_library("FFMPEG_${component}_LIBRARY" - NAMES - "${component}" - PATHS - "${FFMPEG_ROOT}/lib" - ~/Library/Frameworks - /Library/Frameworks - /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 - /sw/lib - /opt/local/lib - /opt/csw/lib - /opt/lib - /usr/freeware/lib64 - "${FFMPEG_ROOT}/bin" - DOC "FFMPEG's ${component} library") - mark_as_advanced("FFMPEG_${component}_LIBRARY") - - if (FFMPEG_${component}_LIBRARY AND FFMPEG_${component}_INCLUDE_DIR) - set(_deps_found TRUE) - set(_deps_link) - foreach (_ffmpeg_dep IN LISTS ARGN) - if (TARGET "FFMPEG::${_ffmpeg_dep}") - list(APPEND _deps_link "FFMPEG::${_ffmpeg_dep}") - else () - set(_deps_found FALSE) - endif () - endforeach () - if (_deps_found) - if (NOT TARGET "FFMPEG::${component}") - add_library("FFMPEG::${component}" UNKNOWN IMPORTED) - set_target_properties("FFMPEG::${component}" PROPERTIES - IMPORTED_LOCATION "${FFMPEG_${component}_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_${component}_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LIBRARIES "${_deps_link}") - endif () - set("FFMPEG_${component}_FOUND" 1 - PARENT_SCOPE) - - set(version_header_path "${FFMPEG_${component}_INCLUDE_DIR}/lib${component}/version.h") - if (EXISTS "${version_header_path}") - string(TOUPPER "${component}" component_upper) - file(STRINGS "${version_header_path}" version - REGEX "#define *LIB${component_upper}_VERSION_(MAJOR|MINOR|MICRO) ") - string(REGEX REPLACE ".*_MAJOR *\([0-9]*\).*" "\\1" major "${version}") - string(REGEX REPLACE ".*_MINOR *\([0-9]*\).*" "\\1" minor "${version}") - string(REGEX REPLACE ".*_MICRO *\([0-9]*\).*" "\\1" micro "${version}") - if (NOT major STREQUAL "" AND - NOT minor STREQUAL "" AND - NOT micro STREQUAL "") - set("FFMPEG_${component}_VERSION" "${major}.${minor}.${micro}" - PARENT_SCOPE) - endif () - endif () - else () - set("FFMPEG_${component}_FOUND" 0 - PARENT_SCOPE) - set(what) - if (NOT FFMPEG_${component}_LIBRARY) - set(what "library") - endif () - if (NOT FFMPEG_${component}_INCLUDE_DIR) - if (what) - string(APPEND what " or headers") - else () - set(what "headers") - endif () - endif () - set("FFMPEG_${component}_NOT_FOUND_MESSAGE" - "Could not find the ${what} for ${component}." - PARENT_SCOPE) - endif () - endif () -endfunction () - -_ffmpeg_find(avutil avutil.h) -_ffmpeg_find(avresample avresample.h - avutil) -_ffmpeg_find(swresample swresample.h - avutil) -_ffmpeg_find(swscale swscale.h - avutil) -_ffmpeg_find(avcodec avcodec.h - avutil) -_ffmpeg_find(avformat avformat.h - avcodec avutil) -_ffmpeg_find(avfilter avfilter.h - avutil) -_ffmpeg_find(avdevice avdevice.h - avformat avutil) - -if (TARGET FFMPEG::avutil) - set(_ffmpeg_version_header_path "${FFMPEG_avutil_INCLUDE_DIR}/libavutil/ffversion.h") - if (EXISTS "${_ffmpeg_version_header_path}") - file(STRINGS "${_ffmpeg_version_header_path}" _ffmpeg_version - REGEX "FFMPEG_VERSION") - string(REGEX REPLACE ".*\"n?\(.*\)\"" "\\1" FFMPEG_VERSION "${_ffmpeg_version}") - unset(_ffmpeg_version) - else () - set(FFMPEG_VERSION FFMPEG_VERSION-NOTFOUND) - endif () - unset(_ffmpeg_version_header_path) -endif () - -set(FFMPEG_INCLUDE_DIRS) -set(FFMPEG_LIBRARIES) -set(_ffmpeg_required_vars) -foreach (_ffmpeg_component IN LISTS FFMPEG_FIND_COMPONENTS) - if (TARGET "FFMPEG::${_ffmpeg_component}") - set(FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS - "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIR}") - set(FFMPEG_${_ffmpeg_component}_LIBRARIES - "${FFMPEG_${_ffmpeg_component}_LIBRARY}") - list(APPEND FFMPEG_INCLUDE_DIRS - "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS}") - list(APPEND FFMPEG_LIBRARIES - "${FFMPEG_${_ffmpeg_component}_LIBRARIES}") - if (FFMEG_FIND_REQUIRED_${_ffmpeg_component}) - list(APPEND _ffmpeg_required_vars - "FFMPEG_${_ffmpeg_required_vars}_INCLUDE_DIRS" - "FFMPEG_${_ffmpeg_required_vars}_LIBRARIES") - endif () - endif () -endforeach () -unset(_ffmpeg_component) - -if (FFMPEG_INCLUDE_DIRS) - list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) -endif () - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(FFMPEG - REQUIRED_VARS FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES ${_ffmpeg_required_vars} - VERSION_VAR FFMPEG_VERSION - HANDLE_COMPONENTS) -unset(_ffmpeg_required_vars) diff --git a/cmake/FindGStreamer.cmake b/cmake/FindGStreamer.cmake index ed0b86f947b..d7d9cfad819 100644 --- a/cmake/FindGStreamer.cmake +++ b/cmake/FindGStreamer.cmake @@ -1,35 +1,6 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -# FindGStreamer -# --------- -# -# Locate the gstreamer-1.0 library and some of its plugins. -# Defines the following imported target: -# -# ``GStreamer::GStreamer`` -# If the gstreamer-1.0 library is available and target GStreamer::Base, -# GStreamer::Audio, GStreamer::Video, GStreamer::Pbutils and -# GStreamer::Allocators exist -# -# If target GStreamer::GStreamer exists, the following targets may be defined: -# -# ``GStreamer::App`` -# If the gstapp-1.0 library is available and target GStreamer::GStreamer exists -# ``GStreamer::Photography`` -# If the gstphotography-1.0 library is available and target GStreamer::GStreamer exists -# ``GStreamer::Gl`` -# If the gstgl-1.0 library is available and target GStreamer::GStreamer exists -# - -################################################################################ - -if(ANDROID) - set(QGC_GST_STATIC_BUILD ON) - list(APPEND PKG_CONFIG_ARGN --static) -endif() - if(ANDROID OR IOS) + set(QGC_GST_STATIC_BUILD ON CACHE BOOL "Build GST Statically") + if(DEFINED ENV{GST_VERSION}) set(QGC_GST_TARGET_VERSION $ENV{GST_VERSION} CACHE STRING "Environment Provided GStreamer Version") else() @@ -37,6 +8,10 @@ if(ANDROID OR IOS) endif() endif() +if(QGC_GST_STATIC_BUILD) + list(APPEND PKG_CONFIG_ARGN --static) +endif() + ################################################################################ # NOTE: CMP0144 in regards to GSTREAMER_ROOT @@ -52,12 +27,8 @@ if(WIN32) find_program(PKG_CONFIG_PROGRAM pkg-config PATHS ${GSTREAMER_PREFIX}/bin) if(PKG_CONFIG_PROGRAM) set(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_PROGRAM}) - cmake_print_variables(PKG_CONFIG_EXECUTABLE) endif() set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/lib/pkgconfig;${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig;$ENV{PKG_CONFIG_PATH}") - # cmake_path(CONVERT "${GSTREAMER_PREFIX}/lib/pkgconfig;${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig;$ENV{PKG_CONFIG_PATH}" TO_NATIVE_PATH_LIST PKG_CONFIG_PATH NORMALIZE) - # cmake_print_variables(PKG_CONFIG_PATH) - # set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}") cmake_path(CONVERT "${GSTREAMER_PREFIX}" TO_CMAKE_PATH_LIST PREFIX_PATH NORMALIZE) cmake_path(CONVERT "${GSTREAMER_PREFIX}/lib" TO_CMAKE_PATH_LIST LIBDIR_PATH NORMALIZE) cmake_path(CONVERT "${GSTREAMER_PREFIX}/include" TO_CMAKE_PATH_LIST INCLUDE_PATH NORMALIZE) @@ -67,7 +38,6 @@ if(WIN32) --define-variable=libdir=${LIBDIR_PATH} --define-variable=includedir=${INCLUDE_PATH} ) - cmake_print_variables(PKG_CONFIG_ARGN) elseif(MACOS) set(GSTREAMER_PREFIX "/Library/Frameworks/GStreamer.framework") set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/Versions/Current/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}") @@ -75,9 +45,10 @@ elseif(LINUX) set(GSTREAMER_PREFIX "/usr") set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/pkgconfig:$ENV{PKG_CONFIG_PATH}") elseif(IOS) - set(GSTREAMER_PREFIX "~/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework") if(DEFINED ENV{GSTREAMER_PREFIX_IOS} AND EXISTS $ENV{GSTREAMER_PREFIX_IOS}) set(GSTREAMER_PREFIX_IOS $ENV{GSTREAMER_PREFIX_IOS}) + elseif(EXISTS "~/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework") + set(GSTREAMER_PREFIX_IOS "~/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework") else() FetchContent_Declare(gstreamer URL "https://gstreamer.freedesktop.org/data/pkg/ios/${QGC_GST_TARGET_VERSION}/gstreamer-1.0-devel-${QGC_GST_TARGET_VERSION}-ios-universal.pkg" @@ -86,18 +57,26 @@ elseif(IOS) FetchContent_MakeAvailable(gstreamer) set(GSTREAMER_PREFIX_IOS ${gstreamer_SOURCE_DIR}) endif() - # TODO: set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_IOS}/) + set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_IOS}) elseif(ANDROID) set(GSTREAMER_PREFIX_ANDROID) if(DEFINED ENV{GSTREAMER_PREFIX_ANDROID} AND EXISTS $ENV{GSTREAMER_PREFIX_ANDROID}) set(GSTREAMER_PREFIX_ANDROID $ENV{GSTREAMER_PREFIX_ANDROID}) else() - FetchContent_Declare(gstreamer - URL "https://gstreamer.freedesktop.org/data/pkg/android/${QGC_GST_TARGET_VERSION}/gstreamer-1.0-android-universal-${QGC_GST_TARGET_VERSION}.tar.xz" - DOWNLOAD_EXTRACT_TIMESTAMP true - ) - FetchContent_MakeAvailable(gstreamer) - set(GSTREAMER_PREFIX_ANDROID ${gstreamer_SOURCE_DIR}) + set(GSTREAMER_ARCHIVE "gstreamer-1.0-android-universal-${QGC_GST_TARGET_VERSION}.tar.xz") + set(GSTREAMER_URL "https://gstreamer.freedesktop.org/data/pkg/android/${QGC_GST_TARGET_VERSION}/${GSTREAMER_ARCHIVE}") + set(GSTREAMER_TARBALL "${CMAKE_BINARY_DIR}/_deps/gstreamer/${GSTREAMER_ARCHIVE}") + set(GSTREAMER_INSTALL_DIR "${CMAKE_BINARY_DIR}/_deps/gstreamer/install/gstreamer") + if(NOT EXISTS ${GSTREAMER_TARBALL}) + message(STATUS "Downloading GStreamer from ${GSTREAMER_URL}") + file(DOWNLOAD ${GSTREAMER_URL} ${GSTREAMER_TARBALL} SHOW_PROGRESS) + endif() + if(NOT EXISTS ${GSTREAMER_INSTALL_DIR}) + message(STATUS "Extracting GStreamer to ${GSTREAMER_INSTALL_DIR}") + file(MAKE_DIRECTORY ${GSTREAMER_INSTALL_DIR}) + file(ARCHIVE_EXTRACT INPUT ${GSTREAMER_TARBALL} DESTINATION ${GSTREAMER_INSTALL_DIR}) + endif() + set(GSTREAMER_PREFIX_ANDROID ${GSTREAMER_INSTALL_DIR}) endif() if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL armeabi-v7a) set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_ANDROID}/armv7) @@ -108,24 +87,19 @@ elseif(ANDROID) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL x86_64) set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_ANDROID}/x86_64) endif() - set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig:$ENV{PKG_CONFIG_PATH}") + set(ENV{PKG_CONFIG_PATH} "") set(ENV{PKG_CONFIG_LIBDIR} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig") - # set(ENV{PKG_CONFIG_SYSROOT_DIR} "${GSTREAMER_PREFIX}") - message(STATUS "PKG_CONFIG_PATH $ENV{PKG_CONFIG_PATH}") - # message(STATUS "PKG_CONFIG_SYSROOT_DIR $ENV{PKG_CONFIG_SYSROOT_DIR}") list(APPEND PKG_CONFIG_ARGN --dont-define-prefix --define-variable=prefix=${GSTREAMER_PREFIX} --define-variable=libdir=${GSTREAMER_PREFIX}/lib --define-variable=includedir=${GSTREAMER_PREFIX}/include ) - cmake_print_variables(PKG_CONFIG_ARGN) if(CMAKE_HOST_WIN32) find_program(PKG_CONFIG_PROGRAM pkg-config PATHS ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/tools/windows) if(PKG_CONFIG_PROGRAM) set(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_PROGRAM}) - cmake_print_variables(PKG_CONFIG_EXECUTABLE) endif() endif() endif() @@ -140,6 +114,10 @@ find_dependency(GObject) set(GStreamer_VERSION ${QGC_GST_TARGET_VERSION}) find_package(PkgConfig QUIET) if(PkgConfig_FOUND) + message(STATUS "PKG_CONFIG_PATH $ENV{PKG_CONFIG_PATH}") + message(STATUS "PKG_CONFIG_LIBDIR $ENV{PKG_CONFIG_LIBDIR}") + # message(STATUS "PKG_CONFIG_SYSROOT_DIR $ENV{PKG_CONFIG_SYSROOT_DIR}") + cmake_print_variables(PKG_CONFIG_EXECUTABLE PKG_CONFIG_ARGN) pkg_check_modules(GStreamer gstreamer-1.0) else() find_file(GStreamer_VERSION_HEADER @@ -356,6 +334,17 @@ endforeach() ################################################################################ +if(TARGET PkgConfig::PC_GSTREAMER_GL) + get_target_property(_qt_incs PkgConfig::PC_GSTREAMER_GL INTERFACE_INCLUDE_DIRECTORIES) + set(__qt_fixed_incs) + foreach(path IN LISTS _qt_incs) + if(IS_DIRECTORY "${path}") + list(APPEND __qt_fixed_incs "${path}") + endif() + endforeach() + set_property(TARGET PkgConfig::PC_GSTREAMER_GL PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${__qt_fixed_incs}") +endif() + # Create target GStreamer::GStreamer include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GStreamer @@ -375,19 +364,173 @@ if(GStreamer_FOUND AND NOT TARGET GStreamer::GStreamer) GStreamer::Video GStreamer::Gl ) - set_target_properties(GStreamer::GStreamer PROPERTIES VERSION ${GStreamer_Core_VERSION}) - set(GStreamer_VERSION ${GStreamer_Core_VERSION}) + set_target_properties(GStreamer::GStreamer PROPERTIES VERSION ${GStreamer_VERSION}) endif() -if(TARGET PkgConfig::PC_GSTREAMER_GL) - get_target_property(_qt_incs PkgConfig::PC_GSTREAMER_GL INTERFACE_INCLUDE_DIRECTORIES) - set(__qt_fixed_incs) - foreach(path IN LISTS _qt_incs) - if(IS_DIRECTORY "${path}") - list(APPEND __qt_fixed_incs "${path}") +################################################################################ + +set(GST_TARGET_PLUGINS + gstcoreelements + gstisomp4 + gstlibav + gstmatroska + gstmpegtsdemux + gstopengl + gstplayback + gstrtp + gstrtpmanager + gstrtsp + gstsdpelem + gsttcp + gstudp + gstvideoparsersbad + gstx264 + gstasf + gstva +) +if(ANDROID) + list(APPEND GST_TARGET_PLUGINS gstandroidmedia) +elseif(IOS) + list(APPEND GST_TARGET_PLUGINS gstapplemedia) +endif() + +find_package(PkgConfig QUIET) +if(PkgConfig_FOUND) + pkg_check_modules(GST_PLUGINS IMPORTED_TARGET ${GST_TARGET_PLUGINS}) + if(GST_PLUGINS_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE PkgConfig::GST_PLUGINS) + if(WIN32) + # install(FILES ${GST_PLUGINS_LIBRARIES} DESTINATION ${CMAKE_INSTALL_BINDIR}) + elseif(LINUX) + # install(FILES ${GST_PLUGINS_LIBRARIES} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() + endif() + + pkg_check_modules(GSTREAMER_PLUGINS_BASE IMPORTED_TARGET gstreamer-plugins-base-1.0) + if(GSTREAMER_PLUGINS_BASE_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE PkgConfig::GSTREAMER_PLUGINS_BASE) + endif() +endif() + +if(NOT GST_PLUGINS_FOUND) + foreach(plugin IN LISTS GST_TARGET_PLUGINS) + find_library(GStreamer_${plugin}_LIBRARY + NAMES ${plugin} + PATHS + ${GSTREAMER_PREFIX}/lib + ${GSTREAMER_PREFIX}/lib/gstreamer-1.0 + ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu + ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/gstreamer-1.0 + ${GSTREAMER_PREFIX}/Versions/Current/lib + ${GSTREAMER_PREFIX}/Versions/Current/lib/gstreamer-1.0 + ) + if(GStreamer_${plugin}_LIBRARY) + cmake_print_variables(GStreamer_${plugin}_LIBRARY) + target_link_libraries(GStreamer::GStreamer INTERFACE ${GStreamer_${plugin}_LIBRARY}) + if(WIN32) + # install(FILES ${GStreamer_${plugin}_LIBRARY} DESTINATION ${CMAKE_INSTALL_BINDIR}) + elseif(LINUX) + # install(FILES ${GStreamer_${plugin}_LIBRARY} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() endif() endforeach() - set_property(TARGET PkgConfig::PC_GSTREAMER_GL PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${__qt_fixed_incs}") + + # if(ANDROID) + # find_path(GStreamer_${component}_INCLUDE_DIR + # NAMES ${header} + # PATH_SUFFIXES gstreamer-1.0 + # PATHS ${GSTREAMER_PREFIX}/include + # ) + # target_include_directories(GStreamer::GStreamer + # INTERFACE + # ${GSTREAMER_PREFIX}/include/gstreamer-1.0 + # ${GSTREAMER_PREFIX}/include/glib-2.0 + # ${GSTREAMER_PREFIX}/lib/glib-2.0/include + # ${GSTREAMER_PREFIX}/lib/graphene-1.0/include + # ${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include + # ${GSTREAMER_PREFIX}/include + # ) + + find_package(FFmpeg) + if(FFMPEG_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE FFmpeg::FFmpeg) + endif() + + find_package(BZip2) + if(BZIP2_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE BZip2::BZip2) + endif() + + find_library(graphene_LIBRARY graphene-1.0) + if(graphene_LIBRARY) + target_link_libraries(GStreamer::GStreamer INTERFACE ${graphene_LIBRARY}) + endif() + + find_library(x264_LIBRARY x264) + if(x264_LIBRARY) + target_link_libraries(GStreamer::GStreamer INTERFACE ${x264_LIBRARY}) + endif() + + find_package(JPEG) + if(JPEG_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE JPEG::JPEG) + endif() + + find_package(PNG) + if(PNG_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE PNG::PNG) + endif() + + find_package(Intl) + if(Intl_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE Intl::Intl) + endif() + + find_package(Iconv) + if(Iconv_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE Iconv::Iconv) + endif() + + find_package(EGL) + if(EGL_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE EGL::EGL) + endif() + + find_package(Threads) + if(Threads_FOUND) + target_link_libraries(GStreamer::GStreamer INTERFACE Threads::Threads) + endif() + # endif() +endif() + +if(ANDROID) + target_link_options(GStreamer::GStreamer INTERFACE "-Wl,-Bsymbolic") +endif() + +if(QGC_GST_STATIC_BUILD) + target_compile_definitions(GStreamer::GStreamer INTERFACE QGC_GST_STATIC_BUILD) endif() ################################################################################ + +# Use Latest Revisions for each minor version: 1.16.3, 1.18.6, 1.20.7, 1.22.12, 1.24.7 +string(REPLACE "." ";" GST_VERSION_LIST ${GStreamer_VERSION}) +list(GET GST_VERSION_LIST 0 GST_VERSION_MAJOR) +list(GET GST_VERSION_LIST 1 GST_VERSION_MINOR) +list(GET GST_VERSION_LIST 2 GST_VERSION_PATCH) +cmake_print_variables(GST_VERSION_MAJOR GST_VERSION_MINOR GST_VERSION_PATCH) + +if(GST_VERSION_MINOR EQUAL 16) + set(GST_VERSION_PATCH 3) +elseif(GST_VERSION_MINOR EQUAL 18) + set(GST_VERSION_PATCH 6) +elseif(GST_VERSION_MINOR EQUAL 20) + set(GST_VERSION_PATCH 7) +elseif(GST_VERSION_MINOR EQUAL 22) + set(GST_VERSION_PATCH 12) +elseif(GST_VERSION_MINOR EQUAL 24) + set(GST_VERSION_PATCH 7) +endif() + +set(GST_PLUGINS_VERSION ${GST_VERSION_MAJOR}.${GST_VERSION_MINOR}.${GST_VERSION_PATCH}) +cmake_print_variables(GST_PLUGINS_VERSION) diff --git a/cmake/FindLibExiv2.cmake b/cmake/FindLibExiv2.cmake new file mode 100644 index 00000000000..83e1d6b7907 --- /dev/null +++ b/cmake/FindLibExiv2.cmake @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2018 Christophe Giboudeaux +# SPDX-FileCopyrightText: 2010 Alexander Neundorf +# SPDX-FileCopyrightText: 2008 Gilles Caulier +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +FindLibExiv2 +------------ + +Try to find the Exiv2 library. + +This will define the following variables: + +``LibExiv2_FOUND`` + True if (the requested version of) Exiv2 is available + +``LibExiv2_VERSION`` + The version of Exiv2 + +``LibExiv2_INCLUDE_DIRS`` + The include dirs of Exiv2 for use with target_include_directories() + +``LibExiv2_LIBRARIES`` + The Exiv2 library for use with target_link_libraries(). + This can be passed to target_link_libraries() instead of + the ``LibExiv2::LibExiv2`` target + +If ``LibExiv2_FOUND`` is TRUE, it will also define the following imported +target: + +``LibExiv2::LibExiv2`` + The Exiv2 library + +In general we recommend using the imported target, as it is easier to use. +Bear in mind, however, that if the target is in the link interface of an +exported library, it must be made available by the package config file. + +Since 5.53.0. +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_EXIV2 QUIET exiv2) + +find_path(LibExiv2_INCLUDE_DIRS NAMES exiv2/exif.hpp + HINTS ${PC_EXIV2_INCLUDEDIR} +) + +find_library(LibExiv2_LIBRARIES NAMES exiv2 libexiv2 + HINTS ${PC_EXIV2_LIBRARY_DIRS} +) + +set(LibExiv2_VERSION ${PC_EXIV2_VERSION}) + +if(NOT LibExiv2_VERSION AND DEFINED LibExiv2_INCLUDE_DIRS) + # With exiv >= 0.27, the version #defines are in exv_conf.h instead of version.hpp + foreach(_exiv2_version_file "version.hpp" "exv_conf.h") + if(EXISTS "${LibExiv2_INCLUDE_DIRS}/exiv2/${_exiv2_version_file}") + file(READ "${LibExiv2_INCLUDE_DIRS}/exiv2/${_exiv2_version_file}" _exiv_version_file_content) + string(REGEX MATCH "#define EXIV2_MAJOR_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_MAJOR_VERSION_MATCH ${_exiv_version_file_content}) + string(REGEX MATCH "#define EXIV2_MINOR_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_MINOR_VERSION_MATCH ${_exiv_version_file_content}) + string(REGEX MATCH "#define EXIV2_PATCH_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_PATCH_VERSION_MATCH ${_exiv_version_file_content}) + if(EXIV2_MAJOR_VERSION_MATCH) + string(REGEX REPLACE ".*_MAJOR_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1" EXIV2_MAJOR_VERSION ${EXIV2_MAJOR_VERSION_MATCH}) + string(REGEX REPLACE ".*_MINOR_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1" EXIV2_MINOR_VERSION ${EXIV2_MINOR_VERSION_MATCH}) + string(REGEX REPLACE ".*_PATCH_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1" EXIV2_PATCH_VERSION ${EXIV2_PATCH_VERSION_MATCH}) + endif() + endif() + endforeach() + + set(LibExiv2_VERSION "${EXIV2_MAJOR_VERSION}.${EXIV2_MINOR_VERSION}.${EXIV2_PATCH_VERSION}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibExiv2 + FOUND_VAR LibExiv2_FOUND + REQUIRED_VARS LibExiv2_LIBRARIES LibExiv2_INCLUDE_DIRS + VERSION_VAR LibExiv2_VERSION +) + +mark_as_advanced(LibExiv2_INCLUDE_DIRS LibExiv2_LIBRARIES) + +if(LibExiv2_FOUND AND NOT TARGET LibExiv2::LibExiv2) + add_library(LibExiv2::LibExiv2 UNKNOWN IMPORTED) + set_target_properties(LibExiv2::LibExiv2 PROPERTIES + IMPORTED_LOCATION "${LibExiv2_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${LibExiv2_INCLUDE_DIRS}" + ) + if (LibExiv2_VERSION VERSION_LESS 0.28.0) + # exiv2 0.27 or older still uses std::auto_ptr, which is no longer available + # by default when using newer C++ versions + set_target_properties(LibExiv2::LibExiv2 PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR=1;_HAS_AUTO_PTR_ETC=1" + ) + endif() +endif() + +include(FeatureSummary) +set_package_properties(LibExiv2 PROPERTIES + URL "https://www.exiv2.org" + DESCRIPTION "Image metadata support" +) diff --git a/cmake/FindWaylandProtocols.cmake b/cmake/FindWaylandProtocols.cmake new file mode 100644 index 00000000000..a4449885d99 --- /dev/null +++ b/cmake/FindWaylandProtocols.cmake @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: 2019 Vlad Zahorodnii +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +FindWaylandProtocols +-------------------- + +Try to find wayland-protocols on a Unix system. + +This will define the following variables: + +``WaylandProtocols_FOUND`` + True if (the requested version of) wayland-protocols is available +``WaylandProtocols_VERSION`` + The version of wayland-protocols +``WaylandProtocols_DATADIR`` + The wayland protocols data directory +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PKG_wayland_protocols QUIET wayland-protocols) + +set(WaylandProtocols_VERSION ${PKG_wayland_protocols_VERSION}) +pkg_get_variable(WaylandProtocols_DATADIR wayland-protocols pkgdatadir) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WaylandProtocols + FOUND_VAR WaylandProtocols_FOUND + REQUIRED_VARS WaylandProtocols_DATADIR + VERSION_VAR WaylandProtocols_VERSION +) + +include(FeatureSummary) +set_package_properties(WaylandProtocols PROPERTIES + DESCRIPTION "Specifications of extended Wayland protocols" + URL "https://wayland.freedesktop.org/" +) diff --git a/cmake/Qt6QGCConfiguration.cmake b/cmake/Qt6QGCConfiguration.cmake index a170f4f4399..f00bcf3ad39 100644 --- a/cmake/Qt6QGCConfiguration.cmake +++ b/cmake/Qt6QGCConfiguration.cmake @@ -54,3 +54,7 @@ endif() include(CMakePrintHelpers) cmake_print_variables(QT_VERSION QT_MKSPEC QT_LIBRARY_HINTS) + +# if(ANDROID) + # set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT}) +# endif() diff --git a/src/Settings/CMakeLists.txt b/src/Settings/CMakeLists.txt index 9db4d8cf668..3a9b440c2c2 100644 --- a/src/Settings/CMakeLists.txt +++ b/src/Settings/CMakeLists.txt @@ -51,6 +51,7 @@ target_link_libraries(Settings PRIVATE Qt6::Multimedia API + GStreamerReceiver QmlControls Vehicle VideoManager diff --git a/src/Settings/VideoDecoderOptions.h b/src/Settings/VideoDecoderOptions.h deleted file mode 100644 index f8ef9fec947..00000000000 --- a/src/Settings/VideoDecoderOptions.h +++ /dev/null @@ -1,20 +0,0 @@ -/**************************************************************************** -* - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -#pragma once - - -enum VideoDecoderOptions { - ForceVideoDecoderDefault = 0, - ForceVideoDecoderSoftware, - ForceVideoDecoderNVIDIA, - ForceVideoDecoderVAAPI, - ForceVideoDecoderDirectX3D, - ForceVideoDecoderVideoToolbox, -}; diff --git a/src/Settings/VideoSettings.cc b/src/Settings/VideoSettings.cc index 3b0b0df594a..2d8931c6009 100644 --- a/src/Settings/VideoSettings.cc +++ b/src/Settings/VideoSettings.cc @@ -14,6 +14,10 @@ #include #include +#ifdef QGC_GST_STREAMING +#include "GStreamer.h" +#endif + #ifndef QGC_DISABLE_UVC #include #include @@ -56,27 +60,29 @@ DECLARE_SETTINGGROUP(Video, "Video") _nameToMetaDataMap[videoSourceName]->setEnumInfo(videoSourceCookedList, videoSourceList); +#ifdef QGC_GST_STREAMING const QVariantList removeForceVideoDecodeList{ #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - VideoDecoderOptions::ForceVideoDecoderDirectX3D, - VideoDecoderOptions::ForceVideoDecoderVideoToolbox, + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, #elif defined(Q_OS_WIN) - VideoDecoderOptions::ForceVideoDecoderVAAPI, - VideoDecoderOptions::ForceVideoDecoderVideoToolbox, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, #elif defined(Q_OS_MAC) - VideoDecoderOptions::ForceVideoDecoderDirectX3D, - VideoDecoderOptions::ForceVideoDecoderVAAPI, + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, #elif defined(Q_OS_ANDROID) - VideoDecoderOptions::ForceVideoDecoderDirectX3D, - VideoDecoderOptions::ForceVideoDecoderVideoToolbox, - VideoDecoderOptions::ForceVideoDecoderVAAPI, - VideoDecoderOptions::ForceVideoDecoderNVIDIA, + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, + GStreamer::VideoDecoderOptions::ForceVideoDecoderNVIDIA, #endif }; - for(const auto& value : removeForceVideoDecodeList) { + for (const auto &value : removeForceVideoDecodeList) { _nameToMetaDataMap[forceVideoDecoderName]->removeEnumInfo(value); } +#endif // Set default value for videoSource _setDefaults(); diff --git a/src/Settings/VideoSettings.h b/src/Settings/VideoSettings.h index daed65b6a6a..51437f6cb86 100644 --- a/src/Settings/VideoSettings.h +++ b/src/Settings/VideoSettings.h @@ -10,7 +10,6 @@ #pragma once #include "SettingsGroup.h" -#include "VideoDecoderOptions.h" class VideoSettings : public SettingsGroup { @@ -37,8 +36,6 @@ class VideoSettings : public SettingsGroup DEFINE_SETTINGFACT(lowLatencyMode) DEFINE_SETTINGFACT(forceVideoDecoder) - Q_ENUM(VideoDecoderOptions) - Q_PROPERTY(bool streamConfigured READ streamConfigured NOTIFY streamConfiguredChanged) Q_PROPERTY(QString rtspVideoSource READ rtspVideoSource CONSTANT) Q_PROPERTY(QString udp264VideoSource READ udp264VideoSource CONSTANT) diff --git a/src/VideoManager/VideoManager.cc b/src/VideoManager/VideoManager.cc index ee2502322ec..b3187332eed 100644 --- a/src/VideoManager/VideoManager.cc +++ b/src/VideoManager/VideoManager.cc @@ -21,7 +21,6 @@ #include "SubtitleWriter.h" #ifdef QGC_GST_STREAMING #include "GStreamer.h" -#include "VideoDecoderOptions.h" #else #include "GLVideoItemStub.h" #endif @@ -38,6 +37,7 @@ #include #include +#include QGC_LOGGING_CATEGORY(VideoManagerLog, "qgc.videomanager.videomanager") @@ -118,7 +118,7 @@ VideoManager::setToolbox(QGCToolbox *toolbox) connect(pVehicleMgr, &MultiVehicleManager::activeVehicleChanged, this, &VideoManager::_setActiveVehicle); #ifdef QGC_GST_STREAMING - GStreamer::blacklist(static_cast(_videoSettings->forceVideoDecoder()->rawValue().toInt())); + GStreamer::blacklist(static_cast(_videoSettings->forceVideoDecoder()->rawValue().toInt())); #endif int index = 0; diff --git a/src/VideoManager/VideoReceiver/GStreamer/CMakeLists.txt b/src/VideoManager/VideoReceiver/GStreamer/CMakeLists.txt index f1f723be955..d77333d3993 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/GStreamer/CMakeLists.txt @@ -20,8 +20,11 @@ endif() target_sources(GStreamerReceiver PRIVATE - gstqgc.c - gstqgcvideosinkbin.c + gstqgc.cc + gstqgcelement.cc + gstqgcelements.h + gstqgcvideosinkbin.cc + gstqgcvideosinkbin.h GStreamer.cc GStreamer.h GstVideoReceiver.cc @@ -31,8 +34,8 @@ target_sources(GStreamerReceiver if(IOS) target_sources(GStreamerReceiver PRIVATE - gst_ios_init.h gst_ios_init.m + gst_ios_init.h ) endif() @@ -47,6 +50,3 @@ target_link_libraries(GStreamerReceiver ) target_compile_definitions(QGC PUBLIC QGC_GST_STREAMING) -if(CMAKE_BUILD_TYPE STREQUAL "Release") - target_compile_definitions(GStreamerReceiver PRIVATE QGC_INSTALL_RELEASE) -endif() diff --git a/src/VideoManager/VideoReceiver/GStreamer/GLVideoItemStub.h b/src/VideoManager/VideoReceiver/GStreamer/GLVideoItemStub.h index 38d58d46881..63e454b66e7 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/GLVideoItemStub.h +++ b/src/VideoManager/VideoReceiver/GStreamer/GLVideoItemStub.h @@ -18,7 +18,5 @@ class GLVideoItemStub : public QQuickItem public: GLVideoItemStub(QQuickItem *parent = nullptr) : - QQuickItem(parent) - {} - ~GLVideoItemStub() = default; + QQuickItem(parent) {} }; diff --git a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc index 0e2784c9831..79b485c7aa9 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc +++ b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc @@ -7,30 +7,54 @@ * ****************************************************************************/ - -/** - * @file - * @brief QGC Video Streaming Initialization - * @author Gus Grubba - */ - #include "GStreamer.h" #include "GstVideoReceiver.h" #include "QGCLoggingCategory.h" +#ifdef Q_OS_IOS +#include "gst_ios_init.h" +#endif -#include +#include -QGC_LOGGING_CATEGORY(GStreamerLog, "GStreamerLog") -QGC_LOGGING_CATEGORY(GStreamerAPILog, "GStreamerAPILog") +QGC_LOGGING_CATEGORY(GStreamerLog, "qgc.videomanager.videoreceiver.gstreamer") +QGC_LOGGING_CATEGORY(GStreamerAPILog, "qgc.videomanager.videoreceiver.gstreamer.api") -static void qt_gst_log(GstDebugCategory * category, - GstDebugLevel level, - const gchar * file, - const gchar * function, - gint line, - GObject * object, - GstDebugMessage * message, - gpointer data) +G_BEGIN_DECLS +#ifdef QGC_GST_STATIC_BUILD +GST_PLUGIN_STATIC_DECLARE(coreelements); +GST_PLUGIN_STATIC_DECLARE(playback); +GST_PLUGIN_STATIC_DECLARE(libav); +GST_PLUGIN_STATIC_DECLARE(rtp); +GST_PLUGIN_STATIC_DECLARE(rtsp); +GST_PLUGIN_STATIC_DECLARE(udp); +GST_PLUGIN_STATIC_DECLARE(videoparsersbad); +GST_PLUGIN_STATIC_DECLARE(x264); +GST_PLUGIN_STATIC_DECLARE(rtpmanager); +GST_PLUGIN_STATIC_DECLARE(isomp4); +GST_PLUGIN_STATIC_DECLARE(matroska); +GST_PLUGIN_STATIC_DECLARE(mpegtsdemux); +GST_PLUGIN_STATIC_DECLARE(opengl); +GST_PLUGIN_STATIC_DECLARE(tcp); +GST_PLUGIN_STATIC_DECLARE(asf); +GST_PLUGIN_STATIC_DECLARE(va); +#ifdef Q_OS_ANDROID +GST_PLUGIN_STATIC_DECLARE(androidmedia); +#elif defined(Q_OS_IOS) +GST_PLUGIN_STATIC_DECLARE(applemedia); +#endif // Q_OS_ANDROID +#endif // QGC_GST_STATIC_BUILD +GST_PLUGIN_STATIC_DECLARE(qml6); +GST_PLUGIN_STATIC_DECLARE(qgc); +G_END_DECLS + +static void _QtGstLog(GstDebugCategory *category, + GstDebugLevel level, + const gchar *file, + const gchar *function, + gint line, + GObject *object, + GstDebugMessage *message, + gpointer data) { Q_UNUSED(data); @@ -40,7 +64,7 @@ static void qt_gst_log(GstDebugCategory * category, QMessageLogger log(file, line, function); - char* object_info = gst_info_strdup_printf("%" GST_PTR_FORMAT, static_cast(object)); + char *object_info = gst_info_strdup_printf("%" GST_PTR_FORMAT, static_cast(object)); switch (level) { default: @@ -66,165 +90,116 @@ static void qt_gst_log(GstDebugCategory * category, object_info = nullptr; } -#if defined(Q_OS_IOS) -#include "gst_ios_init.h" -#endif - -#include "VideoReceiver.h" - -G_BEGIN_DECLS -// The static plugins we use -#ifdef QGC_GST_STATIC_BUILD - GST_PLUGIN_STATIC_DECLARE(coreelements); - GST_PLUGIN_STATIC_DECLARE(playback); - GST_PLUGIN_STATIC_DECLARE(libav); - GST_PLUGIN_STATIC_DECLARE(rtp); - GST_PLUGIN_STATIC_DECLARE(rtsp); - GST_PLUGIN_STATIC_DECLARE(udp); - GST_PLUGIN_STATIC_DECLARE(videoparsersbad); - GST_PLUGIN_STATIC_DECLARE(x264); - GST_PLUGIN_STATIC_DECLARE(rtpmanager); - GST_PLUGIN_STATIC_DECLARE(isomp4); - GST_PLUGIN_STATIC_DECLARE(matroska); - GST_PLUGIN_STATIC_DECLARE(mpegtsdemux); - GST_PLUGIN_STATIC_DECLARE(opengl); - GST_PLUGIN_STATIC_DECLARE(tcp); -#if defined(Q_OS_ANDROID) - GST_PLUGIN_STATIC_DECLARE(androidmedia); -#elif defined(Q_OS_IOS) - GST_PLUGIN_STATIC_DECLARE(applemedia); -#endif -#endif - GST_PLUGIN_STATIC_DECLARE(qml6); - GST_PLUGIN_STATIC_DECLARE(qgc); -G_END_DECLS - -#if (defined(Q_OS_MAC) && defined(QGC_INSTALL_RELEASE)) || defined(Q_OS_WIN) || defined(Q_OS_LINUX) -static void qgcputenv(const QString& key, const QString& root, const QString& path) +static void qgcputenv(const QString &key, const QString &root, const QString &path = "") { const QString value = root + path; - qputenv(key.toStdString().c_str(), QByteArray(value.toStdString().c_str())); + (void) qputenv(key.toStdString().c_str(), QByteArray(value.toStdString().c_str())); } -#endif -void -GStreamer::blacklist(VideoDecoderOptions option) +void GStreamer::blacklist(VideoDecoderOptions option) { - GstRegistry* registry = gst_registry_get(); + GstRegistry* const registry = gst_registry_get(); - if (registry == nullptr) { + if (!registry) { qCCritical(GStreamerLog) << "Failed to get gstreamer registry."; return; } - auto changeRank = [registry](const char* featureName, uint16_t rank) { - GstPluginFeature* feature = gst_registry_lookup_feature(registry, featureName); - if (feature == nullptr) { + auto changeRank = [registry](const char *featureName, uint16_t rank) { + GstPluginFeature* const feature = gst_registry_lookup_feature(registry, featureName); + if (!feature) { qCDebug(GStreamerLog) << "Failed to change ranking of feature. Featuer does not exist:" << featureName; return; } qCDebug(GStreamerLog) << "Changing feature (" << featureName << ") to use rank:" << rank; gst_plugin_feature_set_rank(feature, rank); - gst_registry_add_feature(registry, feature); + (void) gst_registry_add_feature(registry, feature); gst_object_unref(feature); }; - // Set rank for specific features changeRank("bcmdec", GST_RANK_NONE); switch (option) { - case ForceVideoDecoderDefault: - break; - case ForceVideoDecoderSoftware: - for(auto name : {"avdec_h264", "avdec_h265"}) { - changeRank(name, GST_RANK_PRIMARY + 1); - } - break; - case ForceVideoDecoderVAAPI: - for(auto name : {"vaapimpeg2dec", "vaapimpeg4dec", "vaapih263dec", "vaapih264dec", "vaapih265dec", "vaapivc1dec"}) { - changeRank(name, GST_RANK_PRIMARY + 1); - } - break; - case ForceVideoDecoderNVIDIA: - for(auto name : {"nvh265dec", "nvh265sldec", "nvh264dec", "nvh264sldec"}) { - changeRank(name, GST_RANK_PRIMARY + 1); - } - break; - case ForceVideoDecoderDirectX3D: - for(auto name : {"d3d11vp9dec", "d3d11h265dec", "d3d11h264dec"}) { - changeRank(name, GST_RANK_PRIMARY + 1); - } - break; - case ForceVideoDecoderVideoToolbox: - changeRank("vtdec", GST_RANK_PRIMARY + 1); - break; - default: - qCWarning(GStreamerLog) << "Can't handle decode option:" << option; + case ForceVideoDecoderDefault: + break; + case ForceVideoDecoderSoftware: + for (const char *name : {"avdec_h264", "avdec_h265"}) { + changeRank(name, GST_RANK_PRIMARY + 1); + } + break; + case ForceVideoDecoderVAAPI: + for (const char *name : {"vaapimpeg2dec", "vaapimpeg4dec", "vaapih263dec", "vaapih264dec", "vaapih265dec", "vaapivc1dec"}) { + changeRank(name, GST_RANK_PRIMARY + 1); + } + break; + case ForceVideoDecoderNVIDIA: + for (const char *name : {"nvh265dec", "nvh265sldec", "nvh264dec", "nvh264sldec"}) { + changeRank(name, GST_RANK_PRIMARY + 1); + } + break; + case ForceVideoDecoderDirectX3D: + for (const char *name : {"d3d11vp9dec", "d3d11h265dec", "d3d11h264dec"}) { + changeRank(name, GST_RANK_PRIMARY + 1); + } + break; + case ForceVideoDecoderVideoToolbox: + changeRank("vtdec", GST_RANK_PRIMARY + 1); + break; + default: + qCWarning(GStreamerLog) << "Can't handle decode option:" << option; + break; } } -void -GStreamer::initialize(int argc, char* argv[], int debuglevel) +void GStreamer::initialize(int argc, char *argv[], int debuglevel) { - qRegisterMetaType("STATUS"); + (void) qRegisterMetaType("STATUS"); -#ifdef Q_OS_MAC - #ifdef QGC_INSTALL_RELEASE - const QString currentDir = QCoreApplication::applicationDirPath(); - qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no", ""); - qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/libexec/gstreamer-1.0/gst-plugin-scanner"); - qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/libexec/gstreamer-1.0/gst-ptp-helper"); - // qgcputenv("GTK_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current"); - qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gio/modules"); - qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); - qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); - qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); - qgcputenv("GST_PLUGIN_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); - #endif -#elif defined(Q_OS_WIN) const QString currentDir = QCoreApplication::applicationDirPath(); - // qgcputenv("GST_PLUGIN_SCANNER", "C:/gstreamer/1.0/msvc_x86_64", "/libexec/gstreamer-1.0/gst-plugin-scanner"); - // qgcputenv("GST_PTP_HELPER_1_0", "C:/gstreamer/1.0/msvc_x86_64", "/libexec/gstreamer-1.0/gst-ptp-helper"); - // qgcputenv("GTK_PATH", "C:/gstreamer/1.0/msvc_x86_64", ""); - // qgcputenv("GIO_EXTRA_MODULES", "C:/gstreamer/1.0/msvc_x86_64", "/lib/gio/modules"); - // qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", "C:/gstreamer/1.0/msvc_x86_64", "/lib/gstreamer-1.0"); - // qgcputenv("GST_PLUGIN_SYSTEM_PATH", "C:/gstreamer/1.0/msvc_x86_64", "/lib/gstreamer-1.0"); - qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, ""); - qgcputenv("GST_PLUGIN_PATH", currentDir, ""); -#elif defined(Q_OS_LINUX) - // const QString currentDir = QCoreApplication::applicationDirPath(); - // qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no", ""); - // qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/../lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner"); - // qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/../lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper"); - // qgcputenv("GTK_PATH", currentDir, ""); - // qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../lib/gio/modules"); - // qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir, "/../lib"); - // qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir, "/../lib"); - // qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, "/../lib"); - // qgcputenv("GST_PLUGIN_PATH", currentDir, "/../lib"); + +#ifndef QGC_INSTALL_RELEASE + qunsetenv("GST_PLUGIN_SYSTEM_PATH_1_0"); + qunsetenv("GST_PLUGIN_SYSTEM_PATH"); + qunsetenv("GST_PLUGIN_PATH_1_0"); + qunsetenv("GST_PLUGIN_PATH"); + Q_UNUSED(currentDir); +#elif defined(Q_OS_MAC) + qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no"); + qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/libexec/gstreamer-1.0/gst-plugin-scanner"); + qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/libexec/gstreamer-1.0/gst-ptp-helper"); + qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gio/modules"); + qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); + qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); + qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); + qgcputenv("GST_PLUGIN_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/Current/lib/gstreamer-1.0"); +#elif defined(Q_OS_WIN) + qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no"); + qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/gst-plugin-scanner"); + qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/gst-ptp-helper"); + qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../lib/gio/modules"); + qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir); + qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir); + qgcputenv("GST_PLUGIN_PATH_1_0", currentDir); + qgcputenv("GST_PLUGIN_PATH", currentDir); #endif - //-- If gstreamer debugging is not configured via environment then use internal QT logging if (qEnvironmentVariableIsEmpty("GST_DEBUG")) { gst_debug_set_default_threshold(static_cast(debuglevel)); gst_debug_remove_log_function(gst_debug_log_default); - gst_debug_add_log_function(qt_gst_log, nullptr, nullptr); + gst_debug_add_log_function(_QtGstLog, nullptr, nullptr); } - // Initialize GStreamer -#if defined(Q_OS_IOS) - //-- iOS specific initialization +#ifdef Q_OS_IOS gst_ios_pre_init(); #endif - GError* error = nullptr; + GError *error = nullptr; if (!gst_init_check(&argc, &argv, &error)) { - qCCritical(GStreamerLog) << "gst_init_check() failed: " << error->message; + qCCritical(GStreamerLog) << "gst_init_check() failed:" << error->message; g_error_free(error); } - // The static plugins we use #ifdef QGC_GST_STATIC_BUILD GST_PLUGIN_STATIC_REGISTER(coreelements); GST_PLUGIN_STATIC_REGISTER(playback); @@ -240,30 +215,25 @@ GStreamer::initialize(int argc, char* argv[], int debuglevel) GST_PLUGIN_STATIC_REGISTER(mpegtsdemux); GST_PLUGIN_STATIC_REGISTER(opengl); GST_PLUGIN_STATIC_REGISTER(tcp); - -#if defined(Q_OS_ANDROID) + GST_PLUGIN_STATIC_REGISTER(asf); + GST_PLUGIN_STATIC_REGISTER(va); +#ifdef Q_OS_ANDROID GST_PLUGIN_STATIC_REGISTER(androidmedia); #elif defined(Q_OS_IOS) GST_PLUGIN_STATIC_REGISTER(applemedia); -#endif -#endif - -#if defined(Q_OS_IOS) gst_ios_post_init(); -#endif - +#endif // Q_OS_ANDROID +#endif // QGC_GST_STATIC_BUILD GST_PLUGIN_STATIC_REGISTER(qml6); GST_PLUGIN_STATIC_REGISTER(qgc); } -void* -GStreamer::createVideoSink(QObject* parent, QQuickItem* widget) +void *GStreamer::createVideoSink(QObject *parent, QQuickItem *widget) { Q_UNUSED(parent) - GstElement* sink; - - if ((sink = gst_element_factory_make("qgcvideosinkbin", nullptr)) != nullptr) { + GstElement* const sink = gst_element_factory_make("qgcvideosinkbin", nullptr); + if (sink) { g_object_set(sink, "widget", widget, NULL); } else { qCCritical(GStreamerLog) << "gst_element_factory_make('qgcvideosinkbin') failed"; @@ -272,17 +242,14 @@ GStreamer::createVideoSink(QObject* parent, QQuickItem* widget) return sink; } -void -GStreamer::releaseVideoSink(void* sink) +void GStreamer::releaseVideoSink(void *sink) { - if (sink != nullptr) { + if (sink) { gst_object_unref(GST_ELEMENT(sink)); } } -VideoReceiver* -GStreamer::createVideoReceiver(QObject* parent) +VideoReceiver *GStreamer::createVideoReceiver(QObject *parent) { - Q_UNUSED(parent) - return new GstVideoReceiver(nullptr); + return new GstVideoReceiver(parent); } diff --git a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h index 71b185b18f5..a7af6d21ca8 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h +++ b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h @@ -10,20 +10,27 @@ #pragma once #include -#include - -#include "Settings/VideoDecoderOptions.h" Q_DECLARE_LOGGING_CATEGORY(GStreamerLog) Q_DECLARE_LOGGING_CATEGORY(GStreamerAPILog) class VideoReceiver; +class QQuickItem; class GStreamer { public: + enum VideoDecoderOptions { + ForceVideoDecoderDefault = 0, + ForceVideoDecoderSoftware, + ForceVideoDecoderNVIDIA, + ForceVideoDecoderVAAPI, + ForceVideoDecoderDirectX3D, + ForceVideoDecoderVideoToolbox, + }; + static void blacklist(VideoDecoderOptions option); - static void initialize(int argc, char* argv[], int debuglevel); - static void* createVideoSink(QObject* parent, QQuickItem* widget); - static void releaseVideoSink(void* sink); - static VideoReceiver* createVideoReceiver(QObject* parent); + static void initialize(int argc, char *argv[], int debuglevel); + static void *createVideoSink(QObject *parent, QQuickItem *widget); + static void releaseVideoSink(void *sink); + static VideoReceiver *createVideoReceiver(QObject *parent = nullptr); }; diff --git a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.h b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.h index 2f86cdb70c6..b1379bf20c4 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.h +++ b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.h @@ -13,7 +13,9 @@ G_BEGIN_DECLS -void gst_ios_pre_init(void); -void gst_ios_post_init(void); +void gst_ios_pre_init(); + +/// Lower the ranks of filesrc and giosrc so iosavassetsrc is tried first in gst_element_make_from_uri() for file:// +void gst_ios_post_init(); G_END_DECLS diff --git a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m index 6158e1bca87..76a1f221826 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m +++ b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m @@ -1,8 +1,23 @@ +/**************************************************************************** + * + * (c) 2009-2024 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + #import #import #include "gst_ios_init.h" +#define GST_IOS_GIO_MODULE_GNUTLS +#if defined(GST_IOS_GIO_MODULE_GNUTLS) + #include + GST_G_IO_MODULE_DECLARE(gnutls); +#endif + G_BEGIN_DECLS #define GST_G_IO_MODULE_DECLARE(name) \ @@ -13,68 +28,60 @@ extern void G_PASTE(g_io_module_, G_PASTE(name, _load_static)) (void) G_END_DECLS -#define GST_IOS_GIO_MODULE_GNUTLS +void gst_ios_pre_init() +{ + const NSString *const resources = [[NSBundle mainBundle] resourcePath]; + const NSString *const tmp = NSTemporaryDirectory(); + const NSString *const cache = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; + const NSString *const docs = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; -#if defined(GST_IOS_GIO_MODULE_GNUTLS) - #include - GST_G_IO_MODULE_DECLARE(gnutls); -#endif + const gchar *const resources_dir = [resources UTF8String]; + const gchar *const tmp_dir = [tmp UTF8String]; + const gchar *const cache_dir = [cache UTF8String]; + const gchar *const docs_dir = [docs UTF8String]; -void gst_ios_pre_init(void) -{ - NSString *resources = [[NSBundle mainBundle] resourcePath]; - NSString *tmp = NSTemporaryDirectory(); - NSString *cache = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; - NSString *docs = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; - - const gchar *resources_dir = [resources UTF8String]; - const gchar *tmp_dir = [tmp UTF8String]; - const gchar *cache_dir = [cache UTF8String]; - const gchar *docs_dir = [docs UTF8String]; - gchar *ca_certificates; - - g_setenv ("TMP", tmp_dir, TRUE); - g_setenv ("TEMP", tmp_dir, TRUE); - g_setenv ("TMPDIR", tmp_dir, TRUE); - g_setenv ("XDG_RUNTIME_DIR", resources_dir, TRUE); - g_setenv ("XDG_CACHE_HOME", cache_dir, TRUE); - - g_setenv ("HOME", docs_dir, TRUE); - g_setenv ("XDG_DATA_DIRS", resources_dir, TRUE); - g_setenv ("XDG_CONFIG_DIRS", resources_dir, TRUE); - g_setenv ("XDG_CONFIG_HOME", cache_dir, TRUE); - g_setenv ("XDG_DATA_HOME", resources_dir, TRUE); - g_setenv ("FONTCONFIG_PATH", resources_dir, TRUE); - - ca_certificates = g_build_filename (resources_dir, "ssl", "certs", "ca-certificates.crt", NULL); - g_setenv ("CA_CERTIFICATES", ca_certificates, TRUE); - g_free (ca_certificates); + g_setenv("TMP", tmp_dir, TRUE); + g_setenv("TEMP", tmp_dir, TRUE); + g_setenv("TMPDIR", tmp_dir, TRUE); + g_setenv("XDG_RUNTIME_DIR", resources_dir, TRUE); + g_setenv("XDG_CACHE_HOME", cache_dir, TRUE); + + g_setenv("HOME", docs_dir, TRUE); + g_setenv("XDG_DATA_DIRS", resources_dir, TRUE); + g_setenv("XDG_CONFIG_DIRS", resources_dir, TRUE); + g_setenv("XDG_CONFIG_HOME", cache_dir, TRUE); + g_setenv("XDG_DATA_HOME", resources_dir, TRUE); + g_setenv("FONTCONFIG_PATH", resources_dir, TRUE); + + gchar *const ca_certificates = g_build_filename(resources_dir, "ssl", "certs", "ca-certificates.crt", NULL); + g_setenv("CA_CERTIFICATES", ca_certificates, TRUE); + g_free(ca_certificates); } -void gst_ios_post_init(void) +void gst_ios_post_init() { - GstPluginFeature *plugin; - GstRegistry *reg; - /* Lower the ranks of filesrc and giosrc so iosavassetsrc is - * tried first in gst_element_make_from_uri() for file:// */ - #if defined(GST_IOS_GIO_MODULE_GNUTLS) GST_G_IO_MODULE_LOAD(gnutls); #endif - reg = gst_registry_get(); - plugin = gst_registry_lookup_feature(reg, "filesrc"); - if (plugin) - gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY); - plugin = gst_registry_lookup_feature(reg, "giosrc"); - if (plugin) - gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY-1); - if (!gst_registry_lookup_feature(reg, "vtdec_hw")) { + GstRegistry *const reg = gst_registry_get(); + GstPluginFeature *plugin = gst_registry_lookup_feature(reg, "filesrc"); + if (plugin) { + gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY); + } + + plugin = gst_registry_lookup_feature(reg, "giosrc"); + if (plugin) { + gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY - 1); + } + + if (!gst_registry_lookup_feature(reg, "vtdec_hw")) { /* Usually there is no vtdec_hw plugin on iOS - in that case * we are increasing vtdec rank since VideoToolbox on iOS * tries to use hardware implementation first */ - plugin = gst_registry_lookup_feature(reg, "vtdec"); - if (plugin) - gst_plugin_feature_set_rank(plugin, GST_RANK_PRIMARY + 1); + plugin = gst_registry_lookup_feature(reg, "vtdec"); + if (plugin) { + gst_plugin_feature_set_rank(plugin, GST_RANK_PRIMARY + 1); + } } } diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgc.c b/src/VideoManager/VideoReceiver/GStreamer/gstqgc.c deleted file mode 100644 index f8b8cf5d813..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqgc.c +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2020 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/** - * @file - * @brief GStreamer plugin for QGC's Video Receiver - * @author Andrew Voznyts - * @author Tomaz Canabrava - */ - -#include - -gboolean gst_qgc_video_sink_bin_plugin_init(GstPlugin *plugin); - -static gboolean -plugin_init(GstPlugin* plugin) -{ - if (!gst_qgc_video_sink_bin_plugin_init(plugin)) { - return FALSE; - } - - return TRUE; -} - -#define PACKAGE "QGC Video Receiver" -#define PACKAGE_VERSION "current" -#define GST_LICENSE "LGPL" -#define GST_PACKAGE_NAME "GStreamer plugin for QGC's Video Receiver" -#define GST_PACKAGE_ORIGIN "http://qgroundcontrol.com/" - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - qgc, "QGC Video Receiver plugin", - plugin_init, PACKAGE_VERSION, - GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgc.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqgc.cc new file mode 100644 index 00000000000..09dc771b85a --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgc.cc @@ -0,0 +1,39 @@ +/**************************************************************************** + * + * (c) 2009-2024 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "gstqgcelements.h" +#include "gstqgcvideosinkbin.h" + +static gboolean +plugin_init(GstPlugin *plugin) +{ + gboolean ret = FALSE; + + ret |= GST_ELEMENT_REGISTER(qgcvideosinkbin, plugin); + + return ret; +} + +#define PACKAGE "QGC Video Receiver" +#define VERSION "current" +#define GST_LICENSE "LGPL" +#define GST_PACKAGE_NAME "GStreamer plugin for QGC's Video Receiver" +#define GST_PACKAGE_ORIGIN "https://qgroundcontrol.com/" + +GST_PLUGIN_DEFINE( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + qgc, + "QGC Video Receiver Plugin", + plugin_init, + VERSION, + GST_LICENSE, + GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN +) diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc new file mode 100644 index 00000000000..68154a64f98 --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc @@ -0,0 +1,11 @@ +#include "gstqgcelements.h" +#include "gstqgcvideosinkbin.h" + +void +qgc_element_init(GstPlugin *plugin) +{ + static gsize res = FALSE; + if (g_once_init_enter(&res)) { + g_once_init_leave(&res, TRUE); + } +} diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgcelements.h b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelements.h new file mode 100644 index 00000000000..82befd308cb --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelements.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +void qgc_element_init(GstPlugin *plugin); + +GST_ELEMENT_REGISTER_DECLARE(qgcvideosinkbin); + +G_END_DECLS diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.c b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.cc similarity index 59% rename from src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.c rename to src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.cc index 4e26e158f02..c6198fc14d3 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.c +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.cc @@ -7,38 +7,20 @@ * ****************************************************************************/ -/** - * @file - * @brief GStreamer plugin for QGC's Video Receiver - * @author Andrew Voznyts - * @author Tomaz Canabrava - */ - -#include +#include "gstqgcvideosinkbin.h" +#include "gstqgcelements.h" + #include -#include GST_DEBUG_CATEGORY_STATIC(gst_qgc_video_sink_bin_debug); #define GST_CAT_DEFAULT gst_qgc_video_sink_bin_debug -typedef struct _GstQgcVideoSinkElement GstQgcVideoSinkElement; - -typedef struct _GstQgcVideoSinkBin { - GstBin bin; - GstElement* glupload; - GstElement* qmlglsink; -} GstQgcVideoSinkBin; - -typedef struct _GstQgcVideoSinkBinClass { - GstBinClass parent_class; -} GstQgcVideoSinkBinClass; +static void gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void gst_qgc_video_sink_bin_dispose(GObject *object); +// static void gst_qgc_video_sink_bin_finalize(GObject *object); -#define GST_TYPE_VIDEO_SINK_BIN (_vsb_get_type()) -#define GST_QGC_VIDEO_SINK_BIN_CAST(obj) ((GstQgcVideoSinkBin *)(obj)) -#define GST_QGC_VIDEO_SINK_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_VIDEO_SINK_BIN, GstQgcVideoSinkBin)) -#define GST_QGC_VIDEO_SINK_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VIDEO_SINK_BIN, GstQgcVideoSinkBinClass)) -#define GST_IS_VIDEO_SINK_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VIDEO_SINK_BIN)) -#define GST_IS_VIDEO_SINK_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VIDEO_SINK_BIN)) +static gboolean gst_qgc_video_sink_bin_sink_pad_query(GstPad *pad, GstObject *parent, GstQuery *query); enum { PROP_0, @@ -63,109 +45,60 @@ enum { #define DEFAULT_PAR_D 1 #define DEFAULT_SYNC TRUE -static GstBinClass *parent_class; +#define gst_qgc_video_sink_bin_parent_class parent_class +G_DEFINE_TYPE(GstQgcVideoSinkBin, gst_qgc_video_sink_bin, GST_TYPE_BIN); -static void _vsb_init(GTypeInstance *instanceData, void *vsbVoid); -static void _vsb_dispose(GObject *object); -static void _vsb_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void _vsb_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static GType _vsb_get_type(void); -static void _vsb_class_init(void *klass, void *classData); - -static gboolean -_vsb_sink_pad_query(GstPad* pad, GstObject* parent, GstQuery* query) -{ - GstQgcVideoSinkBin *vsb; - GstElement* element; - - vsb = GST_QGC_VIDEO_SINK_BIN(parent); - - switch (GST_QUERY_TYPE(query)) { - case GST_QUERY_CAPS: - element = vsb->glupload; - break; - case GST_QUERY_CONTEXT: - element = vsb->qmlglsink; - break; - default: - return gst_pad_query_default (pad, parent, query); - } - - if (element == NULL) { - GST_ERROR_OBJECT(vsb, "No element found"); - return FALSE; - } - - GstPad* sinkpad = gst_element_get_static_pad(element, "sink"); - - if (sinkpad == NULL) { - GST_ERROR_OBJECT(vsb, "No sink pad found"); - return FALSE; - } - - const gboolean ret = gst_pad_query(sinkpad, query); - - gst_object_unref(sinkpad); - sinkpad = NULL; - - return ret; -} +// static gboolean qgcvideosinkbin (GstPlugin * plugin); +GST_ELEMENT_REGISTER_DEFINE_WITH_CODE(qgcvideosinkbin, "qgcvideosinkbin", GST_RANK_NONE, GST_TYPE_QGC_VIDEO_SINK_BIN, qgc_element_init(plugin)); static void -_vsb_init(GTypeInstance *instanceData, void *vsbVoid) +gst_qgc_video_sink_bin_init(GstQgcVideoSinkBin *vsb) { - Q_UNUSED(vsbVoid); - - GstQgcVideoSinkBin *vsb; - vsb = (GstQgcVideoSinkBin *)instanceData; - - gboolean initialized = FALSE; - GstElement* glcolorconvert = NULL; - GstPad* pad = NULL; + (void) vsb; + gboolean initialized = FALSE; + GstElement *glcolorconvert = NULL; + GstPad *pad = NULL; do { - if ((vsb->glupload = gst_element_factory_make("glupload", NULL)) == NULL) { + if (!(vsb->glupload = gst_element_factory_make("glupload", NULL))) { GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glupload') failed"); break; } - if ((vsb->qmlglsink = gst_element_factory_make("qml6glsink", NULL)) == NULL) { + if (!(vsb->qmlglsink = gst_element_factory_make("qml6glsink", NULL))) { GST_ERROR_OBJECT(vsb, "gst_element_factory_make('qml6glsink') failed"); break; } - if ((glcolorconvert = gst_element_factory_make("glcolorconvert", NULL)) == NULL) { + if (!(glcolorconvert = gst_element_factory_make("glcolorconvert", NULL))) { GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glcolorconvert' failed)"); break; } - if ((pad = gst_element_get_static_pad(vsb->glupload, "sink")) == NULL) { + if (!(pad = gst_element_get_static_pad(vsb->glupload, "sink"))) { GST_ERROR_OBJECT(vsb, "gst_element_get_static_pad(glupload, 'sink') failed"); break; } - gst_object_ref(vsb->glupload); - gst_object_ref(vsb->qmlglsink); + (void) gst_object_ref(vsb->glupload); + (void) gst_object_ref(vsb->qmlglsink); gst_bin_add_many(GST_BIN(vsb), vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); - gboolean ret = gst_element_link_many(vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); - + const gboolean ret = gst_element_link_many(vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); glcolorconvert = NULL; - if (!ret) { GST_ERROR_OBJECT(vsb, "gst_element_link_many() failed"); break; } - GstPad* ghostpad; - - if ((ghostpad = gst_ghost_pad_new("sink", pad)) == NULL) { + GstPad *ghostpad = NULL; + if (!(ghostpad = gst_ghost_pad_new("sink", pad))) { GST_ERROR_OBJECT(vsb, "gst_ghost_pad_new('sink') failed"); break; } - gst_pad_set_query_function(ghostpad, _vsb_sink_pad_query); + gst_pad_set_query_function(ghostpad, gst_qgc_video_sink_bin_sink_pad_query); if (!gst_element_add_pad(GST_ELEMENT(vsb), ghostpad)) { GST_ERROR_OBJECT(vsb, "gst_element_add_pad() failed"); @@ -175,23 +108,23 @@ _vsb_init(GTypeInstance *instanceData, void *vsbVoid) initialized = TRUE; } while(0); - if (pad != NULL) { + if (pad) { gst_object_unref(pad); pad = NULL; } - if (glcolorconvert != NULL) { + if (glcolorconvert) { gst_object_unref(glcolorconvert); glcolorconvert = NULL; } if (!initialized) { - if (vsb->qmlglsink != NULL) { + if (vsb->qmlglsink) { gst_object_unref(vsb->qmlglsink); vsb->qmlglsink = NULL; } - if (vsb->glupload != NULL) { + if (vsb->glupload) { gst_object_unref(vsb->glupload); vsb->glupload = NULL; } @@ -199,31 +132,95 @@ _vsb_init(GTypeInstance *instanceData, void *vsbVoid) } static void -_vsb_dispose(GObject *object) +gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass * klass) { - GstQgcVideoSinkBin *vsb; + GObjectClass *const gobject_klass = reinterpret_cast(klass); + GstElementClass *const gstelement_klass = reinterpret_cast(klass); - vsb = GST_QGC_VIDEO_SINK_BIN(object); + parent_class = g_type_class_peek_parent((GstBinClass*)klass); - if (vsb->qmlglsink != NULL) { - gst_object_unref(vsb->qmlglsink); - vsb->qmlglsink = NULL; + gobject_klass->dispose = gst_qgc_video_sink_bin_dispose; + gobject_klass->get_property = gst_qgc_video_sink_bin_get_property; + gobject_klass->set_property = gst_qgc_video_sink_bin_set_property; + + g_object_class_install_property(gobject_klass, PROP_ENABLE_LAST_SAMPLE, + g_param_spec_boolean(PROP_ENABLE_LAST_SAMPLE_NAME, "Enable Last Buffer", + "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property(gobject_klass, PROP_LAST_SAMPLE, + g_param_spec_boxed(PROP_LAST_SAMPLE_NAME, "Last Sample", + "The last sample received in the sink", GST_TYPE_SAMPLE, + static_cast(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property(gobject_klass, PROP_WIDGET, + g_param_spec_pointer(PROP_WIDGET_NAME, "QQuickItem", + "The QQuickItem to place in the object hierarchy", + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property(gobject_klass, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean(PROP_FORCE_ASPECT_RATIO_NAME, "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + DEFAULT_FORCE_ASPECT_RATIO, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property(gobject_klass, PROP_PIXEL_ASPECT_RATIO, + gst_param_spec_fraction(PROP_PIXEL_ASPECT_RATIO_NAME, "Pixel Aspect Ratio", + "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D, + G_MAXINT, 1, 1, 1, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property(gobject_klass, PROP_SYNC, + g_param_spec_boolean(PROP_SYNC_NAME, "Sync", + "Sync on the clock", DEFAULT_SYNC, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + gst_element_class_set_static_metadata(gstelement_klass, + "QGC Video Sink Bin", "Sink/Video/Bin", + "Video rendering for QGC", + "Andrew Voznytsa , Tomaz Canabrava "); +} + +static gboolean +gst_qgc_video_sink_bin_sink_pad_query(GstPad *pad, GstObject *parent, GstQuery *query) +{ + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(parent); + GstElement *element = NULL; + + switch (GST_QUERY_TYPE(query)) { + case GST_QUERY_CAPS: + element = vsb->glupload; + break; + case GST_QUERY_CONTEXT: + element = vsb->qmlglsink; + break; + default: + return gst_pad_query_default(pad, parent, query); } - if (vsb->glupload != NULL) { - gst_object_unref(vsb->glupload); - vsb->glupload = NULL; + if (!element) { + GST_ERROR_OBJECT(vsb, "No element found"); + return FALSE; } - G_OBJECT_CLASS(parent_class)->dispose(object); + GstPad *sinkpad = gst_element_get_static_pad(element, "sink"); + if (!sinkpad) { + GST_ERROR_OBJECT(vsb, "No sink pad found"); + return FALSE; + } + + const gboolean ret = gst_pad_query(sinkpad, query); + + gst_object_unref(sinkpad); + sinkpad = NULL; + + return ret; } static void -_vsb_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GstQgcVideoSinkBin *vsb; - - vsb = GST_QGC_VIDEO_SINK_BIN(object); + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(object); switch (prop_id) { case PROP_ENABLE_LAST_SAMPLE: @@ -279,11 +276,9 @@ _vsb_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *psp } static void -_vsb_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GstQgcVideoSinkBin *vsb; - - vsb = GST_QGC_VIDEO_SINK_BIN(object); + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(object); switch (prop_id) { case PROP_ENABLE_LAST_SAMPLE: @@ -307,88 +302,20 @@ _vsb_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpe } } -static GType -_vsb_get_type(void) -{ - static GType _vsb_type = 0; - - if (!_vsb_type) { - static const GTypeInfo _vsb_info = { - sizeof(GstQgcVideoSinkBinClass), - NULL, - NULL, - (GClassInitFunc)_vsb_class_init, - NULL, - NULL, - sizeof(GstQgcVideoSinkBin), - 0, - (GInstanceInitFunc)_vsb_init, - NULL}; - - _vsb_type = g_type_register_static(GST_TYPE_BIN, "GstQgcVideoSinkBin", &_vsb_info, (GTypeFlags)0); - } - - return _vsb_type; -} - static void -_vsb_class_init(void *klass, void *classData) +gst_qgc_video_sink_bin_dispose(GObject *object) { - Q_UNUSED(classData); - - GObjectClass *gobject_klass; - GstElementClass *gstelement_klass; - - gobject_klass = (GObjectClass *)klass; - gstelement_klass = (GstElementClass *)klass; - - parent_class = g_type_class_peek_parent(klass); - - gobject_klass->dispose = _vsb_dispose; - gobject_klass->get_property = _vsb_get_property; - gobject_klass->set_property = _vsb_set_property; - - g_object_class_install_property(gobject_klass, PROP_ENABLE_LAST_SAMPLE, - g_param_spec_boolean(PROP_ENABLE_LAST_SAMPLE_NAME, "Enable Last Buffer", - "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_klass, PROP_LAST_SAMPLE, - g_param_spec_boxed(PROP_LAST_SAMPLE_NAME, "Last Sample", - "The last sample received in the sink", GST_TYPE_SAMPLE, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(object); - g_object_class_install_property(gobject_klass, PROP_WIDGET, - g_param_spec_pointer(PROP_WIDGET_NAME, "QQuickItem", - "The QQuickItem to place in the object hierarchy", - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_klass, PROP_FORCE_ASPECT_RATIO, - g_param_spec_boolean(PROP_FORCE_ASPECT_RATIO_NAME, "Force aspect ratio", - "When enabled, scaling will respect original aspect ratio", - DEFAULT_FORCE_ASPECT_RATIO, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_klass, PROP_PIXEL_ASPECT_RATIO, - gst_param_spec_fraction(PROP_PIXEL_ASPECT_RATIO_NAME, "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D, - G_MAXINT, 1, 1, 1, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_klass, PROP_SYNC, - g_param_spec_boolean(PROP_SYNC_NAME, "Sync", - "Sync on the clock", DEFAULT_SYNC, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + if (vsb->qmlglsink) { + gst_object_unref(vsb->qmlglsink); + vsb->qmlglsink = NULL; + } - gst_element_class_set_static_metadata(gstelement_klass, - "QGC Video Sink Bin", "Sink/Video/Bin", - "Video rendering for QGC", - "Andrew Voznytsa , Tomaz Canabrava "); -} + if (vsb->glupload) { + gst_object_unref(vsb->glupload); + vsb->glupload = NULL; + } -gboolean -gst_qgc_video_sink_bin_plugin_init(GstPlugin *plugin) -{ - GST_DEBUG_CATEGORY_INIT(gst_qgc_video_sink_bin_debug, "qgcvideosinkbin", 0, "QGC Video Sink Bin"); - return gst_element_register(plugin, "qgcvideosinkbin", GST_RANK_NONE, GST_TYPE_VIDEO_SINK_BIN); + G_OBJECT_CLASS(parent_class)->dispose(object); } diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.h b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.h new file mode 100644 index 00000000000..8bd3698685f --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * (c) 2009-2024 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QGC_VIDEO_SINK_BIN (gst_qgc_video_sink_bin_get_type()) +G_DECLARE_FINAL_TYPE (GstQgcVideoSinkBin, gst_qgc_video_sink_bin, GST, QGC_VIDEO_SINK_BIN, GstBin) + +struct _GstQgcVideoSinkBin { + GstBin bin; + GstElement *glupload; + GstElement *qmlglsink; +}; + +struct _GstQgcVideoSinkBinClass { + GstBinClass parent_class; +}; + +GST_ELEMENT_REGISTER_DECLARE(qgcvideosinkbin); + +G_END_DECLS diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt index dcb51a009be..25e77fe27c4 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt @@ -1,51 +1,6 @@ +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick) find_package(GStreamer REQUIRED COMPONENTS Allocators Audio Codecparsers Controller Mpegts Net Pbutils Riff Rtp Rtsp Sdp Tag OPTIONAL_COMPONENTS Va Photography X11 EGL Wayland) -# Use Latest Revisions for each minor version: 1.16.3, 1.18.6, 1.20.7, 1.22.12, 1.24.7 -string(REPLACE "." ";" GST_VERSION_LIST ${GStreamer_VERSION}) -list(GET GST_VERSION_LIST 0 GST_VERSION_MAJOR) -list(GET GST_VERSION_LIST 1 GST_VERSION_MINOR) -list(GET GST_VERSION_LIST 2 GST_VERSION_PATCH) -cmake_print_variables(GST_VERSION_MAJOR GST_VERSION_MINOR GST_VERSION_PATCH) - -if(GST_VERSION_MINOR EQUAL 16) - set(GST_VERSION_PATCH 3) -elseif(GST_VERSION_MINOR EQUAL 18) - set(GST_VERSION_PATCH 6) -elseif(GST_VERSION_MINOR EQUAL 20) - set(GST_VERSION_PATCH 7) -elseif(GST_VERSION_MINOR EQUAL 22) - set(GST_VERSION_PATCH 12) -elseif(GST_VERSION_MINOR EQUAL 24) - set(GST_VERSION_PATCH 7) -endif() - -set(GST_PLUGINS_VERSION ${GST_VERSION_MAJOR}.${GST_VERSION_MINOR}.${GST_VERSION_PATCH}) -cmake_print_variables(GST_PLUGINS_VERSION) - -if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.22) - FetchContent_Declare(gstreamer_good_plugins - # https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GST_PLUGINS_VERSION}/gstreamer-${GST_PLUGINS_VERSION}.zip?path=subprojects/gst-plugins-good/ext/qt6 - URL https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-${GST_PLUGINS_VERSION}.tar.xz - DOWNLOAD_EXTRACT_TIMESTAMP true - ) - FetchContent_MakeAvailable(gstreamer_good_plugins) - set(QGC_GST_QT6_PLUGIN_PATH "${gstreamer_good_plugins_SOURCE_DIR}/ext/qt6" CACHE PATH "Location of downloaded GST Qt6 plugin sources") -else() - set(QGC_GST_QT6_PLUGIN_PATH "${CMAKE_CURRENT_SOURCE_DIR}/qt6" CACHE PATH "Location of custom local GST plugin") -endif() -cmake_print_variables(QGC_GST_QT6_PLUGIN_PATH) - -################################################################################ - -file(READ ${QGC_GST_QT6_PLUGIN_PATH}/qt6glitem.h FILE_CONTENTS) -string(FIND "${FILE_CONTENTS}" "#include " GST_FIX_INCLUDES) -if(GST_FIX_INCLUDES EQUAL -1) - string(REPLACE "#include " "#include \n#include " FILE_CONTENTS "${FILE_CONTENTS}") - file(WRITE ${QGC_GST_QT6_PLUGIN_PATH}/qt6glitem.h "${FILE_CONTENTS}") -endif() - -################################################################################ - file(GLOB gstqml6gl_SRCS ${QGC_GST_QT6_PLUGIN_PATH}/*.cc ${QGC_GST_QT6_PLUGIN_PATH}/*.h @@ -54,8 +9,6 @@ qt_add_library(gstqml6gl STATIC ${gstqml6gl_SRCS}) target_include_directories(gstqml6gl PUBLIC ${QGC_GST_QT6_PLUGIN_PATH}) -find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick) - target_link_libraries(gstqml6gl PRIVATE Qt6::GuiPrivate @@ -88,22 +41,73 @@ if(GStreamer_Va_FOUND) target_link_libraries(gstqml6gl PUBLIC GStreamer::Va) endif() +if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.22) + FetchContent_Declare(gstreamer_good_plugins + URL https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GST_PLUGINS_VERSION}/gstreamer-${GST_PLUGINS_VERSION}.zip?path=subprojects/gst-plugins-good/ext/qt6 + DOWNLOAD_EXTRACT_TIMESTAMP true + ) + FetchContent_MakeAvailable(gstreamer_good_plugins) + set(QGC_GST_QT6_PLUGIN_PATH "${gstreamer_good_plugins_SOURCE_DIR}/subprojects/gst-plugins-good/ext/qt6" CACHE PATH "Location of downloaded GST Qt6 plugin sources") +else() + set(QGC_GST_QT6_PLUGIN_PATH "${CMAKE_CURRENT_SOURCE_DIR}/qt6" CACHE PATH "Location of custom local GST plugin") +endif() +cmake_print_variables(QGC_GST_QT6_PLUGIN_PATH) + +################################################################################ + +file(READ ${QGC_GST_QT6_PLUGIN_PATH}/qt6glitem.h FILE_CONTENTS) +string(FIND "${FILE_CONTENTS}" "#include " GST_FIX_INCLUDES) +if(GST_FIX_INCLUDES EQUAL -1) + string(REPLACE "#include " "#include \n#include " FILE_CONTENTS "${FILE_CONTENTS}") + file(WRITE ${QGC_GST_QT6_PLUGIN_PATH}/qt6glitem.h "${FILE_CONTENTS}") +endif() + +################################################################################ + +find_package(GLESv2) +if(GLESv2_FOUND) + target_link_libraries(gstqml6gl PUBLIC GLESv2::GLESv2) +endif() + if(GStreamer_X11_FOUND) - # X11, XCB, X11_XCB, GLX + find_package(X11) + if(X11_FOUND) + target_link_libraries(gstqml6gl PUBLIC X11::X11) + endif() + find_package(XCB COMPONENTS XCB GLX) + if(XCB_FOUND) + target_link_libraries(gstqml6gl PUBLIC XCB::XCB XCB::GLX) + endif() + find_package(X11_XCB) + if(X11_XCB_FOUND) + target_link_libraries(gstqml6gl PUBLIC X11::XCB) + endif() target_link_libraries(gstqml6gl PUBLIC GStreamer::X11) target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_X11) endif() if(GStreamer_EGL_FOUND) - # EGL + find_package(EGL) + if(EGL_FOUND) + target_link_libraries(gstqml6gl PUBLIC EGL::EGL) + endif() target_link_libraries(gstqml6gl PUBLIC GStreamer::EGL) target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_EGLFS) endif() if(GStreamer_Wayland_FOUND) - # find_package(Wayland COMPONENTS Client Cursor Egl) - # find_package(WaylandProtocols) - # find_package(WaylandScanner) + find_package(Wayland COMPONENTS Client Cursor Egl) + if(Wayland_FOUND) + target_link_libraries(gstqml6gl PUBLIC Wayland::Client Wayland::Cursor Wayland::Egl) + endif() + find_package(WaylandProtocols) + if(WaylandProtocols_FOUND) + # WaylandProtocols_DATADIR + endif() + find_package(WaylandScanner) + if(WaylandScanner_FOUND) + # target_link_libraries(gstqml6gl PUBLIC Wayland::Scanner) + endif() find_package(Qt6 COMPONENTS WaylandClient) if(Qt6WaylandClient_FOUND) target_link_libraries(gstqml6gl PUBLIC GStreamer::Wayland Qt6::WaylandClient) @@ -112,15 +116,13 @@ if(GStreamer_Wayland_FOUND) endif() if(ANDROID) - # GLESv2, egl target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_ANDROID) elseif(WIN32) - # GDI32, egl, GLESv2 find_package(OpenGL) if(OpenGL_FOUND) target_link_libraries(gstqml6gl PUBLIC OpenGL::GL) - target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_WIN32) endif() + target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_WIN32) elseif(MACOS) # appleframeworks # Foundation, QuartzCore, CoreFoundation @@ -138,6 +140,8 @@ target_compile_definitions(gstqml6gl QT_QPA_HEADER= ) +################################################################################ + if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/resources.qrc") find_package(Qt6 REQUIRED COMPONENTS ShaderTools) @@ -171,6 +175,8 @@ if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/resources.qrc") ) endif() +################################################################################ + if(UNIX) target_compile_options(gstqml6gl PRIVATE @@ -180,124 +186,6 @@ if(UNIX) ) endif() -# gstva, gstasf -set(GST_TARGET_PLUGINS - gstcoreelements - gstisomp4 - gstlibav - gstmatroska - gstmpegtsdemux - gstopengl - gstplayback - gstrtp - gstrtpmanager - gstrtsp - gstsdpelem - gsttcp - gstudp - gstvideoparsersbad - gstx264 -) -if(ANDROID) - list(APPEND GST_TARGET_PLUGINS gstandroidmedia) -elseif(IOS) - list(APPEND GST_TARGET_PLUGINS gstapplemedia) -endif() - -find_package(PkgConfig QUIET) -if(PkgConfig_FOUND) - pkg_check_modules(GST_PLUGINS IMPORTED_TARGET ${GST_TARGET_PLUGINS}) - if(GST_PLUGINS_FOUND) - target_link_libraries(gstqml6gl PUBLIC PkgConfig::GST_PLUGINS) - if(WIN32) - # install(FILES ${GST_PLUGINS_LIBRARIES} DESTINATION ${CMAKE_INSTALL_BINDIR}) - elseif(LINUX) - install(FILES ${GST_PLUGINS_LIBRARIES} DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() - endif() - - pkg_check_modules(GSTREAMER_PLUGINS_BASE IMPORTED_TARGET gstreamer-plugins-base-1.0) - if(GSTREAMER_PLUGINS_BASE_FOUND) - target_link_libraries(gstqml6gl PUBLIC PkgConfig::GSTREAMER_PLUGINS_BASE) - endif() -endif() - -if(NOT GST_PLUGINS_FOUND) - foreach(plugin IN LISTS GST_TARGET_PLUGINS) - find_library(GStreamer_${plugin}_LIBRARY - NAMES ${plugin} - PATHS - ${GSTREAMER_PREFIX}/lib - ${GSTREAMER_PREFIX}/lib/gstreamer-1.0 - ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu - ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/gstreamer-1.0 - ${GSTREAMER_PREFIX}/Versions/Current/lib - ${GSTREAMER_PREFIX}/Versions/Current/lib/gstreamer-1.0 - ) - if(GStreamer_${plugin}_LIBRARY) - cmake_print_variables(GStreamer_${plugin}_LIBRARY) - target_link_libraries(gstqml6gl PUBLIC ${GStreamer_${plugin}_LIBRARY}) - if(WIN32) - # install(FILES ${GStreamer_${plugin}_LIBRARY} DESTINATION ${CMAKE_INSTALL_BINDIR}) - elseif(LINUX) - install(FILES ${GStreamer_${plugin}_LIBRARY} DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() - endif() - endforeach() - - if(ANDROID) - target_include_directories(gstqml6gl - PUBLIC - ${GSTREAMER_PREFIX}/include/gstreamer-1.0 - ${GSTREAMER_PREFIX}/include/glib-2.0 - ${GSTREAMER_PREFIX}/lib/glib-2.0/include - ${GSTREAMER_PREFIX}/lib/graphene-1.0/include - ${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include - ${GSTREAMER_PREFIX}/include - ) - - find_package(FFMPEG REQUIRED COMPONENTS avcodec avfilter avformat avutil swresample) - if(FFMPEG_FOUND) - target_link_libraries(gstqml6gl PUBLIC ${FFMPEG_LIBRARIES}) - target_include_directories(gstqml6gl PUBLIC ${FFMPEG_INCLUDE_DIRS}) - endif() - - find_package(BZip2) - if(BZIP2_FOUND) - target_link_libraries(gstqml6gl PUBLIC BZip2::BZip2) - endif() - - find_library(graphene_LIBRARY graphene-1.0) - if(graphene_LIBRARY) - target_link_libraries(gstqml6gl PUBLIC ${graphene_LIBRARY}) - endif() - - find_library(x264_LIBRARY x264) - if(x264_LIBRARY) - target_link_libraries(gstqml6gl PUBLIC ${x264_LIBRARY}) - endif() - - find_package(JPEG) - if(JPEG_FOUND) - target_link_libraries(gstqml6gl PUBLIC JPEG::JPEG) - endif() - - find_package(PNG) - if(PNG_FOUND) - target_link_libraries(gstqml6gl PUBLIC PNG::PNG) - endif() - - endif() -endif() - -if(ANDROID) - target_link_options(gstqml6gl PUBLIC "-Wl,-Bsymbolic") -endif() - -if(QGC_GST_STATIC_BUILD) - target_compile_definitions(gstqml6gl PUBLIC QGC_GST_STATIC_BUILD) -endif() - if(LINUX) install(DIRECTORY ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/gstreamer1.0 DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(DIRECTORY ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/gio DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -327,3 +215,5 @@ if(WIN32) file(GLOB GST_WIN_PLUGINS ${GST_WIN_PLUGINS_PATH}) install(FILES ${GST_WIN_PLUGINS} DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() + +################################################################################ diff --git a/src/VideoManager/VideoReceiver/QtMultimedia/CMakeLists.txt b/src/VideoManager/VideoReceiver/QtMultimedia/CMakeLists.txt index 76fbd8638a7..7db25fef556 100644 --- a/src/VideoManager/VideoReceiver/QtMultimedia/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/QtMultimedia/CMakeLists.txt @@ -18,13 +18,13 @@ target_sources(QtMultimediaReceiver target_link_libraries(QtMultimediaReceiver PRIVATE + Qt6::Multimedia Qt6::MultimediaQuickPrivate Qt6::Quick QGC Utilities PUBLIC Qt6::Core - Qt6::Multimedia VideoReceiver ) diff --git a/src/VideoManager/VideoReceiver/QtMultimedia/UVCReceiver.cc b/src/VideoManager/VideoReceiver/QtMultimedia/UVCReceiver.cc index fe0167fb38e..0c9f430dd6f 100644 --- a/src/VideoManager/VideoReceiver/QtMultimedia/UVCReceiver.cc +++ b/src/VideoManager/VideoReceiver/QtMultimedia/UVCReceiver.cc @@ -92,5 +92,5 @@ void UVCReceiver::_checkPermission() bool UVCReceiver::enabled() { - return (QMediaDevices::videoInputs().count() > 0); + return !QMediaDevices::videoInputs().isEmpty(); }