#!/usr/bin/env bash # SPDX-License-Identifier: MIT # Copyright (c) 2026 AArts Lab # # Builds the LGPL FFmpeg the Linux packages of Bernard Review bundle -- FFmpeg 8.1.3 (libavcodec 62, # libavformat 62, libavutil 60, libswscale 9, libswresample 6), LGPL version 2.1 or later -- into the same # prefix as the OpenEXR 3.4 / OpenImageIO 3.1 stack. The distributions' FFmpeg is GPL (Ubuntu 26.04's # libavcodec reports "GPL version 2 or later", RPM Fusion's ffmpeg-libs 5.1 on Rocky 9 "GPL version 3 or # later"), so the packages no longer depend on it. tools/linux/build_deps_exr34.sh runs this as its last # stage; on its own it adds FFmpeg to a prefix that script already built (a few minutes). No root. # # Usage: tools/linux/build_ffmpeg_lgpl.sh [--check] [work_dir] # tools/linux/build_ffmpeg_lgpl.sh [--apt] [--check] --companion [work_dir] # --check only check the build tools and -dev packages, build nothing (exit 0 or 3) # the dependency prefix (e.g. ~/deps-exr34, /opt/deps-exr34); FFmpeg lands in its lib/, include/ # [work_dir] where the tarballs are downloaded and built (default: -src, /work) # JOBS= parallel jobs (default: nproc) # --companion build instead the ffmpeg program the streaming companion (bernard-stream) runs as a child # process, into /-companion, with its source archive (see "Companion" below) # --apt (with --companion) install the build packages with apt-get first (root in a Debian / Ubuntu # container) # # Sources, pinned with the SHA-256 of each tarball as downloaded on 2026-09-28 (a mismatch stops the script): # ffmpeg.org's release tarball (its GPG signature was checked against the FFmpeg release signing key, # FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8), the nv-codec-headers tag (MIT, header-only; NVENC / # NVDEC / CUVID load the NVIDIA driver at run time, Linux driver 550.54.14 or newer) and, when the machine has # no nasm, nasm's release tarball, built in /tools for this build only (never installed or shipped). # The FFmpeg tarball is archived in /share/bernard-sources, and /share/bernard-licenses gets # FFmpeg's COPYING.LGPLv2.1 and LICENSE.md, the nv-codec-headers notices and FFmpeg-BUILD.txt (version, # source URL, SHA-256, configure line), which the packages install with the other licence files. # # Configure: LGPL (no --enable-gpl, --enable-nonfree or --enable-version3: nothing used needs them), shared # libraries only, no programs, no documentation, no libavdevice / libavfilter (the player links neither). # --disable-autodetect, then only what is named: zlib, iconv, the NVIDIA interfaces, and VAAPI with libdrm # when libva's -dev headers are there (otherwise the build goes on without VAAPI and says so). No external # codec library at all: the decoders, demuxers and parsers are FFmpeg's own (all of them), and so are the # encoders the export uses (prores_ks, dnxhd, mjpeg, png, aac, pcm_*). Every library gets the RUNPATH $ORIGIN. # The shipped libraries must not carry the builder's home or name: FFmpeg records its configure line # (avcodec_configuration()) and source paths (__FILE__), so it is configured with the neutral prefix # /tmp/bernard-deps (a symbolic link to ) and unpacked and built under /tmp/bernard-ffmpeg-build; the # pkg-config files are then pointed back at , and the libraries are checked to hold no /home/ path. # The last step compiles a check against the installed libavcodec: avcodec_license() must say LGPL. # # Companion (--companion): one ffmpeg program with FFmpeg's libraries linked in statically (it needs only the # system's glibc, zlib, libva, libva-drm and libdrm), the same pinned sources and LGPL configure rules, run in # the container the Windows build uses: # IMG=docker.io/library/ubuntu@sha256:496754492fb28b4d3049432f2ca787449331e23fb14f0dd3fffea86bf5a93eb4 # podman run --rm -v "$PWD":/src:ro -v ~/ffmpeg-linux:/work $IMG \ # bash /src/tools/linux/build_ffmpeg_lgpl.sh --apt --companion /work/out /work # --disable-everything, then only the components of the companion's command lines (the start-up probe: # rawvideo on a pipe; the stream: Matroska V_UNCOMPRESSED RGBA on a pipe; both: scale / format / setparams to # BT.709 limited NV12, for VAAPI hwupload, then an H.264 encoder and h264_metadata, FLV on a pipe): protocols # pipe and file, demuxers rawvideo and matroska, decoder rawvideo, muxer flv, encoders h264_nvenc and # h264_vaapi (hardware only: no software H.264 encoder), filters scale, format, setparams, hwupload, the # h264_metadata bitstream filter; and, so that the binary can check its own output (the companion's colour # round-trip test decodes the FLV it wrote with the same ffmpeg), demuxer flv, parser h264, decoder h264, # encoder and muxer rawvideo. NVENC needs the NVIDIA driver 550.54.14 or newer (the pinned nv-codec-headers 12.2 API). # No QSV (no libvpl on Linux), no libavdevice, no ffplay, no Opus. # # Exit status: 0 built; 1 a check after the build failed; 2 usage or download error; 3 a required tool or # -dev package is missing (nothing is built; the message names the packages to install). set -euo pipefail CHECK_ONLY=0 COMPANION=0 APT=0 while [ $# -gt 0 ]; do case "$1" in --check) CHECK_ONLY=1; shift ;; --companion) COMPANION=1; shift ;; --apt) APT=1; shift ;; *) break ;; esac done if [ $# -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ] || { [ $APT = 1 ] && [ $COMPANION = 0 ]; }; then sed -n '4,/^set -euo/p' "$0" | sed '$d; s/^# \{0,1\}//' exit 2 fi if [ $COMPANION = 1 ]; then OUT=$(mkdir -p "$1" && cd "$1" && pwd) WORK=${2:-$OUT/work} # nv-codec-headers only (nothing of it is shipped but notices): a neutral path, as the build's. PREFIX=/tmp/bernard-ffmpeg-companion-deps rm -rf "${PREFIX:?}" mkdir -p "$PREFIX" else PREFIX=$(mkdir -p "$1" && cd "$1" && pwd) WORK=${2:-${PREFIX}-src} fi mkdir -p "$WORK/tarballs" WORK=$(cd "$WORK" && pwd) JOBS=${JOBS:-$(nproc)} if [ $APT = 1 ]; then printf '\n=== apt-get install (companion build packages)\n' export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq --no-install-recommends gcc libc6-dev make pkgconf curl ca-certificates xz-utils \ zlib1g-dev libva-dev libdrm-dev nasm binutils >/dev/null fi FFMPEG_VERSION=8.1.3 FFMPEG_URL=https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz FFMPEG_SHA256=7138d28c96d9d3e3af4ee3d8cad72741f8ffb40da90c1112235dea3ecd3178a3 NVCODEC_TAG=n12.2.72.0 NVCODEC_URL=https://github.com/FFmpeg/nv-codec-headers/archive/refs/tags/${NVCODEC_TAG}.tar.gz NVCODEC_SHA256=dbeaec433d93b850714760282f1d0992b1254fc3b5a6cb7d76fc1340a1e47563 NASM_VERSION=2.16.03 NASM_URL=https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/nasm-${NASM_VERSION}.tar.xz NASM_SHA256=1412a1c760bbd05db026b6c0d1657affd6631cd0a63cddb6f73cc6d4aa616148 log() { printf '\n=== %s\n' "$*"; } DISTRO=other if [ -r /etc/os-release ]; then . /etc/os-release case " ${ID:-} ${ID_LIKE:-} " in *" debian "*|*" ubuntu "*) DISTRO=deb ;; *" rhel "*|*" fedora "*|*" centos "*|*" rocky "*) DISTRO=rpm ;; esac fi has_header() { local d for d in "$PREFIX/include" /usr/local/include /usr/include /usr/include/x86_64-linux-gnu; do [ -e "$d/$1" ] && return 0 done return 1 } has_cmd() { command -v "$1" >/dev/null 2>&1; } pkg() { if [ "$DISTRO" = rpm ]; then echo "$2"; else echo "$1"; fi; } MISSING_REQUIRED=() has_cmd make || MISSING_REQUIRED+=("$(pkg make make)") has_cmd cc || MISSING_REQUIRED+=("$(pkg gcc gcc)") has_cmd pkg-config || MISSING_REQUIRED+=("$(pkg pkg-config pkgconf-pkg-config)") has_cmd curl || MISSING_REQUIRED+=("$(pkg curl curl)") has_cmd xz || MISSING_REQUIRED+=("$(pkg xz-utils xz)") has_header zlib.h || MISSING_REQUIRED+=("$(pkg zlib1g-dev zlib-devel)") if [ ${#MISSING_REQUIRED[@]} -gt 0 ]; then echo "FFmpeg: missing tools or -dev packages, nothing built: ${MISSING_REQUIRED[*]}" >&2 exit 3 fi # VAAPI (libva with its DRM backend, and libdrm): optional, and a system dependency of the packages when built. WITH_VAAPI=0 MISSING_OPTIONAL=() if has_header va/va.h && has_header va/va_drm.h && has_header xf86drm.h; then WITH_VAAPI=1 else has_header va/va_drm.h || MISSING_OPTIONAL+=("$(pkg libva-dev libva-devel)") has_header xf86drm.h || MISSING_OPTIONAL+=("$(pkg libdrm-dev libdrm-devel)") echo "FFmpeg: VAAPI headers not found, FFmpeg is built without VAAPI (hardware decode and h264_vaapi /" \ "hevc_vaapi): install ${MISSING_OPTIONAL[*]} and run this again to have it." >&2 fi NASM_NOTE="" if ! has_cmd nasm; then NASM_NOTE="nasm not found ($(pkg nasm nasm)): nasm ${NASM_VERSION} is built from its release tarball in $WORK/tools, for this build only" echo "FFmpeg: $NASM_NOTE" >&2 fi if [ $COMPANION = 1 ] && [ $WITH_VAAPI = 0 ]; then echo "FFmpeg (companion): h264_vaapi is required: install ${MISSING_OPTIONAL[*]}" >&2 exit 3 fi if [ $CHECK_ONLY = 1 ]; then exit 0; fi # fetch : downloaded once into /tarballs, checked every time. fetch() { local file="$WORK/tarballs/$1" url=$2 sum=$3 if [ ! -f "$file" ]; then log "download $url" curl -fL --retry 3 -o "$file.part" "$url" mv "$file.part" "$file" fi if ! echo "$sum $file" | sha256sum -c --status; then echo "SHA-256 mismatch for $file: expected $sum, got $(sha256sum "$file" | cut -d' ' -f1)" >&2 exit 2 fi } T_ALL=$SECONDS LIC="$PREFIX/share/bernard-licenses" mkdir -p "$LIC" "$PREFIX/share/bernard-sources" # nasm: FFmpeg's x86 SIMD is assembled by it; without it FFmpeg would be built without its assembly. if ! has_cmd nasm; then fetch "nasm-${NASM_VERSION}.tar.xz" "$NASM_URL" "$NASM_SHA256" rm -rf "${WORK:?}/nasm-${NASM_VERSION}" tar -xJf "$WORK/tarballs/nasm-${NASM_VERSION}.tar.xz" -C "$WORK" log "nasm ${NASM_VERSION}: build (build tool only, in $WORK/tools)" (cd "$WORK/nasm-${NASM_VERSION}" && ./configure --prefix="$WORK/tools" >/dev/null && make -j "$JOBS" >/dev/null && make install >/dev/null) export PATH="$WORK/tools/bin:$PATH" fi echo "nasm: $(command -v nasm) ($(nasm -v))" # nv-codec-headers: headers and ffnvcodec.pc into the prefix (nothing to compile, nothing shipped but notices). fetch "nv-codec-headers-${NVCODEC_TAG}.tar.gz" "$NVCODEC_URL" "$NVCODEC_SHA256" rm -rf "${WORK:?}/nv-codec-headers-${NVCODEC_TAG}" tar -xzf "$WORK/tarballs/nv-codec-headers-${NVCODEC_TAG}.tar.gz" -C "$WORK" make -C "$WORK/nv-codec-headers-${NVCODEC_TAG}" PREFIX="$PREFIX" LIBDIR=lib install >/dev/null # The MIT notice at the top of each header (there is no separate licence file). : > "$LIC/nv-codec-headers-LICENSE.txt" for h in "$WORK/nv-codec-headers-${NVCODEC_TAG}"/include/ffnvcodec/*.h; do { echo "== nv-codec-headers ${NVCODEC_TAG}, include/ffnvcodec/$(basename "$h") ==" sed -n '1,/\*\//p' "$h" echo; } >> "$LIC/nv-codec-headers-LICENSE.txt" done # The companion's ffmpeg: configured with the neutral prefix /tmp/bernard-ffmpeg-companion, unpacked and built # under /tmp/bernard-ffmpeg-build (FFmpeg records both), packed with its licences and its source archive. if [ $COMPANION = 1 ]; then NAME=ffmpeg-${FFMPEG_VERSION}-bernard-lgpl-linux-x86_64-companion CPREFIX=/tmp/bernard-ffmpeg-companion BUILD_ROOT=/tmp/bernard-ffmpeg-build fetch "ffmpeg-${FFMPEG_VERSION}.tar.xz" "$FFMPEG_URL" "$FFMPEG_SHA256" rm -rf "${BUILD_ROOT:?}" "${CPREFIX:?}" SRC="$BUILD_ROOT/ffmpeg-${FFMPEG_VERSION}" BLD="$BUILD_ROOT/build" mkdir -p "$BLD" tar -xJf "$WORK/tarballs/ffmpeg-${FFMPEG_VERSION}.tar.xz" -C "$BUILD_ROOT" CONFIGURE_ARGS=( --prefix="$CPREFIX" --enable-static --disable-shared --disable-programs --enable-ffmpeg --disable-doc --disable-debug --disable-avdevice --disable-autodetect --disable-everything --enable-zlib --enable-ffnvcodec --enable-cuda --enable-nvenc --enable-vaapi --enable-libdrm --enable-protocol=pipe,file --enable-demuxer=rawvideo,matroska,flv --enable-muxer=flv,rawvideo --enable-decoder=rawvideo,h264 --enable-parser=h264 --enable-encoder=h264_nvenc,h264_vaapi,rawvideo --enable-filter=scale,format,setparams,hwupload --enable-bsf=h264_metadata ) log "FFmpeg ${FFMPEG_VERSION} (companion): configure ${CONFIGURE_ARGS[*]}" (cd "$BLD" && PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" \ "$SRC/configure" "${CONFIGURE_ARGS[@]}") > "$BUILD_ROOT/configure.log" 2>&1 || { tail -40 "$BUILD_ROOT/configure.log"; tail -60 "$BLD/ffbuild/config.log"; exit 1; } cat "$BUILD_ROOT/configure.log" if grep -qE '^#define CONFIG_(GPL|GPLV3|VERSION3|NONFREE) 1' "$BLD/config.h"; then echo "FFmpeg configured GPL, version 3 or nonfree -- check the configure line above" >&2 exit 1 fi for want in CONFIG_FFMPEG CONFIG_ZLIB CONFIG_FFNVCODEC CONFIG_CUDA CONFIG_NVENC CONFIG_VAAPI CONFIG_LIBDRM \ CONFIG_H264_NVENC_ENCODER CONFIG_H264_VAAPI_ENCODER CONFIG_RAWVIDEO_DEMUXER CONFIG_MATROSKA_DEMUXER \ CONFIG_RAWVIDEO_DECODER CONFIG_FLV_MUXER CONFIG_PIPE_PROTOCOL CONFIG_FILE_PROTOCOL CONFIG_SCALE_FILTER \ CONFIG_FORMAT_FILTER CONFIG_SETPARAMS_FILTER CONFIG_HWUPLOAD_FILTER CONFIG_H264_METADATA_BSF; do grep -qh "^#define $want 1" "$BLD/config.h" "$BLD/config_components.h" || { echo "FFmpeg configured without $want" >&2; exit 1; } done ENCODERS=$(grep -oE '^#define CONFIG_[A-Z0-9_]+_ENCODER 1' "$BLD/config_components.h" | awk '{print $2}' | LC_ALL=C sort | tr '\n' ' ') if [ "$ENCODERS" != "CONFIG_H264_NVENC_ENCODER CONFIG_H264_VAAPI_ENCODER CONFIG_RAWVIDEO_ENCODER " ]; then echo "FFmpeg (companion) configured with other encoders: $ENCODERS" >&2 exit 1 fi EXTERNAL=$(grep -oE '^#define CONFIG_LIB[A-Z0-9_]+ 1' "$BLD/config.h" | awk '{print $2}' | tr '\n' ' ') if [ "$EXTERNAL" != "CONFIG_LIBDRM " ]; then echo "FFmpeg (companion) configured with external libraries other than libdrm: $EXTERNAL" >&2 exit 1 fi log "FFmpeg ${FFMPEG_VERSION} (companion): build ($JOBS jobs)" make -C "$BLD" -j "$JOBS" >"$BUILD_ROOT/make.log" 2>&1 || { tail -60 "$BUILD_ROOT/make.log"; exit 1; } make -C "$BLD" install >/dev/null PKG="$OUT/$NAME" rm -rf "${PKG:?}" "$OUT/$NAME-src.tar" mkdir -p "$PKG/licenses" cp "$CPREFIX/bin/ffmpeg" "$PKG/ffmpeg" cp "$SRC/COPYING.LGPLv2.1" "$PKG/LICENSE.txt" cp "$SRC/COPYING.LGPLv2.1" "$PKG/licenses/FFmpeg-COPYING.LGPLv2.1.txt" cp "$SRC/LICENSE.md" "$PKG/licenses/FFmpeg-LICENSE.md" cp "$LIC/nv-codec-headers-LICENSE.txt" "$PKG/licenses/" cp "$0" "$PKG/licenses/build_ffmpeg_lgpl.sh" log "FFmpeg ${FFMPEG_VERSION} (companion): check" F="$PKG/ffmpeg" NEEDED=$(readelf -d "$F" | sed -n 's/.*(NEEDED).*\[\(.*\)\]/\1/p' | LC_ALL=C sort | tr '\n' ' ') echo "needs: $NEEDED" for n in $NEEDED; do # libdl, libpthread and librt are glibc too: separate libraries before glibc 2.34 (the el8 build, glibc 2.28). case " libc.so.6 libm.so.6 libz.so.1 libva.so.2 libva-drm.so.2 libdrm.so.2 libdl.so.2 libpthread.so.0 librt.so.1 " in *" $n "*) ;; *) echo "ffmpeg needs $n, not glibc, zlib, libva or libdrm" >&2; exit 1 ;; esac done GLIBC_MAX=$(objdump -T "$F" | grep -oE 'GLIBC_[0-9.]+' | sort -uV | tail -1) echo "newest glibc symbol version: $GLIBC_MAX" leaks=$(strings -a "$F" | grep -F -e /home/ -e /root/ -e /work -e "$WORK" -e "$OUT" -e "$HOME/" || true) user=$(id -un) if [ "$user" != root ]; then leaks+=$(strings -a "$F" | grep -F -e "$user" || true); fi if [ -n "$leaks" ]; then echo "$F holds paths of the build machine:" >&2; echo "$leaks" | head -5 >&2 exit 1 fi if strings -a "$F" | grep -qE -e '--enable-(gpl|nonfree|version3|libopenh264|libkvazaar|libx26[45])'; then echo "$F: its configuration names a GPL, nonfree or external codec option" >&2; exit 1 fi "$F" -hide_banner -L | grep -q 'GNU Lesser General Public' || { echo "ffmpeg -L does not say LGPL" >&2; exit 1; } ENC_LIST=$("$F" -hide_banner -encoders | awk 'f && $1 ~ /^V/ {print $2} /^ *-+$/ {f=1}' | LC_ALL=C sort | tr '\n' ' ') [ "$ENC_LIST" = "h264_nvenc h264_vaapi rawvideo " ] || { echo "ffmpeg -encoders: $ENC_LIST" >&2; exit 1; } CONFIGURATION=$(sed -n 's/^#define FFMPEG_CONFIGURATION "\(.*\)"$/\1/p' "$BLD/config.h") PKGVERS=$(dpkg-query -W -f '${Package} ${Version}\n' gcc libc6-dev binutils nasm libva-dev libdrm-dev zlib1g-dev 2>/dev/null \ || echo "(dpkg-query not available)") { echo "FFmpeg ${FFMPEG_VERSION} for Linux x86_64, LGPL version 2.1 or later: the ffmpeg program that the" echo "Bernard Review streaming companion runs (--companion: only its components, see the configure line)." echo "Built by tools/linux/build_ffmpeg_lgpl.sh --companion (a copy is in licenses/)." echo echo "Licence: LICENSE.txt is FFmpeg's COPYING.LGPLv2.1. licenses/: FFmpeg's LICENSE.md, nv-codec-headers (MIT)." echo "No external codec library. NVENC: nv-codec-headers ${NVCODEC_TAG} (NVENC API 12.2), NVIDIA driver 550.54.14" echo "or newer. VAAPI: the system's libva 2 / libva-drm 2 / libdrm 2 (MIT), loaded as shared libraries." echo "Shared libraries needed: ${NEEDED}(newest glibc symbol version ${GLIBC_MAX})" echo "Encoders (ffmpeg -encoders): ${ENC_LIST}" echo echo "Sources (unmodified; both are in ${NAME}-src.tar, to publish with each release):" echo " FFmpeg ${FFMPEG_VERSION} ${FFMPEG_URL}" echo " SHA-256 ${FFMPEG_SHA256}" echo " nv-codec-headers ${NVCODEC_TAG} ${NVCODEC_URL}" echo " SHA-256 ${NVCODEC_SHA256}" echo echo "Configure line (ffmpeg -buildconf):" echo " ${CONFIGURATION}" echo echo "Build container: ${BERNARD_BUILD_IMAGE:-(not given: set BERNARD_BUILD_IMAGE)}" echo "Packages:" echo "$PKGVERS" | sed 's/^/ /' echo echo "SHA-256 of the files:" (cd "$PKG" && sha256sum ffmpeg | sed 's/^/ /') } > "$PKG/BUILD.txt" SRC_DIR="$BUILD_ROOT/$NAME-src" mkdir -p "$SRC_DIR" cp "$WORK/tarballs/ffmpeg-${FFMPEG_VERSION}.tar.xz" "$WORK/tarballs/nv-codec-headers-${NVCODEC_TAG}.tar.gz" "$SRC_DIR/" cp "$0" "$SRC_DIR/build_ffmpeg_lgpl.sh" cp "$PKG/BUILD.txt" "$SRC_DIR/BUILD.txt" # Fixed dates (the FFmpeg tarball's own), so the same inputs give the same archive. EPOCH=$(TZ=UTC date -d "$(TZ=UTC tar -tvJf "$WORK/tarballs/ffmpeg-${FFMPEG_VERSION}.tar.xz" --full-time \ "ffmpeg-${FFMPEG_VERSION}/VERSION" | awk '{print $4" "$5}')" +%s) find "$PKG" "$SRC_DIR" -exec touch -h -d "@$EPOCH" {} + tar --sort=name --mtime="@$EPOCH" --owner=0 --group=0 --numeric-owner \ -cf "$OUT/$NAME-src.tar" -C "$BUILD_ROOT" "$NAME-src" rm -rf "${BUILD_ROOT:?}" "${CPREFIX:?}" "${PREFIX:?}" log "FFmpeg ${FFMPEG_VERSION} (companion): done in $((SECONDS - T_ALL)) s" (cd "$OUT" && sha256sum "$NAME/ffmpeg" "$NAME-src.tar") exit 0 fi # FFmpeg, from the neutral paths (see the top): NEUTRAL -> , sources and build under BUILD_ROOT. NEUTRAL=/tmp/bernard-deps BUILD_ROOT=/tmp/bernard-ffmpeg-build if [ -e "$NEUTRAL" ] && [ ! -L "$NEUTRAL" ]; then echo "$NEUTRAL exists and is not a symbolic link: remove it (it is the neutral prefix FFmpeg is configured with)" >&2 exit 2 fi ln -sfn "$PREFIX" "$NEUTRAL" fetch "ffmpeg-${FFMPEG_VERSION}.tar.xz" "$FFMPEG_URL" "$FFMPEG_SHA256" SRC="$BUILD_ROOT/ffmpeg-${FFMPEG_VERSION}" BLD="$BUILD_ROOT/build" rm -rf "${BUILD_ROOT:?}" mkdir -p "$BLD" tar -xJf "$WORK/tarballs/ffmpeg-${FFMPEG_VERSION}.tar.xz" -C "$BUILD_ROOT" HW_ARGS=(--enable-ffnvcodec --enable-cuda --enable-cuvid --enable-nvdec --enable-nvenc) if [ $WITH_VAAPI = 1 ]; then HW_ARGS+=(--enable-vaapi --enable-libdrm); fi CONFIGURE_ARGS=( --prefix="$NEUTRAL" --libdir="$NEUTRAL/lib" --shlibdir="$NEUTRAL/lib" --incdir="$NEUTRAL/include" --enable-shared --disable-static --disable-programs --disable-doc --disable-debug --disable-avdevice --disable-avfilter --disable-autodetect --enable-zlib --enable-iconv "${HW_ARGS[@]}" ) log "FFmpeg ${FFMPEG_VERSION}: configure ${CONFIGURE_ARGS[*]}" (cd "$BLD" && PKG_CONFIG_PATH="$NEUTRAL/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" \ "$SRC/configure" "${CONFIGURE_ARGS[@]}") if grep -qE '^#define CONFIG_(GPL|GPLV3|NONFREE) 1' "$BLD/config.h"; then echo "FFmpeg configured GPL or nonfree -- check the configure line above" >&2 exit 1 fi # RUNPATH $ORIGIN, given to make rather than on the configure line (which avcodec_configuration() records): # ffbuild/library.mak expands the link line twice, hence $$$$, and the quotes keep it from the shell. printf '%s\n' "LDSOFLAGS += -Wl,-rpath,'\$\$\$\$ORIGIN'" >> "$BLD/ffbuild/config.mak" log "FFmpeg ${FFMPEG_VERSION}: build ($JOBS jobs)" make -C "$BLD" -j "$JOBS" make -C "$BLD" install # The pkg-config files name the neutral prefix: point them back at (the link is repointed by the # next run, and /tmp does not outlive a reboot). for pc in "$PREFIX"/lib/pkgconfig/lib{avcodec,avformat,avutil,swscale,swresample}.pc; do sed -i "s#$NEUTRAL#$PREFIX#g" "$pc" done cp "$WORK/tarballs/ffmpeg-${FFMPEG_VERSION}.tar.xz" "$PREFIX/share/bernard-sources/" cp "$SRC/COPYING.LGPLv2.1" "$LIC/FFmpeg-COPYING.LGPLv2.1" cp "$SRC/LICENSE.md" "$LIC/FFmpeg-LICENSE.md" # The check: the installed libraries, as the player will load them. log "FFmpeg ${FFMPEG_VERSION}: check" cat > "$BLD/bernard_licence_check.c" <<'EOF' #include #include #include #include #include #include int main(void) { const char *lic = avcodec_license(); printf("avcodec_version: %u.%u.%u\n", avcodec_version() >> 16, (avcodec_version() >> 8) & 0xff, avcodec_version() & 0xff); printf("avcodec_license: %s\n", lic); printf("avformat_license: %s\nswscale_license: %s\nswresample_license: %s\n", avformat_license(), swscale_license(), swresample_license()); printf("avcodec_configuration: %s\n", avcodec_configuration()); const char *need[] = {"prores_ks", "dnxhd", "mjpeg", "png", "aac", "pcm_s24le", "h264_nvenc", "hevc_nvenc", 0}; int bad = strstr(lic, "LGPL") == NULL; for (int i = 0; need[i]; ++i) if (!avcodec_find_encoder_by_name(need[i])) { printf("missing encoder %s\n", need[i]); bad = 1; } const char *dec[] = {"h264", "hevc", "prores", "dnxhd", "mjpeg", "png", "aac", "pcm_s24le", "vp9", 0}; for (int i = 0; dec[i]; ++i) if (!avcodec_find_decoder_by_name(dec[i])) { printf("missing decoder %s\n", dec[i]); bad = 1; } return bad; } EOF cc -o "$BLD/bernard_licence_check" "$BLD/bernard_licence_check.c" \ -I"$PREFIX/include" -L"$PREFIX/lib" -Wl,-rpath,"$PREFIX/lib" -lavcodec -lavformat -lswscale -lswresample -lavutil CHECK_OUT=$("$BLD/bernard_licence_check") || { echo "$CHECK_OUT"; echo "FFmpeg check failed" >&2; exit 1; } echo "$CHECK_OUT" for f in "$PREFIX"/lib/lib{avcodec,avformat,avutil,swscale,swresample}.so.*; do [ -L "$f" ] && continue rp=$(readelf -d "$f" | sed -n 's/.*(\(RPATH\|RUNPATH\)).*\[\(.*\)\]/\2/p') echo "$(basename "$f"): RUNPATH '$rp', needs: $(readelf -d "$f" | sed -n 's/.*(NEEDED).*\[\(.*\)\]/\1/p' | tr '\n' ' ')" if [ "$rp" != '$ORIGIN' ]; then echo "$f: RUNPATH '$rp', \$ORIGIN expected" >&2 exit 1 fi # Nothing of the build machine in what ships: /home/, the real prefix or work folder, the user's name. leaks=$(strings -a "$f" | grep -F -e /home/ -e "$PREFIX" -e "$WORK" -e "$HOME" || true) user=$(id -un) if [ "$user" != root ]; then leaks+=$(strings -a "$f" | grep -F -e "$user" || true); fi if [ -n "$leaks" ]; then echo "$f holds paths of the build machine:" >&2; echo "$leaks" | head -5 >&2 exit 1 fi done rm -rf "${BUILD_ROOT:?}" CONFIGURATION=$(echo "$CHECK_OUT" | sed -n 's/^avcodec_configuration: //p') LICENCE=$(echo "$CHECK_OUT" | sed -n 's/^avcodec_license: //p') cat > "$LIC/FFmpeg-BUILD.txt" </share/bernard-sources. Configuration (avcodec_configuration()): ${CONFIGURATION} nv-codec-headers ${NVCODEC_TAG} (MIT, headers only): ${NVCODEC_URL}, SHA-256 ${NVCODEC_SHA256} EOF VFILE="$LIC/VERSIONS.txt.part"; [ -f "$VFILE" ] || VFILE="$LIC/VERSIONS.txt" touch "$VFILE" sed -i '/^FFmpeg /d;/^nv-codec-headers /d' "$VFILE" echo "FFmpeg ${FFMPEG_VERSION} (${LICENCE}$([ $WITH_VAAPI = 1 ] && echo ", VAAPI" || echo ", no VAAPI"), NVENC/NVDEC)" >> "$VFILE" echo "nv-codec-headers ${NVCODEC_TAG} (headers)" >> "$VFILE" log "FFmpeg ${FFMPEG_VERSION}: done in $((SECONDS - T_ALL)) s, ${LICENCE} -> $PREFIX" if [ ${#MISSING_OPTIONAL[@]} -gt 0 ]; then echo "FFmpeg built without VAAPI (their -dev packages are missing): ${MISSING_OPTIONAL[*]}" >&2 fi [ -n "$NASM_NOTE" ] && echo "FFmpeg: $NASM_NOTE" >&2 exit 0