From 5f52253892d360e84899c06b725736db0add5bc9 Mon Sep 17 00:00:00 2001 From: Hitesh Kumar Saini Date: Sun, 13 Oct 2024 18:40:17 +0530 Subject: [PATCH] build --- .github/workflows/build.yaml | 41 ++- .github/workflows/publish.yaml | 52 ---- LICENSE | 19 ++ README.md | 7 - build.gradle.kts | 44 +-- buildscripts/README.md | 125 -------- buildscripts/build.sh | 39 +-- buildscripts/bundle_default.sh | 56 ++++ buildscripts/bundle_encoders-gpl.sh | 57 ++++ buildscripts/bundle_full.sh | 56 ++++ buildscripts/flavors/default.sh | 279 ++++++++++++++++++ buildscripts/flavors/encoders-gpl.sh | 127 ++++++++ buildscripts/flavors/full.sh | 132 +++++++++ buildscripts/include/depinfo.sh | 21 +- buildscripts/include/download-deps.sh | 39 ++- buildscripts/include/download-sdk.sh | 4 +- buildscripts/patch-encoders-gpl.sh | 21 ++ buildscripts/patches-encoders-gpl/ffmpeg | 1 + .../libx264/fix_x86_asm.patch | 13 + .../mpv/depend_on_fftools_ffi.patch | 48 +++ .../mpv/mpv_lavc_set_java_vm.patch | 1 + .../patches/ffmpeg/dash_base_url_escape.patch | 26 ++ .../patches/mpv/mpv_lavc_set_java_vm.patch | 44 +++ buildscripts/scripts/dav1d.sh | 4 +- buildscripts/scripts/ffmpeg.sh | 245 ++++++++++++++- buildscripts/scripts/fftools_ffi.sh | 22 ++ buildscripts/scripts/libass.sh | 8 +- buildscripts/scripts/libogg.build | 17 ++ buildscripts/scripts/libogg.sh | 24 ++ buildscripts/scripts/libvorbis.build | 17 ++ buildscripts/scripts/libvorbis.sh | 26 ++ buildscripts/scripts/libvpx.sh | 22 ++ buildscripts/scripts/libx264.build | 26 ++ buildscripts/scripts/libx264.sh | 26 ++ buildscripts/scripts/libxml2.sh | 31 ++ buildscripts/scripts/lua.sh | 36 --- buildscripts/scripts/mbedtls.sh | 4 +- buildscripts/scripts/mpv-android.sh | 27 -- buildscripts/scripts/mpv.sh | 11 +- buildscripts/scripts/shaderc.sh | 43 +++ gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 61574 bytes gradlew | 34 +-- libmpv/build.gradle.kts | 94 ------ libmpv/proguard-rules.pro | 1 - libmpv/src/main/cpp/CMakeLists.txt | 37 --- libmpv/src/main/cpp/event.cpp | 106 ------- libmpv/src/main/cpp/event.h | 3 - libmpv/src/main/cpp/globals.h | 7 - libmpv/src/main/cpp/jni_utils.cpp | 51 ---- libmpv/src/main/cpp/jni_utils.h | 16 - libmpv/src/main/cpp/log.cpp | 9 - libmpv/src/main/cpp/log.h | 15 - libmpv/src/main/cpp/main.cpp | 96 ------ libmpv/src/main/cpp/property.cpp | 123 -------- libmpv/src/main/cpp/render.cpp | 27 -- .../src/main/java/dev/jdtech/mpv/MPVLib.java | 241 --------------- 56 files changed, 1504 insertions(+), 1197 deletions(-) delete mode 100644 .github/workflows/publish.yaml delete mode 100644 README.md delete mode 100644 buildscripts/README.md create mode 100755 buildscripts/bundle_default.sh create mode 100644 buildscripts/bundle_encoders-gpl.sh create mode 100644 buildscripts/bundle_full.sh create mode 100644 buildscripts/flavors/default.sh create mode 100644 buildscripts/flavors/encoders-gpl.sh create mode 100644 buildscripts/flavors/full.sh create mode 100644 buildscripts/patch-encoders-gpl.sh create mode 120000 buildscripts/patches-encoders-gpl/ffmpeg create mode 100644 buildscripts/patches-encoders-gpl/libx264/fix_x86_asm.patch create mode 100644 buildscripts/patches-encoders-gpl/mpv/depend_on_fftools_ffi.patch create mode 120000 buildscripts/patches-encoders-gpl/mpv/mpv_lavc_set_java_vm.patch create mode 100644 buildscripts/patches/ffmpeg/dash_base_url_escape.patch create mode 100644 buildscripts/patches/mpv/mpv_lavc_set_java_vm.patch mode change 100755 => 100644 buildscripts/scripts/ffmpeg.sh create mode 100644 buildscripts/scripts/fftools_ffi.sh create mode 100644 buildscripts/scripts/libogg.build create mode 100644 buildscripts/scripts/libogg.sh create mode 100644 buildscripts/scripts/libvorbis.build create mode 100644 buildscripts/scripts/libvorbis.sh create mode 100644 buildscripts/scripts/libvpx.sh create mode 100644 buildscripts/scripts/libx264.build create mode 100644 buildscripts/scripts/libx264.sh create mode 100644 buildscripts/scripts/libxml2.sh delete mode 100755 buildscripts/scripts/lua.sh delete mode 100755 buildscripts/scripts/mpv-android.sh create mode 100644 buildscripts/scripts/shaderc.sh delete mode 100755 libmpv/build.gradle.kts delete mode 100644 libmpv/proguard-rules.pro delete mode 100644 libmpv/src/main/cpp/CMakeLists.txt delete mode 100644 libmpv/src/main/cpp/event.cpp delete mode 100644 libmpv/src/main/cpp/event.h delete mode 100644 libmpv/src/main/cpp/globals.h delete mode 100644 libmpv/src/main/cpp/jni_utils.cpp delete mode 100644 libmpv/src/main/cpp/jni_utils.h delete mode 100644 libmpv/src/main/cpp/log.cpp delete mode 100644 libmpv/src/main/cpp/log.h delete mode 100644 libmpv/src/main/cpp/main.cpp delete mode 100644 libmpv/src/main/cpp/property.cpp delete mode 100644 libmpv/src/main/cpp/render.cpp delete mode 100644 libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7010deb..c30783b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,15 +1,18 @@ name: Build libmpv-android -on: +on: push: branches: - main pull_request: +permissions: + contents: write + jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -20,21 +23,39 @@ jobs: java-version: 17 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 + - name: Setup Flutter SDK + uses: subosito/flutter-action@v1 + with: + channel: "stable" - name: Symlink SDK working-directory: ./buildscripts run: | mkdir sdk ln -s ${ANDROID_HOME} ./sdk/android-sdk-linux - - name: Download dependencies + - name: Bundle (default) working-directory: ./buildscripts - run: ./download.sh - - name: Apply patches + run: | + sudo chmod +x bundle_default.sh + ./bundle_default.sh + - name: Bundle (full) working-directory: ./buildscripts - run: ./patch.sh - - name: Build + run: | + sudo chmod +x bundle_full.sh + ./bundle_full.sh + - name: Bundle (encoders-gpl) working-directory: ./buildscripts - run: ./build.sh + run: | + sudo chmod +x bundle_encoders-gpl.sh + ./bundle_encoders-gpl.sh - uses: actions/upload-artifact@v4 with: - name: libmpv-release.aar - path: ./libmpv/build/outputs/aar/libmpv-release.aar + name: artifact + path: ./output/* + - uses: softprops/action-gh-release@v1 + if: github.ref == 'refs/heads/main' + with: + draft: true + prerelease: false + tag_name: "vnext" + files: | + output/* diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index dd458a5..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: Publish - -on: - push: - tags: - - v* - -jobs: - publish: - name: Publish - runs-on: ubuntu-latest - environment: release - if: ${{ contains(github.repository_owner, 'jarnedemeulemeester') || startsWith(github.ref, 'refs/tags/v') }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Setup Java JDK - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - name: Symlink SDK - working-directory: ./buildscripts - run: | - mkdir sdk - ln -s ${ANDROID_HOME} ./sdk/android-sdk-linux - - name: Download dependencies - working-directory: ./buildscripts - run: ./download.sh - - name: Apply patches - working-directory: ./buildscripts - run: ./patch.sh - - name: Build - working-directory: ./buildscripts - run: ./build.sh - - name: Publish to MavenCentral - run: ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository - env: - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - SIGNING_KEY: ${{ secrets.SIGNING_KEY }} - SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} - - name: Create release - uses: softprops/action-gh-release@v2 - with: - draft: true - files: | - ./libmpv/build/outputs/aar/libmpv-release.aar diff --git a/LICENSE b/LICENSE index 81d2ff3..cfaa955 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +For the "default" and "full" flavors, the following license applies: + Copyright (c) 2016 Ilya Zhuravlev Copyright (c) 2016 sfan5 @@ -6,3 +8,20 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For the "encoders-gpl" flavor, the following license applies: + +Copyright (C) 2023 Callum Moffat + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/README.md b/README.md deleted file mode 100644 index 7d27336..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# libmpv for Android - -Based on [mpv-android](https://github.com/mpv-android/mpv-android) - -## Building from source - -Take a look at [README.md](buildscripts/README.md) inside the `buildscripts` directory. diff --git a/build.gradle.kts b/build.gradle.kts index 99629b3..ed1e353 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,4 @@ +@Suppress("DSL_SCOPE_VIOLATION") // False positive plugins { alias(libs.plugins.android.library) apply false alias(libs.plugins.publish.plugin) apply true @@ -10,44 +11,11 @@ allprojects { } } -// Create variables with empty default values -ext["signing.keyId"] = null -ext["signing.password"] = null -ext["signing.key"] = null -ext["ossrhUsername"] = null -ext["ossrhPassword"] = null -ext["sonatypeStagingProfileId"] = null - -val secretPropsFile: File = project.rootProject.file("local.properties") -if (secretPropsFile.exists()) { - // Read local.properties file first if it exists - secretPropsFile.reader().use { - java.util.Properties().apply { - load(it) - } - }.onEach { (name, value) -> - ext[name.toString()] = value - } -} else { - // Use system environment variables - ext["ossrhUsername"] = System.getenv("OSSRH_USERNAME") - ext["ossrhPassword"] = System.getenv("OSSRH_PASSWORD") - ext["sonatypeStagingProfileId"] = System.getenv("SONATYPE_STAGING_PROFILE_ID") - ext["signing.keyId"] = System.getenv("SIGNING_KEY_ID") - ext["signing.password"] = System.getenv("SIGNING_PASSWORD") - ext["signing.key"] = System.getenv("SIGNING_KEY") +tasks.wrapper { + gradleVersion = "7.6" + distributionType = Wrapper.DistributionType.ALL } -fun getExtraString(name: String) = ext[name]?.toString() - -nexusPublishing { - this.repositories { - sonatype { - stagingProfileId = getExtraString("sonatypeStagingProfileId") - username = getExtraString("ossrhUsername") - password = getExtraString("ossrhPassword") - nexusUrl = uri("https://s01.oss.sonatype.org/service/local/") - snapshotRepositoryUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") - } - } +apply { + from("$rootDir/scripts/publish-root.gradle") } \ No newline at end of file diff --git a/buildscripts/README.md b/buildscripts/README.md deleted file mode 100644 index 28c8566..0000000 --- a/buildscripts/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# Building - -## Download dependencies - -`download.sh` will take care of installing the Android SDK, NDK and downloading the sources. - -If you're running on Debian/Ubuntu or RHEL/Fedora it will also install the necessary dependencies for you. - -```shell -./download.sh -``` - -If you already have the Android SDK installed you can symlink `android-sdk-linux` to your SDK root -before running the script, it will still install the necessary SDK packages. - -A matching NDK version inside the SDK will be picked up automatically or downloaded/installed otherwise. - -## Patching - -```shell -./patch.sh -``` - -Run `patch.sh` to apply the custom patches to the dependencies. These patches are located in the `patches` folder. - -**Note** running `patch.sh` resets the dependencies to a clean state. - -## Build - -```shell -./build.sh -``` - -Run `build.sh` with `--clean` to clean the build directories before building. - -This builds for all architectures (`armeabi-v7a` `arm64-v8a` `x86` `x86_64`) by default. - -If you want to build only for a specific arch, build the native part like this: -```shell -./build.sh --arch arm64 mpv -./build.sh --arch x86_64 mpv -``` - -You also need to tell gradle to only build said architectures. See [Specify ABIs](https://developer.android.com/studio/projects/gradle-external-native-builds#specify-abi) for more information -```kotlin -android { - ... - defaultConfig { - ... - ndk { - abiFilters += listOf("x86_64", "arm64-v8a") - } - } -} -``` - -Finally you can build the AAR: -```shell -./build.sh -n -``` - -# Developing - -## Getting logs - -```shell -adb logcat # get all logs, useful when drivers/vendor libs output to logcat -adb logcat -s "mpv" # get only mpv logs -``` - -## Rebuilding a single component - -If you've made changes to a single component (e.g. ffmpeg or mpv) and want a new build you can of course just run ./build.sh but it's also possible to just build a single component like this: - -```shell -./build.sh -n ffmpeg -# optional: add --clean to build from a clean state -``` - -Note this will build the component for all architectures, specify `--arch` to build for a single arch. - -Afterwards, build mpv-android: - -```shell -./build.sh -n -``` - -## Using Android Studio - -You can use Android Studio to develop the Java part of the codebase. Before using it, make sure to build the project at least once by following the steps in the **Build** section. - -You should point Android Studio to existing SDK installation at `mpv-android/buildscripts/sdk/android-sdk-linux`. Then click "Open an existing Android Studio project" and select `mpv-android`. - -If Android Studio complains about project sync failing (`Error:Exception thrown while executing model rule: NdkComponentModelPlugin.Rules#createNativeBuildModel`), go to "File -> Project Structure -> SDK Location" and set "Android NDK Location" to `mpv-android/buildscripts/sdk/android-ndk-rVERSION`. - -Note that if you build from Android Studio only the Java part will be built. If you make any changes to libraries (ffmpeg, mpv, ...) or mpv-android native code (`app/src/main/jni/*`), first rebuild native code with: - -```shell -./build.sh -n -``` - -then build the project from Android Studio. - -Also, debugging native code does not work from within the studio at the moment, you will have to use gdb for that. - -## Debugging native code with gdb - -You first need to rebuild mpv-android with gdbserver support: - -```shell -NDK_DEBUG=1 ./build.sh -n -adb install -r ../app/build/outputs/apk/debug/app-debug.apk -``` - -After that, ndk-gdb can be used to debug the app: - -```shell -cd mpv-android/app/src/main/ -../../../buildscripts/sdk/android-ndk-r*/ndk-gdb --launch -``` - -# Credits, notes, etc - -These build scripts were created by @sfan5 and modified by @jarnedemeulemeester. - diff --git a/buildscripts/build.sh b/buildscripts/build.sh index 2659eeb..32b9828 100755 --- a/buildscripts/build.sh +++ b/buildscripts/build.sh @@ -5,7 +5,7 @@ cd "$( dirname "${BASH_SOURCE[0]}" )" cleanbuild=0 nodeps=0 -target=mpv-android +target=mpv archs=(armv7l arm64 x86 x86_64) getdeps () { @@ -15,9 +15,8 @@ getdeps () { loadarch () { unset CC CXX CPATH LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH - unset CFLAGS CXXFLAGS CPPFLAGS LDFLAGS - local apilvl=26 + local apilvl=21 # ndk_triple: what the toolchain actually is # cc_triple: what Google pretends the toolchain is if [ "$1" == "armv7l" ]; then @@ -47,6 +46,11 @@ loadarch () { export prefix_dir="$PWD/prefix/$prefix_name" export native_dir="$PWD/../libmpv/src/main/jniLibs/$prefix_name" export CC=$cc_triple-clang + if [[ "$1" == arm* ]]; then + export AS="$CC" + else + export AS="nasm" + fi export CXX=$cc_triple-clang++ export LDFLAGS="-Wl,-O1,--icf=safe -Wl,-z,max-page-size=16384" export AR=llvm-ar @@ -91,7 +95,7 @@ CROSSFILE } build () { - if [ $1 != "mpv-android" ] && [ ! -d deps/$1 ]; then + if [ ! -d deps/$1 ]; then printf >&2 '\e[1;31m%s\e[m\n' "Target $1 not found" return 1 fi @@ -103,23 +107,14 @@ build () { build $dep done fi - if [ "$1" != "mpv-android" ]; then - printf >&2 '\e[1;34m%s\e[m\n' "Building $1..." - pushd deps/$1 - BUILDSCRIPT=../../scripts/$1.sh - [ $cleanbuild -eq 1 ] && $BUILDSCRIPT clean + + printf >&2 '\e[1;34m%s\e[m\n' "Building $1..." + pushd deps/$1 + BUILDSCRIPT=../../scripts/$1.sh + sudo chmod +x $BUILDSCRIPT + [ $cleanbuild -eq 1 ] && $BUILDSCRIPT clean $BUILDSCRIPT build popd - fi -} - -assemble () { - printf >&2 '\e[1;34m%s\e[m\n' "Assembling $1..." - pushd .. - BUILDSCRIPT=buildscripts/scripts/mpv-android.sh - [ $cleanbuild -eq 1 ] && $BUILDSCRIPT clean - $BUILDSCRIPT build - popd } usage () { @@ -166,10 +161,4 @@ else build $target fi -if [ "$target" == "mpv-android" ]; then - assemble - [ -d ../libmpv/build/outputs/aar ] && ls -lh ../libmpv/build/outputs/aar/*.aar - [ -d ../libmpv/build/libs ] && ls -lh ../libmpv/build/libs/*.jar -fi - exit 0 diff --git a/buildscripts/bundle_default.sh b/buildscripts/bundle_default.sh new file mode 100755 index 0000000..67c7bd5 --- /dev/null +++ b/buildscripts/bundle_default.sh @@ -0,0 +1,56 @@ +# -------------------------------------------------- + +if [ ! -f "deps" ]; then + sudo rm -r deps +fi +if [ ! -f "prefix" ]; then + sudo rm -r prefix +fi + +./download.sh +./patch.sh + +# -------------------------------------------------- + +if [ ! -f "scripts/ffmpeg" ]; then + rm scripts/ffmpeg.sh +fi +cp flavors/default.sh scripts/ffmpeg.sh + +# -------------------------------------------------- + +./build.sh + +# -------------------------------------------------- + +cd deps/media-kit-android-helper + +sudo chmod +x gradlew +./gradlew assembleRelease + +unzip -o app/build/outputs/apk/release/app-release.apk -d app/build/outputs/apk/release + +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/arm64-v8a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/arm64-v8a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/armeabi-v7a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/armeabi-v7a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86_64/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86_64" + +cd ../.. + +zip -r "default-arm64-v8a.jar" lib/arm64-v8a +zip -r "default-armeabi-v7a.jar" lib/armeabi-v7a +zip -r "default-x86.jar" lib/x86 +zip -r "default-x86_64.jar" lib/x86_64 + +mkdir -p ../../../../../../../../../../output + +cp *.jar ../../../../../../../../../../output + +md5sum *.jar + +cd ../../../../../../../../.. + +# -------------------------------------------------- + +zip -r debug-symbols-default.zip prefix/*/lib +cp debug-symbols-default.zip ../output diff --git a/buildscripts/bundle_encoders-gpl.sh b/buildscripts/bundle_encoders-gpl.sh new file mode 100644 index 0000000..4769213 --- /dev/null +++ b/buildscripts/bundle_encoders-gpl.sh @@ -0,0 +1,57 @@ +# -------------------------------------------------- +set -euxo pipefail + +export ENCODERS_GPL=1 + +if [ -d deps ]; then + sudo rm -r deps +fi +if [ -d prefix ]; then + sudo rm -r prefix +fi + +./download.sh +./patch-encoders-gpl.sh + +# -------------------------------------------------- + +rm scripts/ffmpeg.sh +cp flavors/encoders-gpl.sh scripts/ffmpeg.sh + +# -------------------------------------------------- + +./build.sh + +# -------------------------------------------------- + +cd deps/media-kit-android-helper + +sudo chmod +x gradlew +./gradlew assembleRelease + +unzip -o app/build/outputs/apk/release/app-release.apk -d app/build/outputs/apk/release + +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/arm64-v8a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/arm64-v8a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/armeabi-v7a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/armeabi-v7a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86_64/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86_64" + +cd ../.. + +zip -r "encoders-gpl-arm64-v8a.jar" lib/arm64-v8a +zip -r "encoders-gpl-armeabi-v7a.jar" lib/armeabi-v7a +zip -r "encoders-gpl-x86.jar" lib/x86 +zip -r "encoders-gpl-x86_64.jar" lib/x86_64 + +mkdir -p ../../../../../../../../../../output + +cp *.jar ../../../../../../../../../../output + +md5sum *.jar + +cd ../../../../../../../../.. + +# -------------------------------------------------- + +zip -r debug-symbols-encoders-gpl.zip prefix/*/lib +cp debug-symbols-encoders-gpl.zip ../output diff --git a/buildscripts/bundle_full.sh b/buildscripts/bundle_full.sh new file mode 100644 index 0000000..8c1222d --- /dev/null +++ b/buildscripts/bundle_full.sh @@ -0,0 +1,56 @@ +# -------------------------------------------------- + +if [ ! -f "deps" ]; then + sudo rm -r deps +fi +if [ ! -f "prefix" ]; then + sudo rm -r prefix +fi + +./download.sh +./patch.sh + +# -------------------------------------------------- + +if [ ! -f "scripts/ffmpeg" ]; then + rm scripts/ffmpeg.sh +fi +cp flavors/full.sh scripts/ffmpeg.sh + +# -------------------------------------------------- + +./build.sh + +# -------------------------------------------------- + +cd deps/media-kit-android-helper + +sudo chmod +x gradlew +./gradlew assembleRelease + +unzip -o app/build/outputs/apk/release/app-release.apk -d app/build/outputs/apk/release + +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/arm64-v8a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/arm64-v8a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/armeabi-v7a/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/armeabi-v7a" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86" +ln -sf "$(pwd)/app/build/outputs/apk/release/lib/x86_64/libmediakitandroidhelper.so" "../../../libmpv/src/main/jniLibs/x86_64" + +cd ../.. + +zip -r "full-arm64-v8a.jar" lib/arm64-v8a +zip -r "full-armeabi-v7a.jar" lib/armeabi-v7a +zip -r "full-x86.jar" lib/x86 +zip -r "full-x86_64.jar" lib/x86_64 + +mkdir -p ../../../../../../../../../../output + +cp *.jar ../../../../../../../../../../output + +md5sum *.jar + +cd ../../../../../../../../.. + +# -------------------------------------------------- + +zip -r debug-symbols-full.zip prefix/*/lib +cp debug-symbols-full.zip ../output diff --git a/buildscripts/flavors/default.sh b/buildscripts/flavors/default.sh new file mode 100644 index 0000000..7e09c87 --- /dev/null +++ b/buildscripts/flavors/default.sh @@ -0,0 +1,279 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf _build$ndk_suffix + exit 0 +else + exit 255 +fi + +mkdir -p _build$ndk_suffix +cd _build$ndk_suffix + +cpu=armv7-a +[[ "$ndk_triple" == "aarch64"* ]] && cpu=armv8-a +[[ "$ndk_triple" == "x86_64"* ]] && cpu=generic +[[ "$ndk_triple" == "i686"* ]] && cpu="i686 --disable-asm" + +cpuflags= +[[ "$ndk_triple" == "arm"* ]] && cpuflags="$cpuflags -mfpu=neon -mcpu=cortex-a8" + +../configure \ + --target-os=android --enable-cross-compile --cross-prefix=$ndk_triple- --ar=$AR --cc=$CC --ranlib=$RANLIB \ + --arch=${ndk_triple%%-*} --cpu=$cpu --pkg-config=pkg-config --nm=llvm-nm \ + --extra-cflags="-I$prefix_dir/include $cpuflags" --extra-ldflags="-L$prefix_dir/lib" \ + \ + --disable-gpl \ + --disable-nonfree \ + --enable-version3 \ + --enable-static \ + --disable-shared \ + --disable-vulkan \ + --disable-iconv \ + --disable-stripping \ + --pkg-config-flags=--static \ + \ + --disable-muxers \ + --disable-decoders \ + --disable-encoders \ + --disable-demuxers \ + --disable-parsers \ + --disable-protocols \ + --disable-devices \ + --disable-filters \ + --disable-doc \ + --disable-avdevice \ + --disable-postproc \ + --disable-programs \ + --disable-gray \ + --disable-swscale-alpha \ + \ + --enable-jni \ + --enable-bsfs \ + --enable-mediacodec \ + \ + --disable-dxva2 \ + --disable-vaapi \ + --disable-vdpau \ + --disable-bzlib \ + --disable-linux-perf \ + --disable-videotoolbox \ + --disable-audiotoolbox \ + \ + --enable-small \ + --enable-hwaccels \ + --enable-optimizations \ + --enable-runtime-cpudetect \ + \ + --enable-mbedtls \ + \ + --enable-libdav1d \ + \ + --enable-libxml2 \ + \ + --enable-avutil \ + --enable-avcodec \ + --enable-avfilter \ + --enable-avformat \ + --enable-swscale \ + --enable-swresample \ + \ + --enable-decoder=flv \ + --enable-decoder=h263 \ + --enable-decoder=h263i \ + --enable-decoder=h263p \ + --enable-decoder=h264* \ + --enable-decoder=mpeg1video \ + --enable-decoder=mpeg2* \ + --enable-decoder=mpeg4* \ + --enable-decoder=vp6 \ + --enable-decoder=vp6a \ + --enable-decoder=vp6f \ + --enable-decoder=vp8* \ + --enable-decoder=vp9* \ + --enable-decoder=hevc* \ + --enable-decoder=av1* \ + --enable-decoder=libdav1d \ + --enable-decoder=theora \ + --enable-decoder=msmpeg* \ + --enable-decoder=mjpeg* \ + --enable-decoder=wmv* \ + \ + --enable-decoder=aac* \ + --enable-decoder=ac3 \ + --enable-decoder=alac \ + --enable-decoder=als \ + --enable-decoder=ape \ + --enable-decoder=atrac* \ + --enable-decoder=eac3 \ + --enable-decoder=flac \ + --enable-decoder=gsm* \ + --enable-decoder=mp1* \ + --enable-decoder=mp2* \ + --enable-decoder=mp3* \ + --enable-decoder=mpc* \ + --enable-decoder=opus \ + --enable-decoder=ra* \ + --enable-decoder=ralf \ + --enable-decoder=shorten \ + --enable-decoder=tak \ + --enable-decoder=tta \ + --enable-decoder=vorbis \ + --enable-decoder=wavpack \ + --enable-decoder=wma* \ + --enable-decoder=pcm* \ + --enable-decoder=dsd* \ + --enable-decoder=dca \ + \ + --enable-decoder=ssa \ + --enable-decoder=ass \ + --enable-decoder=dvbsub \ + --enable-decoder=dvdsub \ + --enable-decoder=srt \ + --enable-decoder=stl \ + --enable-decoder=subrip \ + --enable-decoder=subviewer \ + --enable-decoder=subviewer1 \ + --enable-decoder=text \ + --enable-decoder=vplayer \ + --enable-decoder=webvtt \ + --enable-decoder=movtext \ + \ + --enable-decoder=mjpeg \ + --enable-decoder=ljpeg \ + --enable-decoder=jpegls \ + --enable-decoder=jpeg2000 \ + --enable-decoder=png \ + --enable-decoder=gif \ + --enable-decoder=bmp \ + --enable-decoder=tiff \ + --enable-decoder=webp \ + --enable-decoder=jpegls \ + \ + --enable-demuxer=concat \ + --enable-demuxer=data \ + --enable-demuxer=flv \ + --enable-demuxer=hls \ + --enable-demuxer=latm \ + --enable-demuxer=live_flv \ + --enable-demuxer=loas \ + --enable-demuxer=m4v \ + --enable-demuxer=mov \ + --enable-demuxer=mpegps \ + --enable-demuxer=mpegts \ + --enable-demuxer=mpegvideo \ + --enable-demuxer=hevc \ + --enable-demuxer=rtsp \ + --enable-demuxer=mpeg4 \ + --enable-demuxer=mjpeg* \ + --enable-demuxer=avi \ + --enable-demuxer=av1 \ + --enable-demuxer=matroska \ + --enable-demuxer=dash \ + --enable-demuxer=webm_dash_manifest \ + \ + --enable-demuxer=aac \ + --enable-demuxer=ac3 \ + --enable-demuxer=aiff \ + --enable-demuxer=ape \ + --enable-demuxer=asf \ + --enable-demuxer=au \ + --enable-demuxer=avi \ + --enable-demuxer=flac \ + --enable-demuxer=flv \ + --enable-demuxer=matroska \ + --enable-demuxer=mov \ + --enable-demuxer=m4v \ + --enable-demuxer=mp3 \ + --enable-demuxer=mpc* \ + --enable-demuxer=ogg \ + --enable-demuxer=pcm* \ + --enable-demuxer=rm \ + --enable-demuxer=shorten \ + --enable-demuxer=tak \ + --enable-demuxer=tta \ + --enable-demuxer=wav \ + --enable-demuxer=wv \ + --enable-demuxer=xwma \ + --enable-demuxer=dsf \ + --enable-demuxer=truehd \ + --enable-demuxer=dts \ + --enable-demuxer=dtshd \ + \ + --enable-demuxer=ass \ + --enable-demuxer=srt \ + --enable-demuxer=stl \ + --enable-demuxer=webvtt \ + --enable-demuxer=subviewer \ + --enable-demuxer=subviewer1 \ + --enable-demuxer=vplayer \ + \ + --enable-parser=h263 \ + --enable-parser=h264 \ + --enable-parser=hevc \ + --enable-parser=mpeg4 \ + --enable-parser=mpeg4video \ + --enable-parser=mpegvideo \ + \ + --enable-parser=aac* \ + --enable-parser=ac3 \ + --enable-parser=cook \ + --enable-parser=dca \ + --enable-parser=flac \ + --enable-parser=gsm \ + --enable-parser=mpegaudio \ + --enable-parser=tak \ + --enable-parser=vorbis \ + --enable-parser=dca \ + \ + --enable-filter=overlay \ + --enable-filter=equalizer \ + \ + --enable-protocol=async \ + --enable-protocol=cache \ + --enable-protocol=crypto \ + --enable-protocol=data \ + --enable-protocol=ffrtmphttp \ + --enable-protocol=file \ + --enable-protocol=ftp \ + --enable-protocol=hls \ + --enable-protocol=http \ + --enable-protocol=httpproxy \ + --enable-protocol=https \ + --enable-protocol=pipe \ + --enable-protocol=rtmp \ + --enable-protocol=rtmps \ + --enable-protocol=rtmpt \ + --enable-protocol=rtmpts \ + --enable-protocol=rtp \ + --enable-protocol=subfile \ + --enable-protocol=tcp \ + --enable-protocol=tls \ + --enable-protocol=srt \ + --enable-protocol=udp \ + \ + --enable-encoder=mjpeg \ + --enable-encoder=ljpeg \ + --enable-encoder=jpegls \ + --enable-encoder=jpeg2000 \ + --enable-encoder=png \ + --enable-encoder=jpegls \ + \ + --enable-network \ + +make -j$cores +make DESTDIR="$prefix_dir" install + +ln -sf "$prefix_dir"/lib/libswresample.so "$native_dir" +ln -sf "$prefix_dir"/lib/libpostproc.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavutil.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavcodec.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavformat.so "$native_dir" +ln -sf "$prefix_dir"/lib/libswscale.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavfilter.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavdevice.so "$native_dir" diff --git a/buildscripts/flavors/encoders-gpl.sh b/buildscripts/flavors/encoders-gpl.sh new file mode 100644 index 0000000..6e626b7 --- /dev/null +++ b/buildscripts/flavors/encoders-gpl.sh @@ -0,0 +1,127 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf _build$ndk_suffix + exit 0 +else + exit 255 +fi + +mkdir -p _build$ndk_suffix +cd _build$ndk_suffix + +cpu=armv7-a +[[ "$ndk_triple" == "aarch64"* ]] && cpu=armv8-a +[[ "$ndk_triple" == "x86_64"* ]] && cpu=generic +[[ "$ndk_triple" == "i686"* ]] && cpu="i686 --disable-asm" + +cpuflags= +[[ "$ndk_triple" == "arm"* ]] && cpuflags="$cpuflags -mfpu=neon -mcpu=cortex-a8" + +../configure \ + --target-os=android --enable-cross-compile --cross-prefix=$ndk_triple- --ar=$AR --cc=$CC --ranlib=$RANLIB \ + --arch=${ndk_triple%%-*} --cpu=$cpu --pkg-config=pkg-config --nm=llvm-nm \ + --extra-cflags="-I$prefix_dir/include $cpuflags" --extra-ldflags="-L$prefix_dir/lib" \ + --pkg-config-flags="--static" \ + \ + --disable-nonfree \ + --enable-version3 \ + --enable-static \ + --disable-shared \ + --disable-vulkan \ + --disable-iconv \ + --disable-stripping \ + --pkg-config-flags=--static \ + \ + --enable-decoders \ + --enable-encoders \ + --enable-libvorbis \ + --enable-libvpx \ + --enable-gpl \ + --enable-libx264 \ + --enable-muxers \ + --enable-demuxers \ + --enable-parsers \ + \ + --disable-protocols \ + --disable-devices \ + --disable-doc \ + --disable-avdevice \ + --disable-postproc \ + --disable-programs \ + --disable-gray \ + --disable-swscale-alpha \ + \ + --enable-jni \ + --enable-bsfs \ + --enable-mediacodec \ + \ + --disable-dxva2 \ + --disable-vaapi \ + --disable-vdpau \ + --disable-bzlib \ + --disable-linux-perf \ + --disable-videotoolbox \ + --disable-audiotoolbox \ + \ + --enable-small \ + --enable-hwaccels \ + --enable-optimizations \ + --enable-runtime-cpudetect \ + \ + --enable-mbedtls \ + \ + --enable-libdav1d \ + \ + --enable-libxml2 \ + \ + --enable-avutil \ + --enable-avcodec \ + --enable-avfilter \ + --enable-avformat \ + --enable-swscale \ + --enable-swresample \ + \ + --enable-filters \ + \ + --enable-protocol=async \ + --enable-protocol=cache \ + --enable-protocol=crypto \ + --enable-protocol=data \ + --enable-protocol=ffrtmphttp \ + --enable-protocol=file \ + --enable-protocol=ftp \ + --enable-protocol=hls \ + --enable-protocol=http \ + --enable-protocol=httpproxy \ + --enable-protocol=https \ + --enable-protocol=pipe \ + --enable-protocol=rtmp \ + --enable-protocol=rtmps \ + --enable-protocol=rtmpt \ + --enable-protocol=rtmpts \ + --enable-protocol=rtp \ + --enable-protocol=subfile \ + --enable-protocol=tcp \ + --enable-protocol=tls \ + --enable-protocol=srt \ + --enable-protocol=udp \ + \ + --enable-network \ + +make -j$cores +make DESTDIR="$prefix_dir" install + +ln -sf "$prefix_dir"/lib/libswresample.so "$native_dir" +ln -sf "$prefix_dir"/lib/libpostproc.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavutil.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavcodec.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavformat.so "$native_dir" +ln -sf "$prefix_dir"/lib/libswscale.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavfilter.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavdevice.so "$native_dir" diff --git a/buildscripts/flavors/full.sh b/buildscripts/flavors/full.sh new file mode 100644 index 0000000..4cfb1a5 --- /dev/null +++ b/buildscripts/flavors/full.sh @@ -0,0 +1,132 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf _build$ndk_suffix + exit 0 +else + exit 255 +fi + +mkdir -p _build$ndk_suffix +cd _build$ndk_suffix + +cpu=armv7-a +[[ "$ndk_triple" == "aarch64"* ]] && cpu=armv8-a +[[ "$ndk_triple" == "x86_64"* ]] && cpu=generic +[[ "$ndk_triple" == "i686"* ]] && cpu="i686 --disable-asm" + +cpuflags= +[[ "$ndk_triple" == "arm"* ]] && cpuflags="$cpuflags -mfpu=neon -mcpu=cortex-a8" + +../configure \ + --target-os=android --enable-cross-compile --cross-prefix=$ndk_triple- --ar=$AR --cc=$CC --ranlib=$RANLIB \ + --arch=${ndk_triple%%-*} --cpu=$cpu --pkg-config=pkg-config --nm=llvm-nm \ + --extra-cflags="-I$prefix_dir/include $cpuflags" --extra-ldflags="-L$prefix_dir/lib" \ + \ + --disable-gpl \ + --disable-nonfree \ + --enable-version3 \ + --enable-static \ + --disable-shared \ + --disable-vulkan \ + --disable-iconv \ + --disable-stripping \ + --pkg-config-flags=--static \ + \ + --enable-decoders \ + --enable-demuxers \ + --enable-parsers \ + \ + --disable-muxers \ + --disable-encoders \ + --disable-protocols \ + --disable-devices \ + --disable-filters \ + --disable-doc \ + --disable-avdevice \ + --disable-postproc \ + --disable-programs \ + --disable-gray \ + --disable-swscale-alpha \ + \ + --enable-jni \ + --enable-bsfs \ + --enable-mediacodec \ + \ + --disable-dxva2 \ + --disable-vaapi \ + --disable-vdpau \ + --disable-bzlib \ + --disable-linux-perf \ + --disable-videotoolbox \ + --disable-audiotoolbox \ + \ + --enable-small \ + --enable-hwaccels \ + --enable-optimizations \ + --enable-runtime-cpudetect \ + \ + --enable-mbedtls \ + \ + --enable-libdav1d \ + \ + --enable-libxml2 \ + \ + --enable-avutil \ + --enable-avcodec \ + --enable-avfilter \ + --enable-avformat \ + --enable-swscale \ + --enable-swresample \ + \ + --enable-filter=overlay \ + --enable-filter=equalizer \ + \ + --enable-protocol=async \ + --enable-protocol=cache \ + --enable-protocol=crypto \ + --enable-protocol=data \ + --enable-protocol=ffrtmphttp \ + --enable-protocol=file \ + --enable-protocol=ftp \ + --enable-protocol=hls \ + --enable-protocol=http \ + --enable-protocol=httpproxy \ + --enable-protocol=https \ + --enable-protocol=pipe \ + --enable-protocol=rtmp \ + --enable-protocol=rtmps \ + --enable-protocol=rtmpt \ + --enable-protocol=rtmpts \ + --enable-protocol=rtp \ + --enable-protocol=subfile \ + --enable-protocol=tcp \ + --enable-protocol=tls \ + --enable-protocol=srt \ + --enable-protocol=udp \ + \ + --enable-encoder=mjpeg \ + --enable-encoder=ljpeg \ + --enable-encoder=jpegls \ + --enable-encoder=jpeg2000 \ + --enable-encoder=png \ + --enable-encoder=jpegls \ + \ + --enable-network \ + +make -j$cores +make DESTDIR="$prefix_dir" install + +ln -sf "$prefix_dir"/lib/libswresample.so "$native_dir" +ln -sf "$prefix_dir"/lib/libpostproc.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavutil.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavcodec.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavformat.so "$native_dir" +ln -sf "$prefix_dir"/lib/libswscale.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavfilter.so "$native_dir" +ln -sf "$prefix_dir"/lib/libavdevice.so "$native_dir" diff --git a/buildscripts/include/depinfo.sh b/buildscripts/include/depinfo.sh index 68804c8..46b3351 100755 --- a/buildscripts/include/depinfo.sh +++ b/buildscripts/include/depinfo.sh @@ -6,7 +6,6 @@ v_sdk=11076708_latest v_ndk=27.1.12297006 v_sdk_build_tools=35.0.0 -v_lua=5.2.4 v_libass=0.17.3 v_harfbuzz=10.0.1 v_fribidi=1.0.16 @@ -14,8 +13,12 @@ v_freetype=2-13-3 v_mbedtls=3.6.1 v_libplacebo=7.349.0 v_dav1d=1.4.3 +v_libxml2=2.10.3 v_ffmpeg=7.1 v_mpv=0.39.0 +v_libogg=1.3.5 +v_libvorbis=1.3.7 +v_libvpx=1.13 ## Dependency tree @@ -23,13 +26,21 @@ v_mpv=0.39.0 dep_mbedtls=() dep_dav1d=() -dep_ffmpeg=(mbedtls dav1d) +dep_libvorbis=(libogg) +if [ -n "$ENCODERS_GPL" ]; then + dep_ffmpeg=(mbedtls dav1d libxml2 libvorbis libvpx libx264) +else + dep_ffmpeg=(mbedtls dav1d libxml2) +fi dep_freetype2=() dep_fribidi=() dep_harfbuzz=() dep_libass=(freetype fribidi harfbuzz) dep_lua=() +dep_shaderc=() dep_libplacebo=() -dep_mpv=(ffmpeg libass lua libplacebo) -dep_mpv_android=(mpv) - +if [ -n "$ENCODERS_GPL" ]; then + dep_mpv=(ffmpeg libass libplacebo fftools_ffi) +else + dep_mpv=(ffmpeg libass libplacebo) +fi diff --git a/buildscripts/include/download-deps.sh b/buildscripts/include/download-deps.sh index 365f53e..49fae40 100755 --- a/buildscripts/include/download-deps.sh +++ b/buildscripts/include/download-deps.sh @@ -12,6 +12,21 @@ mkdir -p deps && cd deps # dav1d [ ! -d dav1d ] && git clone --depth 1 --branch $v_dav1d https://code.videolan.org/videolan/dav1d.git dav1d +# libxml2 +[ ! -d libxml2 ] && git clone --depth 1 --branch v$v_libxml2 --recursive https://gitlab.gnome.org/GNOME/libxml2.git libxml2 + +# libogg +[ ! -d libogg ] && $WGET https://github.com/xiph/ogg/releases/download/v${v_libogg}/libogg-${v_libogg}.tar.gz && tar -xf libogg-${v_libogg}.tar.gz && mv libogg-${v_libogg} libogg && rm libogg-${v_libogg}.tar.gz + +# libvorbis +[ ! -d libvorbis ] && $WGET https://github.com/xiph/vorbis/releases/download/v${v_libvorbis}/libvorbis-${v_libvorbis}.tar.gz && tar -xf libvorbis-${v_libvorbis}.tar.gz && mv libvorbis-${v_libvorbis} libvorbis && rm libvorbis-${v_libvorbis}.tar.gz + +# libvpx +[ ! -d libvpx ] && git clone --depth 1 --branch meson-$v_libvpx https://gitlab.freedesktop.org/gstreamer/meson-ports/libvpx.git + +# libx264 +[ ! -d libx264 ] && git clone --depth 1 https://code.videolan.org/videolan/x264.git --branch master libx264 + # ffmpeg [ ! -d ffmpeg ] && git clone --depth 1 --branch n$v_ffmpeg https://github.com/FFmpeg/FFmpeg.git ffmpeg @@ -27,16 +42,26 @@ mkdir -p deps && cd deps # libass [ ! -d libass ] && git clone --depth 1 --branch $v_libass https://github.com/libass/libass.git libass -# lua -if [ ! -d lua ]; then - mkdir lua - $WGET http://www.lua.org/ftp/lua-$v_lua.tar.gz -O - | \ - tar -xz -C lua --strip-components=1 -fi +# shaderc +mkdir -p shaderc +cat >shaderc/README <<'HEREDOC' +Shaderc sources are provided by the NDK. +see /sources/third_party/shaderc +HEREDOC +# libplacebo [ ! -d libplacebo ] && git clone --depth 1 --branch v$v_libplacebo --recurse-submodules https://code.videolan.org/videolan/libplacebo.git libplacebo # mpv -[ ! -d mpv ] && git clone --depth 1 --branch v$v_mpv https://github.com/mpv-player/mpv.git mpv +[ ! -d mpv ] && git clone --depth 1 --branch v$v_mpv https://github.com/mpv-player/mpv.git mpv + +# fftools_ffi +[ ! -d fftools_ffi ] && git clone --depth 1 --branch main https://github.com/moffatman/fftools-ffi.git fftools_ffi + +# media-kit-android-helper +[ ! -d media-kit-android-helper ] && git clone --depth 1 --branch main https://github.com/media-kit/media-kit-android-helper.git + +# media_kit +[ ! -d media_kit ] && git clone --depth 1 --single-branch --branch main https://github.com/alexmercerind/media_kit.git cd .. diff --git a/buildscripts/include/download-sdk.sh b/buildscripts/include/download-sdk.sh index ef317dc..5bc1670 100755 --- a/buildscripts/include/download-sdk.sh +++ b/buildscripts/include/download-sdk.sh @@ -10,12 +10,12 @@ if [ "$os" == "linux" ]; then if [ $TRAVIS -eq 0 ]; then hash yum &>/dev/null && { - sudo yum install autoconf pkgconfig libtool ninja-build \ + sudo yum install autoconf pkgconfig libtool ninja-build unzip \ python3-pip python3-setuptools unzip wget; python3 -m pip install meson jsonschema jinja2; } apt-get -v &>/dev/null && { sudo apt-get update; - sudo apt-get install -y autoconf pkg-config libtool ninja-build nasm \ + sudo apt-get install -y autoconf pkg-config libtool ninja-build nasm unzip \ python3-pip python3-setuptools unzip; python3 -m pip install meson jsonschema jinja2; } fi diff --git a/buildscripts/patch-encoders-gpl.sh b/buildscripts/patch-encoders-gpl.sh new file mode 100644 index 0000000..2352eba --- /dev/null +++ b/buildscripts/patch-encoders-gpl.sh @@ -0,0 +1,21 @@ +#!/bin/bash -e + +PATCHES=(patches-encoders-gpl/*) +ROOT=$(pwd) + +for dep_path in "${PATCHES[@]}"; do + if [ -d "$dep_path" ]; then + patches=($dep_path/*) + dep=$(echo $dep_path |cut -d/ -f 2) + cd deps/$dep + echo Patching $dep + git reset --hard + for patch in "${patches[@]}"; do + echo Applying $patch + git apply "$ROOT/$patch" + done + cd $ROOT + fi +done + +exit 0 diff --git a/buildscripts/patches-encoders-gpl/ffmpeg b/buildscripts/patches-encoders-gpl/ffmpeg new file mode 120000 index 0000000..e2bf6e7 --- /dev/null +++ b/buildscripts/patches-encoders-gpl/ffmpeg @@ -0,0 +1 @@ +../patches/ffmpeg \ No newline at end of file diff --git a/buildscripts/patches-encoders-gpl/libx264/fix_x86_asm.patch b/buildscripts/patches-encoders-gpl/libx264/fix_x86_asm.patch new file mode 100644 index 0000000..b5630b2 --- /dev/null +++ b/buildscripts/patches-encoders-gpl/libx264/fix_x86_asm.patch @@ -0,0 +1,13 @@ +diff --git a/configure b/configure +index e242e73c..219381ab 100755 +--- a/configure ++++ b/configure +@@ -738,7 +739,7 @@ LDFLAGS="$LDFLAGS $libm" + + stack_alignment=4 + case $host_cpu in +- i*86) ++ *86) + ARCH="X86" + AS="${AS-nasm}" + AS_EXT=".asm" diff --git a/buildscripts/patches-encoders-gpl/mpv/depend_on_fftools_ffi.patch b/buildscripts/patches-encoders-gpl/mpv/depend_on_fftools_ffi.patch new file mode 100644 index 0000000..cb69350 --- /dev/null +++ b/buildscripts/patches-encoders-gpl/mpv/depend_on_fftools_ffi.patch @@ -0,0 +1,48 @@ +diff --git a/meson.build b/meson.build +index a56bb1f37c..7cd3b195f9 100644 +--- a/meson.build ++++ b/meson.build +@@ -23,6 +23,9 @@ libavutil = dependency('libavutil', version: '>= 56.70.100') + libswresample = dependency('libswresample', version: '>= 3.9.100') + libswscale = dependency('libswscale', version: '>= 5.9.100') + ++# fftools-ffi ++libfftools_ffi = dependency('fftools-ffi') ++ + libass = dependency('libass', version: '>= 0.12.2') + + # the dependency order of libass -> ffmpeg is necessary due to +@@ -33,7 +36,8 @@ dependencies = [libass, + libavformat, + libavutil, + libswresample, +- libswscale] ++ libswscale, ++ libfftools_ffi] + + # Keeps track of all enabled/disabled features + features = { +@@ -244,7 +248,10 @@ sources = files( + ## tree_allocator + 'ta/ta.c', + 'ta/ta_talloc.c', +- 'ta/ta_utils.c' ++ 'ta/ta_utils.c', ++ ++ ## fftools-ffi hack ++ 'fftools-ffi.c' + ) + + +diff --git a/fftools-ffi.c b/fftools-ffi.c +new file mode 100644 +index 0000000..6cd4258 +--- /dev/null ++++ b/fftools-ffi.c +@@ -0,0 +1,6 @@ ++#include "fftools-ffi/dart_api.h" ++ ++void* a = FFToolsFFIInitialize; ++void* b = FFToolsFFIExecuteFFmpeg; ++void* c = FFToolsFFIExecuteFFprobe; ++void* d = FFToolsCancel; diff --git a/buildscripts/patches-encoders-gpl/mpv/mpv_lavc_set_java_vm.patch b/buildscripts/patches-encoders-gpl/mpv/mpv_lavc_set_java_vm.patch new file mode 120000 index 0000000..1b46060 --- /dev/null +++ b/buildscripts/patches-encoders-gpl/mpv/mpv_lavc_set_java_vm.patch @@ -0,0 +1 @@ +../../patches/mpv/mpv_lavc_set_java_vm.patch \ No newline at end of file diff --git a/buildscripts/patches/ffmpeg/dash_base_url_escape.patch b/buildscripts/patches/ffmpeg/dash_base_url_escape.patch new file mode 100644 index 0000000..36ed6d5 --- /dev/null +++ b/buildscripts/patches/ffmpeg/dash_base_url_escape.patch @@ -0,0 +1,26 @@ +diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c +index 29d4680..c50afaf 100644 +--- a/libavformat/dashdec.c ++++ b/libavformat/dashdec.c +@@ -768,7 +768,9 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur + baseurl = xmlNodeGetContent(node); + root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path; + if (node) { +- xmlNodeSetContent(node, root_url); ++ char* root_url_content = xmlEncodeSpecialChars(NULL, root_url); ++ xmlNodeSetContent(node, root_url_content); ++ xmlFree(root_url_content); + updated = 1; + } + +@@ -802,7 +804,9 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur + memset(p + 1, 0, strlen(p)); + } + av_strlcat(tmp_str, text + start, tmp_max_url_size); +- xmlNodeSetContent(baseurl_nodes[i], tmp_str); ++ char* tmp_str_content = xmlEncodeSpecialChars(NULL, tmp_str); ++ xmlNodeSetContent(baseurl_nodes[i], tmp_str_content); ++ xmlFree(tmp_str_content); + updated = 1; + xmlFree(text); + } diff --git a/buildscripts/patches/mpv/mpv_lavc_set_java_vm.patch b/buildscripts/patches/mpv/mpv_lavc_set_java_vm.patch new file mode 100644 index 0000000..a5a5e92 --- /dev/null +++ b/buildscripts/patches/mpv/mpv_lavc_set_java_vm.patch @@ -0,0 +1,44 @@ +diff --git a/libmpv/client.h b/libmpv/client.h +index fb10e5e..afbc952 100644 +--- a/libmpv/client.h ++++ b/libmpv/client.h +@@ -1707,6 +1707,15 @@ MPV_EXPORT mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout); + */ + MPV_EXPORT void mpv_wakeup(mpv_handle *ctx); + ++/** ++ * Calls av_jni_set_java_vm() with the given JavaVM*. ++ * https://github.com/FFmpeg/FFmpeg/blob/0ba719f726632d73592311615087a0d64aa2fb60/libavcodec/jni.h#L26-L36 ++ * ++ * The av_jni_set_java_vm() symbol is not visible when statically linking with libavcodec. ++ * It is important to call this method so that libavcodec can access JNI environment & thus, mediacodec APIs. ++ */ ++MPV_EXPORT int mpv_lavc_set_java_vm(void *vm); ++ + /** + * Set a custom function that should be called when there are new events. Use + * this if blocking in mpv_wait_event() to wait for new events is not feasible. +diff --git a/libmpv/mpv.def b/libmpv/mpv.def +index 232490d..d7a2842 100644 +--- a/player/client.c ++++ b/player/client.c +@@ -22,6 +22,8 @@ + #include + #include + ++#include ++ + #include "common/common.h" + #include "common/global.h" + #include "common/msg.h" +@@ -967,6 +969,10 @@ void mpv_wakeup(mpv_handle *ctx) + pthread_mutex_unlock(&ctx->lock); + } + ++int mpv_lavc_set_java_vm(void *vm) { ++ return av_jni_set_java_vm(vm, NULL); ++} ++ + // map client API types to internal types + static const struct m_option type_conv[] = { + [MPV_FORMAT_STRING] = { .type = CONF_TYPE_STRING }, diff --git a/buildscripts/scripts/dav1d.sh b/buildscripts/scripts/dav1d.sh index 7df636d..87a7198 100755 --- a/buildscripts/scripts/dav1d.sh +++ b/buildscripts/scripts/dav1d.sh @@ -17,9 +17,7 @@ fi unset CC CXX # meson wants these unset meson setup $build --cross-file "$prefix_dir"/crossfile.txt \ - -Denable_tests=false \ - -Db_lto=true \ - -Dstack_alignment=16 + -Denable_tests=false -Db_lto=true -Dstack_alignment=16 ninja -C $build -j$cores DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/ffmpeg.sh b/buildscripts/scripts/ffmpeg.sh old mode 100755 new mode 100644 index affccce..7e09c87 --- a/buildscripts/scripts/ffmpeg.sh +++ b/buildscripts/scripts/ffmpeg.sh @@ -24,14 +24,247 @@ cpuflags= [[ "$ndk_triple" == "arm"* ]] && cpuflags="$cpuflags -mfpu=neon -mcpu=cortex-a8" ../configure \ - --target-os=android --enable-cross-compile --cross-prefix=$ndk_triple- --cc=$CC \ + --target-os=android --enable-cross-compile --cross-prefix=$ndk_triple- --ar=$AR --cc=$CC --ranlib=$RANLIB \ --arch=${ndk_triple%%-*} --cpu=$cpu --pkg-config=pkg-config --nm=llvm-nm \ --extra-cflags="-I$prefix_dir/include $cpuflags" --extra-ldflags="-L$prefix_dir/lib" \ - --enable-{jni,mediacodec,mbedtls,libdav1d} --disable-vulkan \ - --disable-static --enable-shared --enable-{gpl,version3} \ - --disable-{stripping,doc,programs} \ - --disable-{muxers,encoders,devices,filters} \ - --disable-v4l2-m2m + \ + --disable-gpl \ + --disable-nonfree \ + --enable-version3 \ + --enable-static \ + --disable-shared \ + --disable-vulkan \ + --disable-iconv \ + --disable-stripping \ + --pkg-config-flags=--static \ + \ + --disable-muxers \ + --disable-decoders \ + --disable-encoders \ + --disable-demuxers \ + --disable-parsers \ + --disable-protocols \ + --disable-devices \ + --disable-filters \ + --disable-doc \ + --disable-avdevice \ + --disable-postproc \ + --disable-programs \ + --disable-gray \ + --disable-swscale-alpha \ + \ + --enable-jni \ + --enable-bsfs \ + --enable-mediacodec \ + \ + --disable-dxva2 \ + --disable-vaapi \ + --disable-vdpau \ + --disable-bzlib \ + --disable-linux-perf \ + --disable-videotoolbox \ + --disable-audiotoolbox \ + \ + --enable-small \ + --enable-hwaccels \ + --enable-optimizations \ + --enable-runtime-cpudetect \ + \ + --enable-mbedtls \ + \ + --enable-libdav1d \ + \ + --enable-libxml2 \ + \ + --enable-avutil \ + --enable-avcodec \ + --enable-avfilter \ + --enable-avformat \ + --enable-swscale \ + --enable-swresample \ + \ + --enable-decoder=flv \ + --enable-decoder=h263 \ + --enable-decoder=h263i \ + --enable-decoder=h263p \ + --enable-decoder=h264* \ + --enable-decoder=mpeg1video \ + --enable-decoder=mpeg2* \ + --enable-decoder=mpeg4* \ + --enable-decoder=vp6 \ + --enable-decoder=vp6a \ + --enable-decoder=vp6f \ + --enable-decoder=vp8* \ + --enable-decoder=vp9* \ + --enable-decoder=hevc* \ + --enable-decoder=av1* \ + --enable-decoder=libdav1d \ + --enable-decoder=theora \ + --enable-decoder=msmpeg* \ + --enable-decoder=mjpeg* \ + --enable-decoder=wmv* \ + \ + --enable-decoder=aac* \ + --enable-decoder=ac3 \ + --enable-decoder=alac \ + --enable-decoder=als \ + --enable-decoder=ape \ + --enable-decoder=atrac* \ + --enable-decoder=eac3 \ + --enable-decoder=flac \ + --enable-decoder=gsm* \ + --enable-decoder=mp1* \ + --enable-decoder=mp2* \ + --enable-decoder=mp3* \ + --enable-decoder=mpc* \ + --enable-decoder=opus \ + --enable-decoder=ra* \ + --enable-decoder=ralf \ + --enable-decoder=shorten \ + --enable-decoder=tak \ + --enable-decoder=tta \ + --enable-decoder=vorbis \ + --enable-decoder=wavpack \ + --enable-decoder=wma* \ + --enable-decoder=pcm* \ + --enable-decoder=dsd* \ + --enable-decoder=dca \ + \ + --enable-decoder=ssa \ + --enable-decoder=ass \ + --enable-decoder=dvbsub \ + --enable-decoder=dvdsub \ + --enable-decoder=srt \ + --enable-decoder=stl \ + --enable-decoder=subrip \ + --enable-decoder=subviewer \ + --enable-decoder=subviewer1 \ + --enable-decoder=text \ + --enable-decoder=vplayer \ + --enable-decoder=webvtt \ + --enable-decoder=movtext \ + \ + --enable-decoder=mjpeg \ + --enable-decoder=ljpeg \ + --enable-decoder=jpegls \ + --enable-decoder=jpeg2000 \ + --enable-decoder=png \ + --enable-decoder=gif \ + --enable-decoder=bmp \ + --enable-decoder=tiff \ + --enable-decoder=webp \ + --enable-decoder=jpegls \ + \ + --enable-demuxer=concat \ + --enable-demuxer=data \ + --enable-demuxer=flv \ + --enable-demuxer=hls \ + --enable-demuxer=latm \ + --enable-demuxer=live_flv \ + --enable-demuxer=loas \ + --enable-demuxer=m4v \ + --enable-demuxer=mov \ + --enable-demuxer=mpegps \ + --enable-demuxer=mpegts \ + --enable-demuxer=mpegvideo \ + --enable-demuxer=hevc \ + --enable-demuxer=rtsp \ + --enable-demuxer=mpeg4 \ + --enable-demuxer=mjpeg* \ + --enable-demuxer=avi \ + --enable-demuxer=av1 \ + --enable-demuxer=matroska \ + --enable-demuxer=dash \ + --enable-demuxer=webm_dash_manifest \ + \ + --enable-demuxer=aac \ + --enable-demuxer=ac3 \ + --enable-demuxer=aiff \ + --enable-demuxer=ape \ + --enable-demuxer=asf \ + --enable-demuxer=au \ + --enable-demuxer=avi \ + --enable-demuxer=flac \ + --enable-demuxer=flv \ + --enable-demuxer=matroska \ + --enable-demuxer=mov \ + --enable-demuxer=m4v \ + --enable-demuxer=mp3 \ + --enable-demuxer=mpc* \ + --enable-demuxer=ogg \ + --enable-demuxer=pcm* \ + --enable-demuxer=rm \ + --enable-demuxer=shorten \ + --enable-demuxer=tak \ + --enable-demuxer=tta \ + --enable-demuxer=wav \ + --enable-demuxer=wv \ + --enable-demuxer=xwma \ + --enable-demuxer=dsf \ + --enable-demuxer=truehd \ + --enable-demuxer=dts \ + --enable-demuxer=dtshd \ + \ + --enable-demuxer=ass \ + --enable-demuxer=srt \ + --enable-demuxer=stl \ + --enable-demuxer=webvtt \ + --enable-demuxer=subviewer \ + --enable-demuxer=subviewer1 \ + --enable-demuxer=vplayer \ + \ + --enable-parser=h263 \ + --enable-parser=h264 \ + --enable-parser=hevc \ + --enable-parser=mpeg4 \ + --enable-parser=mpeg4video \ + --enable-parser=mpegvideo \ + \ + --enable-parser=aac* \ + --enable-parser=ac3 \ + --enable-parser=cook \ + --enable-parser=dca \ + --enable-parser=flac \ + --enable-parser=gsm \ + --enable-parser=mpegaudio \ + --enable-parser=tak \ + --enable-parser=vorbis \ + --enable-parser=dca \ + \ + --enable-filter=overlay \ + --enable-filter=equalizer \ + \ + --enable-protocol=async \ + --enable-protocol=cache \ + --enable-protocol=crypto \ + --enable-protocol=data \ + --enable-protocol=ffrtmphttp \ + --enable-protocol=file \ + --enable-protocol=ftp \ + --enable-protocol=hls \ + --enable-protocol=http \ + --enable-protocol=httpproxy \ + --enable-protocol=https \ + --enable-protocol=pipe \ + --enable-protocol=rtmp \ + --enable-protocol=rtmps \ + --enable-protocol=rtmpt \ + --enable-protocol=rtmpts \ + --enable-protocol=rtp \ + --enable-protocol=subfile \ + --enable-protocol=tcp \ + --enable-protocol=tls \ + --enable-protocol=srt \ + --enable-protocol=udp \ + \ + --enable-encoder=mjpeg \ + --enable-encoder=ljpeg \ + --enable-encoder=jpegls \ + --enable-encoder=jpeg2000 \ + --enable-encoder=png \ + --enable-encoder=jpegls \ + \ + --enable-network \ make -j$cores make DESTDIR="$prefix_dir" install diff --git a/buildscripts/scripts/fftools_ffi.sh b/buildscripts/scripts/fftools_ffi.sh new file mode 100644 index 0000000..a8e6b19 --- /dev/null +++ b/buildscripts/scripts/fftools_ffi.sh @@ -0,0 +1,22 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +build=_build$ndk_suffix + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf $build + exit 0 +else + exit 255 +fi + +unset CC CXX # meson wants these unset + +CFLAGS=-fPIC CXXFLAGS=-fPIC meson setup $build --cross-file "$prefix_dir"/crossfile.txt + +ninja -C $build -j$cores +DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/libass.sh b/buildscripts/scripts/libass.sh index 2a9a44e..fd95d94 100755 --- a/buildscripts/scripts/libass.sh +++ b/buildscripts/scripts/libass.sh @@ -18,8 +18,12 @@ mkdir -p _build$ndk_suffix cd _build$ndk_suffix ../configure \ - --host=$ndk_triple --with-pic \ - --enable-static --disable-shared \ + CFLAGS=-fPIC CXXFLAGS=-fPIC \ + --host=$ndk_triple \ + --with-pic \ + --disable-asm \ + --enable-static\ + --disable-shared \ --disable-require-system-font-provider make -j$cores diff --git a/buildscripts/scripts/libogg.build b/buildscripts/scripts/libogg.build new file mode 100644 index 0000000..16cfd10 --- /dev/null +++ b/buildscripts/scripts/libogg.build @@ -0,0 +1,17 @@ +# https://mesonbuild.com/External-Project-module.html + +project('libogg', 'c') + +mod = import('unstable-external_project') + +p = mod.add_project('configure', + configure_options : [ + '--prefix=@PREFIX@', + '--disable-shared', + '--enable-static', + ], + verbose: true, +) + +libogg_dep = p.dependency('libogg') +meson.override_dependency('libogg', libogg_dep) diff --git a/buildscripts/scripts/libogg.sh b/buildscripts/scripts/libogg.sh new file mode 100644 index 0000000..c100114 --- /dev/null +++ b/buildscripts/scripts/libogg.sh @@ -0,0 +1,24 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +build=_build$ndk_suffix + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf $build + exit 0 +else + exit 255 +fi + +cp ../../scripts/libogg.build meson.build + +unset CC CXX # meson wants these unset + +CFLAGS=-fPIC CXXFLAGS=-fPIC meson setup $build --cross-file "$prefix_dir"/crossfile.txt -Ddefault_library=static + +meson compile -C $build libogg +DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/libvorbis.build b/buildscripts/scripts/libvorbis.build new file mode 100644 index 0000000..4755ea7 --- /dev/null +++ b/buildscripts/scripts/libvorbis.build @@ -0,0 +1,17 @@ +# https://mesonbuild.com/External-Project-module.html + +project('libvorbis', 'c') + +mod = import('unstable-external_project') + +p = mod.add_project('configure', + configure_options : [ + '--prefix=@PREFIX@', + '--enable-static', + '--disable-shared', + ], + verbose: true, +) + +libvorbis_dep = p.dependency('libvorbis') +meson.override_dependency('libvorbis', libvorbis_dep) diff --git a/buildscripts/scripts/libvorbis.sh b/buildscripts/scripts/libvorbis.sh new file mode 100644 index 0000000..5933f27 --- /dev/null +++ b/buildscripts/scripts/libvorbis.sh @@ -0,0 +1,26 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +build=_build$ndk_suffix + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf $build + exit 0 +else + exit 255 +fi + +cp ../../scripts/libvorbis.build meson.build +# -mno-ieee-fp is not supported by clang +sed s/\-mno\-ieee\-fp// -i {configure,configure.ac} + +unset CC CXX # meson wants these unset + +CFLAGS=-fPIC CXXFLAGS=-fPIC meson setup $build --cross-file "$prefix_dir"/crossfile.txt -Ddefault_library=static + +meson compile -C $build libvorbis +DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/libvpx.sh b/buildscripts/scripts/libvpx.sh new file mode 100644 index 0000000..c3d0449 --- /dev/null +++ b/buildscripts/scripts/libvpx.sh @@ -0,0 +1,22 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +build=_build$ndk_suffix + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf $build + exit 0 +else + exit 255 +fi + +unset CC CXX # meson wants these unset + +meson setup $build --cross-file "$prefix_dir"/crossfile.txt -Ddefault_library=static -Dcpu_features_path="$ANDROID_HOME/ndk/$v_ndk/sources/android/cpufeatures" + +ninja -C $build -j$cores +DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/libx264.build b/buildscripts/scripts/libx264.build new file mode 100644 index 0000000..776ac2f --- /dev/null +++ b/buildscripts/scripts/libx264.build @@ -0,0 +1,26 @@ +# https://mesonbuild.com/External-Project-module.html + +project('libx264', 'c') + +mod = import('unstable-external_project') + +configure_options = [ + '--prefix=@PREFIX@', + '--disable-shared', + '--enable-static', + '--disable-cli', + '--enable-pic' +] + +if host_machine.cpu() == 'i686' + # See https://github.com/android/ndk/issues/693 + configure_options += '--disable-asm' +endif + +p = mod.add_project('configure', + configure_options : configure_options, + verbose: true +) + +libx264_dep = p.dependency('libx264') +meson.override_dependency('libx264', libx264_dep) diff --git a/buildscripts/scripts/libx264.sh b/buildscripts/scripts/libx264.sh new file mode 100644 index 0000000..eb597a2 --- /dev/null +++ b/buildscripts/scripts/libx264.sh @@ -0,0 +1,26 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +build=_build$ndk_suffix + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf $build + exit 0 +else + exit 255 +fi + +cp ../../scripts/libx264.build meson.build + +unset CC CXX # meson wants these unset + +mkdir $build + +meson setup $build --cross-file "$prefix_dir"/crossfile.txt --prefix="$prefix_dir" + +meson compile -C $build libx264 +meson install -C $build diff --git a/buildscripts/scripts/libxml2.sh b/buildscripts/scripts/libxml2.sh new file mode 100644 index 0000000..4418462 --- /dev/null +++ b/buildscripts/scripts/libxml2.sh @@ -0,0 +1,31 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf _build$ndk_suffix + exit 0 +else + exit 255 +fi + +[ -f configure ] || ./autogen.sh + +mkdir -p _build$ndk_suffix +cd _build$ndk_suffix + +../configure \ + CFLAGS=-fPIC CXXFLAGS=-fPIC \ + --host=$ndk_triple \ + --disable-shared \ + --enable-static \ + --with-minimum \ + --with-threads \ + --with-tree \ + --without-lzma \ + +make -j$cores +make DESTDIR="$prefix_dir" install diff --git a/buildscripts/scripts/lua.sh b/buildscripts/scripts/lua.sh deleted file mode 100755 index 38a0f24..0000000 --- a/buildscripts/scripts/lua.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -e - -. ../../include/depinfo.sh -. ../../include/path.sh - -if [ "$1" == "build" ]; then - true -elif [ "$1" == "clean" ]; then - make clean - exit 0 -else - exit 255 -fi - -# Building seperately from source tree is not supported, this means we are forced to always clean -$0 clean - -# LUA_T= and LUAC_T= to disable building lua & luac -# -Dgetlocaledecpoint()=('.') fixes bionic missing decimal_point in localeconv -make CC="$CC" AR="$AR rc" RANLIB="$RANLIB" \ - MYCFLAGS="-fPIC -Dgetlocaledecpoint\(\)=\(\'.\'\)" \ - PLAT=linux LUA_T= LUAC_T= -j$cores - -# TO_BIN=/dev/null disables installing lua & luac -make INSTALL=${INSTALL:-install} INSTALL_TOP="$prefix_dir" TO_BIN=/dev/null install - -# make pc only generates a partial pkg-config file because ???? -mkdir -p $prefix_dir/lib/pkgconfig -make pc >$prefix_dir/lib/pkgconfig/lua.pc -cat >>$prefix_dir/lib/pkgconfig/lua.pc <<'EOF' -Name: Lua -Description: -Version: ${version} -Libs: -L${libdir} -llua -Cflags: -I${includedir} -EOF diff --git a/buildscripts/scripts/mbedtls.sh b/buildscripts/scripts/mbedtls.sh index f2aec46..220a812 100755 --- a/buildscripts/scripts/mbedtls.sh +++ b/buildscripts/scripts/mbedtls.sh @@ -14,5 +14,5 @@ fi $0 clean # separate building not supported, always clean -make -j$cores no_test -make DESTDIR="$prefix_dir" install +make CFLAGS=-fPIC CXXFLAGS=-fPIC -j$cores no_test +make CFLAGS=-fPIC CXXFLAGS=-fPIC DESTDIR="$prefix_dir" install diff --git a/buildscripts/scripts/mpv-android.sh b/buildscripts/scripts/mpv-android.sh deleted file mode 100755 index 98ee640..0000000 --- a/buildscripts/scripts/mpv-android.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -e - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -BUILD="$DIR/.." -MPV_ANDROID="$DIR/../.." - -. $BUILD/include/path.sh -. $BUILD/include/depinfo.sh - -if [ "$1" == "build" ]; then - true -elif [ "$1" == "clean" ]; then - rm -rf $MPV_ANDROID/{libmpv,.}/build $MPV_ANDROID/libmpv/src/main/{libs,obj} - exit 0 -else - exit 255 -fi - -nativeprefix () { - if [ -f $BUILD/prefix/$1/lib/libmpv.so ]; then - echo $BUILD/prefix/$1 - else - echo >&2 "Warning: libmpv.so not found in native prefix for $1, support will be omitted" - fi -} - -./gradlew assembleRelease diff --git a/buildscripts/scripts/mpv.sh b/buildscripts/scripts/mpv.sh index 92f16a3..cd7ec65 100755 --- a/buildscripts/scripts/mpv.sh +++ b/buildscripts/scripts/mpv.sh @@ -17,10 +17,15 @@ fi unset CC CXX # meson wants these unset meson setup $build --cross-file "$prefix_dir"/crossfile.txt \ + --prefer-static \ --default-library shared \ - -Diconv=disabled -Dlua=enabled \ - -Dlibmpv=true -Dcplayer=false \ - -Dmanpage-build=disabled + -Dgpl=false \ + -Dlibmpv=true \ + -Dcplayer=false \ + -Dlua=disabled \ + -Diconv=disabled \ + -Djavascript=disabled \ + -Dmanpage-build=disabled ninja -C $build -j$cores DESTDIR="$prefix_dir" ninja -C $build install diff --git a/buildscripts/scripts/shaderc.sh b/buildscripts/scripts/shaderc.sh new file mode 100644 index 0000000..3da0902 --- /dev/null +++ b/buildscripts/scripts/shaderc.sh @@ -0,0 +1,43 @@ +#!/bin/bash -e + +. ../../include/depinfo.sh +. ../../include/path.sh + +if [ "$1" == "build" ]; then + true +elif [ "$1" == "clean" ]; then + rm -rf local include libs + exit 0 +else + exit 255 +fi + +builddir=$PWD + +abi=armeabi-v7a +[[ "$ndk_triple" == "aarch64"* ]] && abi=arm64-v8a +[[ "$ndk_triple" == "x86_64"* ]] && abi=x86_64 +[[ "$ndk_triple" == "i686"* ]] && abi=x86 + +# build using the NDK's scripts, but keep object files in our build dir +cd "$(dirname "$(which ndk-build)")/sources/third_party/shaderc" +ndk-build -j$cores \ + NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ + APP_PLATFORM=android-26 APP_STL=c++_shared APP_ABI=$abi \ + NDK_APP_OUT="$builddir" NDK_APP_LIBS_OUT="$builddir/libs" \ + libshaderc_combined + +cd "$builddir" +cp -r include/* "$prefix_dir/include" +cp libs/*/$abi/libshaderc.a "$prefix_dir/lib/libshaderc_combined.a" + +# create a pkgconfig file +# 'libc++' instead of 'libstdc++': workaround for meson linking bug +mkdir -p "$prefix_dir"/lib/pkgconfig +cat >"$prefix_dir"/lib/pkgconfig/shaderc_combined.pc <<"END" +Name: shaderc_combined +Description: +Version: 2022.1-unknown +Libs: -L/usr/lib -lshaderc_combined -llibc++ +Cflags: -I${includedir} +END diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X diff --git a/gradlew b/gradlew index f5feea6..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -15,8 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# SPDX-License-Identifier: Apache-2.0 -# ############################################################################## # @@ -57,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -85,9 +83,10 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -134,13 +133,10 @@ location of your Java installation." fi else JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi fi # Increase the maximum file descriptors if we can. @@ -148,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -156,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -201,15 +197,11 @@ if "$cygwin" || "$msys" ; then done fi - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/libmpv/build.gradle.kts b/libmpv/build.gradle.kts deleted file mode 100755 index ba35b22..0000000 --- a/libmpv/build.gradle.kts +++ /dev/null @@ -1,94 +0,0 @@ -plugins { - alias(libs.plugins.android.library) - `maven-publish` - signing -} - -android { - namespace = "dev.jdtech.mpv" - compileSdk = 35 - buildToolsVersion = "35.0.0" - ndkVersion = "27.1.12297006" - - defaultConfig { - minSdk = 26 - consumerProguardFiles("proguard-rules.pro") - externalNativeBuild { - cmake { - arguments += listOf( - "-DANDROID_STL=c++_shared", - "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON", - ) - cFlags += "-Werror" - cppFlags += "-std=c++11" - } - } - } - - externalNativeBuild { - cmake { - path = file("src/main/cpp/CMakeLists.txt") - version = "3.30.3" - } - } - - publishing { - singleVariant("release") { - withSourcesJar() - } - } -} - -dependencies { - implementation(libs.androidx.annotation) -} - -publishing { - publications { - create("release") { - groupId = "dev.jdtech.mpv" - artifactId = "libmpv" - version = "0.4.1" - - afterEvaluate { - from(components["release"]) - } - - pom { - name = "dev.jdtech.mpv" - description = "libmpv for Android" - url = "https://github.com/jarnedemeulemeester/libmpv-android" - licenses { - license { - name = "MIT license" - url = "https://github.com/jarnedemeulemeester/libmpv-android/blob/main/LICENSE" - } - } - developers { - developer { - id = "jarnedemeulemeester" - name = "Jarne Demeulemeester" - email = "jarnedemeulemeester@gmail.com" - } - } - scm { - url = "https://github.com/jarnedemeulemeester/libmpv-android.git" - connection = "scm:git@github.com:jarnedemeulemeester/libmpv-android.git" - developerConnection = "scm:git@github.com:jarnedemeulemeester/libmpv-android.git" - } - issueManagement { - url = "https://github.com/jarnedemeulemeester/libmpv-android/issues" - } - } - } - } -} - -signing { - useInMemoryPgpKeys( - rootProject.ext["signing.keyId"]?.toString(), - rootProject.ext["signing.key"]?.toString(), - rootProject.ext["signing.password"]?.toString(), - ) - sign(publishing.publications) -} diff --git a/libmpv/proguard-rules.pro b/libmpv/proguard-rules.pro deleted file mode 100644 index cf1ca81..0000000 --- a/libmpv/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ --keep class dev.jdtech.mpv.MPVLib { *; } diff --git a/libmpv/src/main/cpp/CMakeLists.txt b/libmpv/src/main/cpp/CMakeLists.txt deleted file mode 100644 index a1b8f62..0000000 --- a/libmpv/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -cmake_minimum_required(VERSION 3.22.1) - -project("libmpv") - -add_library( - player - SHARED - main.cpp render.cpp log.cpp jni_utils.cpp property.cpp event.cpp -) - -add_library( - mpv - SHARED - IMPORTED -) - -set_target_properties( - mpv - PROPERTIES IMPORTED_LOCATION - ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libmpv.so -) - -add_library( - avcodec - SHARED - IMPORTED -) - -set_target_properties( - avcodec - PROPERTIES IMPORTED_LOCATION - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../buildscripts/prefix/${ANDROID_ABI}/lib/libavcodec.so -) - -include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../../../buildscripts/prefix/${ANDROID_ABI}/include ) - -target_link_libraries( player mpv avcodec log ) \ No newline at end of file diff --git a/libmpv/src/main/cpp/event.cpp b/libmpv/src/main/cpp/event.cpp deleted file mode 100644 index 549f3e3..0000000 --- a/libmpv/src/main/cpp/event.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include - -#include - -#include "globals.h" -#include "jni_utils.h" -#include "log.h" - -static void sendPropertyUpdateToJava(JNIEnv *env, mpv_event_property *prop) { - jstring jprop = env->NewStringUTF(prop->name); - jstring jvalue = nullptr; - switch (prop->format) { - case MPV_FORMAT_NONE: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_S, jprop); - break; - case MPV_FORMAT_FLAG: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sb, jprop, *(int*)prop->data); - break; - case MPV_FORMAT_INT64: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sl, jprop, *(int64_t*)prop->data); - break; - case MPV_FORMAT_DOUBLE: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sd, jprop, *(double*)prop->data); - break; - case MPV_FORMAT_STRING: - jvalue = env->NewStringUTF(*(const char**)prop->data); - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_SS, jprop, jvalue); - break; - default: - ALOGV("sendPropertyUpdateToJava: Unknown property update format received in callback: %d!", prop->format); - break; - } - if (jprop) - env->DeleteLocalRef(jprop); - if (jvalue) - env->DeleteLocalRef(jvalue); -} - -static void sendEventToJava(JNIEnv *env, int event) { - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_event, event); -} - -static inline bool invalid_utf8(unsigned char c) { - return c == 0xc0 || c == 0xc1 || c >= 0xf5; -} - -static void sendLogMessageToJava(JNIEnv *env, mpv_event_log_message *msg) { - // filter the most obvious cases of invalid utf-8 - int invalid = 0; - for (int i = 0; msg->text[i]; i++) - invalid |= invalid_utf8((unsigned char) msg->text[i]); - if (invalid) - return; - - jstring jprefix = env->NewStringUTF(msg->prefix); - jstring jtext = env->NewStringUTF(msg->text); - - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_logMessage_SiS, - jprefix, (jint) msg->log_level, jtext); - - if (jprefix) - env->DeleteLocalRef(jprefix); - if (jtext) - env->DeleteLocalRef(jtext); -} - -void *event_thread(void *arg) { - JNIEnv *env = nullptr; - acquire_jni_env(g_vm, &env); - if (!env) - die("failed to acquire java env"); - - while (true) { - mpv_event *mp_event; - mpv_event_property *mp_property; - mpv_event_log_message *msg; - - mp_event = mpv_wait_event(g_mpv, -1.0); - - if (g_event_thread_request_exit) - break; - - if (mp_event->event_id == MPV_EVENT_NONE) - continue; - - switch (mp_event->event_id) { - case MPV_EVENT_LOG_MESSAGE: - msg = (mpv_event_log_message*)mp_event->data; - ALOGV("[%s:%s] %s", msg->prefix, msg->level, msg->text); - sendLogMessageToJava(env, msg); - break; - case MPV_EVENT_PROPERTY_CHANGE: - mp_property = (mpv_event_property*)mp_event->data; - sendPropertyUpdateToJava(env, mp_property); - break; - default: - ALOGV("event: %s\n", mpv_event_name(mp_event->event_id)); - sendEventToJava(env, mp_event->event_id); - break; - } - } - - g_vm->DetachCurrentThread(); - - return nullptr; -} diff --git a/libmpv/src/main/cpp/event.h b/libmpv/src/main/cpp/event.h deleted file mode 100644 index ebb20d2..0000000 --- a/libmpv/src/main/cpp/event.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void *event_thread(void *arg); diff --git a/libmpv/src/main/cpp/globals.h b/libmpv/src/main/cpp/globals.h deleted file mode 100644 index e2427b8..0000000 --- a/libmpv/src/main/cpp/globals.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -extern JavaVM *g_vm; -extern mpv_handle *g_mpv; -extern std::atomic g_event_thread_request_exit; diff --git a/libmpv/src/main/cpp/jni_utils.cpp b/libmpv/src/main/cpp/jni_utils.cpp deleted file mode 100644 index ebd519b..0000000 --- a/libmpv/src/main/cpp/jni_utils.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "jni_utils.h" - -#include -#include - -bool acquire_jni_env(JavaVM *vm, JNIEnv **env) -{ - int ret = vm->GetEnv((void**) env, JNI_VERSION_1_6); - if (ret == JNI_EDETACHED) - return vm->AttachCurrentThread(env, nullptr) == 0; - else - return ret == JNI_OK; -} - -// Apparently it's considered slow to FindClass and GetMethodID every time we need them, -// so let's have a nice cache here -jclass java_Integer, java_Double, java_Boolean; -jmethodID java_Integer_init, java_Integer_intValue, java_Double_init, java_Double_doubleValue, java_Boolean_init, java_Boolean_booleanValue; -jmethodID java_GLSurfaceView_requestRender; - -jclass mpv_MPVLib; -jmethodID mpv_MPVLib_eventProperty_S, mpv_MPVLib_eventProperty_Sb, mpv_MPVLib_eventProperty_Sl, mpv_MPVLib_eventProperty_Sd, mpv_MPVLib_eventProperty_SS, mpv_MPVLib_event, mpv_MPVLib_logMessage_SiS; - -void init_methods_cache(JNIEnv *env) { - static bool methods_initialized = false; - if (methods_initialized) - return; - - #define FIND_CLASS(name) reinterpret_cast(env->NewGlobalRef(env->FindClass(name))) - java_Integer = FIND_CLASS("java/lang/Integer"); - java_Integer_init = env->GetMethodID(java_Integer, "", "(I)V"); - java_Integer_intValue = env->GetMethodID(java_Integer, "intValue", "()I"); - java_Double = FIND_CLASS("java/lang/Double"); - java_Double_init = env->GetMethodID(java_Double, "", "(D)V"); - java_Double_doubleValue = env->GetMethodID(java_Double, "doubleValue", "()D"); - java_Boolean = FIND_CLASS("java/lang/Boolean"); - java_Boolean_init = env->GetMethodID(java_Boolean, "", "(Z)V"); - java_Boolean_booleanValue = env->GetMethodID(java_Boolean, "booleanValue", "()Z"); - - mpv_MPVLib = FIND_CLASS("dev/jdtech/mpv/MPVLib"); - mpv_MPVLib_eventProperty_S = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;)V"); // eventProperty(String) - mpv_MPVLib_eventProperty_Sb = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Z)V"); // eventProperty(String, boolean) - mpv_MPVLib_eventProperty_Sl = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;J)V"); // eventProperty(String, long) - mpv_MPVLib_eventProperty_Sd = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;D)V"); // eventProperty(String, double) - mpv_MPVLib_eventProperty_SS = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); // eventProperty(String, String) - mpv_MPVLib_event = env->GetStaticMethodID(mpv_MPVLib, "event", "(I)V"); // event(int) - mpv_MPVLib_logMessage_SiS = env->GetStaticMethodID(mpv_MPVLib, "logMessage", "(Ljava/lang/String;ILjava/lang/String;)V"); // logMessage(String, int, String) - #undef FIND_CLASS - - methods_initialized = true; -} diff --git a/libmpv/src/main/cpp/jni_utils.h b/libmpv/src/main/cpp/jni_utils.h deleted file mode 100644 index af0b08f..0000000 --- a/libmpv/src/main/cpp/jni_utils.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#define jni_func_name(name) Java_dev_jdtech_mpv_MPVLib_##name -#define jni_func(return_type, name, ...) JNIEXPORT return_type JNICALL jni_func_name(name) (JNIEnv *env, jobject obj, ##__VA_ARGS__) - -bool acquire_jni_env(JavaVM *vm, JNIEnv **env); -void init_methods_cache(JNIEnv *env); - -extern jclass java_Integer, java_Double, java_Boolean; -extern jmethodID java_Integer_init, java_Integer_intValue, java_Double_init, java_Double_doubleValue, java_Boolean_init, java_Boolean_booleanValue; -extern jmethodID java_GLSurfaceView_requestRender; - -extern jclass mpv_MPVLib; -extern jmethodID mpv_MPVLib_eventProperty_S, mpv_MPVLib_eventProperty_Sb, mpv_MPVLib_eventProperty_Sl, mpv_MPVLib_eventProperty_Sd, mpv_MPVLib_eventProperty_SS, mpv_MPVLib_event, mpv_MPVLib_logMessage_SiS; diff --git a/libmpv/src/main/cpp/log.cpp b/libmpv/src/main/cpp/log.cpp deleted file mode 100644 index 98a4642..0000000 --- a/libmpv/src/main/cpp/log.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "log.h" - -#include - -void die(const char *msg) -{ - ALOGE("%s", msg); - exit(1); -} diff --git a/libmpv/src/main/cpp/log.h b/libmpv/src/main/cpp/log.h deleted file mode 100644 index f7003f9..0000000 --- a/libmpv/src/main/cpp/log.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#define DEBUG 1 - -#define LOG_TAG "mpv" -#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) -#if DEBUG -#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#else -#define ALOGV(...) -#endif - -void die(const char *msg); diff --git a/libmpv/src/main/cpp/main.cpp b/libmpv/src/main/cpp/main.cpp deleted file mode 100644 index a61df51..0000000 --- a/libmpv/src/main/cpp/main.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include - -extern "C" { - #include -} - -#include "log.h" -#include "jni_utils.h" -#include "event.h" - -#define ARRAYLEN(a) (sizeof(a)/sizeof(a[0])) - -extern "C" { - jni_func(void, create, jobject appctx); - jni_func(void, init); - jni_func(void, destroy); - - jni_func(void, command, jobjectArray jarray); -}; - -JavaVM *g_vm; -mpv_handle *g_mpv; -std::atomic g_event_thread_request_exit(false); - -static pthread_t event_thread_id; - -static void prepare_environment(JNIEnv *env, jobject appctx) { - setlocale(LC_NUMERIC, "C"); - - if (!env->GetJavaVM(&g_vm) && g_vm) - av_jni_set_java_vm(g_vm, nullptr); - init_methods_cache(env); -} - -jni_func(void, create, jobject appctx) { - prepare_environment(env, appctx); - - if (g_mpv) - die("mpv is already initialized"); - - g_mpv = mpv_create(); - if (!g_mpv) - die("context init failed"); - - mpv_request_log_messages(g_mpv, "v"); -} - -jni_func(void, init) { - if (!g_mpv) - die("mpv is not created"); - - if (mpv_initialize(g_mpv) < 0) - die("mpv init failed"); - - g_event_thread_request_exit = false; - pthread_create(&event_thread_id, nullptr, event_thread, nullptr); -} - -jni_func(void, destroy) { - if (!g_mpv) - die("mpv destroy called but it's already destroyed"); - - // poke event thread and wait for it to exit - g_event_thread_request_exit = true; - mpv_wakeup(g_mpv); - pthread_join(event_thread_id, nullptr); - - mpv_terminate_destroy(g_mpv); - g_mpv = nullptr; -} - -jni_func(void, command, jobjectArray jarray) { - const char *arguments[128] = { 0 }; - int len = env->GetArrayLength(jarray); - if (!g_mpv) - die("Cannot run command: mpv is not initialized"); - if (len >= ARRAYLEN(arguments)) - die("Cannot run command: too many arguments"); - - for (int i = 0; i < len; ++i) - arguments[i] = env->GetStringUTFChars((jstring)env->GetObjectArrayElement(jarray, i), nullptr); - - mpv_command(g_mpv, arguments); - - for (int i = 0; i < len; ++i) - env->ReleaseStringUTFChars((jstring)env->GetObjectArrayElement(jarray, i), arguments[i]); -} diff --git a/libmpv/src/main/cpp/property.cpp b/libmpv/src/main/cpp/property.cpp deleted file mode 100644 index 5d52c04..0000000 --- a/libmpv/src/main/cpp/property.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include - -#include - -#include "jni_utils.h" -#include "log.h" -#include "globals.h" - -extern "C" { - jni_func(jint, setOptionString, jstring option, jstring value); - - jni_func(jobject, getPropertyInt, jstring property); - jni_func(void, setPropertyInt, jstring property, jobject value); - jni_func(jobject, getPropertyDouble, jstring property); - jni_func(void, setPropertyDouble, jstring property, jobject value); - jni_func(jobject, getPropertyBoolean, jstring property); - jni_func(void, setPropertyBoolean, jstring property, jobject value); - jni_func(jstring, getPropertyString, jstring jproperty); - jni_func(void, setPropertyString, jstring jproperty, jstring jvalue); - - jni_func(void, observeProperty, jstring property, jint format); -} - -jni_func(jint, setOptionString, jstring joption, jstring jvalue) { - if (!g_mpv) - die("mpv is not initialized"); - - const char *option = env->GetStringUTFChars(joption, nullptr); - const char *value = env->GetStringUTFChars(jvalue, nullptr); - - int result = mpv_set_option_string(g_mpv, option, value); - - env->ReleaseStringUTFChars(joption, option); - env->ReleaseStringUTFChars(jvalue, value); - - return result; -} - -static int common_get_property(JNIEnv *env, jstring jproperty, mpv_format format, void *output) { - if (!g_mpv) - die("get_property called but mpv is not initialized"); - - const char *prop = env->GetStringUTFChars(jproperty, nullptr); - int result = mpv_get_property(g_mpv, prop, format, output); - if (result < 0) - ALOGE("mpv_get_property(%s) format %d returned error %s", prop, format, mpv_error_string(result)); - env->ReleaseStringUTFChars(jproperty, prop); - - return result; -} - -static int common_set_property(JNIEnv *env, jstring jproperty, mpv_format format, void *value) { - if (!g_mpv) - die("set_property called but mpv is not initialized"); - - const char *prop = env->GetStringUTFChars(jproperty, nullptr); - int result = mpv_set_property(g_mpv, prop, format, value); - if (result < 0) - ALOGE("mpv_set_property(%s, %p) format %d returned error %s", prop, value, format, mpv_error_string(result)); - env->ReleaseStringUTFChars(jproperty, prop); - - return result; -} - -jni_func(jobject, getPropertyInt, jstring jproperty) { - int64_t value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_INT64, &value) < 0) - return nullptr; - return env->NewObject(java_Integer, java_Integer_init, (jint)value); -} - -jni_func(jobject, getPropertyDouble, jstring jproperty) { - double value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_DOUBLE, &value) < 0) - return nullptr; - return env->NewObject(java_Double, java_Double_init, (jdouble)value); -} - -jni_func(jobject, getPropertyBoolean, jstring jproperty) { - int value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_FLAG, &value) < 0) - return nullptr; - return env->NewObject(java_Boolean, java_Boolean_init, (jboolean)value); -} - -jni_func(jstring, getPropertyString, jstring jproperty) { - char *value; - if (common_get_property(env, jproperty, MPV_FORMAT_STRING, &value) < 0) - return nullptr; - jstring jvalue = env->NewStringUTF(value); - mpv_free(value); - return jvalue; -} - -jni_func(void, setPropertyInt, jstring jproperty, jobject jvalue) { - int64_t value = env->CallIntMethod(jvalue, java_Integer_intValue); - common_set_property(env, jproperty, MPV_FORMAT_INT64, &value); -} - -jni_func(void, setPropertyDouble, jstring jproperty, jobject jvalue) { - double value = env->CallDoubleMethod(jvalue, java_Double_doubleValue); - common_set_property(env, jproperty, MPV_FORMAT_DOUBLE, &value); -} - -jni_func(void, setPropertyBoolean, jstring jproperty, jobject jvalue) { - int value = env->CallBooleanMethod(jvalue, java_Boolean_booleanValue); - common_set_property(env, jproperty, MPV_FORMAT_FLAG, &value); -} - -jni_func(void, setPropertyString, jstring jproperty, jstring jvalue) { - const char *value = env->GetStringUTFChars(jvalue, nullptr); - common_set_property(env, jproperty, MPV_FORMAT_STRING, &value); - env->ReleaseStringUTFChars(jvalue, value); -} - -jni_func(void, observeProperty, jstring property, jint format) { - if (!g_mpv) - die("mpv is not initialized"); - const char *prop = env->GetStringUTFChars(property, nullptr); - mpv_observe_property(g_mpv, 0, prop, (mpv_format)format); - env->ReleaseStringUTFChars(property, prop); -} diff --git a/libmpv/src/main/cpp/render.cpp b/libmpv/src/main/cpp/render.cpp deleted file mode 100644 index 061df84..0000000 --- a/libmpv/src/main/cpp/render.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "jni_utils.h" -#include "globals.h" - -extern "C" { - jni_func(void, attachSurface, jobject surface_); - jni_func(void, detachSurface); -}; - -static jobject surface; - -jni_func(void, attachSurface, jobject surface_) { - surface = env->NewGlobalRef(surface_); - int64_t wid = (int64_t)(intptr_t) surface; - mpv_set_option(g_mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); -} - -jni_func(void, detachSurface) { - int64_t wid = 0; - mpv_set_option(g_mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); - - env->DeleteGlobalRef(surface); - surface = nullptr; -} diff --git a/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java b/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java deleted file mode 100644 index fb91913..0000000 --- a/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java +++ /dev/null @@ -1,241 +0,0 @@ -package dev.jdtech.mpv; - -// Wrapper for native library - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; - -import android.content.Context; -import android.view.Surface; - -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; - -@SuppressWarnings("unused") -public class MPVLib { - - static { - String[] libs = {"mpv", "player"}; - for (String lib : libs) { - System.loadLibrary(lib); - } - } - - public static native void create(Context appctx); - - public static native void init(); - - public static native void destroy(); - - public static native void attachSurface(Surface surface); - - public static native void detachSurface(); - - public static native void command(@NonNull String[] cmd); - - public static native int setOptionString(@NonNull String name, @NonNull String value); - - public static native Integer getPropertyInt(@NonNull String property); - - public static native void setPropertyInt(@NonNull String property, @NonNull Integer value); - - public static native Double getPropertyDouble(@NonNull String property); - - public static native void setPropertyDouble(@NonNull String property, @NonNull Double value); - - public static native Boolean getPropertyBoolean(@NonNull String property); - - public static native void setPropertyBoolean(@NonNull String property, @NonNull Boolean value); - - public static native String getPropertyString(@NonNull String property); - - public static native void setPropertyString(@NonNull String property, @NonNull String value); - - public static native void observeProperty(@NonNull String property, @Format int format); - - private static final List observers = new ArrayList<>(); - - public static void addObserver(EventObserver o) { - synchronized (observers) { - observers.add(o); - } - } - - public static void removeObserver(EventObserver o) { - synchronized (observers) { - observers.remove(o); - } - } - - public static void eventProperty(String property, long value) { - synchronized (observers) { - for (EventObserver o : observers) - o.eventProperty(property, value); - } - } - - public static void eventProperty(String property, double value) { - synchronized (observers) { - for (EventObserver o : observers) - o.eventProperty(property, value); - } - } - - public static void eventProperty(String property, boolean value) { - synchronized (observers) { - for (EventObserver o : observers) - o.eventProperty(property, value); - } - } - - public static void eventProperty(String property, String value) { - synchronized (observers) { - for (EventObserver o : observers) - o.eventProperty(property, value); - } - } - - public static void eventProperty(String property) { - synchronized (observers) { - for (EventObserver o : observers) - o.eventProperty(property); - } - } - - public static void event(@Event int eventId) { - synchronized (observers) { - for (EventObserver o : observers) - o.event(eventId); - } - } - - private static final List log_observers = new ArrayList<>(); - - public static void addLogObserver(LogObserver o) { - synchronized (log_observers) { - log_observers.add(o); - } - } - - public static void removeLogObserver(LogObserver o) { - synchronized (log_observers) { - log_observers.remove(o); - } - } - - public static void logMessage(String prefix, @LogLevel int level, String text) { - synchronized (log_observers) { - for (LogObserver o : log_observers) - o.logMessage(prefix, level, text); - } - } - - public interface EventObserver { - void eventProperty(@NonNull String property); - - void eventProperty(@NonNull String property, long value); - - void eventProperty(@NonNull String property, double value); - - void eventProperty(@NonNull String property, boolean value); - - void eventProperty(@NonNull String property, @NonNull String value); - - void event(@Event int eventId); - } - - public interface LogObserver { - void logMessage(@NonNull String prefix, @LogLevel int level, @NonNull String text); - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - MPV_FORMAT_NONE, - MPV_FORMAT_STRING, - MPV_FORMAT_OSD_STRING, - MPV_FORMAT_FLAG, - MPV_FORMAT_INT64, - MPV_FORMAT_DOUBLE, - MPV_FORMAT_NODE, - MPV_FORMAT_NODE_ARRAY, - MPV_FORMAT_NODE_MAP, - MPV_FORMAT_BYTE_ARRAY - }) - public @interface Format {} - - public static final int MPV_FORMAT_NONE = 0; - public static final int MPV_FORMAT_STRING = 1; - public static final int MPV_FORMAT_OSD_STRING = 2; - public static final int MPV_FORMAT_FLAG = 3; - public static final int MPV_FORMAT_INT64 = 4; - public static final int MPV_FORMAT_DOUBLE = 5; - public static final int MPV_FORMAT_NODE = 6; - public static final int MPV_FORMAT_NODE_ARRAY = 7; - public static final int MPV_FORMAT_NODE_MAP = 8; - public static final int MPV_FORMAT_BYTE_ARRAY = 9; - - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - MPV_EVENT_NONE, - MPV_EVENT_SHUTDOWN, - MPV_EVENT_LOG_MESSAGE, - MPV_EVENT_GET_PROPERTY_REPLY, - MPV_EVENT_SET_PROPERTY_REPLY, - MPV_EVENT_COMMAND_REPLY, - MPV_EVENT_START_FILE, - MPV_EVENT_END_FILE, - MPV_EVENT_FILE_LOADED, - MPV_EVENT_CLIENT_MESSAGE, - MPV_EVENT_VIDEO_RECONFIG, - MPV_EVENT_AUDIO_RECONFIG, - MPV_EVENT_SEEK, - MPV_EVENT_PLAYBACK_RESTART, - MPV_EVENT_PROPERTY_CHANGE, - MPV_EVENT_QUEUE_OVERFLOW, - MPV_EVENT_HOOK - }) - public @interface Event {} - - public static final int MPV_EVENT_NONE = 0; - public static final int MPV_EVENT_SHUTDOWN = 1; - public static final int MPV_EVENT_LOG_MESSAGE = 2; - public static final int MPV_EVENT_GET_PROPERTY_REPLY = 3; - public static final int MPV_EVENT_SET_PROPERTY_REPLY = 4; - public static final int MPV_EVENT_COMMAND_REPLY = 5; - public static final int MPV_EVENT_START_FILE = 6; - public static final int MPV_EVENT_END_FILE = 7; - public static final int MPV_EVENT_FILE_LOADED = 8; - public static final int MPV_EVENT_CLIENT_MESSAGE = 16; - public static final int MPV_EVENT_VIDEO_RECONFIG = 17; - public static final int MPV_EVENT_AUDIO_RECONFIG = 18; - public static final int MPV_EVENT_SEEK = 20; - public static final int MPV_EVENT_PLAYBACK_RESTART = 21; - public static final int MPV_EVENT_PROPERTY_CHANGE = 22; - public static final int MPV_EVENT_QUEUE_OVERFLOW = 24; - public static final int MPV_EVENT_HOOK = 25; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - MPV_LOG_LEVEL_NONE, - MPV_LOG_LEVEL_FATAL, - MPV_LOG_LEVEL_ERROR, - MPV_LOG_LEVEL_WARN, - MPV_LOG_LEVEL_INFO, - MPV_LOG_LEVEL_V, - MPV_LOG_LEVEL_DEBUG, - MPV_LOG_LEVEL_TRACE - }) - public @interface LogLevel {} - - public static final int MPV_LOG_LEVEL_NONE = 0; - public static final int MPV_LOG_LEVEL_FATAL = 10; - public static final int MPV_LOG_LEVEL_ERROR = 20; - public static final int MPV_LOG_LEVEL_WARN = 30; - public static final int MPV_LOG_LEVEL_INFO = 40; - public static final int MPV_LOG_LEVEL_V = 50; - public static final int MPV_LOG_LEVEL_DEBUG = 60; - public static final int MPV_LOG_LEVEL_TRACE = 70; -}