227 lines
8.5 KiB
Bash
227 lines
8.5 KiB
Bash
#!/usr/bin/env bash
|
|||
|
|
|
||
|
|
set -Eeuo pipefail
|
||
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||
|
|
# shellcheck source=lib.sh
|
||
|
|
. "${SCRIPT_DIR}/lib.sh"
|
||
|
|
|
||
|
|
LOCK_FILE="${RKMEDIA_ROOT}/sources.lock.json"
|
||
|
|
WORK_DIR="${RKMEDIA_ROOT}/out/work"
|
||
|
|
SOURCE_DIR="${RKMEDIA_ROOT}/out/sources"
|
||
|
|
OUTPUT_DIR="${RKMEDIA_ROOT}/out"
|
||
|
|
JOBS="$(nproc)"
|
||
|
|
FETCH=1
|
||
|
|
PACKAGE_VERSION="$(tr -d '[:space:]' < "${RKMEDIA_ROOT}/VERSION")"
|
||
|
|
RUNTIME_PREFIX=/opt/rkmedia
|
||
|
|
|
||
|
|
usage() {
|
||
|
|
cat <<'EOF'
|
||
|
|
Usage: build-media.sh [options]
|
||
|
|
|
||
|
|
--source-dir DIR Locked source checkouts (default: out/sources)
|
||
|
|
--work-dir DIR Build work directory (default: out/work)
|
||
|
|
--output-dir DIR Package output directory (default: out)
|
||
|
|
--jobs N Parallel jobs (default: nproc)
|
||
|
|
--no-fetch Require sources to exist; never access the network
|
||
|
|
--version VERSION Debian package version (default: VERSION file)
|
||
|
|
EOF
|
||
|
|
}
|
||
|
|
|
||
|
|
while (($#)); do
|
||
|
|
case "$1" in
|
||
|
|
--source-dir) [[ $# -ge 2 ]] || die "--source-dir requires a directory"; SOURCE_DIR="$2"; shift 2 ;;
|
||
|
|
--work-dir) [[ $# -ge 2 ]] || die "--work-dir requires a directory"; WORK_DIR="$2"; shift 2 ;;
|
||
|
|
--output-dir) [[ $# -ge 2 ]] || die "--output-dir requires a directory"; OUTPUT_DIR="$2"; shift 2 ;;
|
||
|
|
--jobs) [[ $# -ge 2 ]] || die "--jobs requires a number"; JOBS="$2"; shift 2 ;;
|
||
|
|
--no-fetch) FETCH=0; shift ;;
|
||
|
|
--version) [[ $# -ge 2 ]] || die "--version requires a value"; PACKAGE_VERSION="$2"; shift 2 ;;
|
||
|
|
-h|--help) usage; exit 0 ;;
|
||
|
|
*) die "unknown argument: $1" ;;
|
||
|
|
esac
|
||
|
|
done
|
||
|
|
|
||
|
|
[[ "${JOBS}" =~ ^[1-9][0-9]*$ ]] || die "--jobs must be a positive integer"
|
||
|
|
[[ "${PACKAGE_VERSION}" =~ ^[0-9A-Za-z.+:~-]+$ ]] || die "invalid Debian package version: ${PACKAGE_VERSION}"
|
||
|
|
require_arm64_trixie
|
||
|
|
for command_name in cmake git jq meson ninja pkg-config make patch readelf strip; do
|
||
|
|
need_command "${command_name}"
|
||
|
|
done
|
||
|
|
|
||
|
|
SOURCE_DIR="$(absolute_path "${SOURCE_DIR}")"
|
||
|
|
WORK_DIR="$(absolute_path "${WORK_DIR}")"
|
||
|
|
OUTPUT_DIR="$(absolute_path "${OUTPUT_DIR}")"
|
||
|
|
mkdir -p -- "${SOURCE_DIR}" "${WORK_DIR}" "${OUTPUT_DIR}"
|
||
|
|
|
||
|
|
if ((FETCH)); then
|
||
|
|
"${SCRIPT_DIR}/fetch-sources.sh" --lock "${LOCK_FILE}" --dest "${SOURCE_DIR}"
|
||
|
|
fi
|
||
|
|
|
||
|
|
while IFS=$'\t' read -r name commit; do
|
||
|
|
dir="${SOURCE_DIR}/${name}"
|
||
|
|
[[ -d "${dir}/.git" ]] || die "missing locked source: ${dir}"
|
||
|
|
[[ "$(git -C "${dir}" rev-parse HEAD)" == "${commit}" ]] || die "source commit mismatch: ${name}"
|
||
|
|
done < <(jq -r '.sources[] | select(.build == true) | [.name, .commit] | @tsv' "${LOCK_FILE}")
|
||
|
|
|
||
|
|
BUILD_ROOT="${WORK_DIR}/build"
|
||
|
|
BUILD_PREFIX="${WORK_DIR}/prefix"
|
||
|
|
STAGE_DIR="${WORK_DIR}/stage"
|
||
|
|
reset_child_dir "${WORK_DIR}" "${BUILD_ROOT}"
|
||
|
|
reset_child_dir "${WORK_DIR}" "${BUILD_PREFIX}"
|
||
|
|
reset_child_dir "${WORK_DIR}" "${STAGE_DIR}"
|
||
|
|
|
||
|
|
export SOURCE_DATE_EPOCH
|
||
|
|
SOURCE_DATE_EPOCH="$(jq -er '.source_date_epoch' "${LOCK_FILE}")"
|
||
|
|
export CFLAGS="${CFLAGS:--O2 -pipe -ffile-prefix-map=${WORK_DIR}=. -fdebug-prefix-map=${WORK_DIR}=.}"
|
||
|
|
export CXXFLAGS="${CXXFLAGS:--O2 -pipe -ffile-prefix-map=${WORK_DIR}=. -fdebug-prefix-map=${WORK_DIR}=.}"
|
||
|
|
export LDFLAGS="${LDFLAGS:-}"
|
||
|
|
|
||
|
|
log "building MPP"
|
||
|
|
cmake -S "${SOURCE_DIR}/mpp" -B "${BUILD_ROOT}/mpp" -G Ninja \
|
||
|
|
-DCMAKE_BUILD_TYPE=Release \
|
||
|
|
-DCMAKE_INSTALL_PREFIX="${BUILD_PREFIX}" \
|
||
|
|
-DCMAKE_INSTALL_LIBDIR=lib \
|
||
|
|
-DBUILD_SHARED_LIBS=ON \
|
||
|
|
-DBUILD_TEST=OFF
|
||
|
|
cmake --build "${BUILD_ROOT}/mpp" --parallel "${JOBS}"
|
||
|
|
cmake --install "${BUILD_ROOT}/mpp"
|
||
|
|
|
||
|
|
log "building RGA"
|
||
|
|
meson setup "${BUILD_ROOT}/rga" "${SOURCE_DIR}/rga" \
|
||
|
|
--prefix="${BUILD_PREFIX}" \
|
||
|
|
--libdir=lib \
|
||
|
|
--buildtype=release \
|
||
|
|
--default-library=shared \
|
||
|
|
-Dcpp_args=-fpermissive \
|
||
|
|
-Dlibdrm=false \
|
||
|
|
-Dlibrga_demo=false
|
||
|
|
meson compile -C "${BUILD_ROOT}/rga" -j "${JOBS}"
|
||
|
|
meson install -C "${BUILD_ROOT}/rga"
|
||
|
|
|
||
|
|
log "building dav1d"
|
||
|
|
meson setup "${BUILD_ROOT}/dav1d" "${SOURCE_DIR}/dav1d" \
|
||
|
|
--prefix="${BUILD_PREFIX}" \
|
||
|
|
--libdir=lib \
|
||
|
|
--buildtype=release \
|
||
|
|
--default-library=shared \
|
||
|
|
-Denable_tools=false \
|
||
|
|
-Denable_tests=false \
|
||
|
|
-Denable_examples=false \
|
||
|
|
-Denable_docs=false
|
||
|
|
meson compile -C "${BUILD_ROOT}/dav1d" -j "${JOBS}"
|
||
|
|
meson install -C "${BUILD_ROOT}/dav1d"
|
||
|
|
|
||
|
|
export PKG_CONFIG_PATH="${BUILD_PREFIX}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
|
||
|
|
export LD_LIBRARY_PATH="${BUILD_PREFIX}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
|
||
|
|
|
||
|
|
log "building FFmpeg-Rockchip"
|
||
|
|
mkdir -p -- "${BUILD_ROOT}/ffmpeg"
|
||
|
|
pushd "${BUILD_ROOT}/ffmpeg" >/dev/null
|
||
|
|
"${SOURCE_DIR}/ffmpeg-rockchip/configure" \
|
||
|
|
--prefix="${BUILD_PREFIX}" \
|
||
|
|
--libdir="${BUILD_PREFIX}/lib" \
|
||
|
|
--enable-shared \
|
||
|
|
--disable-static \
|
||
|
|
--disable-debug \
|
||
|
|
--disable-doc \
|
||
|
|
--enable-pic \
|
||
|
|
--enable-gpl \
|
||
|
|
--enable-version3 \
|
||
|
|
--enable-libdrm \
|
||
|
|
--enable-rkmpp \
|
||
|
|
--enable-rkrga \
|
||
|
|
--enable-libdav1d \
|
||
|
|
--extra-cflags="-I${BUILD_PREFIX}/include" \
|
||
|
|
--extra-ldflags="-L${BUILD_PREFIX}/lib -Wl,-rpath,${RUNTIME_PREFIX}/lib"
|
||
|
|
make -j "${JOBS}"
|
||
|
|
make install
|
||
|
|
popd >/dev/null
|
||
|
|
|
||
|
|
FFMPEG_BUILD="${BUILD_PREFIX}/bin/ffmpeg"
|
||
|
|
for decoder in h264_rkmpp hevc_rkmpp vp9_rkmpp av1_rkmpp mjpeg_rkmpp; do
|
||
|
|
"${FFMPEG_BUILD}" -hide_banner -decoders 2>/dev/null | awk '{print $2}' | grep -Fxq "${decoder}" \
|
||
|
|
|| die "FFmpeg is missing decoder ${decoder}"
|
||
|
|
done
|
||
|
|
for encoder in h264_rkmpp hevc_rkmpp mjpeg_rkmpp; do
|
||
|
|
"${FFMPEG_BUILD}" -hide_banner -encoders 2>/dev/null | awk '{print $2}' | grep -Fxq "${encoder}" \
|
||
|
|
|| die "FFmpeg is missing encoder ${encoder}"
|
||
|
|
done
|
||
|
|
for filter in scale_rkrga vpp_rkrga overlay_rkrga; do
|
||
|
|
"${FFMPEG_BUILD}" -hide_banner -filters 2>/dev/null | awk '{print $2}' | grep -Fxq "${filter}" \
|
||
|
|
|| die "FFmpeg is missing filter ${filter}"
|
||
|
|
done
|
||
|
|
|
||
|
|
log "building libdisplay-info"
|
||
|
|
meson setup "${BUILD_ROOT}/libdisplay-info" "${SOURCE_DIR}/libdisplay-info" \
|
||
|
|
--prefix="${BUILD_PREFIX}" \
|
||
|
|
--libdir=lib \
|
||
|
|
--buildtype=release \
|
||
|
|
--default-library=shared
|
||
|
|
meson compile -C "${BUILD_ROOT}/libdisplay-info" -j "${JOBS}"
|
||
|
|
meson install -C "${BUILD_ROOT}/libdisplay-info"
|
||
|
|
|
||
|
|
log "building Kodi for GBM/GLES with external FFmpeg-Rockchip"
|
||
|
|
cmake -S "${SOURCE_DIR}/kodi" -B "${BUILD_ROOT}/kodi" -G Ninja \
|
||
|
|
-DCMAKE_BUILD_TYPE=Release \
|
||
|
|
-DCMAKE_INSTALL_PREFIX="${RUNTIME_PREFIX}" \
|
||
|
|
-DCMAKE_INSTALL_RPATH="${RUNTIME_PREFIX}/lib" \
|
||
|
|
-DCMAKE_BUILD_RPATH="${BUILD_PREFIX}/lib" \
|
||
|
|
-DCMAKE_PREFIX_PATH="${BUILD_PREFIX}" \
|
||
|
|
-DCORE_PLATFORM_NAME=gbm \
|
||
|
|
-DAPP_RENDER_SYSTEM=gles \
|
||
|
|
-DENABLE_INTERNAL_FFMPEG=OFF \
|
||
|
|
-DFFMPEG_PATH="${BUILD_PREFIX}" \
|
||
|
|
-DENABLE_INTERNAL_FMT=ON \
|
||
|
|
-DENABLE_INTERNAL_FLATBUFFERS=ON
|
||
|
|
cmake --build "${BUILD_ROOT}/kodi" --parallel "${JOBS}"
|
||
|
|
|
||
|
|
mkdir -p -- "${STAGE_DIR}${RUNTIME_PREFIX}"
|
||
|
|
cp -a -- "${BUILD_PREFIX}/." "${STAGE_DIR}${RUNTIME_PREFIX}/"
|
||
|
|
DESTDIR="${STAGE_DIR}" cmake --install "${BUILD_ROOT}/kodi"
|
||
|
|
|
||
|
|
log "adding runtime integration and source provenance"
|
||
|
|
cp -a -- "${RKMEDIA_ROOT}/packaging/rootfs/." "${STAGE_DIR}/"
|
||
|
|
mkdir -p -- "${STAGE_DIR}/usr/bin" "${STAGE_DIR}/usr/share/doc/rk1-media-stack/licenses"
|
||
|
|
ln -sfn /opt/rkmedia/bin/ffmpeg-rk "${STAGE_DIR}/usr/bin/ffmpeg-rk"
|
||
|
|
ln -sfn /opt/rkmedia/bin/ffprobe-rk "${STAGE_DIR}/usr/bin/ffprobe-rk"
|
||
|
|
ln -sfn /opt/rkmedia/bin/kodi-rk "${STAGE_DIR}/usr/bin/kodi-rk"
|
||
|
|
install -m 0644 "${LOCK_FILE}" "${STAGE_DIR}/usr/share/doc/rk1-media-stack/sources.lock.json"
|
||
|
|
|
||
|
|
while IFS=$'\t' read -r name license_path; do
|
||
|
|
source_license="${SOURCE_DIR}/${name}/${license_path}"
|
||
|
|
destination="${STAGE_DIR}/usr/share/doc/rk1-media-stack/licenses/${name}"
|
||
|
|
[[ -e "${source_license}" ]] || die "locked license path is missing: ${name}/${license_path}"
|
||
|
|
mkdir -p -- "${destination}"
|
||
|
|
cp -a -- "${source_license}" "${destination}/"
|
||
|
|
done < <(jq -r '.sources[] | select(.build == true) as $source | $source.license_files[] | [$source.name, .] | @tsv' "${LOCK_FILE}")
|
||
|
|
|
||
|
|
rm -rf -- \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/include" \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/lib/pkgconfig" \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/share/pkgconfig"
|
||
|
|
find "${STAGE_DIR}${RUNTIME_PREFIX}" -type f \( -name '*.a' -o -name '*.la' \) -delete
|
||
|
|
|
||
|
|
while IFS= read -r -d '' candidate; do
|
||
|
|
if file --brief "${candidate}" | grep -q '^ELF '; then
|
||
|
|
strip --strip-unneeded "${candidate}" || die "failed to strip ${candidate}"
|
||
|
|
fi
|
||
|
|
done < <(find "${STAGE_DIR}${RUNTIME_PREFIX}" -type f -print0)
|
||
|
|
|
||
|
|
for required in \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/bin/ffmpeg" \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/bin/ffprobe" \
|
||
|
|
"${STAGE_DIR}${RUNTIME_PREFIX}/bin/kodi" \
|
||
|
|
"${STAGE_DIR}/usr/lib/systemd/system/kodi-rk.service"; do
|
||
|
|
[[ -e "${required}" ]] || die "staged runtime file is missing: ${required}"
|
||
|
|
done
|
||
|
|
|
||
|
|
if find "${STAGE_DIR}${RUNTIME_PREFIX}" -type f -exec grep -IlF "${WORK_DIR}" {} + | grep -q .; then
|
||
|
|
die "build path leaked into a staged text file"
|
||
|
|
fi
|
||
|
|
|
||
|
|
"${SCRIPT_DIR}/package-media.sh" \
|
||
|
|
--stage "${STAGE_DIR}" \
|
||
|
|
--output-dir "${OUTPUT_DIR}" \
|
||
|
|
--version "${PACKAGE_VERSION}"
|
||
|
|
|
||
|
|
log "media build complete"
|