mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-04 00:47:00 +01:00
Upstream mpv-android moved its build to NDK r30 (30.0.16248370), and each mpv-android revision pins its own NDK, so the two move together. The new revision also updates harfbuzz to 14.5.0, unibreak to 8.0, fribidi to 1.0.17, libxml2 to 2.15.4, fontconfig to 2.18.3 and curl to 8.22.0, and builds libass with assembly on x86_64 (nasm, already installed in CI). r30 brings an LLVM update with codegen and LTO fixes and sysroots up to API 37. It is also the NDK current SDK managers install, so a fresh setup no longer needs r29 installed beside it. The script change invalidates the cached libmpv tree, so CI rebuilds it once. The staged libraries are the same set as before, all 16 KiB aligned.
210 lines
8.1 KiB
Bash
210 lines
8.1 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd -- "$script_dir/.." && pwd)"
|
|
source_dir="${PSTR_MPV_SOURCE_DIR:-$repo_root/.build/mpv-android}"
|
|
revision=687c7fd586d826fd0387809e14bec7a2b4fc45a1
|
|
destination="$repo_root/android/app/build/generated/mpv"
|
|
|
|
# The staged tree depends only on the pinned revision and on this script, which
|
|
# also pins the NDK. A tree stamped with both is reused as is: that is what lets
|
|
# CI restore it from a cache instead of rebuilding FFmpeg and every other
|
|
# dependency from source on each run.
|
|
stamp="$revision $(sha256sum "${BASH_SOURCE[0]}" | cut -d' ' -f1)"
|
|
if [[ "$(cat "$destination/STAMP" 2>/dev/null)" == "$stamp" &&
|
|
-f "$destination/jniLibs/arm64-v8a/libmpv.so" &&
|
|
-f "$destination/jniLibs/x86_64/libmpv.so" &&
|
|
-f "$destination/mpv-android-source-$revision.tar.gz" ]]; then
|
|
echo "libmpv $revision is already staged in $destination"
|
|
exit 0
|
|
fi
|
|
rm -f -- "$destination/STAMP"
|
|
|
|
if [[ ! -d "$source_dir/.git" ]]; then
|
|
git clone https://github.com/mpv-android/mpv-android.git "$source_dir"
|
|
fi
|
|
git -C "$source_dir" fetch --depth=1 origin "$revision"
|
|
git -C "$source_dir" checkout --detach "$revision"
|
|
git -C "$source_dir" submodule sync --recursive
|
|
git -C "$source_dir" submodule update --init --recursive
|
|
|
|
if [[ -n "${ANDROID_NDK_HOME:-}" ]]; then
|
|
ndk_dir="$ANDROID_NDK_HOME"
|
|
elif [[ -n "${ANDROID_HOME:-}" ]]; then
|
|
ndk_dir="$ANDROID_HOME/ndk/30.0.16248370"
|
|
else
|
|
echo "error: set ANDROID_NDK_HOME or ANDROID_HOME to an Android NDK r30 installation" >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "$ndk_dir/source.properties" ]] ||
|
|
! grep -q '^Pkg.Revision = 30\.0\.16248370$' "$ndk_dir/source.properties"; then
|
|
echo "error: libmpv requires Android NDK 30.0.16248370: $ndk_dir" >&2
|
|
exit 1
|
|
fi
|
|
ndk_dir="$(cd -- "$ndk_dir" && pwd -P)"
|
|
mpv_sdk_dir="$source_dir/buildscripts/sdk"
|
|
mpv_ndk_link="$mpv_sdk_dir/android-ndk-r30"
|
|
mkdir -p "$mpv_sdk_dir"
|
|
if [[ -e "$mpv_ndk_link" && ! -L "$mpv_ndk_link" ]]; then
|
|
echo "error: refusing to replace non-symlink NDK path: $mpv_ndk_link" >&2
|
|
exit 1
|
|
fi
|
|
ln -sfn "$ndk_dir" "$mpv_ndk_link"
|
|
|
|
ensure_lua_source() {
|
|
local lua_dir="$source_dir/buildscripts/deps/lua"
|
|
if [[ -f "$lua_dir/Makefile" ]]; then
|
|
return
|
|
fi
|
|
|
|
local lua_url="https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/lua5.2/5.2.4-3build2/lua5.2_5.2.4.orig.tar.gz"
|
|
local lua_sha256="86fb7e23cbbddfcd92684e5f8017ff41c9112251d1656dbece415a97fad171c0"
|
|
local lua_archive
|
|
local lua_staging
|
|
lua_archive="$(mktemp)"
|
|
lua_staging="$(mktemp -d)"
|
|
if ! curl --fail --location --retry 3 --output "$lua_archive" "$lua_url"; then
|
|
rm -f -- "$lua_archive"
|
|
rm -rf -- "$lua_staging"
|
|
echo "error: failed to download the pinned Lua 5.2.4 source" >&2
|
|
exit 1
|
|
fi
|
|
if ! printf '%s %s\n' "$lua_sha256" "$lua_archive" | sha256sum --check --status; then
|
|
rm -f -- "$lua_archive"
|
|
rm -rf -- "$lua_staging"
|
|
echo "error: Lua 5.2.4 source checksum mismatch" >&2
|
|
exit 1
|
|
fi
|
|
mkdir -p "$source_dir/buildscripts/deps"
|
|
tar -xzf "$lua_archive" -C "$lua_staging" --strip-components=1
|
|
rm -f -- "$lua_archive"
|
|
if [[ -e "$lua_dir" || -L "$lua_dir" ]]; then
|
|
# This path is fixed beneath the generated dependency directory, and the
|
|
# valid-source early return above prevents replacing a completed checkout.
|
|
rm -rf -- "$lua_dir"
|
|
fi
|
|
mv "$lua_staging" "$lua_dir"
|
|
}
|
|
|
|
# This pinned mpv-android revision stores its dependency recipes in-tree and
|
|
# materializes their exact source revisions under buildscripts/deps. Some of
|
|
# those dependencies contain submodules of their own. The downloader is
|
|
# idempotent and must run before buildall can resolve the `mpv` target.
|
|
ensure_lua_source
|
|
(cd "$source_dir/buildscripts" && ./include/download-deps.sh)
|
|
ensure_lua_source
|
|
|
|
for arch in arm64 x86_64; do
|
|
(cd "$source_dir/buildscripts" && ./buildall.sh --arch "$arch" mpv)
|
|
done
|
|
|
|
llvm_readelf="$(find "$ndk_dir/toolchains/llvm/prebuilt" -name llvm-readelf -print -quit)"
|
|
if [[ -z "$llvm_readelf" ]]; then
|
|
echo "error: llvm-readelf is missing from Android NDK: $ndk_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# These libraries are supplied by Android itself. Every other DT_NEEDED entry
|
|
# must be packaged in the APK for each ABI. Keep this list explicit: silently
|
|
# treating an unknown library as a platform library produces installable APKs
|
|
# that fail as soon as the dynamic linker loads pstr_mpv/libmpv.
|
|
is_android_system_library() {
|
|
case "$1" in
|
|
libc.so | libdl.so | liblog.so | libm.so | libz.so | libandroid.so | \
|
|
libmediandk.so | libnativewindow.so | libOpenSLES.so | libaaudio.so | \
|
|
libEGL.so | libGLESv1_CM.so | libGLESv2.so | libGLESv3.so | \
|
|
libjnigraphics.so | libvulkan.so)
|
|
return 0
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
stage_shared_dependency_closure() {
|
|
local arch="$1"
|
|
local abi="$2"
|
|
local ndk_triple="$3"
|
|
local prefix_lib="$source_dir/buildscripts/prefix/$arch/lib"
|
|
local ndk_lib="$ndk_dir/toolchains/llvm/prebuilt/$(basename "$(dirname "$(dirname "$llvm_readelf")")")/sysroot/usr/lib/$ndk_triple"
|
|
local output_dir="$destination/jniLibs/$abi"
|
|
local current needed source soname
|
|
local -a pending=(libmpv.so)
|
|
local -A staged=()
|
|
|
|
# Remove stale libraries from an earlier build before constructing the exact
|
|
# closure for this pinned revision.
|
|
mkdir -p "$output_dir"
|
|
find "$output_dir" -maxdepth 1 -type f -name '*.so' -delete
|
|
|
|
while ((${#pending[@]})); do
|
|
current="${pending[0]}"
|
|
pending=("${pending[@]:1}")
|
|
[[ -n "${staged[$current]:-}" ]] && continue
|
|
|
|
if [[ -f "$prefix_lib/$current" ]]; then
|
|
source="$prefix_lib/$current"
|
|
elif [[ "$current" == libc++_shared.so && -f "$ndk_lib/$current" ]]; then
|
|
source="$ndk_lib/$current"
|
|
else
|
|
echo "error: unresolved non-system dependency for $abi: $current" >&2
|
|
exit 1
|
|
fi
|
|
|
|
soname="$($llvm_readelf -d "$source" | sed -n 's/.*SONAME.*\[\(.*\)\]/\1/p')"
|
|
if [[ "$soname" != "$current" ]]; then
|
|
echo "error: $source has SONAME '$soname', expected '$current'" >&2
|
|
exit 1
|
|
fi
|
|
cp -- "$source" "$output_dir/$current"
|
|
staged[$current]=1
|
|
|
|
while IFS= read -r needed; do
|
|
if ! is_android_system_library "$needed" && [[ -z "${staged[$needed]:-}" ]]; then
|
|
pending+=("$needed")
|
|
fi
|
|
done < <("$llvm_readelf" -d "$source" | sed -n 's/.*Shared library: \[\(.*\)\]/\1/p')
|
|
done
|
|
|
|
# Re-read only the packaged copies, so verification also catches a bad or
|
|
# versioned staging filename rather than trusting the source tree.
|
|
for current in "${!staged[@]}"; do
|
|
while IFS= read -r needed; do
|
|
if ! is_android_system_library "$needed" && [[ ! -f "$output_dir/$needed" ]]; then
|
|
echo "error: $abi/$current needs unstaged library $needed" >&2
|
|
exit 1
|
|
fi
|
|
done < <("$llvm_readelf" -d "$output_dir/$current" | sed -n 's/.*Shared library: \[\(.*\)\]/\1/p')
|
|
done
|
|
|
|
printf 'staged %s shared libraries for %s:\n' "${#staged[@]}" "$abi"
|
|
printf ' %s\n' "${!staged[@]}" | LC_ALL=C sort
|
|
}
|
|
|
|
mkdir -p "$destination/include/mpv"
|
|
cp "$source_dir/buildscripts/prefix/arm64/include/mpv/"*.h "$destination/include/mpv/"
|
|
# FFmpeg's JNI entry points are not part of the mpv API, but registering the
|
|
# JavaVM MediaCodec needs is our job now that mpv-android's JNI layer is gone.
|
|
mkdir -p "$destination/include/libavcodec"
|
|
cp "$source_dir/buildscripts/prefix/arm64/include/libavcodec/jni.h" "$destination/include/libavcodec/"
|
|
stage_shared_dependency_closure arm64 arm64-v8a aarch64-linux-android
|
|
stage_shared_dependency_closure x86_64 x86_64 x86_64-linux-android
|
|
|
|
# `git archive` omits dependency working trees. Archive the pinned checkout and
|
|
# downloaded sources together, excluding only generated build/install output
|
|
# and Git administration data, so distributed binaries have corresponding
|
|
# source for mpv and every statically linked dependency.
|
|
tar \
|
|
--exclude='.git' \
|
|
--exclude='buildscripts/prefix' \
|
|
--exclude='buildscripts/sdk' \
|
|
--exclude='buildscripts/deps/*/_build_*' \
|
|
-C "$source_dir" \
|
|
-czf "$destination/mpv-android-source-$revision.tar.gz" \
|
|
.
|
|
printf '%s\n' "$revision" > "$destination/REVISION"
|
|
# Last, so an interrupted run never leaves a stamp over a partial tree.
|
|
printf '%s\n' "$stamp" > "$destination/STAMP"
|