Qt + GStreamer + Android
-
Hello, the title says it all.
What i've done so far:
1. I installed gstreamer on my linux pc.
https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c
2. I read the very informativ tutorials at:
https://gstreamer.freedesktop.org/documentation/tutorials/?gi-language=c
3. I tried and played around with the qmlsink module:
4. I downloaded the precompiled gstreamer libraries for android:
https://gstreamer.freedesktop.org/data/pkg/android/
5. I followed the install guide for gstreamer on android:
https://gstreamer.freedesktop.org/documentation/installing/for-android-development.html?gi-language=c
I already had NDK, gradle and co, because i already develop cross-platform with Qt.6. I built the android tutorials with gradle:
7. So, now, the time has come to combine these things.
I adapted the qmake based project from the qmlsink example.
My test project contains a simple pipeline ("audiotestsrc ! autoaudiosink"), which works just fine on linux.
So i naively set in the pro file:
PKGCONFIG=/PATH/TO/GSTREAMER/arm64/lib/gstreamer-1.0/pkgconfig in the pro file.
And i got: "Cross compiling without sysroot. Disabling pkg-config."
So, i tried to add the libraries manually, which seemed to work instantly.
It compiled, it ran, it crashed...
It crashed not at the beginning, it crashed at a very boring line in the middle.
I tried a lot of combinations of:- CMake QMake
- Qt 6.5 6.8 6.11
- GStreamer 1.26.13 1.28.3 1.29.1
- Debian 12 (openjdk 17), Debian 13 (openjdk 21)
- Huawai Android 7 (API 24), Samsung Android 16 (API 36)
And the result is always the same, it crashes at the same line.
Whether its my old Huawei with Qt 6.5, or with the new Samsung and Qt 6.11.
So, this issue can't be new...
I searched the forum and the web. The conclusion: other people added the libraries manually and it worked (a few year ago).
Most of the information is not up-to-date, library names and the need to register modules for example.
This seemed to be a dead end, so...8. I looked closer into the code of the working Android+GStreamer tutorial programs.
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/tree/main/subprojects/gst-docs/examples/tutorials/android/android-tutorial-1?ref_type=heads
Starting with the build.gradle file of tutorial-1.
This pointed me to the file 'jni/CMakeLists.txt' within the project.
I tried to copy paste the relevant parts into the cmake file of my test project.cmake_minimum_required(VERSION 3.16) project(TestProject_GStreamer_CMake VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Quick) qt_standard_project_setup(REQUIRES 6.8) qt_add_executable(appTestProject_GStreamer_CMake main.cpp gst_handler.h gst_handler.cpp ) qt_add_qml_module(appTestProject_GStreamer_CMake URI TestProject_GStreamer_CMake QML_FILES Main.qml ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(appTestProject_GStreamer_CMake PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appTestProject_GStreamer_CMake MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) # # # # LINUX - working fine # # # if(LINUX) find_package(PkgConfig REQUIRED) pkg_search_module(gstreamer REQUIRED IMPORTED_TARGET gstreamer-1.0) target_link_libraries(appTestProject_GStreamer_CMake PRIVATE Qt6::Quick PkgConfig::gstreamer ) endif() # # # # ANDROID - not working # # # if(ANDROID) set(GSTREAMER_ROOT_ANDROID "/home/felsi/Dokumente/TestProjects/gstreamer-1.0-android-universal-1.26.11") if(NOT DEFINED GSTREAMER_ROOT_ANDROID) message(FATAL_ERROR "GSTREAMER_ROOT_ANDROID is not defined!") endif() if(ANDROID_ABI STREQUAL "armeabi") set(GSTREAMER_ROOT "${GSTREAMER_ROOT_ANDROID}/arm") elseif(ANDROID_ABI STREQUAL "armeabi-v7a") set(GSTREAMER_ROOT "${GSTREAMER_ROOT_ANDROID}/armv7") elseif(ANDROID_ABI STREQUAL "arm64-v8a") set(GSTREAMER_ROOT "${GSTREAMER_ROOT_ANDROID}/arm64") elseif(ANDROID_ABI STREQUAL "x86") set(GSTREAMER_ROOT "${GSTREAMER_ROOT_ANDROID}/x86") elseif(ANDROID_ABI STREQUAL "x86_64") set(GSTREAMER_ROOT "${GSTREAMER_ROOT_ANDROID}/x86_64") else() message(FATAL_ERROR "Target arch ABI not supported: ${ANDROID_ABI}") endif() list(APPEND CMAKE_MODULE_PATH "${GSTREAMER_ROOT}/share/cmake") set(GSTREAMER_NDK_BUILD_PATH "${GSTREAMER_ROOT}/share/gst-android/ndk-build/") set(GSTREAMER_PLUGINS coreelements) find_library(LOG_LIB log REQUIRED) find_package(GStreamerMobile COMPONENTS ${GSTREAMER_PLUGINS} fonts REQUIRED) target_link_libraries(appTestProject_GStreamer_CMake PRIVATE Qt6::Quick PUBLIC GStreamer::mobile ${ANDROID_LIB} ${LOG_LIB} ) endif() install(TARGETS appTestProject_GStreamer_CMake BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )And i got "Could NOT find GLIB2", triggered at find_package(). The glib library is one of the precompiled libraries, included in the downloaded folder. It turned out, that find_package() calls a cmake file, which was added with list(APPEND CMAKE_MODULE_PATH ...).
So i followed the rabbit to ".../share/cmake/FindGSTreamer.cmake" within the downloaded folder of the precompiled gstreamer libraries. This cmake file uses pkg-config and prepares the package, so that the cmake file in the project can easily find and link the needed modules. But i have no clue, why it's working for the tutorial, but not for my test project. I lack knowledge.However, this approach does not seem to be a dead end, it could be even quite elegant compared to the old qmake solutions, spread across the web. Unfortunately, i ran out of ideas how to fix it, because i am not very experienced with cmake and androiddeployqt. But maybe with a little help from some awesome person, who is, this might work...
Thank you for reading the whole post.
-
if you are developing commerical software, it is not legal to link precompiled gstreamer libraries(static) to your project without paying license fee. Check project QGroundcontrol out to see how static libs are added to a project.
Ideally, you build all libs and plugins of gstreamer you need to a single dynamic lib for Android and wrap the dynamic lib with your project just like Qt libs. This is what I did.
https://discourse.gstreamer.org/t/how-to-build-gstreamer-for-android/815To debug the crash, connect your cell phone with you computer and use qtcreator to find out where it crashes. It is likely that the crash is caused by missing plugins or libs. Build and run your code on Linux to find out which libs and plugins are needed and make sure that they are added in your build for Android.
-
if you are developing commerical software, it is not legal to link precompiled gstreamer libraries(static) to your project without paying license fee. Check project QGroundcontrol out to see how static libs are added to a project.
Ideally, you build all libs and plugins of gstreamer you need to a single dynamic lib for Android and wrap the dynamic lib with your project just like Qt libs. This is what I did.
https://discourse.gstreamer.org/t/how-to-build-gstreamer-for-android/815To debug the crash, connect your cell phone with you computer and use qtcreator to find out where it crashes. It is likely that the crash is caused by missing plugins or libs. Build and run your code on Linux to find out which libs and plugins are needed and make sure that they are added in your build for Android.
@JoeCFD
Oh, because of LGPL, i see. Thank you for the hint!
And thank you for sharing, how you accomplished it.
The qml plugins are not part of the precompiled libraries, so at some point, i will have to compile it anyway...
https://gstreamer.freedesktop.org/documentation/installing/building-from-source-using-cerbero.html?gi-language=cAbout the crash:
Yes, i did this, it crashes at a very boring line, which works on linux just fine.
The code is similar to the tutorials, which work on android just fine.Calling gst_something() methods do not crash, but they just do nothing and they return nothing, not even GstMessages* for errors. Hence, the debug says:
F/libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x40 in tid 24125 (qtMainLoopThrea), pid 24085 (GStreamer_CMake)
F/DEBUG : Cause: null pointer dereferenceAs a test, i linked just everything within lib and lib/gstreamer-1.0. (ls -1 *.a)
So, missing libs should not be the problem...About QGroundControl:
To be honest, i just don't understand it.
I see, they use the similar FindGStreamer.cmake, but the whole setup is way more complex than the tutorials.
If i would be able to understand it, i would probably know anyway, what went wrong in the simple code, i posted.
Without cmake experience, it's just mysterious to me, why the FindGStreamer.cmake isn't working in my test project.
Maybe it's trivial for someone familiar with cmake...
If you want to test it, the precompiled libs and my posted cmake is all you need.
A simple cmake based example project, using the precompiled libs might be useful for future readers too.Otherwise i'll try the single dynamic lib approach of yours.
Thank you very much!
-
@JoeCFD
Oh, because of LGPL, i see. Thank you for the hint!
And thank you for sharing, how you accomplished it.
The qml plugins are not part of the precompiled libraries, so at some point, i will have to compile it anyway...
https://gstreamer.freedesktop.org/documentation/installing/building-from-source-using-cerbero.html?gi-language=cAbout the crash:
Yes, i did this, it crashes at a very boring line, which works on linux just fine.
The code is similar to the tutorials, which work on android just fine.Calling gst_something() methods do not crash, but they just do nothing and they return nothing, not even GstMessages* for errors. Hence, the debug says:
F/libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x40 in tid 24125 (qtMainLoopThrea), pid 24085 (GStreamer_CMake)
F/DEBUG : Cause: null pointer dereferenceAs a test, i linked just everything within lib and lib/gstreamer-1.0. (ls -1 *.a)
So, missing libs should not be the problem...About QGroundControl:
To be honest, i just don't understand it.
I see, they use the similar FindGStreamer.cmake, but the whole setup is way more complex than the tutorials.
If i would be able to understand it, i would probably know anyway, what went wrong in the simple code, i posted.
Without cmake experience, it's just mysterious to me, why the FindGStreamer.cmake isn't working in my test project.
Maybe it's trivial for someone familiar with cmake...
If you want to test it, the precompiled libs and my posted cmake is all you need.
A simple cmake based example project, using the precompiled libs might be useful for future readers too.Otherwise i'll try the single dynamic lib approach of yours.
Thank you very much!
-
All plugins are stored in gstreamer/lib/gstreamer-1.0. You add only libs and plugins you need.
I compiled gstreamer with cerbero and tried to use the shared libraries.
The libraries are loading successfully, but i got the same result as with the static libs.I don't know why i haven't noticed it earlier, but there is also this in the debug:
E/oject_GStreamer: [perfctl] 20023 20023 FPSGO ver:-1
E/oject_GStreamer: [perfctl] 0 0 0 0
F/libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x40 in tid 20059 (qtMainLoopThrea), pid 20023 (oject_GStreamer)
D/oject_GStreamer: Can't load libmbrainSDK
D/oject_GStreamer: initMbrain failedAfter searching for perfctl, i have the bad feeling, that i have a completely different problem...
-
Hi, do you need an Android player? If yes try ffmpeg, it is very esasy to use in Qt + Android.
https://github.com/denisgottardello/QtFFmpegPlayer -
Hi, do you need an Android player? If yes try ffmpeg, it is very esasy to use in Qt + Android.
https://github.com/denisgottardello/QtFFmpegPlayer@mrdebug
At the moment, i use QtMultimedia, which works fine on android too.
However, i have some features on my wish list, like mixing and fading between tracks, multiple output devices, etc.
Gstreamer has a comprehensive documentation and it seems to be more suitable than ffmpeg, because of its modularity.But thank you very much for the link.
Wow, your project looks pretty clean and well arranged.