Initial RK1 media-center image project

This commit is contained in:
2026-08-17 18:42:29 +00:00
commit 5fe41e79e9
81 changed files with 5725 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
/out/
+108
View File
@@ -0,0 +1,108 @@
# RK1 media stack
This directory builds an ARM64-only Kodi/GBM appliance stack for an RK3588
running Armbian Debian 13 (Trixie) with the Rockchip vendor 6.1 kernel. All
third-party inputs are immutable Git commits recorded in `sources.lock.json`.
The result is a Debian package whose custom libraries and programs live under
`/opt/rkmedia`; it does not replace Debian's FFmpeg or Kodi packages.
## Why the compatibility MPP and RGA branches are pinned
The current `kodi-rockchip-deb` recipe uses nyanmisaka's `jellyfin-mpp` and
`jellyfin-rga` branches. FFmpeg-Rockchip 8.1 checks for MPP package version
1.3.9 and the `mpp_buffer_sync_begin_f` symbol, and checks the RGA APIs
`c_RkRgaBlit` and `querystring`. These exact branches satisfy that interface.
The official Rockchip MPP/RGA heads inspected when this lock was generated are
recorded as reference metadata, but are deliberately not substituted into the
matched build without a complete hardware regression run.
## Build
Run this on an aarch64 Debian Trixie installation. The native build is large and
can take several hours.
```sh
sudo ./scripts/install-build-deps.sh --install
./scripts/build-media.sh
```
Outputs are written to `out/` by default:
- `rk1-media-stack_<version>_arm64.deb`
- an unpacked `stage/` tree for inspection
- cloned, detached source trees and component build directories
Useful options:
```sh
./scripts/fetch-sources.sh --dest /path/to/sources
./scripts/build-media.sh --source-dir /path/to/sources --work-dir /path/to/work --output-dir /path/to/output --jobs 8
./scripts/build-media.sh --no-fetch
```
Set `RKMEDIA_ALLOW_UNSUPPORTED_HOST=1` only for development. Packages built on
anything other than Trixie are unsupported because their generated shared
library dependencies will describe the build host, not the target image.
## Fast candidate repack
For image composition and hardware validation, the pinned July 2026 upstream
Trixie package can be deterministically repacked in a few minutes instead of
performing the multi-hour native compile:
```sh
./scripts/repack-upstream-deb.sh
```
The script downloads the exact asset in `upstream-deb.lock.json`, verifies its
size and SHA-256 before extraction, removes approximately 270 MB of static
FFmpeg archives and all development pkg-config files, and emits the same
`rk1-media-stack` package format. Kodi remains at `/usr/local`, its compiled
prefix. FFmpeg, FFprobe, MPP, RGA, dav1d, and display-info move under
`/opt/rkmedia`; the launcher supplies the corresponding library path.
Use `--deb PATH` to repack an already-downloaded copy without network access.
The prebuilt asset is reproducible as an input but its original recipe used
moving source branches; its verified asset digest, rather than reconstructed
Git commit guesses, is the provenance boundary.
## Install and operate
Install with APT so runtime dependencies are resolved:
```sh
sudo apt install ./rk1-media-stack_<version>_arm64.deb
sudo systemctl enable --now kodi-rk.service
```
The package creates a locked `kodi` system account, grants it only the existing
`video`, `render`, `audio`, and `input` group memberships, and gives it persistent
state under `/var/lib/kodi`. Kodi takes DRM master on tty1, so a display manager
or another program holding the KMS device must not be active.
The service is enabled during package configuration but is not started inside
an image-build chroot. Edit `/etc/rkmedia/kodi.env` for supported environment
overrides, then restart `kodi-rk.service`.
The following commands are exposed without replacing system FFmpeg:
```sh
ffmpeg-rk -hide_banner -decoders
ffmpeg-rk -hide_banner -encoders
ffmpeg-rk -hide_banner -filters
ffprobe-rk media-file.mkv
```
Expected hardware entries include `h264_rkmpp`, `hevc_rkmpp`, `vp9_rkmpp`,
`av1_rkmpp`, `mjpeg_rkmpp`, and the `scale_rkrga`, `vpp_rkrga`, and
`overlay_rkrga` filters. Runtime access is provided through conservative udev
rules for the DRM, dma-heap, RGA, IEP, VPU, and MPP device nodes.
## Boundaries
- The package does not install or select the kernel, device tree, Panthor
overlay, Mesa, firmware, or bootloader. Those belong to the parent image.
- The package does not claim HDMI link, HDR, passthrough, or codec acceptance;
those require testing on the actual RK1/carrier/TV combination.
- Kodi is pinned to a mainline commit because the current Rockchip GBM work is
newer than a stable Kodi release. Update the lock only as a tested set.
+2
View File
@@ -0,0 +1,2 @@
20260816.1
+15
View File
@@ -0,0 +1,15 @@
Package: rk1-media-stack
Version: @VERSION@
Section: video
Priority: optional
Architecture: arm64
Maintainer: RK1 Media Image Builder <root@localhost>
Installed-Size: @INSTALLED_SIZE@
Depends: @DEPENDS@
Recommends: armbian-firmware, libgl1-mesa-dri, mesa-vulkan-drivers
Homepage: https://github.com/armsurvivors/kodi-rockchip-deb
X-RKMedia-Provenance-SHA256: @LOCK_SHA256@
Description: isolated RK3588 Kodi GBM and FFmpeg hardware media stack
Kodi for direct GBM/GLES rendering plus a matched FFmpeg-Rockchip, MPP,
RGA, dav1d, and libdisplay-info runtime. Custom software is isolated under
/opt/rkmedia and does not replace the distribution FFmpeg packages.
+34
View File
@@ -0,0 +1,34 @@
#!/bin/sh
set -e
if ! getent group kodi >/dev/null 2>&1; then
addgroup --system kodi
fi
if ! getent passwd kodi >/dev/null 2>&1; then
adduser --system --ingroup kodi --home /var/lib/kodi --no-create-home \
--disabled-login --shell /usr/sbin/nologin kodi
fi
for group in video render audio input; do
if getent group "${group}" >/dev/null 2>&1; then
adduser kodi "${group}" >/dev/null
fi
done
systemd-tmpfiles --create rkmedia.conf >/dev/null 2>&1 || true
udevadm control --reload-rules >/dev/null 2>&1 || true
udevadm trigger --action=change --subsystem-match=drm >/dev/null 2>&1 || true
udevadm trigger --action=change --subsystem-match=dma_heap >/dev/null 2>&1 || true
udevadm trigger --action=change --subsystem-match=misc >/dev/null 2>&1 || true
udevadm settle >/dev/null 2>&1 || true
if command -v deb-systemd-helper >/dev/null 2>&1; then
deb-systemd-helper unmask kodi-rk.service >/dev/null || true
deb-systemd-helper enable kodi-rk.service >/dev/null || true
fi
if [ -d /run/systemd/system ]; then
systemctl daemon-reload >/dev/null || true
fi
exit 0
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
set -e
if command -v deb-systemd-helper >/dev/null 2>&1; then
if [ "$1" = purge ]; then
deb-systemd-helper purge kodi-rk.service >/dev/null || true
fi
fi
if [ -d /run/systemd/system ]; then
systemctl daemon-reload >/dev/null || true
fi
# Deliberately retain /var/lib/kodi and the locked account on removal. The
# media database and settings must never be deleted by a package uninstall.
exit 0
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
set -e
if [ "$1" = remove ] && [ -d /run/systemd/system ]; then
systemctl --no-reload stop kodi-rk.service >/dev/null 2>&1 || true
fi
exit 0
@@ -0,0 +1,8 @@
# Environment loaded by kodi-rk.service. This file is preserved across package
# upgrades. Kodi command-line arguments live in the unit so values here never
# undergo unsafe shell word splitting.
KODI_DATA=/var/lib/kodi/.kodi
CRASHLOG_DIR=/var/lib/kodi
XDG_CACHE_HOME=/var/cache/kodi
MESA_SHADER_CACHE_DIR=/var/cache/kodi/mesa_shader_cache
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
set -eu
prefix=/opt/rkmedia
export LD_LIBRARY_PATH="${prefix}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
exec "${prefix}/bin/ffmpeg" "$@"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
set -eu
prefix=/opt/rkmedia
export LD_LIBRARY_PATH="${prefix}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
exec "${prefix}/bin/ffprobe" "$@"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
set -eu
prefix=/opt/rkmedia
data_dir="${KODI_DATA:-${HOME}/.kodi}"
userdata_dir="${data_dir}/userdata"
export PATH="${prefix}/bin:${PATH}"
export LD_LIBRARY_PATH="${prefix}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
mkdir -p "${userdata_dir}"
if [ ! -e "${userdata_dir}/guisettings.xml" ]; then
cp /usr/share/rkmedia/kodi/guisettings.xml "${userdata_dir}/guisettings.xml"
fi
if [ -x "${prefix}/bin/kodi" ]; then
kodi_launcher="${prefix}/bin/kodi"
elif [ -x /usr/local/bin/kodi ]; then
kodi_launcher=/usr/local/bin/kodi
else
printf 'kodi-rk: no Kodi launcher found under /opt/rkmedia or /usr/local\n' >&2
exit 127
fi
exec "${kodi_launcher}" "$@"
@@ -0,0 +1,51 @@
[Unit]
Description=Kodi RK3588 GBM appliance
Documentation=https://github.com/armsurvivors/kodi-rockchip-deb
Wants=network-online.target
After=systemd-user-sessions.service network-online.target sound.target
Conflicts=display-manager.service [email protected]
[Service]
Type=simple
User=kodi
Group=kodi
SupplementaryGroups=video render audio input
Environment=HOME=/var/lib/kodi
Environment=XDG_RUNTIME_DIR=/run/kodi
Environment=LD_LIBRARY_PATH=/opt/rkmedia/lib
EnvironmentFile=-/etc/rkmedia/kodi.env
RuntimeDirectory=kodi
RuntimeDirectoryMode=0700
StateDirectory=kodi
StateDirectoryMode=0750
CacheDirectory=kodi
CacheDirectoryMode=0750
PAMName=login
UtmpIdentifier=tty1
UtmpMode=user
StandardInput=tty
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
ExecStart=/opt/rkmedia/bin/kodi-rk --standalone --logging=console --windowing=gbm --audio-backend=alsa
Restart=always
RestartSec=2s
TimeoutStopSec=15s
LimitNOFILE=16384
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictNamespaces=yes
RestrictSUIDSGID=yes
LockPersonality=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
CapabilityBoundingSet=CAP_SYS_TTY_CONFIG
AmbientCapabilities=CAP_SYS_TTY_CONFIG
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,4 @@
d /var/lib/kodi 0750 kodi kodi -
d /var/lib/kodi/.kodi 0750 kodi kodi -
d /var/cache/kodi 0750 kodi kodi -
@@ -0,0 +1,22 @@
# Primary and render DRM nodes used by Kodi GBM and DRM PRIME.
SUBSYSTEM=="drm", KERNEL=="card[0-9]*", GROUP="video", MODE="0660", TAG+="uaccess"
SUBSYSTEM=="drm", KERNEL=="renderD[0-9]*", GROUP="render", MODE="0660", TAG+="uaccess"
# Rockchip vendor-kernel media accelerators. Optional compatibility names are
# included because their exact node names vary across BSP kernel revisions.
SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660"
KERNEL=="rga", GROUP="video", MODE="0660"
KERNEL=="iep", GROUP="video", MODE="0660"
KERNEL=="mpp_service", GROUP="video", MODE="0660"
KERNEL=="mpp-service", GROUP="video", MODE="0660"
KERNEL=="vpu_service", GROUP="video", MODE="0660"
KERNEL=="vpu-service", GROUP="video", MODE="0660"
KERNEL=="hevc_service", GROUP="video", MODE="0660"
KERNEL=="hevc-service", GROUP="video", MODE="0660"
KERNEL=="rkvdec", GROUP="video", MODE="0660"
KERNEL=="rkvenc", GROUP="video", MODE="0660"
KERNEL=="vepu", GROUP="video", MODE="0660"
KERNEL=="h265e", GROUP="video", MODE="0660"
# Rockchip NPU control/render compatibility nodes used by RKNN diagnostics.
KERNEL=="rknpu*", GROUP="render", MODE="0660"
@@ -0,0 +1,5 @@
<settings version="2">
<setting id="videoplayer.useprimedecoder">true</setting>
<setting id="videoplayer.useprimedecoderforhw" default="true">true</setting>
<setting id="videoplayer.useprimerenderer">0</setting>
</settings>
+226
View File
@@ -0,0 +1,226 @@
#!/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"
+85
View File
@@ -0,0 +1,85 @@
#!/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"
DEST_DIR="${RKMEDIA_ROOT}/out/sources"
usage() {
cat <<'EOF'
Usage: fetch-sources.sh [--lock FILE] [--dest DIRECTORY]
Fetch every build input at the exact commit recorded in the source lock.
Existing repositories are accepted only when their origin and HEAD match.
EOF
}
while (($#)); do
case "$1" in
--lock)
[[ $# -ge 2 ]] || die "--lock requires a file"
LOCK_FILE="$2"
shift 2
;;
--dest)
[[ $# -ge 2 ]] || die "--dest requires a directory"
DEST_DIR="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*) die "unknown argument: $1" ;;
esac
done
need_command git
need_command jq
LOCK_FILE="$(absolute_path "${LOCK_FILE}")"
DEST_DIR="$(absolute_path "${DEST_DIR}")"
[[ -f "${LOCK_FILE}" ]] || die "source lock not found: ${LOCK_FILE}"
jq -e '.schema_version == 1 and (.sources | type == "array")' "${LOCK_FILE}" >/dev/null \
|| die "invalid source lock: ${LOCK_FILE}"
mkdir -p -- "${DEST_DIR}"
verify_checkout() {
local dir="$1" expected_repo="$2" expected_commit="$3"
local actual_repo actual_commit
[[ -d "${dir}/.git" ]] || return 1
actual_repo="$(git -C "${dir}" remote get-url origin 2>/dev/null || true)"
actual_commit="$(git -C "${dir}" rev-parse HEAD 2>/dev/null || true)"
[[ "${actual_repo}" == "${expected_repo}" && "${actual_commit}" == "${expected_commit}" ]]
}
while IFS=$'\t' read -r name repository ref commit; do
[[ "${name}" =~ ^[a-z0-9][a-z0-9._-]*$ ]] || die "unsafe source name in lock: ${name}"
[[ "${commit}" =~ ^[0-9a-f]{40}$ ]] || die "invalid commit for ${name}: ${commit}"
source_dir="${DEST_DIR}/${name}"
if verify_checkout "${source_dir}" "${repository}" "${commit}"; then
log "source already verified: ${name} ${commit}"
continue
fi
if [[ -e "${source_dir}" ]]; then
die "${source_dir} exists but does not match the lock; move it aside and retry"
fi
log "fetching ${name} at ${commit}"
mkdir -p -- "${source_dir}"
git -C "${source_dir}" init --quiet
git -C "${source_dir}" remote add origin "${repository}"
if ! git -C "${source_dir}" fetch --quiet --depth=1 origin "${commit}"; then
log "direct commit fetch was unavailable; fetching history from ${ref}"
git -C "${source_dir}" fetch --quiet --filter=blob:none origin "${ref}"
fi
git -C "${source_dir}" checkout --quiet --detach "${commit}"
verify_checkout "${source_dir}" "${repository}" "${commit}" \
|| die "checkout verification failed for ${name}"
done < <(jq -r '.sources[] | select(.build == true) | [.name, .repository, .ref, .commit] | @tsv' "${LOCK_FILE}")
log "all locked sources are present in ${DEST_DIR}"
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
# shellcheck source=lib.sh
. "${SCRIPT_DIR}/lib.sh"
MODE=check
case "${1:---check}" in
--check) MODE=check ;;
--install) MODE=install ;;
-h|--help)
printf 'Usage: install-build-deps.sh [--check|--install]\n'
exit 0
;;
*) die "unknown argument: $1" ;;
esac
require_arm64_trixie
need_command dpkg-query
packages=(
adduser autoconf automake autopoint autotools-dev build-essential ca-certificates
cmake default-jre devscripts dpkg-dev file gawk gcc g++ gdc gettext git gperf
hwdata jq libasound2-dev libass-dev libavahi-client-dev libavahi-common-dev
libbluetooth-dev libbluray-dev libbz2-dev libcdio++-dev libcdio-dev libcec-dev
libcrossguid-dev libcwiid-dev libcurl4-openssl-dev libdbus-1-dev libdrm-dev
libegl1-mesa-dev libenca-dev libexiv2-dev libflac-dev libfmt-dev
libfontconfig-dev libfreetype6-dev libfribidi-dev libfstrcmp-dev libgbm-dev
libgcrypt20-dev libgif-dev libgl1-mesa-dev libgles2-mesa-dev libglu1-mesa-dev
libgnutls28-dev libgpg-error-dev libgtest-dev libinput-dev libiso9660-dev
libjpeg-dev liblcms2-dev liblirc-dev libltdl-dev liblzo2-dev libmariadb-dev
libmicrohttpd-dev libnfs-dev libogg-dev libp8-platform-dev libpcre2-dev
libplist-dev libpng-dev libpulse-dev libshairplay-dev libsmbclient-dev
libspdlog-dev libsqlite3-dev libssl-dev libtag1-dev libtiff-dev
libtinyxml2-dev libtinyxml-dev libtool libudev-dev libunistring-dev
libvorbis-dev libxkbcommon-dev libxslt1-dev libxt-dev lsb-release meson nasm
ninja-build nlohmann-json3-dev patch pkg-config python3-dev python3-pil
python3-pip rapidjson-dev swig unzip uuid-dev zip zlib1g-dev
)
missing=()
for package in "${packages[@]}"; do
if ! dpkg-query -W -f='${db:Status-Abbrev}' "${package}" 2>/dev/null | grep -q '^ii '; then
missing+=("${package}")
fi
done
if ((${#missing[@]} == 0)); then
log "all build dependencies are installed"
exit 0
fi
if [[ "${MODE}" == "check" ]]; then
printf 'Missing build packages:\n'
printf ' %s\n' "${missing[@]}"
exit 1
fi
[[ "${EUID}" -eq 0 ]] || die "--install must run as root (use sudo)"
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends "${missing[@]}"
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -Eeuo pipefail
RKMEDIA_SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
RKMEDIA_ROOT="$(cd -- "${RKMEDIA_SCRIPT_DIR}/.." && pwd -P)"
log() {
printf '[rkmedia] %s\n' "$*" >&2
}
die() {
printf '[rkmedia] ERROR: %s\n' "$*" >&2
exit 1
}
need_command() {
command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
}
absolute_path() {
realpath -m -- "$1"
}
assert_child_path() {
local parent child
parent="$(absolute_path "$1")"
child="$(absolute_path "$2")"
case "${child}" in
"${parent}"/*) ;;
*) die "refusing operation outside ${parent}: ${child}" ;;
esac
[[ "${child}" != "${parent}" ]] || die "refusing operation on parent directory itself: ${parent}"
}
reset_child_dir() {
local parent="$1"
local child="$2"
assert_child_path "${parent}" "${child}"
rm -rf -- "${child}"
mkdir -p -- "${child}"
}
require_arm64_trixie() {
local arch codename
arch="$(dpkg --print-architecture 2>/dev/null || true)"
codename=""
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
codename="${VERSION_CODENAME:-}"
fi
if [[ "${arch}" != "arm64" || "$(uname -m)" != "aarch64" || "${codename}" != "trixie" ]]; then
if [[ "${RKMEDIA_ALLOW_UNSUPPORTED_HOST:-0}" == "1" ]]; then
log "warning: unsupported build host (dpkg=${arch}, uname=$(uname -m), suite=${codename:-unknown})"
return
fi
die "native Debian Trixie arm64 is required (set RKMEDIA_ALLOW_UNSUPPORTED_HOST=1 only for development)"
fi
}
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
set -Eeuo pipefail
umask 022
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
# shellcheck source=lib.sh
. "${SCRIPT_DIR}/lib.sh"
STAGE_DIR=""
OUTPUT_DIR="${RKMEDIA_ROOT}/out"
PACKAGE_VERSION="$(tr -d '[:space:]' < "${RKMEDIA_ROOT}/VERSION")"
DEPENDS_FROM_DEB=""
usage() {
printf 'Usage: package-media.sh --stage DIRECTORY [--output-dir DIRECTORY] [--version VERSION] [--depends-from-deb FILE]\n'
}
while (($#)); do
case "$1" in
--stage) [[ $# -ge 2 ]] || die "--stage requires a directory"; STAGE_DIR="$2"; shift 2 ;;
--output-dir) [[ $# -ge 2 ]] || die "--output-dir requires a directory"; OUTPUT_DIR="$2"; shift 2 ;;
--version) [[ $# -ge 2 ]] || die "--version requires a value"; PACKAGE_VERSION="$2"; shift 2 ;;
--depends-from-deb) [[ $# -ge 2 ]] || die "--depends-from-deb requires a file"; DEPENDS_FROM_DEB="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown argument: $1" ;;
esac
done
[[ -n "${STAGE_DIR}" ]] || die "--stage is required"
[[ "${PACKAGE_VERSION}" =~ ^[0-9A-Za-z.+:~-]+$ ]] || die "invalid Debian package version: ${PACKAGE_VERSION}"
for command_name in dpkg-deb dpkg-shlibdeps file jq md5sum sed sha256sum; do
need_command "${command_name}"
done
STAGE_DIR="$(absolute_path "${STAGE_DIR}")"
OUTPUT_DIR="$(absolute_path "${OUTPUT_DIR}")"
[[ -x "${STAGE_DIR}/opt/rkmedia/bin/ffmpeg" ]] || die "stage does not contain the RKMedia runtime"
mkdir -p -- "${OUTPUT_DIR}"
PACKAGE_ROOT="${OUTPUT_DIR}/package-root"
reset_child_dir "${OUTPUT_DIR}" "${PACKAGE_ROOT}"
cp -a -- "${STAGE_DIR}/." "${PACKAGE_ROOT}/"
mkdir -p -- "${PACKAGE_ROOT}/DEBIAN" "${PACKAGE_ROOT}/usr/share/doc/rk1-media-stack"
cp -- "${RKMEDIA_ROOT}/packaging/postinst" "${PACKAGE_ROOT}/DEBIAN/postinst"
cp -- "${RKMEDIA_ROOT}/packaging/prerm" "${PACKAGE_ROOT}/DEBIAN/prerm"
cp -- "${RKMEDIA_ROOT}/packaging/postrm" "${PACKAGE_ROOT}/DEBIAN/postrm"
chmod 0755 "${PACKAGE_ROOT}/DEBIAN/postinst" "${PACKAGE_ROOT}/DEBIAN/prerm" "${PACKAGE_ROOT}/DEBIAN/postrm"
printf '/etc/rkmedia/kodi.env\n' > "${PACKAGE_ROOT}/DEBIAN/conffiles"
# A collaborative workspace or permissive host umask must never make core
# target directories such as /etc, /usr, or /opt group-writable via dpkg.
find "${PACKAGE_ROOT}" -type d -exec chmod 0755 {} +
find "${PACKAGE_ROOT}" -type f ! -perm /0111 -exec chmod 0644 {} +
find "${PACKAGE_ROOT}" -type f -perm /0111 -exec chmod 0755 {} +
if find "${PACKAGE_ROOT}" \( -type d -o -type f \) -perm /0022 -print -quit \
| grep -q .; then
die "package contains a group/world-writable path"
fi
if [[ -n "${DEPENDS_FROM_DEB}" ]]; then
DEPENDS_FROM_DEB="$(absolute_path "${DEPENDS_FROM_DEB}")"
[[ -f "${DEPENDS_FROM_DEB}" ]] || die "dependency source package not found: ${DEPENDS_FROM_DEB}"
shlib_depends="$(dpkg-deb --field "${DEPENDS_FROM_DEB}" Depends)"
[[ -n "${shlib_depends}" ]] || die "upstream package has an empty Depends field"
else
analysis_root="${OUTPUT_DIR}/shlibdeps"
reset_child_dir "${OUTPUT_DIR}" "${analysis_root}"
mkdir -p -- "${analysis_root}/debian"
cat > "${analysis_root}/debian/control" <<'EOF'
Source: rk1-media-stack
Section: video
Priority: optional
Package: rk1-media-stack
Architecture: arm64
Description: temporary metadata for dpkg-shlibdeps
EOF
elf_files=()
while IFS= read -r -d '' candidate; do
if file --brief "${candidate}" | grep -q '^ELF '; then
elf_files+=("${candidate}")
fi
done < <(find "${PACKAGE_ROOT}/opt/rkmedia" -type f -print0)
((${#elf_files[@]} > 0)) || die "no ELF files found in media stage"
pushd "${analysis_root}" >/dev/null
shlib_output="$(dpkg-shlibdeps --ignore-missing-info -O \
-l"${PACKAGE_ROOT}/opt/rkmedia/lib" "${elf_files[@]}")"
popd >/dev/null
shlib_depends="${shlib_output#shlibs:Depends=}"
[[ -n "${shlib_depends}" && "${shlib_depends}" != "${shlib_output}" ]] \
|| die "dpkg-shlibdeps did not produce runtime dependencies"
fi
depends="adduser, systemd, udev, ${shlib_depends}"
installed_size="$(du -sk "${PACKAGE_ROOT}" | awk '{print $1}')"
if [[ -f "${PACKAGE_ROOT}/usr/share/doc/rk1-media-stack/upstream-deb.lock.json" ]]; then
provenance_file="${PACKAGE_ROOT}/usr/share/doc/rk1-media-stack/upstream-deb.lock.json"
else
provenance_file="${PACKAGE_ROOT}/usr/share/doc/rk1-media-stack/sources.lock.json"
fi
lock_sha256="$(sha256sum "${provenance_file}" | awk '{print $1}')"
sed \
-e "s/@VERSION@/${PACKAGE_VERSION}/g" \
-e "s/@INSTALLED_SIZE@/${installed_size}/g" \
-e "s/@LOCK_SHA256@/${lock_sha256}/g" \
-e "s/@DEPENDS@/${depends}/g" \
"${RKMEDIA_ROOT}/packaging/control.in" > "${PACKAGE_ROOT}/DEBIAN/control"
pushd "${PACKAGE_ROOT}" >/dev/null
find etc opt usr -type f -print0 \
| sort -z \
| xargs -0 md5sum > DEBIAN/md5sums
popd >/dev/null
if find "${PACKAGE_ROOT}" \( -type d -o -type f \) -perm /0022 -print -quit \
| grep -q .; then
die "package contains a group/world-writable path after metadata generation"
fi
output_deb="${OUTPUT_DIR}/rk1-media-stack_${PACKAGE_VERSION}_arm64.deb"
rm -f -- "${output_deb}"
SOURCE_DATE_EPOCH="$(jq -er '.source_date_epoch' "${RKMEDIA_ROOT}/sources.lock.json")" \
dpkg-deb --root-owner-group --build "${PACKAGE_ROOT}" "${output_deb}"
(
cd "${OUTPUT_DIR}"
sha256sum "$(basename -- "${output_deb}")" \
>"$(basename -- "${output_deb}").sha256"
)
dpkg-deb --info "${output_deb}" >/dev/null
log "created ${output_deb}"
+144
View File
@@ -0,0 +1,144 @@
#!/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}/upstream-deb.lock.json"
WORK_DIR="${RKMEDIA_ROOT}/out/repack-work"
OUTPUT_DIR="${RKMEDIA_ROOT}/out"
CACHE_DIR="${RKMEDIA_ROOT}/out/downloads"
INPUT_DEB=""
PACKAGE_VERSION="20260721.1741+rk1.1"
usage() {
cat <<'EOF'
Usage: repack-upstream-deb.sh [options]
--deb FILE Use an existing upstream .deb instead of downloading
--work-dir DIR Temporary extraction directory
--output-dir DIR Repacked package output directory
--cache-dir DIR Download cache directory
--version VERSION Output Debian package version
EOF
}
while (($#)); do
case "$1" in
--deb) [[ $# -ge 2 ]] || die "--deb requires a file"; INPUT_DEB="$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 ;;
--cache-dir) [[ $# -ge 2 ]] || die "--cache-dir requires a directory"; CACHE_DIR="$2"; shift 2 ;;
--version) [[ $# -ge 2 ]] || die "--version requires a value"; PACKAGE_VERSION="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown argument: $1" ;;
esac
done
for command_name in curl dpkg-deb file jq readelf sha256sum stat; do
need_command "${command_name}"
done
[[ -f "${LOCK_FILE}" ]] || die "upstream asset lock is missing: ${LOCK_FILE}"
jq -e '.schema_version == 1 and (.asset_sha256 | test("^[0-9a-f]{64}$"))' "${LOCK_FILE}" >/dev/null \
|| die "invalid upstream asset lock"
WORK_DIR="$(absolute_path "${WORK_DIR}")"
OUTPUT_DIR="$(absolute_path "${OUTPUT_DIR}")"
CACHE_DIR="$(absolute_path "${CACHE_DIR}")"
mkdir -p -- "${WORK_DIR}" "${OUTPUT_DIR}" "${CACHE_DIR}"
asset_name="$(jq -er '.asset_name' "${LOCK_FILE}")"
asset_url="$(jq -er '.asset_url' "${LOCK_FILE}")"
expected_size="$(jq -er '.asset_size' "${LOCK_FILE}")"
expected_sha256="$(jq -er '.asset_sha256' "${LOCK_FILE}")"
if [[ -z "${INPUT_DEB}" ]]; then
INPUT_DEB="${CACHE_DIR}/${asset_name}"
if [[ ! -f "${INPUT_DEB}" ]]; then
partial="${INPUT_DEB}.partial"
rm -f -- "${partial}"
log "downloading pinned upstream Kodi package"
curl -L --fail --show-error --output "${partial}" "${asset_url}"
mv -- "${partial}" "${INPUT_DEB}"
fi
fi
INPUT_DEB="$(absolute_path "${INPUT_DEB}")"
[[ -f "${INPUT_DEB}" ]] || die "upstream package not found: ${INPUT_DEB}"
actual_size="$(stat -c '%s' "${INPUT_DEB}")"
actual_sha256="$(sha256sum "${INPUT_DEB}" | awk '{print $1}')"
[[ "${actual_size}" == "${expected_size}" ]] || die "upstream package size mismatch"
[[ "${actual_sha256}" == "${expected_sha256}" ]] || die "upstream package SHA-256 mismatch"
[[ "$(dpkg-deb --field "${INPUT_DEB}" Package)" == "$(jq -er '.package' "${LOCK_FILE}")" ]] \
|| die "upstream package name mismatch"
[[ "$(dpkg-deb --field "${INPUT_DEB}" Version)" == "$(jq -er '.package_version' "${LOCK_FILE}")" ]] \
|| die "upstream package version mismatch"
[[ "$(dpkg-deb --field "${INPUT_DEB}" Architecture)" == "arm64" ]] \
|| die "upstream package is not arm64"
STAGE_DIR="${WORK_DIR}/stage"
reset_child_dir "${WORK_DIR}" "${STAGE_DIR}"
dpkg-deb --extract "${INPUT_DEB}" "${STAGE_DIR}"
local_bin="${STAGE_DIR}/usr/local/bin"
local_lib="${STAGE_DIR}/usr/local/lib"
runtime_bin="${STAGE_DIR}/opt/rkmedia/bin"
runtime_lib="${STAGE_DIR}/opt/rkmedia/lib"
mkdir -p -- "${runtime_bin}" "${runtime_lib}"
for program in ffmpeg ffprobe; do
[[ -x "${local_bin}/${program}" ]] || die "upstream package is missing ${program}"
mv -- "${local_bin}/${program}" "${runtime_bin}/${program}"
done
if [[ -x "${local_bin}/di-edid-decode" ]]; then
mv -- "${local_bin}/di-edid-decode" "${runtime_bin}/di-edid-decode"
fi
shopt -s nullglob
runtime_libraries=(
"${local_lib}"/libdav1d.so*
"${local_lib}"/librga.so*
"${local_lib}"/librockchip_mpp.so*
"${local_lib}"/librockchip_vpu.so*
"${local_lib}"/aarch64-linux-gnu/libdisplay-info.so*
)
((${#runtime_libraries[@]} > 0)) || die "no Rockchip runtime libraries found in upstream package"
mv -- "${runtime_libraries[@]}" "${runtime_lib}/"
shopt -u nullglob
find "${local_lib}" -type f \( -name '*.a' -o -name '*.la' \) -delete
rm -rf -- "${local_lib}/pkgconfig" "${local_lib}/aarch64-linux-gnu/pkgconfig"
rm -f -- \
"${STAGE_DIR}/usr/lib/systemd/system/kodi.service" \
"${STAGE_DIR}/usr/lib/systemd/system/kodi-pulse.service" \
"${STAGE_DIR}/usr/lib/systemd/system/pulseaudio.service"
cp -a -- "${RKMEDIA_ROOT}/packaging/rootfs/." "${STAGE_DIR}/"
mkdir -p -- "${STAGE_DIR}/usr/bin" "${STAGE_DIR}/usr/share/doc/rk1-media-stack"
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/upstream-deb.lock.json"
[[ -x "${STAGE_DIR}/usr/local/bin/kodi" ]] || die "Kodi launcher was not retained at its compiled prefix"
[[ -x "${STAGE_DIR}/usr/local/lib/kodi/kodi-gbm" ]] || die "Kodi GBM binary is missing"
for soname in librga.so.2 libdav1d.so.7 librockchip_mpp.so.1 libdisplay-info.so.4; do
[[ -e "${runtime_lib}/${soname}" ]] || die "relocated runtime is missing ${soname}"
readelf -d "${STAGE_DIR}/usr/local/lib/kodi/kodi-gbm" | grep -Fq "Shared library: [${soname}]" \
|| die "Kodi binary does not declare expected dependency ${soname}"
done
if find "${STAGE_DIR}" -type f -name '*.a' -print -quit | grep -q .; then
die "static library remained after repack"
fi
if find "${STAGE_DIR}/usr/local/lib" -type d -name pkgconfig -print -quit | grep -q .; then
die "pkg-config development directory remained after repack"
fi
"${SCRIPT_DIR}/package-media.sh" \
--stage "${STAGE_DIR}" \
--output-dir "${OUTPUT_DIR}" \
--version "${PACKAGE_VERSION}" \
--depends-from-deb "${INPUT_DEB}"
log "repack complete; authoritative input SHA-256: ${actual_sha256}"
+98
View File
@@ -0,0 +1,98 @@
{
"schema_version": 1,
"generated_at": "2026-08-16T16:00:00Z",
"source_date_epoch": 1786886768,
"target": {
"architecture": "arm64",
"gnu_machine": "aarch64-linux-gnu",
"distribution": "debian",
"suite": "trixie",
"install_prefix": "/opt/rkmedia"
},
"sources": [
{
"name": "mpp",
"description": "Rockchip MPP compatibility branch used by ffmpeg-rockchip and kodi-rockchip-deb",
"repository": "https://github.com/nyanmisaka/mpp.git",
"ref": "refs/heads/jellyfin-mpp",
"commit": "a9380ef333102ac318628f83b5f7a460d377749e",
"committed_at": "2025-12-26T12:59:40Z",
"build": true,
"license_files": ["LICENSES"]
},
{
"name": "rga",
"description": "Rockchip RGA compatibility branch used by ffmpeg-rockchip and kodi-rockchip-deb",
"repository": "https://github.com/nyanmisaka/rk-mirrors.git",
"ref": "refs/heads/jellyfin-rga",
"commit": "1d330cc28551943bed3380261a5a9c6fbd58ff53",
"committed_at": "2025-10-19T08:11:31Z",
"build": true,
"license_files": ["COPYING"]
},
{
"name": "dav1d",
"description": "AV1 software fallback required by the matched FFmpeg/Kodi build",
"repository": "https://code.videolan.org/videolan/dav1d.git",
"ref": "refs/tags/1.5.3",
"commit": "b546257f770768b2c88258c533da38b91a06f737",
"committed_at": "2025-12-31T14:50:45Z",
"build": true,
"license_files": ["COPYING"]
},
{
"name": "ffmpeg-rockchip",
"description": "FFmpeg 8.1 with RKMPP decoders/encoders and RKRGA filters",
"repository": "https://github.com/nyanmisaka/ffmpeg-rockchip.git",
"ref": "refs/heads/8.1",
"commit": "d90e3a1c18d7929383cf88c1b3da2e2d1c966cbf",
"committed_at": "2026-08-10T08:42:00Z",
"build": true,
"license_files": ["COPYING.GPLv2", "COPYING.GPLv3", "COPYING.LGPLv2.1", "COPYING.LGPLv3"]
},
{
"name": "libdisplay-info",
"description": "EDID and DisplayID parser required by Kodi's GBM platform",
"repository": "https://gitlab.freedesktop.org/emersion/libdisplay-info.git",
"ref": "refs/heads/main",
"commit": "f1b75310181e364f97a16464efcd92bc82e57ccc",
"committed_at": "2026-07-27T10:12:35Z",
"build": true,
"license_files": ["LICENSE"]
},
{
"name": "kodi",
"description": "Kodi mainline with current GBM DRM PRIME support",
"repository": "https://github.com/xbmc/xbmc.git",
"ref": "refs/heads/master",
"commit": "9c56bf593441a6c246fdc6931177e71f349ee2bc",
"committed_at": "2026-08-16T13:26:08Z",
"build": true,
"license_files": ["LICENSE.md"]
}
],
"reference_heads": [
{
"name": "kodi-rockchip-deb",
"repository": "https://github.com/armsurvivors/kodi-rockchip-deb.git",
"ref": "refs/heads/main",
"commit": "8540dbd24f180aa43cf2d6e55f2ad17bd4f12530",
"observed_at": "2026-08-16T16:00:00Z"
},
{
"name": "rockchip-linux-mpp-official",
"repository": "https://github.com/rockchip-linux/mpp.git",
"ref": "refs/heads/develop",
"commit": "c08762ebfadeb4e986d2fed993bc7a54862d3ebe",
"observed_at": "2026-08-16T16:00:00Z"
},
{
"name": "airockchip-librga-official",
"repository": "https://github.com/airockchip/librga.git",
"ref": "refs/heads/main",
"commit": "2b32edcb97b601b25683e2941d888c8515da6d55",
"observed_at": "2026-08-16T16:00:00Z"
}
]
}
+17
View File
@@ -0,0 +1,17 @@
{
"schema_version": 1,
"release": "20260721-1741",
"release_url": "https://github.com/armsurvivors/kodi-rockchip-deb/releases/tag/20260721-1741",
"recipe_repository": "https://github.com/armsurvivors/kodi-rockchip-deb.git",
"recipe_commit": "4ceb39b453dbbb1de13bd355e2be2542427e2b1e",
"asset_id": 484995753,
"asset_name": "kodi-rockchip-gbm_arm64_kodi_master_ffmpeg_81_trixie.deb",
"asset_url": "https://github.com/armsurvivors/kodi-rockchip-deb/releases/download/20260721-1741/kodi-rockchip-gbm_arm64_kodi_master_ffmpeg_81_trixie.deb",
"asset_size": 147977956,
"asset_sha256": "f9eed4c02d80f12b443604026fb00c4a6ff5ddd1fe5e6c554d81852a849d261a",
"package": "kodi-rockchip-gbm",
"package_version": "20260721-1741-kodi-master-ffmpeg-81",
"architecture": "arm64",
"embedded_ffmpeg_revision": "388741a",
"notes": "The release recipe cloned moving branches without commit locks. The GitHub asset SHA-256 is therefore the authoritative immutable input."
}