Files
2026-08-24 10:03:24 +08:00

350 lines
15 KiB
Bash

#!/usr/bin/env bash
#
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2026 AMLOGIC
#
# gst-aml-vendor build script for AMLbian
# Cross-compiles vendor gst plugins (amlv4l2h264dec et al) from aml-comp
# sources, packages a .deb into BUILD_DEBS. The install side lives in
# lib/function-img.sh as install_gst_aml_vendor_deb, mirroring libencoder.
# ==============================================================================
# Section 2: Default Configuration
# ==============================================================================
# BOARD and ARCH are set (often readonly) by the armbian framework before this
# script is sourced -- do not reassign. DEB_VERSION is our own variable.
DEB_VERSION="${GST_AML_VENDOR_VERSION:-1.0.0}"
# Cross-compile toolchain prefix; inherits from framework if already set.
: "${CROSS_COMPILE:=aarch64-linux-gnu-}"
# Kernel source sub-directory inside aml-comp (provides vendor DRM uapi headers).
: "${AML_KERNEL_SUBDIR:=aml-6.12}"
# libsecmem prebuilt sub-path inside aml-comp/multimedia/libmediadrm/libsecmem-bin/prebuilt/
: "${LIBSECMEM_VERSION:=${PLATFORM_TDK_VERSION:-v4.4.0}}"
: "${LIBSECMEM_ARCH_DIR:=aarch64.lp64.}"
# ==============================================================================
# Section 4: Build Functions
# ==============================================================================
function __gst_aml_vendor_prepare_source {
local rootfs="$1" comp_dir="$2" work="$3"
local _gnu_triplet="${CROSS_COMPILE%%-}"
# dev headers/.pc files needed for cross-compile. --force-overwrite: vendor
# aml-libgles ships a libgbm that collides with Debian libgbm1 pulled in via
# libgstreamer-plugins-base1.0-dev.
mount_chroot "$rootfs"
chroot "$rootfs" /bin/bash -c "
export DEBIAN_FRONTEND=noninteractive TMPDIR=/tmp
apt-get update -y
apt-get install -y --no-install-recommends \
-o Dpkg::Options::=--force-overwrite \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
libdrm-dev libgudev-1.0-dev libv4l-dev pkg-config
"
local rc=$?
umount_chroot "$rootfs"
[[ $rc -eq 0 ]] || return 1
# Vendor DRM uapi headers + libsecmem prebuilt blob.
install -m 0644 -D \
"${comp_dir}/kernel/${AML_KERNEL_SUBDIR}/common_drivers/include/uapi/amlogic/drm/meson_drm.h" \
"${rootfs}/usr/include/meson_drm.h"
mkdir -p "${rootfs}/usr/include/drm"
cp -a "${comp_dir}/kernel/${AML_KERNEL_SUBDIR}/include/uapi/drm/." "${rootfs}/usr/include/drm/"
local secmem="${comp_dir}/multimedia/libmediadrm/libsecmem-bin/prebuilt"
install -m 0644 -D "${secmem}/${LIBSECMEM_VERSION}/${LIBSECMEM_ARCH_DIR}/libsecmem.so" \
"${rootfs}/usr/lib/${_gnu_triplet}/libsecmem.so"
cp -a "${secmem}/noarch/include/." "${rootfs}/usr/include/"
mkdir -p "${rootfs}/usr/lib/${_gnu_triplet}/pkgconfig"
cp -a "${secmem}/noarch/pkgconfig/." \
"${rootfs}/usr/lib/${_gnu_triplet}/pkgconfig/"
# Stage three vendor source subtrees.
rm -rf "${work}" && mkdir -p "${work}/src"
cp -r "${comp_dir}/multimedia/gst-aml-drmbufferpool1/gst-aml-drmbufferpool-1.0" "${work}/src/drmbufferpool"
cp -r "${comp_dir}/multimedia/gst-aml-drm-plugins1/gst-aml-drm-plugins-1.0/src/secmem" "${work}/src/secmem"
cp -r "${comp_dir}/multimedia/gst-plugin-aml-v4l2dec" "${work}/src/v4l2dec"
# Vendor version_config.sh needs git history we don't have; pre-write the
# generated headers and disable the script.
cat > "${work}/src/drmbufferpool/src/bufferpool/aml_version.h" <<'EOF'
#ifndef AML_VERSION_H
#define AML_VERSION_H
static const char* gst_drmbufferpool_version __attribute__((used)) =
"MM-module-name:gst-plugin-drmbufferpool,version:1.1-amlbian";
#endif
EOF
cat > "${work}/src/v4l2dec/src/aml_version.h" <<'EOF'
#ifndef AML_VERSION_H
#define AML_VERSION_H
static const char* gst_amlv4l2_version __attribute__((used)) =
"MM-module-name:gst-plugin-aml-v4l2dec,version:1.1-amlbian";
#endif
EOF
chmod -x "${work}/src/drmbufferpool/version_config.sh" \
"${work}/src/v4l2dec/version_config.sh" 2>/dev/null || true
# aml_gst_shim.o: two yocto-only buffer pool symbols not in Debian gst 1.22.
# Linked into libgstamlv4l2.so via LDFLAGS; hidden visibility keeps them
# out of the exported symbol space.
cat > "${work}/aml_gst_shim.c" <<'EOF'
#include <limits.h>
typedef void GstBufferPool;
typedef int gboolean;
__attribute__((visibility("hidden")))
int gst_buffer_pool_get_outstanding_num(GstBufferPool *p) { (void)p; return INT_MAX; }
__attribute__((visibility("hidden")))
gboolean gst_buffer_pool_increase_max_num(GstBufferPool *p, unsigned int n) {
(void)p; (void)n; return 1;
}
EOF
# libsecmem.so DT_NEEDED's libmediahal_resman.so (closed source, no blob);
# no-op stubs are enough for non-secure decode.
cat > "${work}/libmediahal_resman_stub.c" <<'EOF'
#include <stddef.h>
int resman_init(int a, int b) { (void)a; (void)b; return 0; }
int resman_close(int a) { (void)a; return 0; }
int resman_query(int a, int b, void *c) { (void)a; (void)b; (void)c; return -1; }
int resman_acquire_para(int a, void *b) { (void)a; (void)b; return -1; }
int resman_acquire_wait(int a) { (void)a; return -1; }
int resman_release(int a) { (void)a; return 0; }
int resman_resource_support(int a) { (void)a; return 0; }
int resman_setappinfo(int a, void *b) { (void)a; (void)b; return 0; }
int resman_support(int a) { (void)a; return 0; }
EOF
cat > "${work}/libteec_stub.c" <<'EOF'
#include <stddef.h>
unsigned int TEEC_InitializeContext(const char *n, void *c) { (void)n; (void)c; return 0xFFFF0008U; }
void TEEC_FinalizeContext(void *c) { (void)c; }
unsigned int TEEC_OpenSession(void *c, void *s, const void *d, unsigned int m,
const void *p, void *o, unsigned int *e)
{ (void)c; (void)s; (void)d; (void)m; (void)p; (void)o;
if (e) *e = 0; return 0xFFFF0008U; }
void TEEC_CloseSession(void *s) { (void)s; }
unsigned int TEEC_InvokeCommand(void *s, unsigned int c, void *p, unsigned int *e)
{ (void)s; (void)c; (void)p; if (e) *e = 0; return 0xFFFF0008U; }
unsigned int TEEC_AllocateSharedMemory(void *c, void *m) { (void)c; (void)m; return 0xFFFF0008U; }
void TEEC_ReleaseSharedMemory(void *m) { (void)m; }
EOF
}
function __gst_aml_vendor_build {
local work="$1" rootfs="$2"
local _gnu_triplet="${CROSS_COMPILE%%-}"
local libdir="$rootfs/usr/lib/${_gnu_triplet}"
local _build_triplet
_build_triplet="$(gcc -dumpmachine)"
if [[ ! -f "$libdir/libmediahal_resman.so" && ! -f "$rootfs/usr/lib/libmediahal_resman.so" ]]; then
${CROSS_COMPILE}gcc -shared -fPIC -O2 \
-Wl,-soname,libmediahal_resman.so \
-o "$libdir/libmediahal_resman.so" "$work/libmediahal_resman_stub.c"
GST_AML_VENDOR_BUNDLE_RESMAN=1
fi
if [[ ! -f "$libdir/libteec.so.2" && ! -f "$rootfs/usr/lib/libteec.so.2" && ! -f "$rootfs/usr/lib/libteec.so.2.0.0" ]]; then
${CROSS_COMPILE}gcc -shared -fPIC -O2 \
-Wl,-soname,libteec.so.2 \
-o "$libdir/libteec.so.2" "$work/libteec_stub.c"
ln -sf libteec.so.2 "$libdir/libteec.so"
GST_AML_VENDOR_BUNDLE_LIBTEEC=1
fi
${CROSS_COMPILE}gcc -fPIC -O2 -c \
-o "$work/aml_gst_shim.o" "$work/aml_gst_shim.c"
export CC=${CROSS_COMPILE}gcc
export AR=${CROSS_COMPILE}ar
export STRIP=${CROSS_COMPILE}strip
export PKG_CONFIG=pkg-config
export PKG_CONFIG_SYSROOT_DIR="$rootfs"
export PKG_CONFIG_LIBDIR="$rootfs/usr/lib/${_gnu_triplet}/pkgconfig:$rootfs/usr/share/pkgconfig:$rootfs/usr/lib/pkgconfig"
unset PKG_CONFIG_PATH
# drmbufferpool + drmallocator (autotools)
( cd "$work/src/drmbufferpool" && mkdir -p m4 build-aux && autoreconf -fi \
&& ./configure --host=${_gnu_triplet} --build=${_build_triplet} \
--prefix=/usr --libdir=/usr/lib/${_gnu_triplet} \
--with-sysroot="$rootfs" \
CFLAGS="--sysroot=$rootfs" CPPFLAGS="--sysroot=$rootfs" \
LDFLAGS="--sysroot=$rootfs" \
&& make -j"$(nproc)" \
&& make install DESTDIR="$rootfs" ) || return 1
# secmemallocator (single .c)
local CFLAGS_PKG LIBS_PKG
CFLAGS_PKG=$(pkg-config --cflags gstreamer-1.0 gstreamer-base-1.0 \
gstreamer-allocators-1.0 libsecmem) || return 1
LIBS_PKG=$(pkg-config --libs gstreamer-1.0 gstreamer-base-1.0 \
gstreamer-allocators-1.0 libsecmem) || return 1
( cd "$work/src/secmem" \
&& ${CROSS_COMPILE}gcc -shared -fPIC -O2 --sysroot="$rootfs" \
$CFLAGS_PKG gstsecmemallocator.c $LIBS_PKG \
-Wl,-soname,libgstsecmemallocator.so.0 \
-o "$libdir/libgstsecmemallocator.so.0.0.0" ) || return 1
ln -sf libgstsecmemallocator.so.0.0.0 "$libdir/libgstsecmemallocator.so.0"
ln -sf libgstsecmemallocator.so.0.0.0 "$libdir/libgstsecmemallocator.so"
install -m 0644 -D "$work/src/secmem/gstsecmemallocator.h" \
"$rootfs/usr/include/gstreamer-1.0/gst/allocators/gstsecmemallocator.h"
cat > "$libdir/pkgconfig/gstsecmemallocator.pc" <<EOF
prefix=/usr
libdir=/usr/lib/${_gnu_triplet}
includedir=/usr/include/gstreamer-1.0
Name: gstsecmemallocator
Description: Amlogic gst secmem allocator
Version: 1.0
Libs: -L\${libdir} -lgstsecmemallocator
Cflags: -I\${includedir}
EOF
# v4l2dec (autotools). All deps live in $rootfs so libtool relink works.
# aml_gst_shim.o linked in directly (vs a separate libaml_gst_shim.so).
( cd "$work/src/v4l2dec" && mkdir -p m4 build-aux && autoreconf -fi \
&& ./configure --host=${_gnu_triplet} --build=${_build_triplet} \
--prefix=/usr --libdir=/usr/lib/${_gnu_triplet} \
--with-sysroot="$rootfs" \
CFLAGS="--sysroot=$rootfs" CPPFLAGS="--sysroot=$rootfs" \
LDFLAGS="--sysroot=$rootfs -L$libdir $work/aml_gst_shim.o" \
&& make TARGET_DIR="$rootfs" -j"$(nproc)" \
&& make install TARGET_DIR="$rootfs" DESTDIR="$rootfs" ) || return 1
[[ -f "$libdir/gstreamer-1.0/libgstamlv4l2.so" ]] || {
echo "v4l2dec install MISSING plugin"; return 1; }
}
function __gst_aml_vendor_create_deb {
local rootfs="$1" build_root="$2"
local _gnu_triplet="${CROSS_COMPILE%%-}"
local pkg_name="gst-aml-vendor"
local deb_dir="${build_root}/deb/${pkg_name}-${DEB_VERSION}"
local rdir="$rootfs/usr/lib/${_gnu_triplet}"
local idir="${deb_dir}/usr/lib/${_gnu_triplet}"
rm -rf "${build_root}/deb"
mkdir -p "${deb_dir}/DEBIAN" "$idir/gstreamer-1.0"
[[ "$GST_AML_VENDOR_BUNDLE_RESMAN" ]] && \
install -m 0755 "$rdir/libmediahal_resman.so" "$idir/"
if [[ "$GST_AML_VENDOR_BUNDLE_LIBTEEC" ]]; then
install -m 0755 "$rdir/libteec.so.2" "$idir/"
ln -sf libteec.so.2 "$idir/libteec.so"
fi
install -m 0644 "$rdir/libsecmem.so" "$idir/"
local lib
for lib in libgstdrmbufferpool libgstdrmallocator libgstsecmemallocator; do
cp -a "$rdir/${lib}.so.0.0.0" "$idir/"
ln -sf "${lib}.so.0.0.0" "$idir/${lib}.so.0"
ln -sf "${lib}.so.0.0.0" "$idir/${lib}.so"
done
install -m 0755 "$rdir/gstreamer-1.0/libgstamlv4l2.so" "$idir/gstreamer-1.0/"
cat > "${deb_dir}/DEBIAN/control" <<EOF
Package: ${pkg_name}
Version: ${DEB_VERSION}
Architecture: ${ARCH}
Maintainer: Armbian Build <[email protected]>
Section: libs
Priority: optional
Depends: libc6, libgstreamer1.0-0, libgstreamer-plugins-base1.0-0, libdrm2, libgudev-1.0-0, libv4l-0
Description: Amlogic vendor GStreamer plugins (amlv4l2h264dec et al)
Vendor GStreamer plugins for hardware video decode on Amlogic SoCs.
EOF
cat > "${deb_dir}/DEBIAN/postinst" <<'EOF'
#!/bin/sh
set -e
if [ "$1" = "configure" ]; then
command -v ldconfig >/dev/null 2>&1 && ldconfig
rm -f /root/.cache/gstreamer-1.0/registry.* 2>/dev/null || true
fi
EOF
chmod 0755 "${deb_dir}/DEBIAN/postinst"
( cd "${build_root}/deb" && dpkg-deb --build "${pkg_name}-${DEB_VERSION}" )
local out="${BUILD_DEBS:-${SRC}/output}"
mkdir -p "${out}"
mv "${build_root}/deb/${pkg_name}-${DEB_VERSION}.deb" \
"${out}/linux-${pkg_name}-${BOARD}-amlbian_${DEB_VERSION}_${ARCH}.deb"
}
function __gst_aml_vendor_cleanup_rootfs {
local rootfs="$1"
local _gnu_triplet="${CROSS_COMPILE%%-}"
mount_chroot "$rootfs"
# `remove` not `autoremove` -- autoremove greedily purges packages it
# considers orphans, including PACKAGE_LIST_AML runtime libs.
# Do NOT apt-get remove dev packages here: subsequent build steps
# (venc, jpeg, dma-allocator, gfx2d, conv) still need libdrm-dev,
# libgstreamer-plugins-base1.0-dev, pkg-config headers/pc-files.
# Only clean the apt cache to reclaim space.
chroot "$rootfs" /bin/bash -c "
export DEBIAN_FRONTEND=noninteractive
apt-get clean
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb
" || true
umount_chroot "$rootfs"
# Compile-only artifacts (headers + .pc). The .so files stay -- dpkg
# owns them now via the .deb just installed.
local rdir="$rootfs/usr/lib/${_gnu_triplet}"
rm -f "$rdir/pkgconfig/libsecmem.pc" \
"$rdir/pkgconfig/gstsecmemallocator.pc" \
"$rootfs/usr/include/secmem.h" \
"$rootfs/usr/include/secmem-ca.h" \
"$rootfs/usr/include/meson_drm.h" \
"$rootfs/usr/include/gstreamer-1.0/gst/allocators/gstsecmemallocator.h" 2>/dev/null
rm -rf "$rootfs/usr/include/drm" 2>/dev/null
}
# ==============================================================================
# Section 5: Main
# ==============================================================================
function amlbian_build_gst_aml_vendor {
is_unit_enabled "gst-aml-vendor" || {
display_alert "[SKIP] >> gst-aml-vendor disable in BUILD_UNITS" "" "info"
return 0
}
local rootfs="${ROOTFS_TEMP:-${SDCARD:-}}"
[[ -d "${rootfs}" ]] || { display_alert "GST-AML-VENDOR" "no rootfs" "err"; return 1; }
display_alert "AMLOGIC: Building gst-aml-vendor ${DEB_VERSION} ${BOARD} ${ARCH}" "info"
local comp_dir="$(amlbian_get_aml_comp_dir)"
local build_root="${SRC:-/tmp}/.tmp/gst-aml-vendor-build-${ARCH}"
local work="${build_root}/work"
local out="${BUILD_DEBS:-${SRC}/output}"
local build_log="${out}/gst-aml-vendor-build.log"
rm -rf "${build_root}" && mkdir -p "${work}" "${out}"
local rc
(
set -x
__gst_aml_vendor_prepare_source "$rootfs" "$comp_dir" "$work" || exit 1
__gst_aml_vendor_build "$work" "$rootfs" || exit 1
__gst_aml_vendor_create_deb "$rootfs" "$build_root" || exit 1
__gst_aml_vendor_cleanup_rootfs "$rootfs" || true
) > "$build_log" 2>&1
rc=$?
rm -rf "$work"
if [[ $rc -ne 0 ]]; then
display_alert "GST-AML-VENDOR" "build FAILED -- log: $build_log" "err"
return 1
fi
display_alert "AMLOGIC: gst-aml-vendor build completed" "$out" "info"
return 0
}
# Build runs in docker phase (needs rootfs as sysroot), so this script does
# NOT auto-invoke; install_gst_aml_vendor_deb in lib/function-img.sh drives it.
# ==============================================================================
# End of build-gst-aml-vendor.sh
# ==============================================================================