From 9686b0b9e3805b55318a85c24f26fb1eb2515ffc Mon Sep 17 00:00:00 2001 From: Holden Date: Sun, 6 Oct 2024 04:33:26 -0400 Subject: [PATCH] Video: GStreamer Plugin Improvements --- .github/actions/gstreamer/action.yml | 1 + .github/workflows/macos.yml | 1 - CMakeLists.txt | 8 +- android/libs/gstreamer_android-1.0.c.in | 49 ++ .../org/freedesktop/gstreamer/GStreamer.java | 105 +++ .../mavlink/qgroundcontrol/QGCActivity.java | 10 +- cmake/CreateAppImage.cmake | 17 +- cmake/CreateMacDMG.cmake | 4 +- cmake/Qt6QGCConfiguration.cmake | 1 + cmake/find-modules/FindEGL.cmake | 107 ++- cmake/find-modules/FindFFmpeg.cmake | 89 +-- cmake/find-modules/FindGLESv2.cmake | 4 +- cmake/find-modules/FindGObject.cmake | 4 +- cmake/find-modules/FindGStreamer.cmake | 728 +++++++++--------- cmake/find-modules/FindTaglib.cmake | 92 +++ cmake/find-modules/FindVAAPI.cmake | 34 +- cmake/find-modules/FindWaylandScanner.cmake | 211 +++-- cmake/find-modules/FindXCB.cmake | 149 ++-- cmake/modules/ECMFindModuleHelpers.cmake | 239 +++--- deploy/linux/AppRun | 23 +- .../apprun-hooks/linux-deploy-gstreamer.sh | 8 - src/CMakeLists.txt | 1 + src/Settings/CMakeLists.txt | 1 + src/Settings/VideoDecoderOptions.h | 20 - src/Settings/VideoSettings.cc | 28 +- src/Settings/VideoSettings.h | 3 - src/VideoManager/VideoManager.cc | 19 +- .../VideoReceiver/GStreamer/CMakeLists.txt | 12 +- .../VideoReceiver/GStreamer/GLVideoItemStub.h | 4 +- .../VideoReceiver/GStreamer/GStreamer.cc | 375 ++++----- .../VideoReceiver/GStreamer/GStreamer.h | 27 +- .../VideoReceiver/GStreamer/gst_ios_init.m | 98 +-- .../VideoReceiver/GStreamer/gstqgc.c | 40 - .../VideoReceiver/GStreamer/gstqgc.cc | 35 + .../VideoReceiver/GStreamer/gstqgcelement.cc | 10 + .../VideoReceiver/GStreamer/gstqgcelements.h | 12 + ...gcvideosinkbin.c => gstqgcvideosinkbin.cc} | 418 +++++----- .../GStreamer/gstqgcvideosinkbin.h | 36 + .../GStreamer/gstqml6gl/CMakeLists.txt | 84 +- tools/setup/install-dependencies-debian.sh | 1 + 40 files changed, 1733 insertions(+), 1375 deletions(-) create mode 100644 android/libs/gstreamer_android-1.0.c.in create mode 100644 android/src/org/freedesktop/gstreamer/GStreamer.java create mode 100644 cmake/find-modules/FindTaglib.cmake delete mode 100644 deploy/linux/apprun-hooks/linux-deploy-gstreamer.sh delete mode 100644 src/Settings/VideoDecoderOptions.h delete mode 100644 src/VideoManager/VideoReceiver/GStreamer/gstqgc.c create mode 100644 src/VideoManager/VideoReceiver/GStreamer/gstqgc.cc create mode 100644 src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc create mode 100644 src/VideoManager/VideoReceiver/GStreamer/gstqgcelements.h rename src/VideoManager/VideoReceiver/GStreamer/{gstqgcvideosinkbin.c => gstqgcvideosinkbin.cc} (54%) create mode 100644 src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.h diff --git a/.github/actions/gstreamer/action.yml b/.github/actions/gstreamer/action.yml index 7527b9c53a3..89e97b36db5 100644 --- a/.github/actions/gstreamer/action.yml +++ b/.github/actions/gstreamer/action.yml @@ -25,6 +25,7 @@ runs: run: git clone --depth 1 --branch ${{ inputs.gst_version }} https://github.com/GStreamer/gstreamer.git shell: bash + # macos https://github.com/Homebrew/homebrew-core/blob/4e00e17ab49b90949c27cf43a873ca923f3735aa/Formula/g/gstreamer.rb - name: Configure GStreamer working-directory: ${{ inputs.working_directory }}/gstreamer run: meson setup diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index cf53d6a13de..a415db0b775 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -65,7 +65,6 @@ jobs: for package in *.pkg ; do sudo installer -verbose -pkg "$package" -target / done - echo "PKG_CONFIG_PATH=/Library/Frameworks/GStreamer.framework/lib/pkgconfig:${{ env.PKG_CONFIG_PATH }}" >> "$GITHUB_ENV" - name: Set Up Cache uses: hendrikmuhs/ccache-action@v1.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bbc0d818ef..2bf5201b90d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,10 +110,6 @@ endif() set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) -if(CMAKE_BUILD_TYPE STREQUAL "Release") - add_compile_definitions(QGC_INSTALL_RELEASE) -endif() - ####################################################### # Qt6 Configuration ####################################################### @@ -520,6 +516,10 @@ if(LINUX) FILES ${CMAKE_BINARY_DIR}/metainfo/org.mavlink.qgroundcontrol.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo/ ) + install( + FILES ${CMAKE_SOURCE_DIR}/deploy/linux/AppRun + DESTINATION ${CMAKE_BINARY_DIR} + ) install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/CreateAppImage.cmake") elseif(WIN32) install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/CreateWinInstaller.cmake") diff --git a/android/libs/gstreamer_android-1.0.c.in b/android/libs/gstreamer_android-1.0.c.in new file mode 100644 index 00000000000..2606cd144fa --- /dev/null +++ b/android/libs/gstreamer_android-1.0.c.in @@ -0,0 +1,49 @@ +#include +#include + +#define GST_G_IO_MODULE_DECLARE(name) \ +extern void G_PASTE(g_io_, G_PASTE(name, _load)) (gpointer data) + +#define GST_G_IO_MODULE_LOAD(name) \ +G_PASTE(g_io_, G_PASTE(name, _load)) (NULL) + +/* Declaration of static plugins */ + @PLUGINS_DECLARATION@ + +/* Declaration of static gio modules */ + @G_IO_MODULES_DECLARE@ + +/* Call this function to load GIO modules */ +static void +gst_android_load_gio_modules (void) +{ + GTlsBackend *backend; + const gchar *ca_certs; + + @G_IO_MODULES_LOAD@ + + ca_certs = g_getenv ("CA_CERTIFICATES"); + + backend = g_tls_backend_get_default (); + if (backend && ca_certs) { + GTlsDatabase *db; + GError *error = NULL; + + db = g_tls_file_database_new (ca_certs, &error); + if (db) { + g_tls_backend_set_default_database (backend, db); + g_object_unref (db); + } else { + g_warning ("Failed to create a database from file: %s", + error ? error->message : "Unknown"); + } + } +} + +/* This is called by gst_init() */ +void +gst_init_static_plugins (void) +{ + @PLUGINS_REGISTRATION@ + gst_android_load_gio_modules (); +} diff --git a/android/src/org/freedesktop/gstreamer/GStreamer.java b/android/src/org/freedesktop/gstreamer/GStreamer.java new file mode 100644 index 00000000000..066b2152b49 --- /dev/null +++ b/android/src/org/freedesktop/gstreamer/GStreamer.java @@ -0,0 +1,105 @@ +/** + * Copy this file into your Android project and call init(). If your project + * contains fonts and/or certificates in assets, uncomment copyFonts() and/or + * copyCaCertificates() lines in init(). + */ +package org.freedesktop.gstreamer; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import android.content.Context; +import android.content.res.AssetManager; +import android.system.Os; + +public class GStreamer { + private static native void nativeInit(Context context) throws Exception; + + public static void init(Context context) throws Exception { + //copyFonts(context); + //copyCaCertificates(context); + nativeInit(context); + } + + private static void copyFonts(Context context) { + AssetManager assetManager = context.getAssets(); + File filesDir = context.getFilesDir(); + File fontsFCDir = new File (filesDir, "fontconfig"); + File fontsDir = new File (fontsFCDir, "fonts"); + File fontsCfg = new File (fontsFCDir, "fonts.conf"); + + fontsDir.mkdirs(); + + try { + /* Copy the config file */ + copyFile (assetManager, "fontconfig/fonts.conf", fontsCfg); + /* Copy the fonts */ + for(String filename : assetManager.list("fontconfig/fonts/truetype")) { + File font = new File(fontsDir, filename); + copyFile (assetManager, "fontconfig/fonts/truetype/" + filename, font); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void copyCaCertificates(Context context) { + AssetManager assetManager = context.getAssets(); + File filesDir = context.getFilesDir(); + File sslDir = new File (filesDir, "ssl"); + File certsDir = new File (sslDir, "certs"); + File certs = new File (certsDir, "ca-certificates.crt"); + + certsDir.mkdirs(); + + try { + /* Copy the certificates file */ + copyFile (assetManager, "ssl/certs/ca-certificates.crt", certs); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void copyFile(AssetManager assetManager, String assetPath, File outFile) throws IOException { + InputStream in = null; + OutputStream out = null; + IOException exception = null; + + if (outFile.exists()) + outFile.delete(); + + try { + in = assetManager.open(assetPath); + out = new FileOutputStream(outFile); + + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + out.flush(); + } catch (IOException e) { + exception = e; + } finally { + if (in != null) + try { + in.close(); + } catch (IOException e) { + if (exception == null) + exception = e; + } + if (out != null) + try { + out.close(); + } catch (IOException e) { + if (exception == null) + exception = e; + } + if (exception != null) + throw exception; + } + } +} diff --git a/android/src/org/mavlink/qgroundcontrol/QGCActivity.java b/android/src/org/mavlink/qgroundcontrol/QGCActivity.java index 31d473d300d..f470b11138f 100644 --- a/android/src/org/mavlink/qgroundcontrol/QGCActivity.java +++ b/android/src/org/mavlink/qgroundcontrol/QGCActivity.java @@ -28,6 +28,8 @@ import android.util.Log; import android.view.WindowManager; +// import org.freedesktop.gstreamer.GStreamer; + import com.hoho.android.usbserial.driver.*; import com.hoho.android.usbserial.util.*; @@ -144,7 +146,7 @@ public QGCActivity() public void onInit(int status) { - + // System.loadLibrary("gstreamer_android"); } @Override @@ -160,6 +162,12 @@ public void onCreate(Bundle savedInstanceState) _setupUsbPermissionIntent(); m_usbManager = (UsbManager) m_instance.getSystemService(Context.USB_SERVICE); + + // try { + // GStreamer.init(this); + // } catch (final Exception ex) { + // Log.e(TAG, "Exception GStreamer.init(this)", ex); + // } } @Override diff --git a/cmake/CreateAppImage.cmake b/cmake/CreateAppImage.cmake index 34c57ef5030..e7599d8406b 100644 --- a/cmake/CreateAppImage.cmake +++ b/cmake/CreateAppImage.cmake @@ -2,12 +2,17 @@ message(STATUS "Creating AppImage") # TODO: https://github.com/AppImageCommunity/AppImageUpdate set(APPDIR_PATH "${CMAKE_BINARY_DIR}/AppDir") +# set(APPIMAGETOOL_PATH "${CMAKE_BINARY_DIR}/appimagetool-x86_64.AppImage") set(LD_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-x86_64.AppImage") set(LD_APPIMAGEPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-appimage-x86_64.AppImage") -set(LD_QTPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage") +# set(LD_QTPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage") # set(LD_GSTPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-gstreamer.sh") # set(LD_GTKPLUGIN_PATH "${CMAKE_BINARY_DIR}/linuxdeploy-plugin-gtk.sh") +# if(NOT EXISTS "${APPIMAGETOOL_PATH}") +# file(DOWNLOAD https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage "${APPIMAGETOOL_PATH}") +# execute_process(COMMAND chmod a+x "${APPIMAGETOOL_PATH}") +# endif() if(NOT EXISTS "${LD_PATH}") file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage "${LD_PATH}") execute_process(COMMAND chmod a+x "${LD_PATH}") @@ -16,10 +21,10 @@ if(NOT EXISTS "${LD_APPIMAGEPLUGIN_PATH}") file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage "${LD_APPIMAGEPLUGIN_PATH}") execute_process(COMMAND chmod a+x "${LD_APPIMAGEPLUGIN_PATH}") endif() -if(NOT EXISTS "${LD_QTPLUGIN_PATH}") - file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage "${LD_QTPLUGIN_PATH}") - execute_process(COMMAND chmod a+x "${LD_QTPLUGIN_PATH}") -endif() +# if(NOT EXISTS "${LD_QTPLUGIN_PATH}") +# file(DOWNLOAD https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage "${LD_QTPLUGIN_PATH}") +# execute_process(COMMAND chmod a+x "${LD_QTPLUGIN_PATH}") +# endif() # if(NOT EXISTS "${LD_GTKPLUGIN_PATH}") # file(DOWNLOAD https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh "${LD_GTKPLUGIN_PATH}") # execute_process(COMMAND chmod a+x "${LD_GTKPLUGIN_PATH}") @@ -29,7 +34,7 @@ endif() # execute_process(COMMAND chmod a+x "${LD_GSTPLUGIN_PATH}") # endif() -execute_process(COMMAND ${LD_PATH} --appdir ${APPDIR_PATH} --output appimage) +execute_process(COMMAND ${LD_PATH} --appdir ${APPDIR_PATH} --output appimage --custom-apprun ${CMAKE_BINARY_DIR}/AppRun) # --exclude-library "libX*" # --exclude-library "libglib*" # --exclude-library "libgobject*" diff --git a/cmake/CreateMacDMG.cmake b/cmake/CreateMacDMG.cmake index cce72e9c379..3c3770e4186 100644 --- a/cmake/CreateMacDMG.cmake +++ b/cmake/CreateMacDMG.cmake @@ -1,6 +1,6 @@ # include(BundleUtilities) -message(STATUS "Copy GStreamer framework into bundle") +# message(STATUS "Copy GStreamer framework into bundle") file(COPY /Library/Frameworks/GStreamer.framework DESTINATION staging/QGroundControl.app/Contents/Frameworks) file(REMOVE_RECURSE staging/QGroundControl.app/Contents/Frameworks/GStreamer.framework/Versions/1.0/bin) file(REMOVE_RECURSE staging/QGroundControl.app/Contents/Frameworks/GStreamer.framework/Versions/1.0/etc) @@ -23,7 +23,7 @@ file(REMOVE ${REMOVE_LIB_FILES}) file(REMOVE_RECURSE staging/QGroundControl.app/Contents/Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/include) file(REMOVE_RECURSE staging/QGroundControl.app/Contents/Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0/pkgconfig) -# Fix up library paths to point into bundle +# # Fix up library paths to point into bundle execute_process(COMMAND install_name_tool -change @rpath/libgstgl-1.0.0.dylib @executable_path/../Frameworks/GStreamer.framework/Libraries/libgstgl-1.0.0.dylib staging/QGroundControl.app/Contents/MacOS/QGroundControl) execute_process(COMMAND install_name_tool -change @rpath/libgstvideo-1.0.0.dylib @executable_path/../Frameworks/GStreamer.framework/Libraries/libgstvideo-1.0.0.dylib staging/QGroundControl.app/Contents/MacOS/QGroundControl) execute_process(COMMAND install_name_tool -change @rpath/libgstbase-1.0.0.dylib @executable_path/../Frameworks/GStreamer.framework/Libraries/libgstbase-1.0.0.dylib staging/QGroundControl.app/Contents/MacOS/QGroundControl) diff --git a/cmake/Qt6QGCConfiguration.cmake b/cmake/Qt6QGCConfiguration.cmake index f00bcf3ad39..cfedfef3824 100644 --- a/cmake/Qt6QGCConfiguration.cmake +++ b/cmake/Qt6QGCConfiguration.cmake @@ -57,4 +57,5 @@ cmake_print_variables(QT_VERSION QT_MKSPEC QT_LIBRARY_HINTS) # if(ANDROID) # set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT}) + # message(STATUS "PKG_CONFIG_SYSROOT_DIR $ENV{PKG_CONFIG_SYSROOT_DIR}") # endif() diff --git a/cmake/find-modules/FindEGL.cmake b/cmake/find-modules/FindEGL.cmake index 747901b3a94..9ac8e2fa0cf 100644 --- a/cmake/find-modules/FindEGL.cmake +++ b/cmake/find-modules/FindEGL.cmake @@ -1,42 +1,64 @@ -# SPDX-FileCopyrightText: 2014 Alex Merry -# SPDX-FileCopyrightText: 2014 Martin Gräßlin +#.rst: +# FindEGL +# ------- # -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.rst: -FindEGL -------- - -Try to find EGL. - -This will define the following variables: - -``EGL_FOUND`` - True if (the requested version of) EGL is available -``EGL_VERSION`` - The version of EGL; note that this is the API version defined in the - headers, rather than the version of the implementation (eg: Mesa) -``EGL_LIBRARIES`` - This can be passed to target_link_libraries() instead of the ``EGL::EGL`` - target -``EGL_INCLUDE_DIRS`` - This should be passed to target_include_directories() if the target is not - used for linking -``EGL_DEFINITIONS`` - This should be passed to target_compile_options() if the target is not - used for linking - -If ``EGL_FOUND`` is TRUE, it will also define the following imported target: - -``EGL::EGL`` - The EGL 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. +# Try to find EGL. +# +# This will define the following variables: +# +# ``EGL_FOUND`` +# True if (the requested version of) EGL is available +# ``EGL_VERSION`` +# The version of EGL; note that this is the API version defined in the +# headers, rather than the version of the implementation (eg: Mesa) +# ``EGL_LIBRARIES`` +# This can be passed to target_link_libraries() instead of the ``EGL::EGL`` +# target +# ``EGL_INCLUDE_DIRS`` +# This should be passed to target_include_directories() if the target is not +# used for linking +# ``EGL_DEFINITIONS`` +# This should be passed to target_compile_options() if the target is not +# used for linking +# +# If ``EGL_FOUND`` is TRUE, it will also define the following imported target: +# +# ``EGL::EGL`` +# The EGL 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 pre-1.0.0. -Since pre-1.0.0. -#]=======================================================================] +#============================================================================= +# Copyright 2014 Alex Merry +# Copyright 2014 Martin Gräßlin +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake) include(CheckCXXSourceCompiles) @@ -60,7 +82,6 @@ find_path(EGL_INCLUDE_DIR find_library(EGL_LIBRARY NAMES EGL - libEGL HINTS ${PKG_EGL_LIBRARY_DIRS} ) @@ -97,12 +118,18 @@ endif() cmake_push_check_state(RESET) list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}") list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}") +list(APPEND CMAKE_REQUIRED_DEFINITIONS "${EGL_DEFINITIONS}") + +if(_qt_igy_gui_libs) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${_qt_igy_gui_libs}") +endif() check_cxx_source_compiles(" #include -int main(int argc, char *argv[]) { - EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0; +int main(int, char **) { + [[maybe_unused]] EGLint x = 0; + EGLDisplay dpy = 0; EGLContext ctx = 0; eglDestroyContext(dpy, ctx); }" HAVE_EGL) diff --git a/cmake/find-modules/FindFFmpeg.cmake b/cmake/find-modules/FindFFmpeg.cmake index 27b49a2a509..ecf9b07cb16 100644 --- a/cmake/find-modules/FindFFmpeg.cmake +++ b/cmake/find-modules/FindFFmpeg.cmake @@ -20,10 +20,7 @@ # :: # # FFMPEG_FOUND - System has the all required components. -# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. -# FFMPEG_LIBRARIES - Link these to use the required FFmpeg components. -# FFMPEG_LIBRARY_DIRS - Link directories -# FFMPEG_DEFINITIONS - Compiler switches required for using the required FFmpeg components. +# FFMPEG_SHARED_LIBRARIES - Found FFmpeg shared libraries. # # For each of the components it will additionally set. # @@ -203,11 +200,8 @@ endmacro() # Clear the previously cached variables, because they are recomputed every time # the Find script is included. -unset(FFMPEG_INCLUDE_DIRS) -unset(FFMPEG_LIBRARIES) -unset(FFMPEG_SHARED_LIBRARIES) -unset(FFMPEG_DEFINITIONS) -unset(FFMPEG_LIBRARY_DIRS) +unset(FFMPEG_SHARED_LIBRARIES CACHE) +unset(FFMPEG_STUBS CACHE) # Check for components. foreach (_component ${FFmpeg_FIND_COMPONENTS}) @@ -232,33 +226,34 @@ foreach (_component ${FFmpeg_FIND_COMPONENTS}) endif() endforeach() -if (NOT FFMPEG_SHARED_COMPONENTS AND (ANDROID OR LINUX)) - set(ENABLE_DYNAMIC_RESOLVE_OPENSSL_SYMBOLS TRUE CACHE INTERNAL "") -endif() -set(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS ${LINUX} CACHE INTERNAL "") +function(qt_internal_multimedia_try_add_dynamic_resolve_dependency _component dep) + set(dynamic_resolve_added FALSE PARENT_SCOPE) -function(__try_add_dynamic_resolve_dependency dep added) - set(added TRUE PARENT_SCOPE) + if (NOT ANDROID AND NOT LINUX) + return() + endif() - if(ENABLE_DYNAMIC_RESOLVE_OPENSSL_SYMBOLS AND - (${dep} STREQUAL "ssl" OR ${dep} STREQUAL "crypto")) - set(DYNAMIC_RESOLVE_OPENSSL_SYMBOLS TRUE CACHE INTERNAL "") - elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va") - set(DYNAMIC_RESOLVE_VAAPI_SYMBOLS TRUE CACHE INTERNAL "") - elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va-drm") - set(DYNAMIC_RESOLVE_VA_DRM_SYMBOLS TRUE CACHE INTERNAL "") - elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va-x11") - set(DYNAMIC_RESOLVE_VA_X11_SYMBOLS TRUE CACHE INTERNAL "") - else() - set(added FALSE PARENT_SCOPE) + set(supported_stubs "ssl|crypto|va|va-drm|va-x11") + if(${_component}_SHARED_LIBRARIES) + set(stub_prefix "Qt${PROJECT_VERSION_MAJOR}FFmpegStub-") + if (${dep} MATCHES "^${stub_prefix}(${supported_stubs})$") + string(REPLACE "${stub_prefix}" "" dep "${dep}") + set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "") + + set(dynamic_resolve_added TRUE PARENT_SCOPE) + endif() + elseif (${dep} MATCHES "^(${supported_stubs})$") + set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "") + set(dynamic_resolve_added TRUE PARENT_SCOPE) endif() endfunction() # Function parses package config file to find the static library dependencies # and adds them to the target library. -function(__ffmpeg_internal_set_dependencies lib) - set(PC_FILE ${FFMPEG_DIR}/lib/pkgconfig/lib${lib}.pc) +function(__ffmpeg_internal_set_dependencies _component) + string(TOLOWER ${_component} lib) + set(PC_FILE ${${_component}_LIBRARY_DIR}/pkgconfig/lib${lib}.pc) if(EXISTS ${PC_FILE}) file(READ ${PC_FILE} pcfile) @@ -277,18 +272,22 @@ function(__ffmpeg_internal_set_dependencies lib) foreach(dependency ${deps_no_suffix}) string(REGEX REPLACE ${prefix_l} "" dependency ${dependency}) if(NOT ${lib} STREQUAL ${dependency}) - __try_add_dynamic_resolve_dependency(${dependency} added) - if(NOT added) + qt_internal_multimedia_try_add_dynamic_resolve_dependency(${_component} ${dependency}) + if(NOT dynamic_resolve_added AND NOT ${_component}_SHARED_LIBRARIES) target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency}) endif() endif() endforeach() - list(APPEND deps_lib_suffix ${libs_dependency_lib} ${libs_private_dependency_lib}) - foreach(dependency ${deps_lib_suffix}) - string(REGEX REPLACE ${suffix_lib} "" dependency ${dependency}) - target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency}) - endforeach() + if(NOT ${_component}_SHARED_LIBRARIES) + list(APPEND deps_lib_suffix ${libs_dependency_lib} ${libs_private_dependency_lib}) + foreach(dependency ${deps_lib_suffix}) + string(REGEX REPLACE ${suffix_lib} "" dependency ${dependency}) + target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency}) + endforeach() + endif() + else() + message(WARNING "FFmpeg pc file ${PC_FILE} is not found") endif() endfunction() @@ -309,9 +308,8 @@ endfunction() INTERFACE_LINK_LIBRARIES "${${_component}_LIBRARY_NAME}" INTERFACE_LINK_DIRECTORIES "${${_component}_LIBRARY_DIR}" ) - if(NOT ${_component}_SHARED_LIBRARIES) - __ffmpeg_internal_set_dependencies(${_lowerComponent}) - endif() + + __ffmpeg_internal_set_dependencies(${_component}) target_link_libraries(FFmpeg::${_lowerComponent} INTERFACE "${${_component}_LIBRARY_NAME}") if (UNIX AND NOT APPLE) target_link_options(FFmpeg::${_lowerComponent} INTERFACE "-Wl,--exclude-libs=lib${_lowerComponent}") @@ -324,22 +322,17 @@ endfunction() list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) list(REMOVE_DUPLICATES FFMPEG_LIBRARY_DIRS) list(REMOVE_DUPLICATES FFMPEG_SHARED_LIBRARIES) + list(REMOVE_DUPLICATES FFMPEG_STUBS) message(STATUS "FFmpeg shared libs: ${FFMPEG_SHARED_LIBRARIES}") + message(STATUS "FFmpeg stubs: ${FFMPEG_STUBS}") # cache the vars. - set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) - set(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBRARY_DIRS} CACHE STRING "The FFmpeg library dirs." FORCE) set(FFMPEG_SHARED_LIBRARIES ${FFMPEG_SHARED_LIBRARIES} CACHE STRING "The FFmpeg dynamic libraries." FORCE) + set(FFMPEG_STUBS ${FFMPEG_STUBS} CACHE STRING "The FFmpeg stubs." FORCE) - mark_as_advanced(FFMPEG_INCLUDE_DIRS - FFMPEG_LIBRARIES - FFMPEG_DEFINITIONS - FFMPEG_LIBRARY_DIRS - FFMPEG_SHARED_LIBRARIES - ) + mark_as_advanced(FFMPEG_SHARED_LIBRARIES) + mark_as_advanced(FFMPEG_STUBS) # endif () list(LENGTH FFMPEG_LIBRARY_DIRS DIRS_COUNT) diff --git a/cmake/find-modules/FindGLESv2.cmake b/cmake/find-modules/FindGLESv2.cmake index 4730418209a..645d13079a2 100644 --- a/cmake/find-modules/FindGLESv2.cmake +++ b/cmake/find-modules/FindGLESv2.cmake @@ -80,7 +80,9 @@ if(GLESv2_FOUND AND NOT TARGET GLESv2::GLESv2) IMPORTED_LOCATION "${GLESv2_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${GLESv2_INCLUDE_DIR}") - if(EGL_LIBRARY) + if(TARGET EGL::EGL) + target_link_libraries(GLESv2::GLESv2 INTERFACE "EGL::EGL") + elseif(EGL_LIBRARY) target_link_libraries(GLESv2::GLESv2 INTERFACE "${EGL_LIBRARY}") endif() endif() diff --git a/cmake/find-modules/FindGObject.cmake b/cmake/find-modules/FindGObject.cmake index 54dd35eadb7..89a02435a14 100644 --- a/cmake/find-modules/FindGObject.cmake +++ b/cmake/find-modules/FindGObject.cmake @@ -23,7 +23,7 @@ qt_internal_disable_find_package_global_promotion(GLIB2::GLIB2) if(NOT TARGET GObject::GObject) find_package(PkgConfig QUIET) pkg_check_modules(PC_GOBJECT gobject-2.0 IMPORTED_TARGET) - if (TARGET PkgConfig::PC_GOBJECT) + if(TARGET PkgConfig::PC_GOBJECT) add_library(GObject::GObject INTERFACE IMPORTED) target_link_libraries(GObject::GObject INTERFACE PkgConfig::PC_GOBJECT @@ -35,7 +35,7 @@ if(NOT TARGET GObject::GObject) PATH_SUFFIXES glib-2.0/gobject/ ) find_library(GObject_LIBRARY NAMES gobject-2.0) - if (GObject_LIBRARY AND GObject_INCLUDE_DIR) + if(GObject_LIBRARY AND GObject_INCLUDE_DIR) add_library(GObject::GObject INTERFACE IMPORTED) target_include_directories(GObject::GObject INTERFACE ${GObject_INCLUDE_DIR} diff --git a/cmake/find-modules/FindGStreamer.cmake b/cmake/find-modules/FindGStreamer.cmake index a7f9b9f23d9..5bd6b2230bf 100644 --- a/cmake/find-modules/FindGStreamer.cmake +++ b/cmake/find-modules/FindGStreamer.cmake @@ -1,6 +1,4 @@ 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() @@ -8,6 +6,12 @@ if(ANDROID OR IOS) endif() endif() +if(ANDROID OR IOS) + set(QGC_GST_STATIC_BUILD ON CACHE BOOL "Build GST Statically") +endif() + +find_package(PkgConfig QUIET) + if(QGC_GST_STATIC_BUILD) list(APPEND PKG_CONFIG_ARGN --static) endif() @@ -40,11 +44,15 @@ if(WIN32) ) elseif(MACOS) list(APPEND CMAKE_FRAMEWORK_PATH "/Library/Frameworks") - set(GSTREAMER_PREFIX "/Library/Frameworks/GStreamer.framework") - set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/Versions/Current/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}") + set(GSTREAMER_PREFIX "/Library/Frameworks/GStreamer.framework/Versions/1.0") + find_program(PKG_CONFIG_PROGRAM pkg-config PATHS ${GSTREAMER_PREFIX}/bin) + if(PKG_CONFIG_PROGRAM) + set(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_PROGRAM}) + endif() + set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig:$ENV{PKG_CONFIG_PATH}") 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}") + set(ENV{PKG_CONFIG_PATH} "${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu/pkgconfig:$ENV{PKG_CONFIG_PATH}") elseif(IOS) list(APPEND CMAKE_FRAMEWORK_PATH "~/Library/Developer/GStreamer/iPhone.sdk") if(DEFINED ENV{GSTREAMER_PREFIX_IOS} AND EXISTS $ENV{GSTREAMER_PREFIX_IOS}) @@ -60,7 +68,6 @@ elseif(IOS) endif() 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() @@ -79,6 +86,7 @@ elseif(ANDROID) endif() set(GSTREAMER_PREFIX_ANDROID ${GSTREAMER_INSTALL_DIR}) endif() + if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL armeabi-v7a) set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_ANDROID}/armv7) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL arm64-v8a) @@ -88,24 +96,29 @@ elseif(ANDROID) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL x86_64) set(GSTREAMER_PREFIX ${GSTREAMER_PREFIX_ANDROID}/x86_64) endif() - set(ENV{PKG_CONFIG_PATH} "") - set(ENV{PKG_CONFIG_LIBDIR} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig") - 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 - ) + set(ENV{PKG_CONFIG_PATH} "") 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}) + set(ENV{PKG_CONFIG_LIBDIR} "${GSTREAMER_PREFIX}/lib/pkgconfig;${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig") + endif() + elseif(CMAKE_HOST_LINUX) + if(PkgConfig_FOUND) + set(ENV{PKG_CONFIG_LIBDIR} "${GSTREAMER_PREFIX}/lib/pkgconfig:${GSTREAMER_PREFIX}/lib/gstreamer-1.0/pkgconfig") endif() endif() + + 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 + ) endif() -cmake_print_variables(GSTREAMER_PREFIX) list(PREPEND CMAKE_PREFIX_PATH ${GSTREAMER_PREFIX}) +cmake_print_variables(GSTREAMER_PREFIX) ################################################################################ @@ -113,11 +126,9 @@ include(CMakeFindDependencyMacro) 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() @@ -151,31 +162,63 @@ else() endif() cmake_print_variables(GStreamer_VERSION) +# Use Latest Revisions for each minor version: 1.16.3, 1.18.6, 1.20.7, 1.22.12, 1.24.8 +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 8) +endif() + +set(GST_PLUGINS_VERSION ${GST_VERSION_MAJOR}.${GST_VERSION_MINOR}.${GST_VERSION_PATCH}) +cmake_print_variables(GST_PLUGINS_VERSION) + ################################################################################ -function(find_gstreamer_component component prefix header library) - if(NOT TARGET GStreamer::${component}) +function(find_gstreamer_component component) + cmake_parse_arguments(PARSE_ARGV 1 ARGS "" "PC_NAME;HEADER;LIBRARY" "DEPENDENCIES") + + set(pkgconfig_name ${ARGS_PC_NAME}) + set(header ${ARGS_HEADER}) + set(library ${ARGS_LIBRARY}) + + set(target GStreamer::${component}) + + if(NOT TARGET ${target}) string(TOUPPER ${component} upper) - if(PkgConfig_FOUND) - pkg_check_modules(PC_GSTREAMER_${upper} ${prefix} IMPORTED_TARGET) - endif() + pkg_check_modules(PC_GSTREAMER_${upper} IMPORTED_TARGET ${pkgconfig_name}) if(TARGET PkgConfig::PC_GSTREAMER_${upper}) add_library(GStreamer::${component} INTERFACE IMPORTED) target_link_libraries(GStreamer::${component} INTERFACE PkgConfig::PC_GSTREAMER_${upper}) set_target_properties(GStreamer::${component} PROPERTIES VERSION ${PC_GSTREAMER_${upper}_VERSION}) else() + foreach(dependency IN LISTS ARGS_DEPENDENCIES) + if (NOT TARGET ${dependency}) + set(GStreamer_${component}_FOUND FALSE PARENT_SCOPE) + return() + endif() + endforeach() + find_path(GStreamer_${component}_INCLUDE_DIR NAMES ${header} PATH_SUFFIXES gstreamer-1.0 - PATHS ${GSTREAMER_PREFIX}/include ) find_library(GStreamer_${component}_LIBRARY NAMES ${library} - PATHS ${GSTREAMER_PREFIX}/lib ) if(${component} STREQUAL "Gl") # search the gstglconfig.h include dir under the same root where the library is found - # TODO: replace with cmake_path get_filename_component(gstglLibDir "${GStreamer_Gl_LIBRARY}" PATH) find_path(GStreamer_GlConfig_INCLUDE_DIR NAMES gst/gl/gstglconfig.h @@ -191,15 +234,18 @@ function(find_gstreamer_component component prefix header library) add_library(GStreamer::${component} INTERFACE IMPORTED) target_include_directories(GStreamer::${component} INTERFACE ${GStreamer_${component}_INCLUDE_DIR}) target_link_libraries(GStreamer::${component} INTERFACE ${GStreamer_${component}_LIBRARY}) + if(ARGS_DEPENDENCIES) + target_link_libraries(GStreamer::${component} INTERFACE ${ARGS_DEPENDENCIES}) + endif() set_target_properties(GStreamer::${component} PROPERTIES VERSION ${GStreamer_VERSION}) endif() mark_as_advanced(GStreamer_${component}_INCLUDE_DIR GStreamer_${component}_LIBRARY) endif() endif() - if(TARGET GStreamer::${component}) - # TODO; define_property + if(TARGET ${target}) set(GStreamer_${component}_FOUND TRUE PARENT_SCOPE) + # TODO; define_property get_target_property(Component_VERSION GStreamer::${component} VERSION) set(GStreamer_${component}_VERSION ${Component_VERSION} PARENT_SCOPE) endif() @@ -207,186 +253,223 @@ endfunction() ################################################################################ -# GStreamer required dependencies -find_gstreamer_component(Core gstreamer-1.0 gst/gst.h gstreamer-1.0) -find_gstreamer_component(Base gstreamer-base-1.0 gst/gst.h gstbase-1.0) -find_gstreamer_component(Video gstreamer-video-1.0 gst/video/video.h gstvideo-1.0) -find_gstreamer_component(Gl gstreamer-gl-1.0 gst/gl/gl.h gstgl-1.0) +find_gstreamer_component(Core + PC_NAME gstreamer-1.0 + HEADER gst/gst.h + LIBRARY gstreamer-1.0 + DEPENDENCIES GLIB2::GLIB2 GObject::GObject) +find_gstreamer_component(Base + PC_NAME gstreamer-base-1.0 + HEADER gst/gst.h + LIBRARY gstbase-1.0 + DEPENDENCIES GStreamer::Core) +find_gstreamer_component(Video + PC_NAME gstreamer-video-1.0 + HEADER gst/video/video.h + LIBRARY gstvideo-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) +find_gstreamer_component(Gl + PC_NAME gstreamer-gl-1.0 + HEADER gst/gl/gl.h + LIBRARY gstgl-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base GStreamer::Video) -if(TARGET GStreamer::Core) - target_link_libraries(GStreamer::Core INTERFACE GObject::GObject) +################################################################################ + +if(Allocators IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Allocators + PC_NAME gstreamer-allocators-1.0 + HEADER gst/allocators/allocators.h + LIBRARY gstallocators-1.0 + DEPENDENCIES GStreamer::Core) endif() -if(TARGET GStreamer::Base AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::Base INTERFACE GStreamer::Core) + +if(App IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(App + PC_NAME gstreamer-app-1.0 + HEADER gst/app/gstappsink.h + LIBRARY gstapp-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) endif() -if(TARGET GStreamer::Video AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Video INTERFACE GStreamer::Base) + +if(Audio IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Audio + PC_NAME gstreamer-audio-1.0 + HEADER gst/audio/audio.h + LIBRARY gstaudio-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) endif() -if(TARGET GStreamer::Gl AND TARGET GStreamer::Video) - target_link_libraries(GStreamer::Gl INTERFACE GStreamer::Video) + +if(Codecparsers IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Codecparsers + PC_NAME gstreamer-codecparsers-1.0 + HEADER gst/codecparsers/codecparsers-prelude.h + LIBRARY gstcodecparsers-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) endif() -################################################################################ +if(Controller IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Controller + PC_NAME gstreamer-controller-1.0 + HEADER gst/controller/controller.h + LIBRARY gstcontroller-1.0 + DEPENDENCIES GStreamer::Core) +endif() -# GStreamer optional components -foreach(component ${GStreamer_FIND_COMPONENTS}) - if (${component} STREQUAL "Allocators") - find_gstreamer_component(Allocators gstreamer-allocators-1.0 gst/allocators/allocators.h gstallocators-1.0) - if(TARGET GStreamer::Allocators AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::Allocators INTERFACE GStreamer::Core) - endif() - elseif (${component} STREQUAL "App") - find_gstreamer_component(App gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0) - if(TARGET GStreamer::App AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::App INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Audio") - find_gstreamer_component(Audio gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0) - if(TARGET GStreamer::Audio AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Audio INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Controller") - find_gstreamer_component(Controller gstreamer-controller-1.0 gst/controller/controller.h gstcontroller-1.0) - if(TARGET GStreamer::Controller AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::Controller INTERFACE GStreamer::Core) - endif() - elseif (${component} STREQUAL "Codecparsers") - find_gstreamer_component(Codecparsers gstreamer-codecparsers-1.0 gst/codecparsers/codecparsers-prelude.h gstcodecparsers-1.0) - if(TARGET GStreamer::Codecparsers AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Codecparsers INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Fft") - find_gstreamer_component(Fft gstreamer-fft-1.0 gst/fft/fft.h gstfft-1.0) - if(TARGET GStreamer::Fft AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::Fft INTERFACE GStreamer::Core) - endif() - elseif (${component} STREQUAL "Mpegts") - find_gstreamer_component(Mpegts gstreamer-mpegts-1.0 gst/mpegts/mpegts.h gstmpegts-1.0) - if(TARGET GStreamer::Mpegts AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Mpegts INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Net") - find_gstreamer_component(Net gstreamer-net-1.0 gst/net/net.h gstnet-1.0) - if(TARGET GStreamer::Net AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Net INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Pbutils") - find_gstreamer_component(Pbutils gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0) - if(TARGET GStreamer::Pbutils AND TARGET GStreamer::Audio AND TARGET GStreamer::Video) - target_link_libraries(GStreamer::Pbutils INTERFACE GStreamer::Audio GStreamer::Video) - endif() - elseif (${component} STREQUAL "Photography") - find_gstreamer_component(Photography gstreamer-photography-1.0 gst/interfaces/photography.h gstphotography-1.0) - if(TARGET GStreamer::Photography AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::Photography INTERFACE GStreamer::Core) - endif() - elseif (${component} STREQUAL "Riff") - find_gstreamer_component(Riff gstreamer-riff-1.0 gst/riff/riff.h gstriff-1.0) - if(TARGET GStreamer::Riff AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Riff INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Rtp") - find_gstreamer_component(Rtp gstreamer-rtp-1.0 gst/rtp/rtp.h gstrtp-1.0) - if(TARGET GStreamer::Rtp AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Rtp INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Rtsp") - find_gstreamer_component(Rtsp gstreamer-rtsp-1.0 gst/rtsp/rtsp.h gstrtsp-1.0) - if(TARGET GStreamer::Rtsp AND TARGET GStreamer::Rtp) - target_link_libraries(GStreamer::Rtsp INTERFACE GStreamer::Rtp) - endif() - elseif (${component} STREQUAL "Sdp") - find_gstreamer_component(Sdp gstreamer-sdp-1.0 gst/sdp/sdp.h gstsdp-1.0) - if(TARGET GStreamer::Sdp AND TARGET GStreamer::Rtp) - target_link_libraries(GStreamer::Sdp INTERFACE GStreamer::Rtp) - endif() - elseif (${component} STREQUAL "Tag") - find_gstreamer_component(Tag gstreamer-tag-1.0 gst/tag/tag.h gsttag-1.0) - if(TARGET GStreamer::Tag AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::Tag INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "Va") - find_gstreamer_component(Va gstreamer-va-1.0 gst/va/gstva.h gstva-1.0) - if(TARGET GStreamer::Va AND TARGET GStreamer::Base AND TARGET GStreamer::Allocators) - target_link_libraries(GStreamer::Va INTERFACE GStreamer::Base GStreamer::Allocators) - endif() - elseif (${component} STREQUAL "Prototypes") - find_gstreamer_component(Prototypes gstreamer-gl-prototypes-1.0 gst/gl/glprototypes/all_functions.h gstglproto-1.0) - if(TARGET GStreamer::Prototypes AND TARGET GStreamer::Gl) - target_link_libraries(GStreamer::Prototypes INTERFACE GStreamer::Gl) - endif() - elseif (${component} STREQUAL "X11") - find_gstreamer_component(X11 gstreamer-gl-x11-1.0 gst/gl/x11/x11.h x11-xcb) - if(TARGET GStreamer::X11) - if(GStreamer::Gl) - target_link_libraries(GStreamer::X11 INTERFACE GStreamer::Gl) - endif() - find_package(X11) - if(X11_FOUND) - target_link_libraries(GStreamer::X11 INTERFACE X11::X11) - endif() - find_package(XCB COMPONENTS XCB GLX) - if(XCB_FOUND) - target_link_libraries(GStreamer::X11 INTERFACE XCB::XCB XCB::GLX) - endif() - find_package(X11_XCB) - if(X11_XCB_FOUND) - target_link_libraries(GStreamer::X11 INTERFACE X11::XCB) - endif() - endif() - elseif (${component} STREQUAL "EGL") - find_gstreamer_component(EGL gstreamer-gl-egl-1.0 gst/gl/egl/egl.h egl) - if(TARGET GStreamer::EGL) - if(TARGET GStreamer::Gl) - target_link_libraries(GStreamer::EGL INTERFACE GStreamer::Gl) - endif() - find_package(EGL) - if(EGL_FOUND) - target_link_libraries(GStreamer::EGL INTERFACE EGL::EGL) - endif() - endif() - elseif (${component} STREQUAL "Wayland") - find_gstreamer_component(Wayland gstreamer-gl-wayland-1.0 gst/gl/wayland/wayland.h wayland-egl) - if(TARGET GStreamer::Wayland) - if(TARGET GStreamer::Gl) - target_link_libraries(GStreamer::Wayland INTERFACE GStreamer::Gl) - endif() - find_package(Wayland COMPONENTS Client Cursor Egl) - if(Wayland_FOUND) - target_link_libraries(GStreamer::Wayland INTERFACE 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(GStreamer::Wayland INTERFACE Wayland::Scanner) - endif() - find_package(Qt6 COMPONENTS WaylandClient) - if(Qt6WaylandClient_FOUND) - target_link_libraries(GStreamer::Wayland INTERFACE Qt6::WaylandClient) - endif() - endif() - elseif (${component} STREQUAL "PluginsBase") - find_gstreamer_component(PluginsBase gstreamer-plugins-base-1.0 gst/gst.h ) - if(TARGET GStreamer::PluginsBase AND TARGET GStreamer::Core) - target_link_libraries(GStreamer::PluginsBase INTERFACE GStreamer::Core) - endif() - elseif (${component} STREQUAL "PluginsGood") - find_gstreamer_component(PluginsGood gstreamer-plugins-good-1.0 gst/gst.h ) - if(TARGET GStreamer::PluginsGood AND TARGET GStreamer::Base) - target_link_libraries(GStreamer::PluginsGood INTERFACE GStreamer::Base) - endif() - elseif (${component} STREQUAL "PluginsBad") - find_gstreamer_component(PluginsBad gstreamer-plugins-bad-1.0 gst/gst.h ) - if(TARGET GStreamer::PluginsBad AND TARGET GStreamer::PluginsGood) - target_link_libraries(GStreamer::PluginsBad INTERFACE GStreamer::PluginsGood) - endif() - else() - message(WARNING "FindGStreamer.cmake: Invalid Gstreamer component \"${component}\" requested") - endif() -endforeach() +if(Fft IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Fft + PC_NAME gstreamer-fft-1.0 + HEADER gst/fft/cfft.h + LIBRARY gstfft-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(GlEgl IN_LIST GStreamer_FIND_COMPONENTS) + # find_package(EGL) + find_gstreamer_component(GlEgl + PC_NAME gstreamer-gl-egl-1.0 + HEADER gst/gl/egl/gstgldisplay_egl.h + LIBRARY gstgl-1.0 + DEPENDENCIES GStreamer::Gl EGL::EGL) +endif() + +if(GlPrototypes IN_LIST GStreamer_FIND_COMPONENTS) + # find_package(GLESv2) + # find_package(OpenGL OPTIONAL_COMPONENTS EGL GLX OpenGL) # GLES2 GLES3 + find_gstreamer_component(GlPrototypes + PC_NAME gstreamer-gl-prototypes-1.0 + HEADER gst/gl/glprototypes/all_functions.h + LIBRARY gstglproto-1.0 + DEPENDENCIES GStreamer::Gl GLESv2::GLESv2 OpenGL::GL) +endif() + +if(GlWayland IN_LIST GStreamer_FIND_COMPONENTS) + # find_package(Wayland COMPONENTS Client Cursor Egl) + # find_package(WaylandProtocols) + # find_package(WaylandScanner) + # find_package(Qt6 COMPONENTS WaylandClient) + find_gstreamer_component(GlWayland + PC_NAME gstreamer-gl-wayland-1.0 + HEADER gst/gl/wayland/gstgldisplay_wayland.h + LIBRARY gstgl-1.0 + DEPENDENCIES GStreamer::Gl Wayland::EGL Wayland::Client) +endif() + +if(GlX11 IN_LIST GStreamer_FIND_COMPONENTS) + # find_package(X11) + # find_package(XCB COMPONENTS XCB GLX) + # find_package(X11_XCB) + find_gstreamer_component(GlX11 + PC_NAME gstreamer-gl-x11-1.0 + HEADER gst/gl/x11/gstgldisplay_x11.h + LIBRARY gstgl-1.0 + DEPENDENCIES GStreamer::Gl X11::XCB) +endif() + +if(Mpegts IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Mpegts + PC_NAME gstreamer-mpegts-1.0 + HEADER gst/mpegts/mpegts.h + LIBRARY gstmpegts-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) +endif() + +if(Net IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Net + PC_NAME gstreamer-net-1.0 + HEADER gst/net/net.h + LIBRARY gstnet-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(Pbutils IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Pbutils + PC_NAME gstreamer-pbutils-1.0 + HEADER gst/pbutils/pbutils.h + LIBRARY gstpbutils-1.0 + DEPENDENCIES GStreamer::Video GStreamer::Audio GStreamer::Core GStreamer::Base) +endif() + +if(Photography IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Photography + PC_NAME gstreamer-photography-1.0 + HEADER gst/interfaces/photography.h + LIBRARY gstphotography-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) +endif() + +if(PluginsBad IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(PluginsBad + PC_NAME gstreamer-plugins-bad-1.0 + HEADER gst/gst.h + LIBRARY gstreamer-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(PluginsBase IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(PluginsBase + PC_NAME gstreamer-plugins-base-1.0 + HEADER gst/gst.h + LIBRARY gstreamer-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(PluginsGood IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(PluginsGood + PC_NAME gstreamer-plugins-good-1.0 + HEADER gst/gst.h + LIBRARY gstphotography-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) +endif() + +if(Riff IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Riff + PC_NAME gstreamer-riff-1.0 + HEADER gst/riff/riff.h + LIBRARY gstriff-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(Rtp IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Rtp + PC_NAME gstreamer-rtp-1.0 + HEADER gst/rtp/rtp.h + LIBRARY gstrtp-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Base) +endif() + +if(Sdp IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Sdp + PC_NAME gstreamer-sdp-1.0 + HEADER gst/sdp/sdp.h + LIBRARY gstsdp-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(Rtsp IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Rtsp + PC_NAME gstreamer-rtsp-1.0 + HEADER gst/rtsp/rtsp.h + LIBRARY gstrtsp-1.0 + DEPENDENCIES GStreamer::Sdp GStreamer::Core GLIB2::GIO) +endif() + +if(Tag IN_LIST GStreamer_FIND_COMPONENTS) + find_gstreamer_component(Tag + PC_NAME gstreamer-tag-1.0 + HEADER gst/tag/tag.h + LIBRARY gsttag-1.0 + DEPENDENCIES GStreamer::Core) +endif() + +if(Va IN_LIST GStreamer_FIND_COMPONENTS) + # find_package(VAAPI) + find_gstreamer_component(Va + PC_NAME gstreamer-va-1.0 + HEADER gst/va/gstva.h + LIBRARY gstva-1.0 + DEPENDENCIES GStreamer::Core GStreamer::Video) +endif() ################################################################################ @@ -401,8 +484,6 @@ if(TARGET PkgConfig::PC_GSTREAMER_GL) 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 @@ -427,7 +508,48 @@ endif() ################################################################################ -set(GST_TARGET_PLUGINS +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() + +# TODO: find_path +if(LINUX) + set(GSTREAMER_LIB_PATH ${GSTREAMER_PREFIX}/lib/x86_64-linux-gnu) +elseif(MACOS) + set(GSTREAMER_LIB_PATH ${GSTREAMER_PREFIX}/lib) +elseif(ANDROID OR WIN32) + set(GSTREAMER_LIB_PATH ${GSTREAMER_PREFIX}/lib) +elseif(IOS) + +endif() +set(GSTREAMER_PLUGIN_PATH ${GSTREAMER_LIB_PATH}/gstreamer-1.0) + +target_include_directories(GStreamer::GStreamer + INTERFACE + ${GSTREAMER_PREFIX}/include + ${GSTREAMER_PREFIX}/include/glib-2.0 + ${GSTREAMER_PREFIX}/include/graphene-1.0 + ${GSTREAMER_PREFIX}/include/gstreamer-1.0 + ${GSTREAMER_LIB_PATH}/glib-2.0/include + ${GSTREAMER_LIB_PATH}/graphene-1.0/include + ${GSTREAMER_PLUGIN_PATH}/include +) + +target_link_directories(GStreamer::GStreamer + INTERFACE + ${GSTREAMER_LIB_PATH} + ${GSTREAMER_PLUGIN_PATH} +) + +################################################################################ + +add_library(GStreamer::Plugins INTERFACE IMPORTED) + +set(GST_PLUGINS gstcoreelements gstisomp4 gstlibav @@ -443,197 +565,61 @@ set(GST_TARGET_PLUGINS gstudp gstvideoparsersbad gstx264 - # gstqml6 gstasf gstva + # gstqml6 ) if(ANDROID) - list(APPEND GST_TARGET_PLUGINS gstandroidmedia) + list(APPEND GST_PLUGINS gstandroidmedia) elseif(IOS) - list(APPEND GST_TARGET_PLUGINS gstapplemedia) + list(APPEND GST_PLUGINS gstapplemedia) endif() -find_package(PkgConfig QUIET) -foreach(plugin IN LISTS GST_TARGET_PLUGINS) +foreach(plugin IN LISTS GST_PLUGINS) if(PkgConfig_FOUND) - pkg_check_modules(GST_PLUGIN_${plugin} IMPORTED_TARGET GST_PLUGIN_${plugin} QUIET) + pkg_check_modules(GST_PLUGIN_${plugin} IMPORTED_TARGET ${plugin}) if(GST_PLUGIN_${plugin}_FOUND) - cmake_print_variables(plugin) - target_link_libraries(GStreamer::GStreamer INTERFACE PkgConfig::GST_PLUGIN_${plugin}) + target_link_libraries(GStreamer::Plugins INTERFACE PkgConfig::GST_PLUGIN_${plugin}) endif() endif() + if(NOT GST_PLUGIN_${plugin}_FOUND) find_library(GST_PLUGIN_${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_LIB_PATH} + ${GSTREAMER_PLUGIN_PATH} ) if(GST_PLUGIN_${plugin}_LIBRARY) cmake_print_variables(plugin) - target_link_libraries(GStreamer::GStreamer INTERFACE ${GST_PLUGIN_${plugin}_LIBRARY}) + target_link_libraries(GStreamer::Plugins INTERFACE ${GST_PLUGIN_${plugin}_LIBRARY}) + set(GST_PLUGIN_${plugin}_FOUND TRUE) endif() endif() endforeach() -# set(GST_DEPENDENCIES -# gstreamer-plugins-base-1.0 -# gstreamer-plugins-good-1.0 -# gstreamer-plugins-bad-1.0 -# glib-2.0 -# gio -# gobject-2.0 -# gthread-2.0 -# gmodule-2.0 -# gmodule-no-export-2.0 -# zlib -# drm -# graphene-1.0 -# opus -# ffi -# egl -# dl -# m -# pcre2-8 -# gudev-1.0 -# avcodec -# avdevice -# avfilter -# avformat -# avutil -# postproc -# swscale -# va -# va-drm -# va-glx -# va-wayland -# va-x11 -# orc -# pango -# vpl -# vdpau -# vpx -# x11 -# x264 -# x265 -# x11-xcb -# drm -# png -# zlib -# ) - -pkg_check_modules(GRAPHENE IMPORTED_TARGET graphene-1.0) -if(GRAPHENE_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE PkgConfig::GRAPHENE) -endif() - -pkg_check_modules(X264 IMPORTED_TARGET x264) -if(X264_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE PkgConfig::X264) -endif() - -find_package(VAAPI) -if(VAAPI_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE VAAPI::VAAPI) -endif() - -find_package(ZLIB) -if(ZLIB_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE ZLIB::ZLIB) -endif() - -find_package(OpenGL) -if(OpenGL_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE OpenGL::GL) -endif() - -find_package(GLESv2) -if(GLESv2_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE GLESv2::GLESv2) -endif() - -find_package(FFmpeg COMPONENTS AVCODEC AVFORMAT AVUTIL AVFILTER SWRESAMPLE) # AVDEVICE POSTPROC SWSCALE -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_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(Threads) -if(Threads_FOUND) - target_link_libraries(GStreamer::GStreamer INTERFACE Threads::Threads) -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() - -if(ANDROID OR WIN32) - # find_path(GStreamer_INCLUDE_DIR - # NAMES GStreamer - # 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 - # ) +if(NOT MACOS) + target_link_libraries(GStreamer::GStreamer INTERFACE GStreamer::Plugins) 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) +# set(PLUGINS_DECLARATION) +# set(PLUGINS_REGISTRATION) +# foreach(GST_P ${GST_PLUGINS}) +# list(APPEND LINK_LIBS "gst${GST_P}") +# list(APPEND PLUGINS_DECLARATION "\nGST_PLUGIN_STATIC_DECLARE(${GST_P})") +# list(APPEND PLUGINS_REGISTRATION "\nGST_PLUGIN_STATIC_REGISTER(${GST_P})") +# endforeach() + +# if(ANDROID) +# if(EXISTS ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/androidmedia) +# install(DIRECTORY ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/androidmedia DESTINATION ${CMAKE_BINARY_DIR}/android-build/src/org/freedesktop/androidmedia) +# endif() +# if(EXISTS ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/GStreamer.java) +# install(FILES ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/GStreamer.java DESTINATION ${CMAKE_BINARY_DIR}/android-build/src/org/freedesktop/GStreamer.java) +# endif() +# if(EXISTS ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/gstreamer_android-1.0.c.in) +# configure_file(${GSTREAMER_PREFIX}/share/gst-android/ndk-build/gstreamer_android-1.0.c.in ${CMAKE_CURRENT_BINARY_DIR}/gst_plugin_init_android.c) +# endif() +# endif() diff --git a/cmake/find-modules/FindTaglib.cmake b/cmake/find-modules/FindTaglib.cmake new file mode 100644 index 00000000000..e3a0014fccb --- /dev/null +++ b/cmake/find-modules/FindTaglib.cmake @@ -0,0 +1,92 @@ +# SPDX-FileCopyrightText: 2006 Laurent Montel +# SPDX-FileCopyrightText: 2019 Heiko Becker +# SPDX-FileCopyrightText: 2020 Elvis Angelaccio +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +FindTaglib +---------- + +Try to find the Taglib library. + +This will define the following variables: + +``Taglib_FOUND`` + True if the system has the taglib library of at least the minimum + version specified by the version parameter to find_package() +``Taglib_INCLUDE_DIRS`` + The taglib include dirs for use with target_include_directories +``Taglib_LIBRARIES`` + The taglib libraries for use with target_link_libraries() +``Taglib_VERSION`` + The version of taglib that was found + +If ``Taglib_FOUND`` is TRUE, it will also define the following imported +target: + +``Taglib::Taglib`` + The Taglib library + +Since 5.72.0 +#]=======================================================================] + +find_package(PkgConfig QUIET) + +pkg_check_modules(PC_TAGLIB QUIET taglib) + +find_path(Taglib_INCLUDE_DIRS + NAMES tag.h + PATH_SUFFIXES taglib + HINTS ${PC_TAGLIB_INCLUDEDIR} +) + +find_library(Taglib_LIBRARIES + NAMES tag + HINTS ${PC_TAGLIB_LIBDIR} +) + +set(Taglib_VERSION ${PC_TAGLIB_VERSION}) + +if (Taglib_INCLUDE_DIRS AND NOT Taglib_VERSION) + if(EXISTS "${Taglib_INCLUDE_DIRS}/taglib.h") + file(READ "${Taglib_INCLUDE_DIRS}/taglib.h" TAGLIB_H) + + string(REGEX MATCH "#define TAGLIB_MAJOR_VERSION[ ]+[0-9]+" TAGLIB_MAJOR_VERSION_MATCH ${TAGLIB_H}) + string(REGEX MATCH "#define TAGLIB_MINOR_VERSION[ ]+[0-9]+" TAGLIB_MINOR_VERSION_MATCH ${TAGLIB_H}) + string(REGEX MATCH "#define TAGLIB_PATCH_VERSION[ ]+[0-9]+" TAGLIB_PATCH_VERSION_MATCH ${TAGLIB_H}) + + string(REGEX REPLACE ".*_MAJOR_VERSION[ ]+(.*)" "\\1" TAGLIB_MAJOR_VERSION "${TAGLIB_MAJOR_VERSION_MATCH}") + string(REGEX REPLACE ".*_MINOR_VERSION[ ]+(.*)" "\\1" TAGLIB_MINOR_VERSION "${TAGLIB_MINOR_VERSION_MATCH}") + string(REGEX REPLACE ".*_PATCH_VERSION[ ]+(.*)" "\\1" TAGLIB_PATCH_VERSION "${TAGLIB_PATCH_VERSION_MATCH}") + + set(Taglib_VERSION "${TAGLIB_MAJOR_VERSION}.${TAGLIB_MINOR_VERSION}.${TAGLIB_PATCH_VERSION}") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Taglib + FOUND_VAR + Taglib_FOUND + REQUIRED_VARS + Taglib_LIBRARIES + Taglib_INCLUDE_DIRS + VERSION_VAR + Taglib_VERSION +) + +if (Taglib_FOUND AND NOT TARGET Taglib::Taglib) + add_library(Taglib::Taglib UNKNOWN IMPORTED) + set_target_properties(Taglib::Taglib PROPERTIES + IMPORTED_LOCATION "${Taglib_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${Taglib_INCLUDE_DIRS}" + ) +endif() + +mark_as_advanced(Taglib_LIBRARIES Taglib_INCLUDE_DIRS) + +include(FeatureSummary) +set_package_properties(Taglib PROPERTIES + URL "https://taglib.org/" + DESCRIPTION "A library for reading and editing the meta-data of audio formats" +) diff --git a/cmake/find-modules/FindVAAPI.cmake b/cmake/find-modules/FindVAAPI.cmake index a3ea6cd586e..b1170dc8edc 100644 --- a/cmake/find-modules/FindVAAPI.cmake +++ b/cmake/find-modules/FindVAAPI.cmake @@ -4,13 +4,40 @@ find_package(PkgConfig QUIET) +function(qt_internal_multimedia_set_va_outputs component include_dir lib_path) + if ("${component}" STREQUAL "VA") + set(VAAPI_INCLUDE_DIR "${include_dir}" CACHE INTERNAL "") + get_filename_component(lib_realpath "${lib_path}" REALPATH) + + string(REGEX MATCH "[0-9]+(\\.[0-9]+)*$" VAAPI_SUFFIX "${lib_realpath}") + set(VAAPI_SUFFIX "${VAAPI_SUFFIX}" CACHE INTERNAL "") + + mark_as_advanced(VAAPI_SUFFIX VAAPI_INCLUDE_DIR) + endif() +endfunction() + function(find_component component prefix header library) if(NOT TARGET VAAPI::${component}) string(TOUPPER ${component} upper) - pkg_check_modules(PC_VAAPI_${upper} ${prefix} IMPORTED_TARGET) + pkg_search_module(PC_VAAPI_${upper} ${prefix} IMPORTED_TARGET) if(TARGET PkgConfig::PC_VAAPI_${upper}) add_library(VAAPI::${component} INTERFACE IMPORTED) target_link_libraries(VAAPI::${component} INTERFACE PkgConfig::PC_VAAPI_${upper}) + + if (NOT PC_VAAPI_${upper}_LINK_LIBRARIES) + get_target_property(PC_VAAPI_${upper}_LINK_LIBRARIES PkgConfig::PC_VAAPI_${upper} INTERFACE_LINK_LIBRARIES) + message(STATUS "PC_VAAPI_${upper}_LINK_LIBRARIES is not defined by PkgConfig; " + "Get the value from target properties: ${PC_VAAPI_${upper}_LINK_LIBRARIES}") + endif() + + foreach (lib_path ${PC_VAAPI_${upper}_LINK_LIBRARIES}) + get_filename_component(lib_name "${lib_path}" NAME_WLE) + if (${lib_name} STREQUAL ${prefix}) + qt_internal_multimedia_set_va_outputs(${component} + "${PC_VAAPI_${upper}_INCLUDEDIR}" "${lib_path}") + break() + endif() + endforeach() else() find_path(VAAPI_${component}_INCLUDE_DIR NAMES ${header} @@ -25,6 +52,9 @@ function(find_component component prefix header library) target_link_libraries(VAAPI::${component} INTERFACE ${VAAPI_${component}_LIBRARY}) endif() mark_as_advanced(VAAPI_${component}_INCLUDE_DIR VAAPI_${component}_LIBRARY) + + qt_internal_multimedia_set_va_outputs(${component} + "${VAAPI_${component}_INCLUDE_DIR}" "${VAAPI_${component}_LIBRARY}") endif() endif() @@ -48,6 +78,8 @@ find_package_handle_standard_args(VAAPI REQUIRED_VARS VAAPI_VA_FOUND VAAPI_DRM_FOUND + VAAPI_INCLUDE_DIR + VAAPI_SUFFIX HANDLE_COMPONENTS ) diff --git a/cmake/find-modules/FindWaylandScanner.cmake b/cmake/find-modules/FindWaylandScanner.cmake index 2fa1fd6e8bc..60adaf41845 100644 --- a/cmake/find-modules/FindWaylandScanner.cmake +++ b/cmake/find-modules/FindWaylandScanner.cmake @@ -1,79 +1,81 @@ -# SPDX-FileCopyrightText: 2012-2014 Pier Luigi Fiorini +#.rst: +# FindWaylandScanner +# ------------------ # -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.rst: -FindWaylandScanner ------------------- - -Try to find wayland-scanner. - -If the wayland-scanner executable is not in your PATH, you can provide -an alternative name or full path location with the ``WaylandScanner_EXECUTABLE`` -variable. - -This will define the following variables: - -``WaylandScanner_FOUND`` - True if wayland-scanner is available. - -``WaylandScanner_EXECUTABLE`` - The wayland-scanner executable. - -If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported -target: - -``Wayland::Scanner`` - The wayland-scanner executable. - -This module provides the following functions to generate C protocol -implementations: - - - ``ecm_add_wayland_client_protocol`` - - ``ecm_add_wayland_server_protocol`` - -:: - - ecm_add_wayland_client_protocol( - PROTOCOL - BASENAME - [PRIVATE_CODE]) - - ecm_add_wayland_client_protocol( - PROTOCOL - BASENAME - [PRIVATE_CODE]) - -Generate Wayland client protocol files from ```` XML -definition for the ```` interface and append those files -to ```` or ````. - -``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code -from the compiled DSO for use in other DSOs. The default is to -export this code. - -:: - - ecm_add_wayland_server_protocol( - PROTOCOL - BASENAME - [PRIVATE_CODE]) - - ecm_add_wayland_server_protocol( - PROTOCOL - BASENAME - [PRIVATE_CODE]) - -Generate Wayland server protocol files from ```` XML -definition for the ```` interface and append those files -to ```` or ````. - -``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code -from the compiled DSO for use in other DSOs. The default is to -export this code. +# Try to find wayland-scanner. +# +# If the wayland-scanner executable is not in your PATH, you can provide +# an alternative name or full path location with the ``WaylandScanner_EXECUTABLE`` +# variable. +# +# This will define the following variables: +# +# ``WaylandScanner_FOUND`` +# True if wayland-scanner is available. +# +# ``WaylandScanner_EXECUTABLE`` +# The wayland-scanner executable. +# +# If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported +# target: +# +# ``Wayland::Scanner`` +# The wayland-scanner executable. +# +# This module provides the following functions to generate C protocol +# implementations: +# +# - ``ecm_add_wayland_client_protocol`` +# - ``ecm_add_wayland_server_protocol`` +# +# :: +# +# ecm_add_wayland_client_protocol( +# PROTOCOL +# BASENAME ) +# +# Generate Wayland client protocol files from ```` XML +# definition for the ```` interface and append those files +# to ````. +# +# :: +# +# ecm_add_wayland_server_protocol( +# PROTOCOL +# BASENAME ) +# +# Generate Wayland server protocol files from ```` XML +# definition for the ```` interface and append those files +# to ````. +# +# Since 1.4.0. -Since 1.4.0. -#]=======================================================================] +#============================================================================= +# Copyright 2012-2014 Pier Luigi Fiorini +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake) @@ -105,11 +107,10 @@ set_package_properties(WaylandScanner PROPERTIES DESCRIPTION "Executable that converts XML protocol files to C code" ) -function(ecm_add_wayland_client_protocol target_or_sources_var) +function(ecm_add_wayland_client_protocol out_var) # Parse arguments - set(options PRIVATE_CODE) set(oneValueArgs PROTOCOL BASENAME) - cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN}) + cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN}) if(ARGS_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"") @@ -118,66 +119,52 @@ function(ecm_add_wayland_client_protocol target_or_sources_var) get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE) set(_client_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h") set(_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c") - if(ARGS_PRIVATE_CODE) - set(_code_type private-code) - else() - set(_code_type public-code) - endif() set_source_files_properties(${_client_header} GENERATED) set_source_files_properties(${_code} GENERATED) - set_property(SOURCE ${_client_header} ${_code} PROPERTY SKIP_AUTOMOC ON) + set_property(SOURCE ${_client_header} PROPERTY SKIP_AUTOMOC ON) add_custom_command(OUTPUT "${_client_header}" COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header} - DEPENDS ${_infile} VERBATIM) + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} + VERBATIM + ) add_custom_command(OUTPUT "${_code}" - COMMAND ${WaylandScanner_EXECUTABLE} ${_code_type} ${_infile} ${_code} - DEPENDS ${_infile} ${_client_header} VERBATIM) - - if (TARGET ${target_or_sources_var}) - target_sources(${target_or_sources_var} PRIVATE "${_client_header}" "${_code}") - else() - list(APPEND ${target_or_sources_var} "${_client_header}" "${_code}") - set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE) - endif() + COMMAND ${WaylandScanner_EXECUTABLE} code ${_infile} ${_code} + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} ${_client_header} + VERBATIM + ) + + list(APPEND ${out_var} "${_client_header}" "${_code}") + set(${out_var} ${${out_var}} PARENT_SCOPE) endfunction() -function(ecm_add_wayland_server_protocol target_or_sources_var) +function(ecm_add_wayland_server_protocol out_var) # Parse arguments - set(options PRIVATE_CODE) set(oneValueArgs PROTOCOL BASENAME) - cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN}) + cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN}) if(ARGS_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"") endif() - if(ARGS_PRIVATE_CODE) - set(_private_code_option PRIVATE_CODE) - endif() - - ecm_add_wayland_client_protocol(${target_or_sources_var} + ecm_add_wayland_client_protocol(${out_var} PROTOCOL ${ARGS_PROTOCOL} - BASENAME ${ARGS_BASENAME} - ${_private_code_option}) + BASENAME ${ARGS_BASENAME}) get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE) set(_server_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h") - set(_server_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c") - set_property(SOURCE ${_server_header} ${_server_code} PROPERTY SKIP_AUTOMOC ON) + set_property(SOURCE ${_server_header} PROPERTY SKIP_AUTOMOC ON) set_source_files_properties(${_server_header} GENERATED) add_custom_command(OUTPUT "${_server_header}" COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header} - DEPENDS ${_infile} VERBATIM) + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} + VERBATIM + ) - if (TARGET ${target_or_sources_var}) - target_sources(${target_or_sources_var} PRIVATE "${_server_header}") - else() - list(APPEND ${target_or_sources_var} "${_server_header}") - set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE) - endif() + list(APPEND ${out_var} "${_server_header}") + set(${out_var} ${${out_var}} PARENT_SCOPE) endfunction() diff --git a/cmake/find-modules/FindXCB.cmake b/cmake/find-modules/FindXCB.cmake index f18c2fd0959..26b9bf89633 100644 --- a/cmake/find-modules/FindXCB.cmake +++ b/cmake/find-modules/FindXCB.cmake @@ -1,66 +1,88 @@ -# SPDX-FileCopyrightText: 2011 Fredrik Höglund -# SPDX-FileCopyrightText: 2013 Martin Gräßlin -# SPDX-FileCopyrightText: 2014-2015 Alex Merry +#.rst: +# FindXCB +# ------- # -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.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 - XF86DRI XFIXES XINERAMA XINPUT XKB - XTEST XV XVMC - -If no components are specified, this module will act as though all components -were passed to OPTIONAL_COMPONENTS. Before 5.82 this excluded XINPUT. Since 5.82 -all components are searched for. - -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__FOUND`` will be set to -true if the corresponding xcb library was found, and false otherwise. If -``XCB__FOUND`` is true, the imported target ``XCB::`` -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. +# 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__FOUND`` will be set to +# true if the corresponding xcb library was found, and false otherwise. If +# ``XCB__FOUND`` is true, the imported target ``XCB::`` +# 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. -Since pre-1.0.0. -#]=======================================================================] +#============================================================================= +# Copyright 2011 Fredrik Höglund +# Copyright 2013 Martin Gräßlin +# Copyright 2014-2015 Alex Merry +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake) @@ -96,10 +118,12 @@ set(XCB_known_components SCREENSAVER SYNC UTIL + XEVIE XF86DRI XINERAMA XINPUT XKB + XPRINT XTEST XV XVMC @@ -113,6 +137,9 @@ foreach(_comp ${XCB_known_components}) set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}") set(XCB_${_comp}_lib "xcb-${_lc_comp}") set(XCB_${_comp}_header "xcb/${_lc_comp}.h") + if(USE_XCB_${_comp}_STATIC) + set(XCB_${_comp}_lib "lib${XCB_${_comp}_lib}.a") + endif() endforeach() # exceptions set(XCB_XCB_component_deps) diff --git a/cmake/modules/ECMFindModuleHelpers.cmake b/cmake/modules/ECMFindModuleHelpers.cmake index 92c796e6bdd..a5dabb1074b 100644 --- a/cmake/modules/ECMFindModuleHelpers.cmake +++ b/cmake/modules/ECMFindModuleHelpers.cmake @@ -1,114 +1,134 @@ -# SPDX-FileCopyrightText: 2014 Alex Merry +#.rst: +# ECMFindModuleHelpers +# -------------------- # -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.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() - -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( - RESULT_VAR - KNOWN_COMPONENTS [ [...]] - [SKIP_DEPENDENCY_HANDLING]) - -This macro will populate with a list of components found in -_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 _FIND_REQUIRED) and call -``return()``. - -The order of components in 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 -__component_deps will be checked for dependent components. -If is listed in _FIND_COMPONENTS, then all its (transitive) -dependencies will also be added to . - -:: - - ecm_find_package_handle_library_components( - COMPONENTS [ [...]] - [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 __lib variable should contain the name of this library, -and __header variable should contain the name of a header -file associated with it (whatever relative path is normally passed to -'#include'). __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 ::. - -Additional variables can be used to provide additional information: - -If ``SKIP_PKG_CONFIG``, the __pkg_config variable is set, and -pkg-config is found, the pkg-config module given by -__pkg_config will be searched for and used to help locate the -library and header file. It will also be used to set -__VERSION. - -Note that if version information is found via pkg-config, -__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 will be set to contain the imported -targets for the components listed in __component_deps. -_FOUND will also be set to ``FALSE`` if any of the components in -__component_deps are not found. This requires the components -in __component_deps to be listed before in the -``COMPONENTS`` argument. - -The following variables will be set: - -``_TARGETS`` - the imported targets -``_LIBRARIES`` - the found libraries -``_INCLUDE_DIRS`` - the combined required include directories for the components -``_DEFINITIONS`` - the "other" CFLAGS provided by pkg-config, if any -``_VERSION`` - the value of ``__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:: - 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 - ``_TARGETS``, for example, will contain all the targets found in any - call (although no duplicates). +# 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() +# +# 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( +# RESULT_VAR +# KNOWN_COMPONENTS [ [...]] +# [SKIP_DEPENDENCY_HANDLING]) +# +# This macro will populate with a list of components found in +# _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 _FIND_REQUIRED) and call +# return(). +# +# The order of components in 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 +# __component_deps will be checked for dependent components. +# If is listed in _FIND_COMPONENTS, then all its (transitive) +# dependencies will also be added to . +# +# :: +# +# ecm_find_package_handle_library_components( +# COMPONENTS [ [...]] +# [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 __lib variable should contain the name of this library, +# and __header variable should contain the name of a header +# file associated with it (whatever relative path is normally passed to +# '#include'). __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 ::. +# +# Additional variables can be used to provide additional information: +# +# If SKIP_PKG_CONFIG, the __pkg_config variable is set, and +# pkg-config is found, the pkg-config module given by +# __pkg_config will be searched for and used to help locate the +# library and header file. It will also be used to set +# __VERSION. +# +# Note that if version information is found via pkg-config, +# __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 will be set to contain the imported +# targets for the components listed in __component_deps. +# _FOUND will also be set to false if any of the components in +# __component_deps are not found. This requires the components +# in __component_deps to be listed before in the +# COMPONENTS argument. +# +# The following variables will be set: +# +# ``_TARGETS`` +# the imported targets +# ``_LIBRARIES`` +# the found libraries +# ``_INCLUDE_DIRS`` +# the combined required include directories for the components +# ``_DEFINITIONS`` +# the "other" CFLAGS provided by pkg-config, if any +# ``_VERSION`` +# the value of ``__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 +# ``_TARGETS``, for example, will contain all the targets found in any +# call (although no duplicates). +# +# Since pre-1.0.0. -Since pre-1.0.0. -#]=======================================================================] +#============================================================================= +# Copyright 2014 Alex Merry +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. macro(ecm_find_package_version_check module_name) - if(CMAKE_VERSION VERSION_LESS 3.16.0) - message(FATAL_ERROR "CMake 3.16.0 is required by Find${module_name}.cmake") + 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 3.16.0) - message(AUTHOR_WARNING "Your project should require at least CMake 3.16.0 to use Find${module_name}.cmake") + 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() @@ -223,7 +243,10 @@ macro(ecm_find_package_handle_library_components module_name) set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) endif() - set(FPHSA_NAME_MISMATCHED 1) + set(_name_mismatched_arg) + if(NOT CMAKE_VERSION VERSION_LESS 3.17) + set(_name_mismatched_arg NAME_MISMATCHED) + endif() find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} FOUND_VAR ${module_name}_${ecm_fpwc_comp}_FOUND @@ -233,8 +256,8 @@ macro(ecm_find_package_handle_library_components module_name) ${ecm_fpwc_dep_vars} VERSION_VAR ${module_name}_${ecm_fpwc_comp}_VERSION + ${_name_mismatched_arg} ) - unset(FPHSA_NAME_MISMATCHED) mark_as_advanced( ${module_name}_${ecm_fpwc_comp}_LIBRARY diff --git a/deploy/linux/AppRun b/deploy/linux/AppRun index aab85507839..1373a15a9da 100755 --- a/deploy/linux/AppRun +++ b/deploy/linux/AppRun @@ -1,12 +1,21 @@ -#! /usr/bin/env bash +#!/bin/bash -# autogenerated by linuxdeploy - -# make sure errors in sourced scripts will cause this script to stop set -e -this_dir="$(readlink -f "$(dirname "$0")")" +HERE="$(dirname "$(readlink -f "${0}")")" + +# export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH}" + +export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no" +export GIO_EXTRA_MODULES="$HERE/usr/lib/gio/modules" -source "$this_dir"/apprun-hooks/"linuxdeploy-plugin-gstreamer.sh" +export GST_PLUGIN_SYSTEM_PATH="$HERE/usr/lib/gstreamer-1.0" +export GST_PLUGIN_SYSTEM_PATH_1_0="$HERE/usr/lib/gstreamer-1.0" +export GST_PLUGIN_PATH="$HERE/usr/lib/gstreamer-1.0" +export GST_PLUGIN_PATH_1_0="$HERE/usr/lib/gstreamer-1.0" +export GST_PLUGIN_SCANNER="$HERE/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" +export GST_PLUGIN_SCANNER_1_0="$HERE/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" +export GST_PTP_HELPER="$HERE/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" +export GST_PTP_HELPER_1_0="$HERE/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" -exec "$this_dir"/AppRun.wrapped "$@" +exec "$HERE/usr/bin/QGroundControl" "$@" diff --git a/deploy/linux/apprun-hooks/linux-deploy-gstreamer.sh b/deploy/linux/apprun-hooks/linux-deploy-gstreamer.sh deleted file mode 100644 index eba949d216a..00000000000 --- a/deploy/linux/apprun-hooks/linux-deploy-gstreamer.sh +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/bash - -export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no" -export GST_PLUGIN_SYSTEM_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0" -export GST_PLUGIN_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0" - -export GST_PLUGIN_SCANNER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" -export GST_PTP_HELPER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f5b46a0107..93b769f7eea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,6 +83,7 @@ target_link_libraries(QGC FollowMe Gimbal GPS + GStreamerReceiver Joystick MAVLink MissionManager 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..fbc9066eeef 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") @@ -53,20 +53,7 @@ VideoManager::VideoManager(QGCApplication* app, QGCToolbox* toolbox) , _subtitleWriter(new SubtitleWriter(this)) { #ifdef QGC_GST_STREAMING - // Gstreamer debug settings - int gstDebugLevel = 0; - QSettings settings; - if (settings.contains(AppSettings::gstDebugLevelName)) { - gstDebugLevel = settings.value(AppSettings::gstDebugLevelName).toInt(); - } - QStringList args = _app->arguments(); - const qsizetype argc = args.size(); - char** argv = new char*[argc]; - for (qsizetype i = 0; i < argc; i++) { - argv[i] = args[i].toUtf8().data(); - } - GStreamer::initialize(argc, argv, gstDebugLevel); - delete[] argv; + GStreamer::initialize(); #else qmlRegisterType("org.freedesktop.gstreamer.Qt6GLVideoItem", 1, 0, "GstGLQt6VideoItem"); #endif @@ -118,7 +105,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 bf4b14e47c4..531b5b591a7 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,13 +34,14 @@ target_sources(GStreamerReceiver if(IOS) target_sources(GStreamerReceiver PRIVATE - gst_ios_init.h gst_ios_init.m + gst_ios_init.h ) endif() target_link_libraries(GStreamerReceiver PRIVATE + QGC Utilities PUBLIC Qt6::Core @@ -46,4 +50,4 @@ target_link_libraries(GStreamerReceiver VideoReceiver ) -target_compile_definitions(QGC PUBLIC QGC_GST_STREAMING) +target_compile_definitions(GStreamerReceiver PUBLIC QGC_GST_STREAMING) 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 00b3c502432..7635b30d1ad 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc +++ b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc @@ -7,30 +7,59 @@ * ****************************************************************************/ - -/** - * @file - * @brief QGC Video Streaming Initialization - * @author Gus Grubba - */ - #include "GStreamer.h" #include "GstVideoReceiver.h" +#include "AppSettings.h" #include "QGCLoggingCategory.h" +#ifdef Q_OS_IOS +#include "gst_ios_init.h" +#endif -#include +#include +#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") + +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); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_MAC) +GST_PLUGIN_STATIC_DECLARE(va); +#endif +#ifdef 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 -static void qt_gst_log(GstDebugCategory * category, - GstDebugLevel level, - const gchar * file, - const gchar * function, - gint line, - GObject * object, - GstDebugMessage * message, - gpointer data) +static void qt_gst_log(GstDebugCategory *category, + GstDebugLevel level, + const gchar *file, + const gchar *function, + gint line, + GObject *object, + GstDebugMessage *message, + gpointer data) { Q_UNUSED(data); @@ -40,7 +69,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 +95,40 @@ 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())); + const QByteArray keyArray = key.toLocal8Bit(); + const QByteArray valueArray = (root + path).toLocal8Bit(); + (void) qputenv(keyArray, valueArray); } -#endif -void -GStreamer::blacklist(VideoDecoderOptions option) +static void _setGstEnvVars() { - GstRegistry* registry = gst_registry_get(); - - if (registry == nullptr) { - 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) { - 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); - 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; - } -} - -void -GStreamer::initialize(int argc, char* argv[], int debuglevel) -{ - 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) && !defined(Q_OS_ANDROID) - // 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"); -#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); - } - // Initialize GStreamer -#if defined(Q_OS_IOS) - //-- iOS specific initialization - gst_ios_pre_init(); +#if defined(Q_OS_MAC) + _qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no"); + _qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-plugin-scanner"); + _qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-ptp-helper"); + _qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/lib/gio/modules"); + _qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0"); // PlugIns/gstreamer + _qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0"); + _qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0"); + _qgcputenv("GST_PLUGIN_PATH", currentDir, "/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0"); +#elif defined(Q_OS_WIN) + _qgcputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no"); + _qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/../libexec/gstreamer-1.0/gst-plugin-scanner"); + _qgcputenv("GST_PTP_HELPER_1_0", currentDir, "/../libexec/gstreamer-1.0/gst-ptp-helper"); + _qgcputenv("GIO_EXTRA_MODULES", currentDir, "/../lib/gio/modules"); + _qgcputenv("GST_PLUGIN_SYSTEM_PATH_1_0", currentDir, "/../lib/gstreamer-1.0"); + _qgcputenv("GST_PLUGIN_SYSTEM_PATH", currentDir, "/../lib/gstreamer-1.0"); + _qgcputenv("GST_PLUGIN_PATH_1_0", currentDir, "/../lib/gstreamer-1.0"); + _qgcputenv("GST_PLUGIN_PATH", currentDir, "/../lib/gstreamer-1.0"); #endif +} - GError* error = nullptr; - if (!gst_init_check(&argc, &argv, &error)) { - qCCritical(GStreamerLog) << "gst_init_check() failed: " << error->message; - g_error_free(error); - } - - // The static plugins we use +static void _registerPlugins() +{ #ifdef QGC_GST_STATIC_BUILD GST_PLUGIN_STATIC_REGISTER(coreelements); GST_PLUGIN_STATIC_REGISTER(playback); @@ -240,15 +144,63 @@ 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); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_MAC) + GST_PLUGIN_STATIC_REGISTER(va); +#endif +#ifdef Q_OS_ANDROID GST_PLUGIN_STATIC_REGISTER(androidmedia); #elif defined(Q_OS_IOS) GST_PLUGIN_STATIC_REGISTER(applemedia); #endif #endif +} + +namespace GStreamer +{ + +void initialize() +{ + (void) qRegisterMetaType("STATUS"); + + _setGstEnvVars(); + + if (qEnvironmentVariableIsEmpty("GST_DEBUG")) { + int gstDebugLevel = 0; + QSettings settings; + if (settings.contains(AppSettings::gstDebugLevelName)) { + gstDebugLevel = settings.value(AppSettings::gstDebugLevelName).toInt(); + } + gst_debug_set_default_threshold(static_cast(gstDebugLevel)); + gst_debug_remove_log_function(gst_debug_log_default); + gst_debug_add_log_function(qt_gst_log, nullptr, nullptr); + } + +#ifdef Q_OS_IOS + gst_ios_pre_init(); +#endif + + const QStringList args = QCoreApplication::arguments(); + int argc = args.size(); + QList argList; + argList.reserve(argc); + + char **argv = new char*[argc]; + for (int i = 0; i < argc; i++) { + (void) argList.append(args[i].toUtf8()); + argv[i] = argList[i].data(); + } + + GError *error = nullptr; + if (!gst_init_check(&argc, &argv, &error)) { + qCCritical(GStreamerLog) << Q_FUNC_INFO << error->message; + g_error_free(error); + } + delete[] argv; -#if defined(Q_OS_IOS) + _registerPlugins(); + +#ifdef Q_OS_IOS gst_ios_post_init(); #endif @@ -256,14 +208,68 @@ GStreamer::initialize(int argc, char* argv[], int debuglevel) GST_PLUGIN_STATIC_REGISTER(qgc); } -void* -GStreamer::createVideoSink(QObject* parent, QQuickItem* widget) +void blacklist(VideoDecoderOptions option) { - Q_UNUSED(parent) + GstRegistry *const registry = gst_registry_get(); + + if (!registry) { + qCCritical(GStreamerLog) << "Failed to get gstreamer registry."; + return; + } + + const 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); + (void) gst_registry_add_feature(registry, feature); + gst_object_unref(feature); + }; + + changeRank("bcmdec", GST_RANK_NONE); + + switch (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; + } +} - GstElement* sink; +void *createVideoSink(QObject *parent, QQuickItem *widget) +{ + Q_UNUSED(parent) - if ((sink = gst_element_factory_make("qgcvideosinkbin", nullptr)) != nullptr) { + GstElement *const sink = gst_element_factory_make("qgcvideosinkbin", NULL); + if (sink) { g_object_set(sink, "widget", widget, NULL); } else { qCCritical(GStreamerLog) << "gst_element_factory_make('qgcvideosinkbin') failed"; @@ -272,17 +278,16 @@ GStreamer::createVideoSink(QObject* parent, QQuickItem* widget) return sink; } -void -GStreamer::releaseVideoSink(void* sink) +void releaseVideoSink(void *sink) { - if (sink != nullptr) { + if (sink) { gst_object_unref(GST_ELEMENT(sink)); } } -VideoReceiver* -GStreamer::createVideoReceiver(QObject* parent) +VideoReceiver *createVideoReceiver(QObject *parent) { - Q_UNUSED(parent) - return new GstVideoReceiver(nullptr); + return new GstVideoReceiver(parent); } + +} // namespace GStreamer diff --git a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.h index 71b185b18f5..f70cad0b120 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; + +namespace GStreamer +{ +enum VideoDecoderOptions { + ForceVideoDecoderDefault = 0, + ForceVideoDecoderSoftware, + ForceVideoDecoderNVIDIA, + ForceVideoDecoderVAAPI, + ForceVideoDecoderDirectX3D, + ForceVideoDecoderVideoToolbox, +}; -class GStreamer { -public: - 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); +void initialize(); +void blacklist(VideoDecoderOptions option); +void *createVideoSink(QObject *parent, QQuickItem *widget); +void releaseVideoSink(void *sink); +VideoReceiver *createVideoReceiver(QObject *parent = nullptr); }; diff --git a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m index 6158e1bca87..c0f54f190ff 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m +++ b/src/VideoManager/VideoReceiver/GStreamer/gst_ios_init.m @@ -22,59 +22,61 @@ extern void G_PASTE(g_io_module_, G_PASTE(name, _load_static)) (void) 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); + 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"]; - ca_certificates = g_build_filename (resources_dir, "ssl", "certs", "ca-certificates.crt", NULL); - g_setenv ("CA_CERTIFICATES", ca_certificates, TRUE); - g_free (ca_certificates); + 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]; + + 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:// */ + 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 + #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")) { - /* 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); + 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")) { + /* 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); + } } } 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..f2a3fe1d357 --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgc.cc @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * (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" + +static gboolean +plugin_init(GstPlugin *plugin) +{ + gboolean ret = FALSE; + + // ret |= GST_ELEMENT_REGISTER(qgcvideosinkbin, plugin); + ret |= gst_element_register_qgcvideosinkbin(plugin); + + return ret; +} + +#define GST_PACKAGE_NAME "GStreamer plugin for QGC's Video Receiver" +#define GST_PACKAGE_ORIGIN "https://qgroundcontrol.com/" +#define GST_LICENSE "LGPL" +#define PACKAGE "QGC Video Receiver" +#define PACKAGE_VERSION "current" + +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/gstqgcelement.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc new file mode 100644 index 00000000000..eaba411bc33 --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelement.cc @@ -0,0 +1,10 @@ +#include "gstqgcelements.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..cf5d283c11f --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcelements.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +void qgc_element_init(GstPlugin *plugin); + +gboolean gst_element_register_qgcvideosinkbin(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 54% rename from src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.c rename to src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.cc index 4e26e158f02..ca957f0315f 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.c +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.cc @@ -7,38 +7,30 @@ * ****************************************************************************/ -/** - * @file - * @brief GStreamer plugin for QGC's Video Receiver - * @author Andrew Voznyts - * @author Tomaz Canabrava - */ - -#include -#include -#include - -GST_DEBUG_CATEGORY_STATIC(gst_qgc_video_sink_bin_debug); +#include "gstqgcvideosinkbin.h" +#include "gstqgcelements.h" + #define GST_CAT_DEFAULT gst_qgc_video_sink_bin_debug +GST_DEBUG_CATEGORY_STATIC(GST_CAT_DEFAULT); -typedef struct _GstQgcVideoSinkElement GstQgcVideoSinkElement; +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); -typedef struct _GstQgcVideoSinkBin { - GstBin bin; - GstElement* glupload; - GstElement* qmlglsink; -} GstQgcVideoSinkBin; +static gboolean gst_qgc_video_sink_bin_sink_pad_query(GstPad *pad, GstObject *parent, GstQuery *query); -typedef struct _GstQgcVideoSinkBinClass { - GstBinClass parent_class; -} GstQgcVideoSinkBinClass; +#define DEFAULT_ENABLE_LAST_SAMPLE TRUE +#define DEFAULT_FORCE_ASPECT_RATIO TRUE +#define DEFAULT_PAR_N 0 +#define DEFAULT_PAR_D 1 +#define DEFAULT_SYNC TRUE -#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)) +#define PROP_ENABLE_LAST_SAMPLE_NAME "enable-last-sample" +#define PROP_LAST_SAMPLE_NAME "last-sample" +#define PROP_WIDGET_NAME "widget" +#define PROP_FORCE_ASPECT_RATIO_NAME "force-aspect-ratio" +#define PROP_PIXEL_ASPECT_RATIO_NAME "pixel-aspect-ratio" +#define PROP_SYNC_NAME "sync" enum { PROP_0, @@ -50,191 +42,207 @@ enum { PROP_SYNC, }; -#define PROP_ENABLE_LAST_SAMPLE_NAME "enable-last-sample" -#define PROP_LAST_SAMPLE_NAME "last-sample" -#define PROP_WIDGET_NAME "widget" -#define PROP_FORCE_ASPECT_RATIO_NAME "force-aspect-ratio" -#define PROP_PIXEL_ASPECT_RATIO_NAME "pixel-aspect-ratio" -#define PROP_SYNC_NAME "sync" +#define gst_qgc_video_sink_bin_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE(GstQgcVideoSinkBin, gst_qgc_video_sink_bin, GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, "qgcsinkbin", 0, "QGC Video Sink Bin")); -#define DEFAULT_ENABLE_LAST_SAMPLE TRUE -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 -#define DEFAULT_SYNC TRUE +// GST_ELEMENT_REGISTER_DEFINE_WITH_CODE(qgcvideosinkbin, "qgcvideosinkbin", GST_RANK_NONE, GST_TYPE_QGC_VIDEO_SINK_BIN, qgc_element_init(plugin)); +G_BEGIN_DECLS +gboolean G_PASTE(gst_element_register_, qgcvideosinkbin)(GstPlugin *plugin) +{ + { + { + qgc_element_init(plugin); + } + } + return gst_element_register(plugin, "qgcvideosinkbin", GST_RANK_NONE, (gst_qgc_video_sink_bin_get_type())); +} +G_END_DECLS; -static GstBinClass *parent_class; +static void +gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass) +{ + GObjectClass *const gobject_klass = G_OBJECT_CLASS(klass); + GstElementClass *const gstelement_klass = GST_ELEMENT_CLASS(klass); -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); + parent_class = g_type_class_peek_parent(GST_BIN_CLASS(klass)); -static gboolean -_vsb_sink_pad_query(GstPad* pad, GstObject* parent, GstQuery* query) -{ - GstQgcVideoSinkBin *vsb; - GstElement* element; - - vsb = GST_QGC_VIDEO_SINK_BIN(parent); + 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; - 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); - } + 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))); - if (element == NULL) { - GST_ERROR_OBJECT(vsb, "No element found"); - return FALSE; - } + 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))); - GstPad* sinkpad = gst_element_get_static_pad(element, "sink"); + 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))); - if (sinkpad == NULL) { - GST_ERROR_OBJECT(vsb, "No sink pad found"); - return FALSE; - } + 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))); - const gboolean ret = gst_pad_query(sinkpad, query); + 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))); - gst_object_unref(sinkpad); - sinkpad = NULL; + 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))); - return ret; + gst_element_class_set_static_metadata(gstelement_klass, + "QGC Video Sink Bin", "Sink/Video/Bin", + "Video rendering for QGC", + "Andrew Voznytsa , Tomaz Canabrava "); } 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; - - do { - if ((vsb->glupload = gst_element_factory_make("glupload", NULL)) == NULL) { - GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glupload') failed"); - break; - } - - if ((vsb->qmlglsink = gst_element_factory_make("qml6glsink", NULL)) == NULL) { - GST_ERROR_OBJECT(vsb, "gst_element_factory_make('qml6glsink') failed"); - break; - } - - if ((glcolorconvert = gst_element_factory_make("glcolorconvert", NULL)) == NULL) { - GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glcolorconvert' failed)"); - break; - } - - if ((pad = gst_element_get_static_pad(vsb->glupload, "sink")) == NULL) { - GST_ERROR_OBJECT(vsb, "gst_element_get_static_pad(glupload, 'sink') failed"); - break; - } + gboolean initialized = FALSE; + gboolean ret = FALSE; + GstElement *glcolorconvert = NULL; + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + + vsb->glupload = gst_element_factory_make("glupload", NULL); + if (!vsb->glupload) { + GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glupload') failed"); + goto init_failed; + } - gst_object_ref(vsb->glupload); - gst_object_ref(vsb->qmlglsink); + vsb->qmlglsink = gst_element_factory_make("qml6glsink", NULL); + if (!vsb->qmlglsink) { + GST_ERROR_OBJECT(vsb, "gst_element_factory_make('qml6glsink') failed"); + goto init_failed; + } - gst_bin_add_many(GST_BIN(vsb), vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); + glcolorconvert = gst_element_factory_make("glcolorconvert", NULL); + if (!glcolorconvert) { + GST_ERROR_OBJECT(vsb, "gst_element_factory_make('glcolorconvert' failed)"); + goto init_failed; + } - gboolean ret = gst_element_link_many(vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); + pad = gst_element_get_static_pad(vsb->glupload, "sink"); + if (!pad) { + GST_ERROR_OBJECT(vsb, "gst_element_get_static_pad(glupload, 'sink') failed"); + goto init_failed; + } - glcolorconvert = NULL; + (void) gst_object_ref(vsb->glupload); + (void) gst_object_ref(vsb->qmlglsink); - if (!ret) { - GST_ERROR_OBJECT(vsb, "gst_element_link_many() failed"); - break; - } + gst_bin_add_many(GST_BIN(vsb), vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); - GstPad* ghostpad; + ret = gst_element_link_many(vsb->glupload, glcolorconvert, vsb->qmlglsink, NULL); + glcolorconvert = NULL; + if (!ret) { + GST_ERROR_OBJECT(vsb, "gst_element_link_many() failed"); + goto init_failed; + } - if ((ghostpad = gst_ghost_pad_new("sink", pad)) == NULL) { - GST_ERROR_OBJECT(vsb, "gst_ghost_pad_new('sink') failed"); - break; - } + ghostpad = gst_ghost_pad_new("sink", pad); + if (!ghostpad) { + GST_ERROR_OBJECT(vsb, "gst_ghost_pad_new('sink') failed"); + goto init_failed; + } - 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"); - break; - } + if (!gst_element_add_pad(GST_ELEMENT(vsb), ghostpad)) { + GST_ERROR_OBJECT(vsb, "gst_element_add_pad() failed"); + goto init_failed; + } - initialized = TRUE; - } while(0); + initialized = TRUE; - if (pad != NULL) { +init_failed: + 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; } } } -static void -_vsb_dispose(GObject *object) +static gboolean +gst_qgc_video_sink_bin_sink_pad_query(GstPad *pad, GstObject *parent, GstQuery *query) { - GstQgcVideoSinkBin *vsb; + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(parent); + GstElement *element = NULL; - vsb = GST_QGC_VIDEO_SINK_BIN(object); + 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->qmlglsink != NULL) { - gst_object_unref(vsb->qmlglsink); - vsb->qmlglsink = NULL; + if (!element) { + GST_ERROR_OBJECT(vsb, "No element found"); + return FALSE; } - if (vsb->glupload != NULL) { - gst_object_unref(vsb->glupload); - vsb->glupload = NULL; + GstPad *sinkpad = gst_element_get_static_pad(element, "sink"); + if (!sinkpad) { + GST_ERROR_OBJECT(vsb, "No sink pad found"); + return FALSE; } - G_OBJECT_CLASS(parent_class)->dispose(object); + 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: - do { + if (vsb->qmlglsink) { gboolean enable = FALSE; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_ENABLE_LAST_SAMPLE_NAME, &enable, NULL); g_value_set_boolean(value, enable); - } while(0); + } break; case PROP_LAST_SAMPLE: - do { + if (vsb->qmlglsink) { GstSample *sample = NULL; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_LAST_SAMPLE_NAME, &sample, NULL); gst_value_set_sample(value, sample); @@ -242,35 +250,35 @@ _vsb_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *psp gst_sample_unref(sample); sample = NULL; } - } while(0); + } break; case PROP_WIDGET: - do { + if (vsb->qmlglsink) { gpointer widget = NULL; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_WIDGET_NAME, &widget, NULL); g_value_set_pointer(value, widget); - } while(0); + } break; case PROP_FORCE_ASPECT_RATIO: - do { + if (vsb->qmlglsink) { gboolean enable = FALSE; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_FORCE_ASPECT_RATIO_NAME, &enable, NULL); g_value_set_boolean(value, enable); - } while(0); + } break; case PROP_PIXEL_ASPECT_RATIO: - do { + if (vsb->qmlglsink) { gint num = 0, den = 1; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_PIXEL_ASPECT_RATIO_NAME, &num, &den, NULL); gst_value_set_fraction(value, num, den); - } while(0); + } break; case PROP_SYNC: - do { + if (vsb->qmlglsink) { gboolean enable = FALSE; g_object_get(G_OBJECT(vsb->qmlglsink), PROP_SYNC_NAME, &enable, NULL); g_value_set_boolean(value, enable); - } while(0); + } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -279,11 +287,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 +313,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; + GstQgcVideoSinkBin *const vsb = GST_QGC_VIDEO_SINK_BIN(object); - 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))); - - 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..bce8bdabf12 --- /dev/null +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqgcvideosinkbin.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * (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) +#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_QGC_VIDEO_SINK_BIN, GstQgcVideoSinkBin)) +#define GST_QGC_VIDEO_SINK_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_QGC_VIDEO_SINK_BIN, GstQgcVideoSinkBinClass)) +#define GST_IS_QGC_VIDEO_SINK_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_QGC_VIDEO_SINK_BIN)) +#define GST_IS_QGC_VIDEO_SINK_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_QGC_VIDEO_SINK_BIN)) + +struct _GstQgcVideoSinkBin { + GstBin bin; + GstElement *glupload; + GstElement *qmlglsink; +}; + +struct _GstQgcVideoSinkBinClass { + GstBinClass parent_class; +}; + +GstQgcVideoSinkBin* gst_qgc_video_sink_bin_new(void); + +G_END_DECLS diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt index f4e8fb30b53..ae73d784916 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt @@ -1,5 +1,5 @@ find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick) -find_package(GStreamer REQUIRED COMPONENTS Allocators Audio Codecparsers Controller Fft Mpegts Net Pbutils Riff Rtp Rtsp Sdp Tag OPTIONAL_COMPONENTS Photography Prototypes Va X11 EGL Wayland) +find_package(GStreamer REQUIRED COMPONENTS Allocators Audio Codecparsers Controller Fft Mpegts Net Pbutils Riff Rtp Rtsp Sdp Tag OPTIONAL_COMPONENTS Photography GlPrototypes Va GlX11 GlEGL GlWayland) qt_add_library(gstqml6gl STATIC) @@ -32,8 +32,8 @@ if(GStreamer_Photography_FOUND) target_link_libraries(gstqml6gl PUBLIC GStreamer::Photography) endif() -if(GStreamer_Prototypes_FOUND) - target_link_libraries(gstqml6gl PUBLIC GStreamer::Prototypes) +if(GStreamer_GlPrototypes_FOUND) + target_link_libraries(gstqml6gl PUBLIC GStreamer::GlPrototypes) endif() if(GStreamer_Va_FOUND) @@ -45,7 +45,7 @@ endif() # TODO: Don't Download & Build if gstreamer1.0-qt6 was found if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.22) FetchContent_Declare(gstreamer_good_plugins - # URL https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GStreamer_VERSION}/gstreamer-${GStreamer_VERSION}.zip?path=subprojects/gst-plugins-good/ext/qt6 + # URL 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 ) @@ -77,18 +77,18 @@ target_include_directories(gstqml6gl PUBLIC ${QGC_GST_QT6_PLUGIN_PATH}) ################################################################################ -if(GStreamer_X11_FOUND) - target_link_libraries(gstqml6gl PUBLIC GStreamer::X11) +if(GStreamer_GlX11_FOUND) + target_link_libraries(gstqml6gl PUBLIC GStreamer::GlX11) target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_X11) endif() -if(GStreamer_EGL_FOUND) - target_link_libraries(gstqml6gl PUBLIC GStreamer::EGL) +if(GStreamer_GlEGL_FOUND) + target_link_libraries(gstqml6gl PUBLIC GStreamer::GlEGL) target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_EGLFS) endif() -if(GStreamer_Wayland_FOUND) - target_link_libraries(gstqml6gl PUBLIC GStreamer::Wayland) +if(GStreamer_GlWayland_FOUND) + target_link_libraries(gstqml6gl PUBLIC GStreamer::GlWayland) target_compile_definitions(gstqml6gl PRIVATE HAVE_QT_WAYLAND) endif() @@ -132,12 +132,6 @@ if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/resources.qrc") LIST(APPEND SHADERS ${QGC_GST_QT6_PLUGIN_PATH}/YUV_BIPLANAR.frag) LIST(APPEND OUTPUTS YUV_BIPLANAR.frag.qsb) endif() - if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/RGBA_gles.frag") - LIST(APPEND SHADERS ${QGC_GST_QT6_PLUGIN_PATH}/RGBA.frag@glsl,100es,${QGC_GST_QT6_PLUGIN_PATH}/RGBA_gles.frag) - LIST(APPEND OUTPUTS RGBA_gles.frag.qsb) - # file(COPY_FILE RGBA_gles.frag RGBA_gles.frag.qsb) - # LIST(APPEND OUTPUTS RGBA_gles.frag.qsb.external) - endif() qt6_add_shaders(gstqml6gl "gstqml6gl_shaders" PREFIX "/org/freedesktop/gstreamer/qml6" GLSL "100 es,120,330" @@ -146,6 +140,16 @@ if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/resources.qrc") OUTPUTS ${OUTPUTS} BATCHABLE ) + + if(EXISTS "${QGC_GST_QT6_PLUGIN_PATH}/RGBA_gles.frag") + file(COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/.qsb/RGBA.frag.qsb" "${CMAKE_CURRENT_BINARY_DIR}/.qsb/RGBA.frag.qsb.external") + qt6_add_shaders(gstqml6gl "gstqml6gl_shaders1" + PREFIX "/org/freedesktop/gstreamer/qml6" + OUTPUT_TARGETS gstqml6gl_shaders1 + FILES "${CMAKE_CURRENT_BINARY_DIR}/.qsb/RGBA.frag.qsb.external@glsl,100es,${QGC_GST_QT6_PLUGIN_PATH}/RGBA_gles.frag" + OUTPUTS "RGBA.frag.qsb.external" + ) + endif() endif() endif() @@ -163,27 +167,43 @@ 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}) + install(DIRECTORY ${GSTREAMER_LIB_PATH}/gstreamer1.0 DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(DIRECTORY ${GSTREAMER_LIB_PATH}/gio DESTINATION ${CMAKE_INSTALL_LIBDIR}) + get_target_property(LINKED_PLUGINS GStreamer::Plugins INTERFACE_LINK_LIBRARIES) + install(FILES ${LINKED_PLUGINS} DESTINATION ${CMAKE_INSTALL_LIBDIR}/gstreamer-1.0) elseif(WIN32) cmake_path(CONVERT "${GSTREAMER_PREFIX}/bin/*.dll" TO_CMAKE_PATH_LIST GST_WIN_BINS_PATH) file(GLOB GST_WIN_BINS ${GST_WIN_BINS_PATH}) install(FILES ${GST_WIN_BINS} DESTINATION ${CMAKE_INSTALL_BINDIR}) - cmake_path(CONVERT "${GSTREAMER_PREFIX}/lib/gio/modules/*.dll" TO_CMAKE_PATH_LIST GST_GIO_MODULES_PATH) + cmake_path(CONVERT "${GSTREAMER_LIB_PATH}/gio/modules/*.dll" TO_CMAKE_PATH_LIST GST_GIO_MODULES_PATH) file(GLOB GST_GIO_MODULES ${GST_GIO_MODULES_PATH}) install(FILES ${GST_GIO_MODULES} DESTINATION ${CMAKE_INSTALL_LIBDIR}/gio/modules) - cmake_path(CONVERT "${GSTREAMER_PREFIX}/lib/gstreamer-1.0/*.dll" TO_CMAKE_PATH_LIST GST_WIN_PLUGINS_PATH) + cmake_path(CONVERT "${GSTREAMER_PLUGIN_PATH}/*.dll" TO_CMAKE_PATH_LIST GST_WIN_PLUGINS_PATH) file(GLOB GST_WIN_PLUGINS ${GST_WIN_PLUGINS_PATH}) install(FILES ${GST_WIN_PLUGINS} DESTINATION ${CMAKE_INSTALL_LIBDIR}/gstreamer-1.0) cmake_path(CONVERT "${GSTREAMER_PREFIX}/libexec/gstreamer-1.0/*.exe" TO_CMAKE_PATH_LIST GST_HELPER_BINS_PATH) file(GLOB GST_HELPER_BINS ${GST_HELPER_BINS_PATH}) install(FILES ${GST_HELPER_BINS} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/gstreamer-1.0) +elseif(MACOS) + # cmake_path(CONVERT "${GSTREAMER_PREFIX}/bin/*.dylib" TO_CMAKE_PATH_LIST GST_MACOS_BINS_PATH) + # file(GLOB GST_MACOS_BINS ${GST_MACOS_BINS_PATH}) + # install(FILES ${GST_MACOS_BINS} DESTINATION ${CMAKE_INSTALL_BINDIR}) + + # cmake_path(CONVERT "${GSTREAMER_LIB_PATH}/gio/modules/*.dylib" TO_CMAKE_PATH_LIST GST_GIO_MODULES_PATH) + # file(GLOB GST_GIO_MODULES ${GST_GIO_MODULES_PATH}) + # install(FILES ${GST_GIO_MODULES} DESTINATION ${CMAKE_INSTALL_LIBDIR}/gio/modules) + + # cmake_path(CONVERT "${GSTREAMER_PLUGIN_PATH}/*.dylib" TO_CMAKE_PATH_LIST GST_MACOS_PLUGINS_PATH) + # file(GLOB GST_MACOS_PLUGINS ${GST_MACOS_PLUGINS_PATH}) + # install(FILES ${GST_MACOS_PLUGINS} DESTINATION ${CMAKE_INSTALL_LIBDIR}/gstreamer-1.0) + + # cmake_path(CONVERT "${GSTREAMER_PREFIX}/libexec/gstreamer-1.0/*" TO_CMAKE_PATH_LIST GST_HELPER_BINS_PATH) + # file(GLOB GST_HELPER_BINS ${GST_HELPER_BINS_PATH}) + # install(FILES ${GST_HELPER_BINS} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/gstreamer-1.0) elseif(ANDROID) - # install(DIRECTORY ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/androidmedia DESTINATION ${CMAKE_SOURCE_DIR}/android/src/org/freedesktop/androidmedia) - # install(FILES ${GSTREAMER_PREFIX}/share/gst-android/ndk-build/GStreamer.java DESTINATION ${CMAKE_SOURCE_DIR}/android/src/org/freedesktop/androidmedia) if(CMAKE_HOST_WIN32) cmake_path(CONVERT "${GSTREAMER_PREFIX}/share/gst-android/ndk-build/tools/windows/*.dll" TO_CMAKE_PATH_LIST GST_WIN_TOOLS_PATH) file(GLOB GST_WIN_TOOLS ${GST_WIN_TOOLS_PATH}) @@ -192,3 +212,23 @@ elseif(ANDROID) endif() ################################################################################ + +# LSEnvironment +# +# GST_REGISTRY_REUSE_PLUGIN_SCANNER +# no +# GST_PLUGIN_SCANNER +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-plugin-scanner +# GST_PTP_HELPER_1_0 +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-ptp-helper +# GIO_EXTRA_MODULES +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/gio/modules +# GST_PLUGIN_SYSTEM_PATH_1_0 +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0 +# GST_PLUGIN_SYSTEM_PATH +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0 +# GST_PLUGIN_PATH_1_0 +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0 +# GST_PLUGIN_PATH +# @executable_path/../Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0 +# diff --git a/tools/setup/install-dependencies-debian.sh b/tools/setup/install-dependencies-debian.sh index eae9bbd0afa..81d9f306fc1 100755 --- a/tools/setup/install-dependencies-debian.sh +++ b/tools/setup/install-dependencies-debian.sh @@ -109,6 +109,7 @@ DEBIAN_FRONTEND=noninteractive apt -y --quiet install \ libgles2-mesa-dev \ libglu1-mesa-dev \ libglfw3-dev \ + libgraphene-1.0-dev \ libopenal-dev \ libpulse-dev \ libsdl2-dev \