diff options
author | L. E. Segovia <amy@centricular.com> | 2024-05-01 20:22:28 -0300 |
---|---|---|
committer | GStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org> | 2024-11-01 09:30:55 +0000 |
commit | 87c163b6ec37bf53b2a29aac4d1968f88fd32200 (patch) | |
tree | 65a8273091b5adb217c8c9fa6235555bea7540ea | |
parent | 5c1173f82604749e97bf2adf935303a0a9ab3832 (diff) |
android: Implement CMake module for the GStreamer plugin
See gstreamer/gstreamer!6881
Part-of: <https://gitlab.freedesktop.org/gstreamer/cerbero/-/merge_requests/1523>
-rw-r--r-- | data/mobile/FindGStreamerMobile.cmake | 600 | ||||
-rw-r--r-- | data/mobile/gst_ios_init.m.in | 68 | ||||
-rw-r--r-- | data/mobile/gstreamer_android-1.0.c.in | 49 | ||||
-rw-r--r-- | recipes/gst-android-1.0.recipe | 54 | ||||
-rw-r--r-- | recipes/gstreamer-1.0.recipe | 7 | ||||
-rw-r--r-- | recipes/gstreamer-ios-templates.recipe | 19 |
6 files changed, 780 insertions, 17 deletions
diff --git a/data/mobile/FindGStreamerMobile.cmake b/data/mobile/FindGStreamerMobile.cmake new file mode 100644 index 00000000..3503fb40 --- /dev/null +++ b/data/mobile/FindGStreamerMobile.cmake @@ -0,0 +1,600 @@ +# SPDX-FileCopyrightText: 2024 L. E. Segovia <amy@centricular.com> +# SPDX-License-Ref: LGPL-2.1-or-later + +#[=======================================================================[.rst: +FindGStreamerMobile +------- + +Creates additional mobile targets to install fonts and the CA certificate +bundle. Android and iOS only. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module defines the following :prop_tgt:`INTERFACE` targets: + +``GStreamer::fonts`` + A target that will install GStreamer's default fonts into the app. + +``GStreamer::ca_certificates`` + A target that will install the NSS CA certificate bundle into the app. + +This module defines the following :prop_tgt:`SHARED` targets: + +``GStreamer::mobile`` + A target that will build the shared library consisting of GStreamer plus all the selected plugin components. (Android/iOS only) + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``GStreamer_Mobile_FOUND`` + ON if the system has the GStreamer library. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``GStreamer_CA_BUNDLE`` + Path to /etc/ssl/certs/ca-certificates.crt. +``GStreamer_UBUNTU_R_TTF`` + Path to the TrueType font Ubuntu R. +``GStreamer_FONTS_CONF`` + Path to /etc/fonts.conf. + +Configuration Variables +^^^^^^^^^^^^^^^ + +Like with the main GStreamer library, setting the following variables is +required, depending on the operating system: + +``GStreamer_ROOT_DIR`` + Installation prefix of the GStreamer SDK. + +``GStreamer_JAVA_SRC_DIR`` + Target directory for deploying the selected plugins' Java classfiles to. (Android only) + +``GStreamer_Mobile_MODULE_NAME`` + Name for the GStreamer::mobile shared library. Default is ``gstreamer_android`` (Android) or ``gstreamer_mobile`` (iOS). + +``GStreamerMobile_ASSETS_DIR`` + Target directory for deploying assets to. + +``G_IO_MODULES`` + Set this to the GIO modules you need, additional to any GStreamer plugins. (Usually set to ``gnutls`` or ``openssl``) + +``G_IO_MODULES_PATH`` + Path for the static GIO modules. + +#]=======================================================================] + +if (GStreamer_Mobile_FOUND) + return() +endif() + +##################### +# Setup variables # +##################### + +if (NOT DEFINED GStreamer_ROOT_DIR AND DEFINED GSTREAMER_ROOT) + set(GStreamer_ROOT_DIR ${GSTREAMER_ROOT}) +endif() + +if (NOT GStreamer_ROOT_DIR) + set(GStreamer_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../../") +endif() + +if (NOT EXISTS "${GStreamer_ROOT_DIR}") + message(FATAL_ERROR "The directory GStreamer_ROOT_DIR=${GStreamer_ROOT_DIR} does not exist") +endif() + +set(_gst_required_vars) + +# for setting the default GTlsDatabase +list(APPEND GStreamer_EXTRA_DEPS gio-2.0) + +if (ANDROID) + list(APPEND GStreamer_EXTRA_DEPS zlib) +endif() + +# Prepare Android hotfixes for x264 +if(ANDROID_ABI STREQUAL "armeabi") + set(NEEDS_NOTEXT_FIX TRUE) + set(NEEDS_BSYMBOLIC_FIX TRUE) +elseif(ANDROID_ABI STREQUAL "x86") + set(NEEDS_NOTEXT_FIX TRUE) + set(NEEDS_BSYMBOLIC_FIX TRUE) +elseif(ANDROID_ABI STREQUAL "x86_64") + set(NEEDS_BSYMBOLIC_FIX TRUE) +endif() + +# Set up output variables for Android +if(ANDROID) + if (NOT DEFINED GStreamer_JAVA_SRC_DIR AND DEFINED GSTREAMER_JAVA_SRC_DIR) + set(GStreamer_JAVA_SRC_DIR ${GSTREAMER_JAVA_SRC_DIR}) + elseif(NOT DEFINED GStreamer_JAVA_SRC_DIR) + set(GStreamer_JAVA_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src/") + else() + # Gradle does not let us access the root of the subproject + # so we implement the ndk-build assumption ourselves + set(GStreamer_JAVA_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${GStreamer_JAVA_SRC_DIR}") + endif() + + if(NOT DEFINED GStreamer_NDK_BUILD_PATH AND DEFINED GSTREAMER_NDK_BUILD_PATH) + set(GStreamer_NDK_BUILD_PATH "${GSTREAMER_NDK_BUILD_PATH}") + elseif(NOT DEFINED GStreamer_NDK_BUILD_PATH) + set(GStreamer_NDK_BUILD_PATH "${GStreamer_ROOT}/share/gst-android/ndk-build/") + endif() +endif() + +if(NOT DEFINED GStreamer_Mobile_MODULE_NAME) + if (DEFINED GSTREAMER_ANDROID_MODULE_NAME) + set(GStreamer_Mobile_MODULE_NAME "${GSTREAMER_ANDROID_MODULE_NAME}") + elseif(ANDROID) + set(GStreamer_Mobile_MODULE_NAME gstreamer_android) + else() + set(GStreamer_Mobile_MODULE_NAME gstreamer_mobile) + endif() +endif() + +if(ANDROID) + if(NOT DEFINED GStreamerMobile_ASSETS_DIR AND DEFINED GStreamerMobile_ASSETS_DIR) + set(GStreamerMobile_ASSETS_DIR "${GStreamerMobile_ASSETS_DIR}") + elseif(NOT DEFINED GStreamerMobile_ASSETS_DIR) + set(GStreamerMobile_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src/assets/") + else() + # Same as above + set(GStreamerMobile_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${GStreamerMobile_ASSETS_DIR}") + endif() + + if(NOT DEFINED GStreamer_NDK_BUILD_PATH AND DEFINED GSTREAMER_NDK_BUILD_PATH) + set(GStreamer_NDK_BUILD_PATH "${GSTREAMER_NDK_BUILD_PATH}") + elseif(NOT DEFINED GStreamer_NDK_BUILD_PATH) + set(GStreamer_NDK_BUILD_PATH "${GStreamer_ROOT}/share/gst-android/ndk-build/") + endif() +elseif(IOS) + if(NOT DEFINED GStreamerMobile_ASSETS_DIR AND DEFINED GStreamerMobile_ASSETS_DIR) + set(GStreamerMobile_ASSETS_DIR ${GStreamerMobile_ASSETS_DIR}) + elseif(NOT DEFINED GStreamerMobile_ASSETS_DIR) + set(GStreamerMobile_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets") + else() + # Same as above + set(GStreamerMobile_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${GStreamerMobile_ASSETS_DIR}") + endif() +endif() + +if (ANDROID) + file(READ "${GStreamer_NDK_BUILD_PATH}/GStreamer.java" JAVA_INPUT) +endif() + +if (ANDROID OR APPLE) + set(GSTREAMER_IS_MOBILE ON) +else() + set(GSTREAMER_IS_MOBILE OFF) +endif() + +# Block shared GStreamer on mobile +if (GSTREAMER_IS_MOBILE) + if (NOT DEFINED GStreamer_USE_STATIC_LIBS) + set(GStreamer_USE_STATIC_LIBS ON) + endif() + if (NOT GStreamer_USE_STATIC_LIBS) + message(FATAL_ERROR "Shared library GStreamer is not supported on mobile platforms") + endif() +endif() + +# Now, let's set up targets for each of the components supplied +# These are the required plugins +set(_gst_plugins ${GStreamerMobile_FIND_COMPONENTS}) +# These are custom handled targets, and must be skipped from the loop +list(REMOVE_ITEM _gst_plugins fonts ca_certificates mobile) +list(REMOVE_DUPLICATES _gst_plugins) + +set(GSTREAMER_PLUGINS ${_gst_plugins}) +# These are the API packages +set(GSTREAMER_APIS ${GSTREAMER_PLUGINS}) +list(FILTER GSTREAMER_APIS INCLUDE REGEX "^api_") +# Filter them out, although they're handled the same +# they cannot be considered for the purposes of initialization +list(FILTER GSTREAMER_PLUGINS EXCLUDE REGEX "^api_") + +if (GSTREAMER_IS_MOBILE AND (NOT TARGET GStreamer::mobile)) + # Generate the plugins' declaration strings + # (don't append a semicolon, CMake does it as part of the list) + list(TRANSFORM GSTREAMER_PLUGINS + PREPEND "\nGST_PLUGIN_STATIC_DECLARE\(" + OUTPUT_VARIABLE PLUGINS_DECLARATION + ) + list(TRANSFORM PLUGINS_DECLARATION + APPEND "\)" + OUTPUT_VARIABLE PLUGINS_DECLARATION + ) + if(PLUGINS_DECLARATION) + set(PLUGINS_DECLARATION "${PLUGINS_DECLARATION};") + endif() + + # Generate the plugins' registration strings + list(TRANSFORM GSTREAMER_PLUGINS + PREPEND "\nGST_PLUGIN_STATIC_REGISTER\(" + OUTPUT_VARIABLE PLUGINS_REGISTRATION + ) + list(TRANSFORM PLUGINS_REGISTRATION + APPEND "\)" + OUTPUT_VARIABLE PLUGINS_REGISTRATION + ) + if(PLUGINS_REGISTRATION) + set(PLUGINS_REGISTRATION "${PLUGINS_REGISTRATION};") + endif() + + # Generate list of gio modules + if (NOT G_IO_MODULES) + set(G_IO_MODULES) + endif() + list(TRANSFORM G_IO_MODULES + PREPEND "gio" + OUTPUT_VARIABLE G_IO_MODULES_LIBS + ) + list(TRANSFORM G_IO_MODULES + PREPEND "\nGST_G_IO_MODULE_DECLARE\(" + OUTPUT_VARIABLE G_IO_MODULES_DECLARE + ) + list(TRANSFORM G_IO_MODULES_DECLARE + APPEND "\);" + OUTPUT_VARIABLE G_IO_MODULES_DECLARE + ) + if(G_IO_MODULES_DECLARE) + set(G_IO_MODULES_DECLARE "${G_IO_MODULES_DECLARE};") + endif() + list(TRANSFORM G_IO_MODULES + PREPEND "\nGST_G_IO_MODULE_LOAD\(" + OUTPUT_VARIABLE G_IO_MODULES_LOAD + ) + list(TRANSFORM G_IO_MODULES_LOAD + APPEND "\)" + OUTPUT_VARIABLE G_IO_MODULES_LOAD + ) + if(G_IO_MODULES_LOAD) + set(G_IO_MODULES_LOAD "${G_IO_MODULES_LOAD};") + endif() + + # Generates a source file that declares and registers all the required plugins + if (ANDROID) + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/GStreamer/gstreamer_android-1.0.c.in" + "${GStreamer_Mobile_MODULE_NAME}.c" + ) + else() + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/GStreamer/gst_ios_init.m.in" + "${GStreamer_Mobile_MODULE_NAME}.m" + ) + endif() + + # Creates a shared library including gstreamer, its plugins and all the dependencies + if (ANDROID) + add_library(GStreamerMobile + SHARED + "${GStreamer_Mobile_MODULE_NAME}.c" + ) + else() + add_library(GStreamerMobile SHARED) + enable_language(OBJC OBJCXX) + target_sources(GStreamerMobile + PRIVATE + "${GStreamer_Mobile_MODULE_NAME}.m" + ) + set_source_files_properties("${GStreamer_Mobile_MODULE_NAME}.m" + PROPERTIES + LANGUAGE OBJC + ) + find_library(Foundation_LIB Foundation REQUIRED) + target_link_libraries(GStreamerMobile + PRIVATE + ${Foundation_LIB} + ) + endif() + add_library(GStreamer::mobile ALIAS GStreamerMobile) + + # Assume it's C++ for the sake of gstsoundtouch + set_target_properties( + GStreamerMobile + PROPERTIES + LIBRARY_OUTPUT_NAME ${GStreamer_Mobile_MODULE_NAME} + ) + if (APPLE) + set_target_properties( + GStreamerMobile + PROPERTIES + LINKER_LANGUAGE OBJCXX + FRAMEWORK TRUE + FRAMEWORK_VERSION A + MACOSX_FRAMEWORK_IDENTIFIER org.gstreamer.GStreamerMobile + ) + else() + set_target_properties( + GStreamerMobile + PROPERTIES + LINKER_LANGUAGE CXX + ) + endif() +endif() + +if (GStreamerMobile_FIND_REQUIRED) +find_package(GStreamer COMPONENTS ${_gst_plugins} REQUIRED) +else() +find_package(GStreamer COMPONENTS ${_gst_plugins}) +endif() + +# Path for the static GIO modules +pkg_get_variable(G_IO_MODULES_PATH gio-2.0 giomoduledir) +if (NOT G_IO_MODULES_PATH) + set(G_IO_MODULES_PATH "${GStreamer_ROOT_DIR}/lib/gio/modules") +endif() + +if (GSTREAMER_IS_MOBILE) + set_target_properties( + GStreamerMobile + PROPERTIES + VERSION ${PC_GStreamer_VERSION} + SOVERSION ${PC_GStreamer_VERSION} + ) + + # Handle all libraries, even those specified with -l:libfoo.a (srt) + # Due to the unavailability of pkgconf's `--maximum-traverse-depth` + # on stock pkg-config, I attempt to simulate it through the shared + # libraries listing. + # If pkgconf is available, replace all PC_GStreamer_ entries with + # PC_GStreamer_NoDeps and uncomment the code block above. + foreach(LOCAL_LIB IN LISTS PC_GStreamer_LIBRARIES) + # list(TRANSFORM REPLACE) is of no use here + # https://gitlab.kitware.com/cmake/cmake/-/issues/16899 + if (LOCAL_LIB MATCHES "${_gst_SRT_REGEX_PATCH}") + string(REGEX REPLACE "${_gst_SRT_REGEX_PATCH}" "\\1" LOCAL_LIB "${LOCAL_LIB}") + endif() + string(MAKE_C_IDENTIFIER "_gst_${LOCAL_LIB}" GST_LOCAL_LIB) + # These have already been found by FindGStreamer + if ("${${GST_LOCAL_LIB}}" IN_LIST _gst_IGNORED_SYSTEM_LIBRARIES) + target_link_libraries(GStreamerMobile PRIVATE + "${${GST_LOCAL_LIB}}" + ) + elseif (MSVC) + target_link_libraries(GStreamerMobile PRIVATE + "/WHOLEARCHIVE:${${GST_LOCAL_LIB}}" + ) + elseif(APPLE) + target_link_libraries(GStreamerMobile PRIVATE + "-Wl,-force_load,${${GST_LOCAL_LIB}}" + ) + else() + target_link_libraries(GStreamerMobile PRIVATE + "-Wl,--whole-archive,${${GST_LOCAL_LIB}},--no-whole-archive" + ) + endif() + endforeach() + + target_link_libraries( + GStreamerMobile + PRIVATE + GStreamer::deps + ) + + target_link_options( + GStreamerMobile + INTERFACE + $<TARGET_PROPERTY:GStreamer::GStreamer,INTERFACE_LINK_OPTIONS> + ) + + target_include_directories( + GStreamerMobile + INTERFACE + $<TARGET_PROPERTY:GStreamer::GStreamer,INTERFACE_INCLUDE_DIRECTORIES> + ) + + # Text relocations are required for all 32-bit objects. We + # must disable the warning to allow linking with lld. Unlike gold, ld which + # will silently allow text relocations, lld support must be explicit. + # + # See https://crbug.com/911658#c19 for more information. See also + # https://trac.ffmpeg.org/ticket/7878 + if(DEFINED NEEDS_NOTEXT_FIX) + target_link_options( + GStreamerMobile + PRIVATE + "-Wl,-z,notext" + ) + endif() + + # resolve textrels in the x86 asm + if(DEFINED NEEDS_BSYMBOLIC_FIX) + target_link_options( + GStreamerMobile + PRIVATE + "-Wl,-Bsymbolic" + ) + endif() + + if (ANDROID) + # Collect all Java-based initializer classes + set(GSTREAMER_PLUGINS_CLASSES) + foreach(LOCAL_PLUGIN IN LISTS GSTREAMER_PLUGINS) + file(GLOB_RECURSE + LOCAL_PLUGIN_CLASS + FOLLOW_SYMLINKS + RELATIVE "${GStreamer_NDK_BUILD_PATH}" + "${GStreamer_NDK_BUILD_PATH}/${LOCAL_PLUGIN}/*.java" + ) + list(APPEND GSTREAMER_PLUGINS_CLASSES ${LOCAL_PLUGIN_CLASS}) + endforeach() + + # Same as above, but collect the plugins themselves + set(GSTREAMER_PLUGINS_WITH_CLASSES) + foreach(LOCAL_PLUGIN IN LISTS GSTREAMER_PLUGINS) + if(EXISTS "${GStreamer_NDK_BUILD_PATH}/${LOCAL_PLUGIN}/") + list(APPEND GSTREAMER_PLUGINS_WITH_CLASSES ${LOCAL_PLUGIN}) + endif() + endforeach() + + add_custom_target( + "copyjavasource_${ANDROID_ABI}" + ) + + foreach(LOCAL_FILE IN LISTS GSTREAMER_PLUGINS_CLASSES) + string(MAKE_C_IDENTIFIER "cp_${LOCAL_FILE}" COPYJAVASOURCE_TGT) + add_custom_target( + ${COPYJAVASOURCE_TGT} + COMMAND + "${CMAKE_COMMAND}" -E make_directory + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/" + COMMAND + "${CMAKE_COMMAND}" -E copy + "${GStreamer_NDK_BUILD_PATH}/${LOCAL_FILE}" + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/" + BYPRODUCTS + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/${LOCAL_FILE}" + ) + add_dependencies(copyjavasource_${ANDROID_ABI} ${COPYJAVASOURCE_TGT}) + endforeach() + endif() + + # And, finally, set the GIO modules up + if (G_IO_MODULES_LIBS) + add_library(GStreamer::gio_modules INTERFACE IMPORTED) + + _gst_apply_link_libraries(OFF G_IO_MODULES_LIBS G_IO_MODULES_PATH GStreamer::gio_modules) + target_link_libraries( + GStreamerMobile + PRIVATE + GStreamer::gio_modules + ) + endif() + set(GStreamer_mobile_FOUND TRUE) +endif() + +if(fonts IN_LIST GStreamerMobile_FIND_COMPONENTS) + set(GStreamer_UBUNTU_R_TTF "${GStreamer_NDK_BUILD_PATH}/fontconfig/fonts/Ubuntu-R.ttf" + CACHE FILEPATH "Path to Ubuntu-R.ttf" + ) + set(GStreamer_FONTS_CONF + "${GStreamer_NDK_BUILD_PATH}/fontconfig/fonts.conf" + CACHE FILEPATH "Path to fonts.conf" + ) + if (EXISTS "${GStreamer_UBUNTU_R_TTF}" AND EXISTS "${GStreamer_FONTS_CONF}") + set(GStreamerMobile_fonts_FOUND ON) + set(_gst_required_vars "GStreamer_UBUNTU_R_TTF GStreamer_FONTS_CONF ${gst_required_vars}") + + if (ANDROID) + string(REPLACE "//copyFonts" "copyFonts" JAVA_INPUT "${JAVA_INPUT}") + add_custom_target( + copyfontsres_${ANDROID_ABI} + COMMAND + "${CMAKE_COMMAND}" -E make_directory + "${GStreamerMobile_ASSETS_DIR}/fontconfig/fonts/truetype/" + COMMAND + "${CMAKE_COMMAND}" -E copy + "${GStreamer_UBUNTU_R_TTF}" + "${GStreamerMobile_ASSETS_DIR}/fontconfig/fonts/truetype/" + COMMAND + "${CMAKE_COMMAND}" -E copy + "${GStreamer_FONTS_CONF}" + "${GStreamerMobile_ASSETS_DIR}/fontconfig/" + BYPRODUCTS + "${GStreamerMobile_ASSETS_DIR}/fontconfig/fonts/truetype/Ubuntu-R.ttf" + "${GStreamerMobile_ASSETS_DIR}/fontconfig/fonts.conf" + ) + + if (TARGET GStreamerMobile) + add_dependencies(GStreamerMobile copyfontsres_${ANDROID_ABI}) + endif() + elseif(APPLE) + set(GStreamerMobile_fonts_FOUND ON) + list(APPEND GSTREAMER_RESOURCES "${GStreamer_FONTS_CONF}" "${GStreamer_UBUNTU_R_TTF}") + else() + message(FATAL_ERROR "No fonts assets available for this operating system.") + endif() + else() + set(GStreamerMobile_fonts_FOUND OFF) + endif() +endif() + +if(ca_certificates IN_LIST GStreamerMobile_FIND_COMPONENTS) + set(GStreamer_CA_BUNDLE "${GStreamer_ROOT_DIR}/etc/ssl/certs/ca-certificates.crt" + CACHE FILEPATH "Path to ca-certificates bundle" + ) + if (EXISTS "${GStreamer_CA_BUNDLE}") + set(GStreamerMobile_ca_certificates_FOUND ON) + string(REPLACE "//copyCaCertificates" "copyCaCertificates" JAVA_INPUT "${JAVA_INPUT}") + set(_gst_required_vars "GStreamer_CA_BUNDLE ${_gst_required_vars}") + + if (ANDROID) + add_custom_target( + copycacertificatesres_${ANDROID_ABI} + COMMAND + "${CMAKE_COMMAND}" -E make_directory + "${GStreamerMobile_ASSETS_DIR}/ssl/certs/" + COMMAND + "${CMAKE_COMMAND}" -E copy + "${GStreamer_CA_BUNDLE}" + "${GStreamerMobile_ASSETS_DIR}/ssl/certs/" + BYPRODUCTS "${GStreamerMobile_ASSETS_DIR}/ssl/certs/ca-certificates.crt" + ) + + if (TARGET GStreamerMobile) + add_dependencies(GStreamerMobile copycacertificatesres_${ANDROID_ABI}) + endif() + elseif (APPLE) + list(APPEND GSTREAMER_RESOURCES "${GStreamer_CA_BUNDLE}") + else() + message(FATAL_ERROR "No certificate bundle available for this operating system.") + endif() + else() + set(GStreamerMobile_ca_certificates_FOUND OFF) + endif() +endif() + +if (ANDROID) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/GStreamer.java" "${JAVA_INPUT}") + add_custom_target( + enable_includes_in_gstreamer_java + COMMAND + "${CMAKE_COMMAND}" -E make_directory + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/" + COMMAND + "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_BINARY_DIR}/GStreamer.java" + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/GStreamer.java" + BYPRODUCTS + "${GStreamer_JAVA_SRC_DIR}/org/freedesktop/gstreamer/GStreamer.java" + ) + if (TARGET GStreamerMobile) + add_dependencies(copyjavasource_${ANDROID_ABI} enable_includes_in_gstreamer_java) + add_dependencies(GStreamerMobile copyjavasource_${ANDROID_ABI}) + endif() +endif() + +if (TARGET GStreamerMobile AND GSTREAMER_RESOURCES) + set_target_properties( + GStreamerMobile + PROPERTIES + RESOURCE "${GSTREAMER_RESOURCES}" + ) +endif() + +# Perform final validation +include(FindPackageHandleStandardArgs) +foreach(_gst_PLUGIN IN LISTS _gst_plugins) + set(GStreamerMobile_${_gst_PLUGIN}_FOUND "${GStreamer_${_gst_PLUGIN}_FOUND}") + + if (GStreamer_${_gst_PLUGIN}_FOUND) + target_link_libraries( + GStreamerMobile + PRIVATE + GStreamer::${_gst_PLUGIN} + ) + endif() +endforeach() +# FIXME: CMake does not tolerate interpolation of REQUIRED_VARS +find_package_handle_standard_args(GStreamerMobile + HANDLE_COMPONENTS +) diff --git a/data/mobile/gst_ios_init.m.in b/data/mobile/gst_ios_init.m.in new file mode 100644 index 00000000..b30a0c25 --- /dev/null +++ b/data/mobile/gst_ios_init.m.in @@ -0,0 +1,68 @@ +#include <gst/gst.h> +#include <gio/gio.h> +#include <Foundation/Foundation.h> + +/* Declaration of static plugins */ + @PLUGINS_DECLARATION@ + +/* Declaration of static gio modules */ + @G_IO_MODULES_DECLARE@ + +void +gst_ios_init (void) +{ + GstPluginFeature *plugin; + GstRegistry *reg; + NSString *resources = [[NSBundle mainBundle] resourcePath]; + NSString *tmp = NSTemporaryDirectory(); + NSString *cache = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; + NSString *docs = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; + + const gchar *resources_dir = [resources UTF8String]; + const gchar *tmp_dir = [tmp UTF8String]; + const gchar *cache_dir = [cache UTF8String]; + const gchar *docs_dir = [docs UTF8String]; + gchar *ca_certificates; + + g_setenv ("TMP", tmp_dir, TRUE); + g_setenv ("TEMP", tmp_dir, TRUE); + g_setenv ("TMPDIR", tmp_dir, TRUE); + g_setenv ("XDG_RUNTIME_DIR", resources_dir, TRUE); + g_setenv ("XDG_CACHE_HOME", cache_dir, TRUE); + + g_setenv ("HOME", docs_dir, TRUE); + g_setenv ("XDG_DATA_DIRS", resources_dir, TRUE); + g_setenv ("XDG_CONFIG_DIRS", resources_dir, TRUE); + g_setenv ("XDG_CONFIG_HOME", cache_dir, TRUE); + g_setenv ("XDG_DATA_HOME", resources_dir, TRUE); + g_setenv ("FONTCONFIG_PATH", resources_dir, TRUE); + + ca_certificates = g_build_filename (resources_dir, "ssl", "certs", "ca-certificates.crt", NULL); + g_setenv ("CA_CERTIFICATES", ca_certificates, TRUE); + + @G_IO_MODULES_LOAD@ + + if (ca_certificates) { + GTlsBackend *backend = g_tls_backend_get_default (); + if (backend) { + GTlsDatabase *db = g_tls_file_database_new (ca_certificates, NULL); + if (db) + g_tls_backend_set_default_database (backend, db); + } + } + g_free (ca_certificates); + + gst_init (NULL, NULL); + + @PLUGINS_REGISTRATION@ + + /* Lower the ranks of filesrc and giosrc so iosavassetsrc is + * tried first in gst_element_make_from_uri() for file:// */ + 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); +} diff --git a/data/mobile/gstreamer_android-1.0.c.in b/data/mobile/gstreamer_android-1.0.c.in new file mode 100644 index 00000000..712da54d --- /dev/null +++ b/data/mobile/gstreamer_android-1.0.c.in @@ -0,0 +1,49 @@ +#include <gst/gst.h> +#include <gio/gio.h> + +#define GST_G_IO_MODULE_DECLARE(name) \ +extern void G_PASTE(g_io_, G_PASTE(name, _load)) (gpointer module) + +#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/recipes/gst-android-1.0.recipe b/recipes/gst-android-1.0.recipe index c4df6bf8..3efb0309 100644 --- a/recipes/gst-android-1.0.recipe +++ b/recipes/gst-android-1.0.recipe @@ -1,5 +1,6 @@ # -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python import os +from pathlib import Path import shutil from cerbero.utils import shell from custom import list_gstreamer_1_0_plugins_by_category @@ -20,9 +21,13 @@ class Recipe(recipe.Recipe): 'share/gst-android/ndk-build/gstreamer-1.0.mk', 'share/gst-android/ndk-build/gstreamer_prebuilt.mk', 'share/gst-android/ndk-build/tools.mk', + 'share/gst-android/ndk-build/plugins.cmake', 'share/gst-android/ndk-build/plugins.mk', 'share/gst-android/ndk-build/tools', 'share/gst-android/ndk-build/fontconfig', + 'share/gst-android/ndk-build/GStreamer.java', + 'share/cmake/GStreamer/gstreamer_android-1.0.c.in', + 'share/cmake/FindGStreamerMobile.cmake', ] def prepare(self): @@ -30,22 +35,47 @@ class Recipe(recipe.Recipe): self.deps.append('gst-plugins-rs') async def install(self): - ndk_build_dir_dst = os.path.join(self.config.prefix, 'share', 'gst-android', 'ndk-build') - if not os.path.exists(ndk_build_dir_dst): - os.makedirs(ndk_build_dir_dst) - ndk_build_dir_src = os.path.join(self.config.data_dir, 'ndk-build') + ndk_build_dir_dst = Path(self.config.prefix) / \ + 'share' / 'gst-android' / 'ndk-build' + ndk_build_dir_dst.mkdir(parents=True, exist_ok=True) + ndk_build_dir_src = Path(self.config.data_dir) / 'ndk-build' for f in self.files_devel: fname = os.path.basename(f) - s = os.path.join(ndk_build_dir_src, fname) - d = os.path.join(ndk_build_dir_dst, fname) - if os.path.isfile(s): + s = ndk_build_dir_src / fname + d = ndk_build_dir_dst / fname + if s.is_file(): shutil.copy(s, d) else: shell.copy_dir(s, d) plugins = list_gstreamer_1_0_plugins_by_category(self.config) - f = open(os.path.join(ndk_build_dir_dst, 'plugins.mk'), 'w') - for c, p in plugins.items(): - p = ' '.join(p) - f.write('GSTREAMER_PLUGINS_%s := %s\n' % (c.upper(), p)) - f.close() + plugins_mk = ndk_build_dir_dst / 'plugins.mk' + with plugins_mk.open('w', encoding='utf-8') as f: + categories = [ + f"GSTREAMER_PLUGINS_{c.upper()} := {' '.join(p)}\n" + for c, p in plugins.items() + ] + f.writelines(categories) + + plugins_cmake = ndk_build_dir_dst / 'plugins.cmake' + with plugins_cmake.open('w', encoding='utf-8') as f: + categories = [ + f"set(GSTREAMER_PLUGINS_{c.upper()} {' '.join(p)})\n" + for c, p in plugins.items() + ] + f.writelines(categories) + + dest_dir = os.path.join(self.config.prefix, 'share', 'cmake') + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy( + os.path.join(self.config.data_dir, 'mobile', 'FindGStreamerMobile.cmake'), + dest_dir + ) + dest_dir = os.path.join(dest_dir, 'GStreamer') + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy( + os.path.join(self.config.data_dir, 'mobile', 'gstreamer_android-1.0.c.in'), + dest_dir + ) diff --git a/recipes/gstreamer-1.0.recipe b/recipes/gstreamer-1.0.recipe index dccc3d0d..ca67e231 100644 --- a/recipes/gstreamer-1.0.recipe +++ b/recipes/gstreamer-1.0.recipe @@ -1,5 +1,5 @@ # -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python -from cerbero.utils import shell +import shutil class Recipe(custom.GStreamer): name = 'gstreamer-1.0' @@ -37,12 +37,9 @@ class Recipe(custom.GStreamer): '%(libdir)s/pkgconfig/gstreamer-base-1.0.pc', '%(libdir)s/pkgconfig/gstreamer-controller-1.0.pc', '%(libdir)s/pkgconfig/gstreamer-net-1.0.pc', + 'share/cmake/FindGStreamer.cmake', ] - platform_files_devel = { - Platform.ANDROID: ['share/gst-android/ndk-build/GStreamer.java'], - } - files_lang = ['gstreamer-1.0'] files_typelibs = [ diff --git a/recipes/gstreamer-ios-templates.recipe b/recipes/gstreamer-ios-templates.recipe index 571dd341..f77223a2 100644 --- a/recipes/gstreamer-ios-templates.recipe +++ b/recipes/gstreamer-ios-templates.recipe @@ -1,5 +1,7 @@ # -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python from collections import defaultdict +import os +import shutil from cerbero.utils import shell from custom import list_gstreamer_1_0_plugins_by_category @@ -24,6 +26,8 @@ class Recipe(recipe.Recipe): files_devel = [ 'share/xcode/templates/ios/', + 'share/cmake/GStreamer/gst_ios_init.m.in', + 'share/cmake/FindGStreamerMobile.cmake', ] def prepare(self): @@ -59,3 +63,18 @@ class Recipe(recipe.Recipe): shell.replace (iosinit_m, { '@GST_IOS_PLUGINS_DECLARE@': '\n'.join(decls), '@GST_IOS_PLUGINS_REGISTER@': '\n'.join(regs)}) + + dest_dir = os.path.join(self.config.prefix, 'share', 'cmake') + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy( + os.path.join(self.config.data_dir, 'mobile', 'FindGStreamerMobile.cmake'), + dest_dir + ) + dest_dir = os.path.join(dest_dir, 'GStreamer') + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy( + os.path.join(self.config.data_dir, 'mobile', 'gst_ios_init.m.in'), + dest_dir + ) |