Compare commits

...

29 Commits

Author SHA1 Message Date
38c160e2bd improve add_project_versioning_to_ffmpeg and remove HEADLESS 2026-01-11 09:56:35 -06:00
47e287ef7f update svtav1params 2026-01-09 20:28:02 -06:00
691d0f857a libass 2026-01-06 17:48:09 -06:00
3c3fc6164c add -P to efg and some improvements 2026-01-03 15:31:09 -06:00
1adcaa15a4 tabs to spaces and make utils load first 2026-01-02 17:48:27 -06:00
108561a002 fix lack of which and rpath for darwin again 2025-12-23 20:37:14 -06:00
ff1b0c2304 fixes for rpath and libogg 2025-12-23 17:19:51 -06:00
ff656d477f small fixes for macos rpath 2025-12-23 09:20:44 -06:00
7ce42985e2 update DEFAULT_ENABLE 2025-12-22 18:33:50 -06:00
8feeccc46a add libvpx/vorbis 2025-12-22 18:33:15 -06:00
87f65e48f4 bandaid OOM, ensure mkvtoolnix 2025-12-22 09:21:09 -06:00
200d4c4a6c don't really care about pgo for rust 2025-12-21 11:26:05 -06:00
71c7266661 fix Jenkins syntax error 2025-12-20 23:11:26 -06:00
69ada12884 working PGO 2025-12-20 23:07:30 -06:00
30ddc39ed5 update README and init PGO 2025-12-20 12:02:06 -06:00
25093463af fix darwin not packaging 2025-12-20 11:57:18 -06:00
2356e05ad5 slight oversight 2025-12-19 23:14:36 -06:00
7419027a80 use alternative method to cache images 2025-12-19 23:01:29 -06:00
71a35d1320 flto=full 2025-12-19 15:27:58 -06:00
cf27104939 small mistake on LTO_FLAG 2025-12-19 15:27:28 -06:00
fac5951fc9 fix lto for rust and lame_init_old 2025-12-19 09:56:24 -06:00
ff7921c45d remove docker pruning 2025-12-18 14:50:41 -06:00
65fb35877e improvements to spinner 2025-12-18 13:24:58 -06:00
ad5b8e4482 fix syntax error 2025-12-18 09:02:48 -06:00
e6ab74c351 more fixes for android, and no more cmake3 2025-12-18 08:59:47 -06:00
1b8c411458 fix LTO_FLAG usage 2025-12-18 08:12:33 -06:00
5c9e97e0a2 update rustc 1.88->1.90 2025-12-17 19:01:11 -06:00
687a8473b5 more android fixes 2025-12-17 18:15:02 -06:00
c07b52f5c2 update docker base images shas 2025-12-17 18:11:12 -06:00
19 changed files with 2817 additions and 2411 deletions

20
Jenkinsfile vendored
View File

@@ -13,7 +13,9 @@ def withDockerCreds(body) {
pipeline { pipeline {
agent none agent none
environment { DEBUG = "1" } environment {
DEBUG = "1"
}
options { buildDiscarder logRotator(numToKeepStr: '4') } options { buildDiscarder logRotator(numToKeepStr: '4') }
stages { stages {
stage('build docker image') { stage('build docker image') {
@@ -36,14 +38,16 @@ pipeline {
stage('build ffmpeg on darwin') { stage('build ffmpeg on darwin') {
matrix { matrix {
axes { axes {
axis { name 'OPT_LTO'; values 'OPT=0 LTO=OFF', 'OPT=3 LTO=ON' } axis {
axis { name 'STATIC'; values 'ON', 'OFF' } name 'COMP_OPTS';
values 'OPT=0 LTO=OFF STATIC=OFF', 'OPT=2 LTO=OFF STATIC=ON', 'OPT=3 LTO=ON STATIC=ON PGO=ON'
}
} }
stages { stages {
stage('build on darwin ') { stage('build on darwin ') {
agent { label "darwin" } agent { label "darwin" }
steps { steps {
sh "${OPT_LTO} ./scripts/build.sh" sh "${COMP_OPTS} ./scripts/build.sh"
archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false
} }
} }
@@ -55,15 +59,17 @@ pipeline {
axes { axes {
axis { name 'ARCH'; values 'armv8-a', 'x86-64-v3' } axis { name 'ARCH'; values 'armv8-a', 'x86-64-v3' }
axis { name 'DISTRO'; values 'ubuntu', 'fedora', 'debian', 'archlinux' } axis { name 'DISTRO'; values 'ubuntu', 'fedora', 'debian', 'archlinux' }
axis { name 'OPT_LTO'; values 'OPT=0 LTO=OFF', 'OPT=3 LTO=ON' } axis {
axis { name 'STATIC'; values 'ON', 'OFF' } name 'COMP_OPTS';
values 'OPT=0 LTO=OFF STATIC=OFF', 'OPT=2 LTO=OFF STATIC=ON', 'OPT=3 LTO=ON STATIC=ON PGO=ON'
}
} }
stages { stages {
stage('build ffmpeg on linux using docker') { stage('build ffmpeg on linux using docker') {
agent { label "linux && ${ARCH}" } agent { label "linux && ${ARCH}" }
steps { steps {
withDockerCreds { withDockerCreds {
sh "${OPT_LTO} ./scripts/build_with_docker.sh ${DISTRO}" sh "${COMP_OPTS} ./scripts/build_with_docker.sh ${DISTRO}"
archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false
} }
} }

View File

@@ -32,16 +32,20 @@ The default enabled libraries included in the `ffmpeg` build are:
- libx264 - libx264
- libx265 - libx265
- libwebp - libwebp
- libvpx
- libass
- libvorbis
- libmp3lame - libmp3lame
The user-overridable compile options are: The user-overridable compile options are:
- `CLEAN`: clean build directories before building (default: ON) - `ENABLE`: configure what ffmpeg enables (default: libsvtav1_psy libopus libdav1d libaom librav1e libvmaf libx264 libx265 libwebp libvpx libass libvorbis libmp3lame)
- `LTO`: enable link time optimization (default: ON)
- `OPT`: optimization level (0-3) (default: 3)
- `STATIC`: static or shared build (default: ON)
- `ARCH`: architecture type (x86-64-v{1,2,3,4}, armv8-a, etc) (default: native)
- `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local) - `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local)
- `ENABLE`: configure what ffmpeg enables (default: libsvtav1_psy libopus libdav1d libaom librav1e libvmaf libx264 libx265 libwebp libmp3lame) - `STATIC`: static or shared build (default: ON)
- `LTO`: enable link time optimization (default: ON)
- `CLEAN`: clean build directories before building (default: ON)
- `PGO`: enable profile guided optimization (default: OFF)
- `ARCH`: architecture type (x86-64-v{1,2,3,4}, armv8-a, etc) (default: native)
- `OPT`: optimization level (0-3) (default: 3)
Examples: Examples:
- only build libsvtav1_psy and libopus: `ENABLE='libsvtav1_psy libopus' ./scripts/build.sh` - only build libsvtav1_psy and libopus: `ENABLE='libsvtav1_psy libopus' ./scripts/build.sh`
@@ -77,7 +81,7 @@ encode -i input [options] output
[-v] print relevant version info [-v] print relevant version info
[-s] use same container as input, default is convert to mkv [-s] use same container as input, default is convert to mkv
[output] if unset, defaults to ${HOME}/av1-input-file-name.mkv [output] if unset, defaults to ${PWD}/av1-input-file-name.mkv
[-u] update script (git pull ffmpeg-builder) [-u] update script (git pull ffmpeg-builder)
[-I] system install at /usr/local/bin/encode [-I] system install at /usr/local/bin/encode
@@ -106,6 +110,7 @@ Example usage:
## Estimate film-grain ## Estimate film-grain
```bash ```bash
efg -i input [options] efg -i input [options]
[-P NUM] set preset (default: 10)
[-l NUM] low value (default: 0) [-l NUM] low value (default: 0)
[-s NUM] step value (default: 1) [-s NUM] step value (default: 1)
[-h NUM] high value (default: 30) [-h NUM] high value (default: 30)
@@ -120,33 +125,41 @@ efg -i input [options]
Example usage: Example usage:
- `efg -i input.mkv -p` - `efg -i input.mkv -p`
``` ```
1 +------------------------------------------------------------------------------------------------------+ 10000 +------------------------------------------------------------------------------------------------------------------------------------------+
| *****G***** + + + | | **G* + + + + + |
| *****G** '/tmp/plot.dat' ***G*** | | ** /Volumes/External/ffmpeg-builder/gitignore/tmp/efg-matrix-reloaded.mkv/plot.dat ***G*** |
0.95 |-+ ***** +-| | *G** |
| **G* | | **G |
| *** | 9000 |-+ ** +-|
| **** | | *G** |
0.9 |-+ *G* +-| | **G |
| **** |
| **** |
0.85 |-+ *G* +-|
| *** |
| **** |
0.8 |-+ *G* +-|
| *** |
| **** |
| *G* |
0.75 |-+ *** +-|
| **** |
| *G* |
0.7 |-+ *** +-|
| ** | | ** |
| *** |
| *G* | | *G* |
0.65 |-+ *** +-| 8000 |-+ ** +-|
| **** | | *G** |
| + + + *| | **G |
0.6 +------------------------------------------------------------------------------------------------------+ | ** |
| *G** |
7000 |-+ **G* +-|
| ** |
| *G* |
| **G** |
6000 |-+ **G* +-|
| ** |
| *G* |
| **G** |
| **G* |
5000 |-+ **G** +-|
| **G****G* |
| **G** |
| **G****G* |
| **G****G* |
4000 |-+ **G****G****G* +-|
| **G****|
| |
| |
| + + + + + |
3000 +------------------------------------------------------------------------------------------------------------------------------------------+
0 5 10 15 20 25 30
``` ```

419
lib/0-utils.sh Normal file
View File

@@ -0,0 +1,419 @@
#!/usr/bin/env bash
# shellcheck disable=SC2034
# ANSI colors
RED='\e[0;31m'
CYAN='\e[0;36m'
GREEN='\e[0;32m'
YELLOW='\e[0;33m'
NC='\e[0m'
# echo wrappers
echo_wrapper() {
local args
if [[ $1 == '-n' ]]; then
args=("$1")
shift
fi
# COLOR is override for using ${color}
# shellcheck disable=SC2153
if [[ ${COLOR} == 'OFF' ]]; then
color=''
endColor=''
else
endColor="${NC}"
fi
echo -e "${args[@]}" "${color}${word:-''}${endColor}" "$@"
}
echo_fail() { color="${RED}" word="FAIL" echo_wrapper "$@"; }
echo_info() { color="${CYAN}" word="INFO" echo_wrapper "$@"; }
echo_pass() { color="${GREEN}" word="PASS" echo_wrapper "$@"; }
echo_warn() { color="${YELLOW}" word="WARN" echo_wrapper "$@"; }
echo_exit() {
echo_fail "$@"
exit 1
}
void() { echo "$@" >/dev/null; }
echo_if_fail() {
local cmd=("$@")
local logName="${LOGNAME:-${RANDOM}}-"
local out="${TMP_DIR}/${logName}stdout"
local err="${TMP_DIR}/${logName}stderr"
# set trace to the cmdEvalTrace and open file descriptor
local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace"
exec 5>"${cmdEvalTrace}"
export BASH_XTRACEFD=5
set -x
"${cmd[@]}" >"${out}" 2>"${err}"
local retval=$?
# unset and close file descriptor
set +x
exec 5>&-
# parse out relevant part of the trace
local cmdEvalLines=()
while IFS= read -r line; do
line="${line/${PS4}/}"
test "${line}" == 'set +x' && continue
test "${line}" == '' && continue
cmdEvalLines+=("${line}")
done <"${cmdEvalTrace}"
if ! test ${retval} -eq 0; then
echo
echo_fail "command failed with ${retval}:"
printf "%s\n" "${cmdEvalLines[@]}"
echo_warn "command stdout:"
tail -n 32 "${out}"
echo_warn "command stderr:"
tail -n 32 "${err}"
echo
fi
if [[ -z ${LOGNAME} ]]; then
rm "${out}" "${err}" "${cmdEvalTrace}"
fi
return ${retval}
}
is_root_owned() {
local path=$1
local uid
if stat --version >/dev/null 2>&1; then
# GNU coreutils (Linux)
uid=$(stat -c '%u' "$path")
else
# BSD/macOS
uid=$(stat -f '%u' "$path")
fi
test "$uid" -eq 0
}
dump_arr() {
local arrayNames=("$@")
for arrayName in "${arrayNames[@]}"; do
declare -n array="${arrayName}"
arrayExpanded=("${array[@]}")
# skip showing single element arrays by default
if [[ ! ${#arrayExpanded[@]} -gt 1 ]]; then
if [[ ${SHOW_SINGLE} == true ]]; then
echo_info "${arrayName}='${arrayExpanded[*]}'"
else
continue
fi
fi
echo
# don't care that the variable has "ARR"
echo_info "${arrayName//"_ARR"/}"
printf "\t%s\n" "${arrayExpanded[@]}"
done
}
has_cmd() {
local cmds=("$@")
local rv=0
for cmd in "${cmds[@]}"; do
command -v "${cmd}" >/dev/null 2>&1 || rv=1
done
return ${rv}
}
missing_cmd() {
local cmds=("$@")
local rv=1
for cmd in "${cmds[@]}"; do
if ! has_cmd "${cmd}"; then
echo_warn "missing ${cmd}"
rv=0
fi
done
return ${rv}
}
bash_dirname() {
local tmp=${1:-.}
[[ $tmp != *[!/]* ]] && {
printf '/\n'
return
}
tmp=${tmp%%"${tmp##*[!/]}"}
[[ $tmp != */* ]] && {
printf '.\n'
return
}
tmp=${tmp%/*}
tmp=${tmp%%"${tmp##*[!/]}"}
printf '%s\n' "${tmp:-/}"
}
bash_basename() {
local tmp
path="$1"
suffix="${2:-''}"
tmp=${path%"${path##*[!/]}"}
tmp=${tmp##*/}
tmp=${tmp%"${suffix/"$tmp"/}"}
printf '%s\n' "${tmp:-/}"
}
bash_realpath() {
local file=$1
local dir
# If the file is already absolute
[[ $file == /* ]] && {
printf '%s\n' "$file"
return
}
# Otherwise: split into directory + basename
dir="$(bash_dirname "${file}")"
file="$(bash_basename "${file}")"
# If no directory component, use current directory
if [[ $dir == "$file" ]]; then
dir="$PWD"
else
# Save current dir, move into target dir, capture $PWD, then return
local oldpwd="$PWD"
cd "$dir" || return 1
dir="$PWD"
cd "$oldpwd" || return 1
fi
printf '%s/%s\n' "$dir" "$file"
}
line_contains() {
local line="$1"
local substr="$2"
if [[ $line == *"${substr}"* ]]; then
return 0
else
return 1
fi
}
line_starts_with() {
local line="$1"
local substr="$2"
if [[ $line == "${substr}"* ]]; then
return 0
else
return 1
fi
}
is_linux() {
line_contains "${OSTYPE}" 'linux'
}
is_darwin() {
line_contains "$(print_os)" darwin
}
is_windows() {
line_contains "$(print_os)" windows
}
is_android() {
line_contains "$(print_os)" android
}
print_os() {
# cached response
if [[ -n ${FB_OS} ]]; then
echo "${FB_OS}"
return 0
fi
unset FB_OS
if [[ -f /etc/os-release ]]; then
source /etc/os-release
FB_OS="${ID}"
if [[ ${VERSION_ID} != '' ]]; then
FB_OS+="-${VERSION_ID}"
fi
if line_starts_with "${FB_OS}" 'arch'; then
FB_OS='archlinux'
fi
else
FB_OS="$(uname -o)"
fi
# lowercase
FB_OS="${FB_OS,,}"
# special treatment for windows
if line_contains "${FB_OS}" 'windows' || line_contains "${FB_OS}" 'msys'; then
FB_OS='windows'
fi
echo "${FB_OS}"
}
is_positive_integer() {
local input="$1"
if [[ ${input} != ?(-)+([[:digit:]]) || ${input} -lt 0 ]]; then
echo_fail "${input} is not a positive integer"
return 1
fi
return 0
}
print_line_indent() {
local line="$1"
if [[ ${line} =~ ^( +) ]]; then
echo -n "${BASH_REMATCH[1]}"
fi
}
replace_line() {
local file="$1"
local search="$2"
local newLine="$3"
local newFile="${TMP_DIR}/$(bash_basename "${file}")"
test -f "${newFile}" && rm "${newFile}"
while IFS= read -r line; do
if line_contains "${line}" "${search}"; then
print_line_indent "${line}" >>"${newFile}"
echo -en "${newLine}" >>"${newFile}"
continue
fi
echo "${line}" >>"${newFile}"
done <"${file}"
cp "${newFile}" "${file}"
}
remove_line() {
local file="$1"
local search="$2"
replace_line "${file}" "${search}" ''
}
bash_sort() {
local arr=("$@")
local n=${#arr[@]}
local i j val1 val2
# Bubble sort, numeric comparison
for ((i = 0; i < n; i++)); do
for ((j = 0; j < n - i - 1; j++)); do
read -r val1 _ <<<"${arr[j]}"
read -r val2 _ <<<"${arr[j + 1]}"
if (("${val1}" > "${val2}")); then
local tmp=${arr[j]}
arr[j]=${arr[j + 1]}
arr[j + 1]=$tmp
fi
done
done
printf '%s\n' "${arr[@]}"
}
_start_spinner() {
local spinChars=(
"-"
'\'
"|"
"/"
)
sleep 1
while true; do
for ((ind = 0; ind < "${#spinChars[@]}"; ind++)); do
echo -ne "${spinChars[${ind}]}" '\b\b'
sleep .25
done
done
}
spinner() {
local action="$1"
local spinPidFile="${TMP_DIR}/.spinner-pid"
case "${action}" in
start)
test -f "${spinPidFile}" && rm "${spinPidFile}"
_start_spinner &
echo $! >"${spinPidFile}"
;;
stop)
test -f "${spinPidFile}" && kill "$(<"${spinPidFile}")"
echo -ne ' \n'
;;
esac
}
get_pkgconfig_version() {
local pkg="$1"
pkg-config --modversion "${pkg}"
}
using_cmake_4() {
local cmakeVersion
IFS=$' \t' read -r _ _ cmakeVersion <<<"$(command cmake --version)"
line_starts_with "${cmakeVersion}" 4
}
recreate_dir() {
local dirs=("$@")
for dir in "${dirs[@]}"; do
test -d "${dir}" && rm -rf "${dir}"
mkdir -p "${dir}" || return 1
done
}
ensure_dir() {
local dirs=("$@")
for dir in "${dirs[@]}"; do
test -d "${dir}" || mkdir -p "${dir}" || return 1
done
}
get_remote_head() {
local url="$1"
local remoteHEAD=''
IFS=$' \t' read -r remoteHEAD _ <<< \
"$(git ls-remote "${url}" HEAD)"
echo "${remoteHEAD}"
}
fb_max() {
local a="$1"
local b="$2"
test "${a}" -gt "${b}" &&
echo "${a}" ||
echo "${b}"
}
print_padded() {
local str="$1"
local padding="$2"
echo -n "${str}"
for ((i = 0; i < padding - ${#str}; i++)); do
echo -n ' '
done
}

View File

@@ -26,6 +26,7 @@ set_compile_opts() {
FFMPEG_EXTRA_FLAGS FFMPEG_EXTRA_FLAGS
CARGO_CINSTALL_FLAGS CARGO_CINSTALL_FLAGS
LTO_FLAG LTO_FLAG
PGO_FLAG
LIB_SUFF LIB_SUFF
BUILD_TYPE BUILD_TYPE
) )
@@ -60,9 +61,20 @@ set_compile_opts() {
LIBDIR="${PREFIX}/lib" LIBDIR="${PREFIX}/lib"
LDFLAGS_ARR=("-L${LIBDIR}") LDFLAGS_ARR=("-L${LIBDIR}")
# HACK rope in libm # android has different library location/names
# cannot build static due to missing liblog
if is_android; then if is_android; then
test -f "${LIBDIR}/libm.so" || ln -s /system/lib64/libm.so "${LIBDIR}/libm.so" if [[ ${STATIC} == 'ON' ]]; then
echo_warn "$(print_os) does not support STATIC=${STATIC}"
STATIC=OFF
echo_warn "setting STATIC=${STATIC}"
fi
LDFLAGS_ARR+=(
"-L/system/lib64"
"-lm"
"-landroid-shmem"
"-landroid-posix-semaphore"
)
fi fi
# use clang # use clang
@@ -84,13 +96,13 @@ set_compile_opts() {
if ! is_darwin; then if ! is_darwin; then
USE_LD=lld USE_LD=lld
LDFLAGS_ARR+=("-fuse-ld=${USE_LD}") LDFLAGS_ARR+=("-fuse-ld=${USE_LD}")
CMAKE_FLAGS+=( # android does not like LINKER_TYPE despite only using lld
"-DCMAKE_LINKER_TYPE=${USE_LD^^}" if ! is_android; then
"-DCMAKE_LINKER=${USE_LD}" CMAKE_FLAGS+=("-DCMAKE_LINKER_TYPE=${USE_LD^^}")
) fi
CMAKE_FLAGS+=("-DCMAKE_LINKER=${USE_LD}")
local compilerDir="${LOCAL_PREFIX}/compiler-tools" local compilerDir="${LOCAL_PREFIX}/compiler-tools"
test -d "${compilerDir}" && rm -rf "${compilerDir}" recreate_dir "${compilerDir}" || return 1
mkdir "${compilerDir}"
# real:gnu:clang:generic # real:gnu:clang:generic
local compilerMap="\ local compilerMap="\
${CC}:gcc:clang:cc ${CC}:gcc:clang:cc
@@ -103,19 +115,33 @@ ld.lld:ld:lld:ld"
realT="$(command -v "${realT}")" realT="$(command -v "${realT}")"
# add fuse-ld for the compiler # add fuse-ld for the compiler
local addFlag='' local addFlag='-v'
if line_contains "${realT}" clang; then addFlag="-fuse-ld=${USE_LD}"; fi if line_contains "${realT}" clang; then addFlag+=" -fuse-ld=${USE_LD}"; fi
# create generic tool version # create generic tool version
echo "#!/usr/bin/env bash echo "#!/usr/bin/env bash
echo \$@ > ${compilerDir}/${genericT}.\${RANDOM} echo \$@ > ${compilerDir}/${genericT}.last-command
exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}" exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
chmod +x "${compilerDir}/${genericT}"
echo_if_fail "${compilerDir}/${genericT}" --version || return 1
# copy generic to gnu/clang variants # copy generic to gnu/clang variants
# cp "${compilerDir}/${genericT}" "${compilerDir}/${gnuT}" 2>/dev/null # cp "${compilerDir}/${genericT}" "${compilerDir}/${gnuT}" 2>/dev/null
# cp "${compilerDir}/${genericT}" "${compilerDir}/${clangT}" 2>/dev/null # cp "${compilerDir}/${genericT}" "${compilerDir}/${clangT}" 2>/dev/null
done <<<"${compilerMap}" done <<<"${compilerMap}"
chmod +x "${compilerDir}"/*
# also add fake which command in case one does not exist
# shellcheck disable=SC2016
echo '#!/usr/bin/env bash
which=""
test -f /bin/which && which=/bin/which
test -f /usr/bin/which && which=/usr/bin/which
if [[ ${which} == "" ]]; then
command -v "$@"
else
${which} "$@"
fi' >"${compilerDir}/which"
chmod +x "${compilerDir}/which"
export PATH="${compilerDir}:${PATH}" export PATH="${compilerDir}:${PATH}"
fi fi
@@ -143,27 +169,46 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
) )
CARGO_CINSTALL_FLAGS=( CARGO_CINSTALL_FLAGS=(
"--release" "--release"
"--verbose"
"--prefix" "${PREFIX}" "--prefix" "${PREFIX}"
"--libdir" "${LIBDIR}" "--libdir" "${LIBDIR}"
) )
PKG_CONFIG_PATH="${LIBDIR}/pkgconfig" PKG_CONFIG_PATH="${LIBDIR}/pkgconfig"
# cmake version 4 breaks some builds
if using_cmake_4; then
CMAKE_FLAGS+=("-DCMAKE_POLICY_VERSION_MINIMUM=3.5")
fi
# add prefix include # add prefix include
# TODO use cygpath for windows # TODO use cygpath for windows
CPPFLAGS_ARR+=("-I${PREFIX}/include") CPPFLAGS_ARR+=("-I${PREFIX}/include")
# if PGO is enabled, first build run will be to generate
# second run will be to use generated profdata
if [[ ${PGO} == 'ON' ]]; then
if [[ ${PGO_RUN} == 'generate' ]]; then
PGO_FLAG="-fprofile-generate"
CFLAGS_ARR+=("${PGO_FLAG}")
LDFLAGS_ARR+=("${PGO_FLAG}")
else
PGO_FLAG="-fprofile-use=${PGO_PROFDATA}"
CFLAGS_ARR+=("${PGO_FLAG}")
LDFLAGS_ARR+=("${PGO_FLAG}")
fi
fi
# enabling link-time optimization # enabling link-time optimization
if [[ ${LTO} == 'ON' ]]; then if [[ ${LTO} == 'ON' ]]; then
LTO_FLAG='-flto' LTO_FLAG='-flto=full'
CFLAGS_ARR+=("${LTO_FLAG}")
LDFLAGS_ARR+=("${LTO_FLAG}")
CONFIGURE_FLAGS+=('--enable-lto') CONFIGURE_FLAGS+=('--enable-lto')
MESON_FLAGS+=("-Db_lto=true") MESON_FLAGS+=("-Db_lto=true")
else else
LTO_FLAG='' LTO_FLAG='unreachable-flag'
MESON_FLAGS+=("-Db_lto=false") MESON_FLAGS+=("-Db_lto=false")
fi fi
CFLAGS_ARR+=("${LTO_FLAG}")
LDFLAGS_ARR+=("${LTO_FLAG}")
# setting optimization level # setting optimization level
if [[ ${OPT} == '' ]]; then if [[ ${OPT} == '' ]]; then
OPT='0' OPT='0'
@@ -211,13 +256,17 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
"-DENABLE_SHARED=ON" "-DENABLE_SHARED=ON"
"-DBUILD_SHARED_LIBS=ON" "-DBUILD_SHARED_LIBS=ON"
"-DCMAKE_INSTALL_RPATH=${LIBDIR}" "-DCMAKE_INSTALL_RPATH=${LIBDIR}"
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON"
"-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}" "-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}"
) )
FFMPEG_EXTRA_FLAGS+=("--extra-ldflags=${LDFLAGS_ARR[*]}") if is_darwin; then
LDFLAGS_ARR+=( CMAKE_FLAGS+=(
"-Wl,-rpath,${LIBDIR}" "-DCMAKE_MACOSX_RPATH=ON"
"-Wl,-rpath-link,${LIBDIR}" "-DCMAKE_INSTALL_NAME_DIR=@rpath"
) )
fi
FFMPEG_EXTRA_FLAGS+=("--extra-ldflags=${LDFLAGS_ARR[*]}")
LDFLAGS_ARR+=("-Wl,-rpath,${LIBDIR}")
CONFIGURE_FLAGS+=( CONFIGURE_FLAGS+=(
'--enable-shared' '--enable-shared'
'--disable-static' '--disable-static'
@@ -274,24 +323,21 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
echo echo
} }
get_remote_head() {
local url="$1"
local remoteHEAD=''
IFS=$' \t' read -r remoteHEAD _ <<< \
"$(git ls-remote "${url}" HEAD)"
echo "${remoteHEAD}"
}
get_build_conf() { get_build_conf() {
local getBuild="${1}" local getBuild="${1}"
local longestBuild=0
local longestVer=0
local longestExt=0
local padding=4
# name version file-extension url dep1,dep2 # name version file-extension url dep1,dep2
# shellcheck disable=SC2016 # shellcheck disable=SC2016
local BUILDS_CONF=' local BUILDS_CONF='
ffmpeg 8.0 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext} ffmpeg 8.0.1 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
libsvtav1_psy 3.0.2-B tar.gz https://github.com/BlueSwordM/svt-av1-psyex/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo libsvtav1_psy 3.0.2-B tar.gz https://github.com/BlueSwordM/svt-av1-psyex/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo
hdr10plus_tool 1.7.1 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext} hdr10plus_tool 1.7.2 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext}
dovi_tool 2.3.1 tar.gz https://github.com/quietvoid/dovi_tool/archive/refs/tags/${ver}.${ext} dovi_tool 2.3.1 tar.gz https://github.com/quietvoid/dovi_tool/archive/refs/tags/${ver}.${ext}
cpuinfo latest git https://github.com/pytorch/cpuinfo/ cpuinfo latest git https://github.com/pytorch/cpuinfo/
@@ -299,14 +345,18 @@ libsvtav1 3.1.2 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${v
librav1e 0.8.1 tar.gz https://github.com/xiph/rav1e/archive/refs/tags/v${ver}.${ext} librav1e 0.8.1 tar.gz https://github.com/xiph/rav1e/archive/refs/tags/v${ver}.${ext}
libaom 3.13.1 tar.gz https://storage.googleapis.com/aom-releases/libaom-${ver}.${ext} libaom 3.13.1 tar.gz https://storage.googleapis.com/aom-releases/libaom-${ver}.${ext}
libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext} libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext}
libopus 1.5.2 tar.gz https://github.com/xiph/opus/releases/download/v${ver}/opus-${ver}.${ext} libopus 1.6 tar.gz https://github.com/xiph/opus/archive/refs/tags/v${ver}.${ext}
libdav1d 1.5.1 tar.xz http://downloads.videolan.org/videolan/dav1d/${ver}/dav1d-${ver}.${ext} libdav1d 1.5.3 tar.xz https://downloads.videolan.org/videolan/dav1d/${ver}/dav1d-${ver}.${ext}
libx264 latest git https://code.videolan.org/videolan/x264.git libx264 latest git https://code.videolan.org/videolan/x264.git
libmp3lame 3.100 tar.gz https://pilotfiber.dl.sourceforge.net/project/lame/lame/${ver}/lame-${ver}.${ext} libmp3lame 3.100 tar.gz https://pilotfiber.dl.sourceforge.net/project/lame/lame/${ver}/lame-${ver}.${ext}
libvpx 1.15.2 tar.gz https://github.com/webmproject/libvpx/archive/refs/tags/v${ver}.${ext}
libvorbis 1.3.7 tar.xz https://github.com/xiph/vorbis/releases/download/v${ver}/libvorbis-${ver}.${ext} libogg
libogg 1.3.6 tar.xz https://github.com/xiph/ogg/releases/download/v${ver}/libogg-${ver}.${ext}
libwebp 1.6.0 tar.gz https://github.com/webmproject/libwebp/archive/refs/tags/v${ver}.${ext} libpng,libjpeg libwebp 1.6.0 tar.gz https://github.com/webmproject/libwebp/archive/refs/tags/v${ver}.${ext} libpng,libjpeg
libjpeg 3.0.3 tar.gz https://github.com/winlibs/libjpeg/archive/refs/tags/libjpeg-turbo-${ver}.${ext} libjpeg 3.0.3 tar.gz https://github.com/winlibs/libjpeg/archive/refs/tags/libjpeg-turbo-${ver}.${ext}
libpng 1.6.50 tar.gz https://github.com/pnggroup/libpng/archive/refs/tags/v${ver}.${ext} zlib libpng 1.6.53 tar.gz https://github.com/pnggroup/libpng/archive/refs/tags/v${ver}.${ext} zlib
zlib 1.3.1 tar.gz https://github.com/madler/zlib/archive/refs/tags/v${ver}.${ext} zlib 1.3.1 tar.gz https://github.com/madler/zlib/archive/refs/tags/v${ver}.${ext}
libplacebo 7.351.0 tar.gz https://github.com/haasn/libplacebo/archive/refs/tags/v${ver}.${ext} glslang,vulkan_loader,glad libplacebo 7.351.0 tar.gz https://github.com/haasn/libplacebo/archive/refs/tags/v${ver}.${ext} glslang,vulkan_loader,glad
@@ -315,17 +365,27 @@ spirv_tools 2025.4 tar.gz https://github.com/KhronosGroup/SPIRV-Tools/archive
spirv_headers 1.4.328.1 tar.gz https://github.com/KhronosGroup/SPIRV-Headers/archive/refs/tags/vulkan-sdk-${ver}.${ext} spirv_headers 1.4.328.1 tar.gz https://github.com/KhronosGroup/SPIRV-Headers/archive/refs/tags/vulkan-sdk-${ver}.${ext}
glad 2.0.8 tar.gz https://github.com/Dav1dde/glad/archive/refs/tags/v${ver}.${ext} glad 2.0.8 tar.gz https://github.com/Dav1dde/glad/archive/refs/tags/v${ver}.${ext}
libx265 4.1 tar.gz https://bitbucket.org/multicoreware/x265_git/downloads/x265_${ver}.${ext} libnuma,cmake3 libx265 4.1 tar.gz https://bitbucket.org/multicoreware/x265_git/downloads/x265_${ver}.${ext} libnuma
libnuma 2.0.19 tar.gz https://github.com/numactl/numactl/archive/refs/tags/v${ver}.${ext} libnuma 2.0.19 tar.gz https://github.com/numactl/numactl/archive/refs/tags/v${ver}.${ext}
cmake3 3.31.8 tar.gz https://github.com/Kitware/CMake/archive/refs/tags/v${ver}.${ext}
'
libass 0.17.4 tar.xz https://github.com/libass/libass/releases/download/${ver}/libass-${ver}.${ext} freetype,fribidi,libunibreak
freetype 2.14.1 tar.xz https://downloads.sourceforge.net/freetype/freetype-${ver}.${ext} libpng,harfbuzz
harfbuzz 12.3.0 tar.xz https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.${ext}
fribidi 1.0.16 tar.xz https://github.com/fribidi/fribidi/releases/download/v${ver}/fribidi-${ver}.${ext}
libunibreak 6.1 tar.gz https://github.com/adah1972/libunibreak/releases/download/libunibreak_${ver//./_}/libunibreak-${ver}.${ext}
'
local supported_builds=() local supported_builds=()
unset ver ext url deps extractedDir unset ver ext url deps extractedDir
while read -r line; do while read -r line; do
test "${line}" == '' && continue test "${line}" == '' && continue
IFS=$' \t' read -r build ver ext url deps <<<"${line}" IFS=$' \t' read -r build ver ext url deps <<<"${line}"
supported_builds+=("${build}") supported_builds+=("${build}")
# padding support
longestBuild="$(fb_max "${#build}" "${longestBuild}")"
longestVer="$(fb_max "${#ver}" "${longestVer}")"
longestExt="$(fb_max "${#ext}" "${longestExt}")"
if [[ ${getBuild} != "${build}" ]]; then if [[ ${getBuild} != "${build}" ]]; then
build='' build=''
continue continue
@@ -333,11 +393,27 @@ cmake3 3.31.8 tar.gz https://github.com/Kitware/CMake/archive/refs/tags/v${v
break break
done <<<"${BUILDS_CONF}" done <<<"${BUILDS_CONF}"
# special arg to print supported builds only
if [[ ${getBuild} == 'supported' ]]; then if [[ ${getBuild} == 'supported' ]]; then
echo "${supported_builds[@]}" echo "${supported_builds[@]}"
return 0 return 0
fi fi
# special arg to print BUILDS_CONF but formatted with spaces
if [[ ${getBuild} == 'format-builds-conf' ]]; then
echo "local BUILDS_CONF='"
while read -r line; do
IFS=$' \t' read -r build ver ext url deps <<<"${line}"
print_padded "${build}" $((padding + longestBuild))
print_padded "${ver}" $((padding + longestVer))
print_padded "${ext}" $((padding + longestExt))
print_padded "${url}" "${padding}"
echo " ${deps}"
done <<<"${BUILDS_CONF}"
echo "'"
return 0
fi
if [[ ${build} == '' ]]; then if [[ ${build} == '' ]]; then
echo_fail "build ${getBuild} is not supported" echo_fail "build ${getBuild} is not supported"
return 1 return 1
@@ -381,7 +457,7 @@ download_release() {
continue continue
fi fi
test -d "${alreadyBuilt}" || continue test -d "${alreadyBuilt}" || continue
echo_warn "removing wrong version: ${extractedDir}" echo_warn "removing wrong version: ${alreadyBuilt}"
rm -rf "${alreadyBuilt}" rm -rf "${alreadyBuilt}"
done done
@@ -502,17 +578,10 @@ do_build() {
echo_info -n "building ${build} " echo_info -n "building ${build} "
# build in background # build in background
local timeBefore=${EPOCHSECONDS} local timeBefore=${EPOCHSECONDS}
LOGNAME="${build}" echo_if_fail "build_${build}" & spinner start
local buildPid=$! LOGNAME="${build}" echo_if_fail "build_${build}"
# start spinner
spinner &
local spinPid=$!
# get build return code
wait ${buildPid}
local retval=$? local retval=$?
# stop spinner spinner stop
kill ${spinPid}
spinner reset
popd >/dev/null || return 1 popd >/dev/null || return 1
test ${retval} -eq 0 || return ${retval} test ${retval} -eq 0 || return ${retval}
@@ -537,6 +606,14 @@ FB_FUNC_NAMES+=('build')
# shellcheck disable=SC2034 # shellcheck disable=SC2034
FB_FUNC_DESCS['build']='build ffmpeg with the desired configuration' FB_FUNC_DESCS['build']='build ffmpeg with the desired configuration'
build() { build() {
# if PGO is enabled, build will call build
# only want to recursively build on the first run
if [[ ${PGO} == 'ON' && ${PGO_RUN} != 'generate' ]]; then
PGO_RUN='generate' build || return 1
# will need to reset compile opts
unset FB_COMPILE_OPTS_SET
fi
set_compile_opts || return 1 set_compile_opts || return 1
for build in ${ENABLE}; do for build in ${ENABLE}; do
@@ -545,9 +622,16 @@ build() {
unset REQUIRES_REBUILD unset REQUIRES_REBUILD
done done
do_build ffmpeg || return 1 do_build ffmpeg || return 1
# skip packaging on PGO generate run
if [[ ${PGO} == 'ON' && ${PGO_RUN} == 'generate' ]]; then
PATH="${PREFIX}/bin:${PATH}" gen_profdata
return $?
fi
local ffmpegBin="${PREFIX}/bin/ffmpeg" local ffmpegBin="${PREFIX}/bin/ffmpeg"
# run ffmpeg to show completion # run ffmpeg to show completion
"${ffmpegBin}" -version "${ffmpegBin}" -version || return 1
# suggestion for path # suggestion for path
hash -r hash -r
@@ -575,10 +659,21 @@ sanitize_sysroot_libs() {
for lib in "${libs[@]}"; do for lib in "${libs[@]}"; do
local libPath="${LIBDIR}/${lib}" local libPath="${LIBDIR}/${lib}"
local useLib="${libPath}.${USE_LIB_SUFF}" local foundLib=false
if [[ ! -f ${useLib} ]]; then for useLib in "${libPath}"*"${USE_LIB_SUFF}"; do
echo_fail "could not find ${useLib}, something is wrong" test -f "${useLib}" || continue
foundLib=true
# darwin sometimes fails to set rpath correctly
if is_darwin && [[ ${STATIC} == 'OFF' ]]; then
install_name_tool \
-id "${useLib}" \
"${useLib}" || return 1
fi
done
if [[ ${foundLib} == false ]]; then
echo_fail "could not find ${libPath}*${USE_LIB_SUFF}, something is wrong"
return 1 return 1
fi fi
@@ -631,7 +726,11 @@ del_pkgconfig_gcc_s() {
### RUST ### ### RUST ###
meta_cargoc_build() { meta_cargoc_build() {
local destdir="${PWD}/fb-local-install" local destdir="${PWD}/fb-local-install"
cargo cinstall \ # let rust handle its own lto/pgo
local newCflags="${CFLAGS//${LTO_FLAG}/}"
newCflags="${newCflags//${PGO_FLAG}/}"
CFLAGS="${newCflags}" cargo cinstall \
--destdir "${destdir}" \ --destdir "${destdir}" \
"${CARGO_CINSTALL_FLAGS[@]}" || return 1 "${CARGO_CINSTALL_FLAGS[@]}" || return 1
# cargo cinstall destdir prepends with entire prefix # cargo cinstall destdir prepends with entire prefix
@@ -685,6 +784,7 @@ build_cpuinfo() {
-DCPUINFO_BUILD_UNIT_TESTS=OFF \ -DCPUINFO_BUILD_UNIT_TESTS=OFF \
-DCPUINFO_BUILD_MOCK_TESTS=OFF \ -DCPUINFO_BUILD_MOCK_TESTS=OFF \
-DCPUINFO_BUILD_BENCHMARKS=OFF \ -DCPUINFO_BUILD_BENCHMARKS=OFF \
-DCPUINFO_LOG_TO_STDIO=ON \
-DUSE_SYSTEM_LIBS=ON || return 1 -DUSE_SYSTEM_LIBS=ON || return 1
sanitize_sysroot_libs libcpuinfo || return 1 sanitize_sysroot_libs libcpuinfo || return 1
} }
@@ -718,7 +818,24 @@ build_libopus() {
sanitize_sysroot_libs libopus || return 1 sanitize_sysroot_libs libopus || return 1
} }
build_libvorbis() {
meta_cmake_build || return 1
sanitize_sysroot_libs \
libvorbis libvorbisenc libvorbisfile || return 1
}
build_libogg() {
meta_cmake_build || return 1
sanitize_sysroot_libs libogg || return 1
}
build_libwebp() { build_libwebp() {
if is_android; then
replace_line CMakeLists.txt \
"if(ANDROID)" \
"if(FALSE)\n"
fi
meta_cmake_build || return 1 meta_cmake_build || return 1
sanitize_sysroot_libs libwebp libsharpyuv || return 1 sanitize_sysroot_libs libwebp libsharpyuv || return 1
} }
@@ -760,44 +877,14 @@ build_spirv_headers() {
-G Ninja || return 1 -G Ninja || return 1
} }
# libx265 does not support cmake >= 4
build_cmake3() {
local cmakeVersion verMajor
# don't need to build if system version is below 4
IFS=$' \t' read -r _ _ cmakeVersion <<<"$(cmake --version)"
IFS='.' read -r verMajor _ _ <<<"${cmakeVersion}"
if [[ ${verMajor} -lt 4 ]]; then
return 0
fi
# don't need to rebuild if already built
local cmake="${LOCAL_PREFIX}/bin/cmake"
if [[ -f ${cmake} ]]; then
IFS=$' \t' read -r _ _ cmakeVersion <<<"$("${cmake}" --version)"
IFS='.' read -r verMajor _ _ <<<"${cmakeVersion}"
if [[ ${verMajor} -lt 4 ]]; then
return 0
fi
fi
local overrideFlags=(
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_PREFIX_PATH=${LOCAL_PREFIX}"
"-DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX}"
)
# reuse variables
for flag in "${CMAKE_FLAGS[@]}"; do
if line_contains "${flag}" 'CMAKE_INSTALL_LIBDIR' ||
line_contains "${flag}" 'COMPILER_LAUNCHER'; then
overrideFlags+=("${flag}")
fi
done
CMAKE_FLAGS='' meta_cmake_build \
"${overrideFlags[@]}" || return 1
}
build_libx265() { build_libx265() {
PATH="${LOCAL_PREFIX}/bin:${PATH}" meta_cmake_build \ # libx265 does not support cmake >= 4
if using_cmake_4; then
remove_line "source/CMakeLists.txt" "cmake_policy(SET CMP0025 OLD)" || return 1
remove_line "source/CMakeLists.txt" "cmake_policy(SET CMP0054 OLD)" || return 1
fi
meta_cmake_build \
-DHIGH_BIT_DEPTH=ON \ -DHIGH_BIT_DEPTH=ON \
-DENABLE_HDR10_PLUS=OFF \ -DENABLE_HDR10_PLUS=OFF \
-S source || return 1 -S source || return 1
@@ -834,8 +921,8 @@ build_libplacebo() {
# copy downloaded glad release as "submodule" # copy downloaded glad release as "submodule"
( (
installDir="${PWD}/3rdparty/glad" installDir="${PWD}/3rdparty/glad"
get_build_conf glad get_build_conf glad || exit 1
CLEAN=OFF download_release CLEAN=OFF download_release || exit 1
cd "${extractedDir}" || exit 1 cd "${extractedDir}" || exit 1
cp -r ./* "${installDir}" cp -r ./* "${installDir}"
) || return 1 ) || return 1
@@ -877,6 +964,26 @@ build_libvmaf() {
fi fi
} }
build_freetype() {
meta_meson_build \
-D tests=disabled || return 1
sanitize_sysroot_libs libfreetype || return 1
}
build_harfbuzz() {
meta_meson_build \
-D tests=disabled \
-D docs=disabled \
-D doc_tests=false || return 1
sanitize_sysroot_libs libharfbuzz || return 1
}
build_fribidi() {
meta_meson_build \
-D tests=false || return 1
sanitize_sysroot_libs libfribidi || return 1
}
### PYTHON ### ### PYTHON ###
build_glad() { build_glad() {
true true
@@ -908,6 +1015,8 @@ meta_configure_build() {
"${configureFlags[@]}" \ "${configureFlags[@]}" \
"${addFlags[@]}" || return 1 "${addFlags[@]}" || return 1
# build # build
# attempt to build twice since build can fail due to OOM
ccache make -j"${JOBS}" ||
ccache make -j"${JOBS}" || return 1 ccache make -j"${JOBS}" || return 1
# install # install
local destdir="${PWD}/fb-local-install" local destdir="${PWD}/fb-local-install"
@@ -919,6 +1028,23 @@ meta_configure_build() {
LDFLAGS="${ldflagsBackup}" LDFLAGS="${ldflagsBackup}"
} }
build_libvpx() {
meta_configure_build \
--disable-examples \
--disable-tools \
--disable-docs \
--disable-unit-tests \
--disable-decode-perf-tests \
--disable-encode-perf-tests \
--enable-vp8 \
--enable-vp9 \
--enable-vp9-highbitdepth \
--enable-better-hw-compatibility \
--enable-webm-io \
--enable-libyuv || return 1
sanitize_sysroot_libs libvpx || return 1
}
build_libx264() { build_libx264() {
# libx264 breaks with LTO # libx264 breaks with LTO
LTO=OFF meta_configure_build \ LTO=OFF meta_configure_build \
@@ -932,13 +1058,6 @@ build_libx264() {
} }
build_libmp3lame() { build_libmp3lame() {
# https://sourceforge.net/p/lame/mailman/message/36081038/
if is_darwin; then
remove_line \
'include/libmp3lame.sym' \
'lame_init_old' || return 1
fi
meta_configure_build \ meta_configure_build \
--enable-nasm \ --enable-nasm \
--disable-frontend || return 1 --disable-frontend || return 1
@@ -953,6 +1072,16 @@ build_libnuma() {
sanitize_sysroot_libs libnuma || return 1 sanitize_sysroot_libs libnuma || return 1
} }
build_libunibreak() {
meta_configure_build || return 1
sanitize_sysroot_libs libunibreak || return 1
}
build_libass() {
meta_configure_build || return 1
sanitize_sysroot_libs libass || return 1
}
add_project_versioning_to_ffmpeg() { add_project_versioning_to_ffmpeg() {
# embed this project's enables/versions # embed this project's enables/versions
# into ffmpeg with FFMPEG_BUILDER_INFO # into ffmpeg with FFMPEG_BUILDER_INFO
@@ -975,34 +1104,10 @@ add_project_versioning_to_ffmpeg() {
echo_fail "could not find ${fname} to add project versioning" echo_fail "could not find ${fname} to add project versioning"
fi fi
local searchFor='static void print_all_libs_info' local printLibLine='print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);'
local foundUsageStart=0 local newPrintLibLine="${printLibLine} "
local newOptFile="${TMP_DIR}/${fname}" newPrintLibLine+="$(printf 'av_log(NULL, AV_LOG_INFO, "%s\\\\n"); ' "${FFMPEG_BUILDER_INFO[@]}")"
test -f "${newOptFile}" && rm "${newOptFile}" replace_line "${optFile}" "${printLibLine}" "${newPrintLibLine}" || return 1
while read -r line; do
# if we found the line previously, add the versioning
if [[ ${foundUsageStart} -eq 1 ]]; then
if line_starts_with "${line}" '}'; then
echo_info "found ${line} on ${lineNum}"
for info in "${FFMPEG_BUILDER_INFO[@]}"; do
local newline="av_log(NULL, AV_LOG_INFO, \"${info}\n\");"
echo "${newline}" >>"${newOptFile}"
lineNum=$((lineNum + 1))
done
newline="av_log(NULL, AV_LOG_INFO, \"\n\");"
echo "${newline}" >>"${newOptFile}"
foundUsageStart=0
fi
fi
# find the line we are searching for
if line_contains "${line}" "${searchFor}"; then
foundUsageStart=1
fi
# start building the new file
echo "${line}" >>"${newOptFile}"
done <"${optFile}"
cp "${newOptFile}" "${optFile}" || return 1
return 0 return 0
} }
@@ -1029,10 +1134,16 @@ build_ffmpeg() {
# lto is broken on darwin for ffmpeg only # lto is broken on darwin for ffmpeg only
# https://trac.ffmpeg.org/ticket/11479 # https://trac.ffmpeg.org/ticket/11479
local ltoBackup="${LTO}"
if is_darwin; then if is_darwin; then
LTO=OFF LTO=OFF
for flag in "${FFMPEG_EXTRA_FLAGS[@]}"; do for flag in "${FFMPEG_EXTRA_FLAGS[@]}"; do
ffmpegFlags+=("${flag// ${LTO_FLAG}/}") if line_contains "${flag}" "${LTO_FLAG}"; then
# get rid of potential space on either side
flag="${flag//${LTO_FLAG} /}"
flag="${flag// ${LTO_FLAG}/}"
fi
ffmpegFlags+=("${flag}")
done done
else else
ffmpegFlags+=("${FFMPEG_EXTRA_FLAGS[@]}") ffmpegFlags+=("${FFMPEG_EXTRA_FLAGS[@]}")
@@ -1040,6 +1151,7 @@ build_ffmpeg() {
meta_configure_build \ meta_configure_build \
"${ffmpegFlags[@]}" || return 1 "${ffmpegFlags[@]}" || return 1
LTO="${ltoBackup}"
${SUDO_MODIFY} cp ff*_g "${PREFIX}/bin" ${SUDO_MODIFY} cp ff*_g "${PREFIX}/bin"
sanitize_sysroot_libs \ sanitize_sysroot_libs \
libavcodec libavdevice libavfilter libswscale \ libavcodec libavdevice libavfilter libswscale \

View File

@@ -14,6 +14,9 @@ DEFAULT_CLEAN=ON
FB_COMP_OPTS_DESC['LTO']='enable link time optimization' FB_COMP_OPTS_DESC['LTO']='enable link time optimization'
DEFAULT_LTO=ON DEFAULT_LTO=ON
FB_COMP_OPTS_DESC['PGO']='enable profile guided optimization'
DEFAULT_PGO=OFF
FB_COMP_OPTS_DESC['OPT']='optimization level (0-3)' FB_COMP_OPTS_DESC['OPT']='optimization level (0-3)'
DEFAULT_OPT=3 DEFAULT_OPT=3
@@ -37,13 +40,14 @@ libvmaf \
libx264 \ libx264 \
libx265 \ libx265 \
libwebp \ libwebp \
libvpx \
libass \
libvorbis \
libmp3lame\ libmp3lame\
" "
# user-overridable compile option variable names # user-overridable compile option variable names
FB_COMP_OPTS=( FB_COMP_OPTS=("${!FB_COMP_OPTS_DESC[@]}")
CLEAN LTO OPT STATIC ARCH PREFIX ENABLE
)
# sets FB_COMP_OPTS to allow for user-overriding # sets FB_COMP_OPTS to allow for user-overriding
check_compile_opts_override() { check_compile_opts_override() {

View File

@@ -11,8 +11,7 @@ DOCKER_WORKDIR='/workdir'
set_docker_run_flags() { set_docker_run_flags() {
local cargo_git="${IGN_DIR}/cargo/git" local cargo_git="${IGN_DIR}/cargo/git"
local cargo_registry="${IGN_DIR}/cargo/registry" local cargo_registry="${IGN_DIR}/cargo/registry"
test -d "${cargo_git}" || mkdir -p "${cargo_git}" ensure_dir "${cargo_git}" "${cargo_registry}"
test -d "${cargo_registry}" || mkdir -p "${cargo_registry}"
DOCKER_RUN_FLAGS=( DOCKER_RUN_FLAGS=(
--rm --rm
-v "${cargo_git}:/root/.cargo/git" -v "${cargo_git}:/root/.cargo/git"
@@ -20,6 +19,7 @@ set_docker_run_flags() {
-v "${REPO_DIR}:${REPO_DIR}" -v "${REPO_DIR}:${REPO_DIR}"
-w "${REPO_DIR}" -w "${REPO_DIR}"
-e "DEBUG=${DEBUG}" -e "DEBUG=${DEBUG}"
-t
) )
for opt in "${FB_COMP_OPTS[@]}"; do for opt in "${FB_COMP_OPTS[@]}"; do
declare -n defOptVal="DEFAULT_${opt}" declare -n defOptVal="DEFAULT_${opt}"
@@ -43,10 +43,10 @@ get_docker_image_tag() {
local image="$1" local image="$1"
local tag='' local tag=''
case "${image}" in case "${image}" in
ubuntu) tag='ubuntu:24.04@sha256:9cbed754112939e914291337b5e554b07ad7c392491dba6daf25eef1332a22e8' ;; ubuntu) tag='ubuntu:24.04@sha256:c35e29c9450151419d9448b0fd75374fec4fff364a27f176fb458d472dfc9e54' ;;
debian) tag='debian:13@sha256:833c135acfe9521d7a0035a296076f98c182c542a2b6b5a0fd7063d355d696be' ;; debian) tag='debian:13@sha256:0d01188e8dd0ac63bf155900fad49279131a876a1ea7fac917c62e87ccb2732d' ;;
fedora) tag='fedora:42@sha256:6af051ad0a294182c3a957961df6203d91f643880aa41c2ffe3d1302e7505890' ;; fedora) tag='fedora:42@sha256:b3d16134560afa00d7cc2a9e4967eb5b954512805f3fe27d8e70bbed078e22ea' ;;
archlinux) tag='ogarcia/archlinux:latest@sha256:b93f426b23cd0ea0e1befd7d58a26eaf3e6eda3c154c0e8dd75145d11c21304c' ;; archlinux) tag='ogarcia/archlinux:latest@sha256:1d70273180e43b1f51b41514bdaa73c61f647891a53a9c301100d5c4807bf628' ;;
esac esac
echo "${tag}" echo "${tag}"
} }
@@ -111,7 +111,7 @@ docker_build_image() {
echo_info "sourcing package manager for ${image}" echo_info "sourcing package manager for ${image}"
local dockerDistro="$(get_docker_image_tag "${image}")" local dockerDistro="$(get_docker_image_tag "${image}")"
# specific file for evaluated package manager info # specific file for evaluated package manager info
distroPkgMgr="${DOCKER_DIR}/$(bash_basename "${image}")-pkg_mgr" local distroPkgMgr="${DOCKER_DIR}/$(bash_basename "${image}")-pkg_mgr"
# get package manager info # get package manager info
docker run \ docker run \
"${DOCKER_RUN_FLAGS[@]}" \ "${DOCKER_RUN_FLAGS[@]}" \
@@ -122,17 +122,14 @@ docker_build_image() {
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${distroPkgMgr}" source "${distroPkgMgr}"
dockerfile="${DOCKER_DIR}/Dockerfile_$(bash_basename "${image}")" local dockerfile="${DOCKER_DIR}/Dockerfile_$(bash_basename "${image}")"
local embedPath='/Dockerfile'
{ {
echo "FROM ${dockerDistro}" echo "FROM ${dockerDistro}"
echo 'SHELL ["/bin/bash", "-c"]' echo 'SHELL ["/bin/bash", "-c"]'
echo 'RUN ln -sf /bin/bash /bin/sh' echo 'RUN ln -sf /bin/bash /bin/sh'
echo 'ENV DEBIAN_FRONTEND=noninteractive' echo 'ENV DEBIAN_FRONTEND=noninteractive'
local installCmds='' echo "RUN ${pkg_mgr_update} && ${pkg_mgr_upgrade} && ${pkg_install} ${req_pkgs[*]}"
installCmds+="${pkg_mgr_update}"
installCmds+=" && ${pkg_mgr_upgrade}"
installCmds+=" && ${pkg_install} ${req_pkgs[*]}"
echo "RUN ${installCmds}"
# ENV for pipx/rust # ENV for pipx/rust
echo 'ENV PIPX_HOME=/root/.local' echo 'ENV PIPX_HOME=/root/.local'
@@ -161,7 +158,7 @@ docker_build_image() {
echo "RUN pipx install virtualenv" echo "RUN pipx install virtualenv"
# rust # rust
local rustupVersion='1.28.2' local rustupVersion='1.28.2'
local rustcVersion='1.88.0' local rustcVersion='1.90.0'
local rustupTarball="rustup-${rustupVersion}.tar.gz" local rustupTarball="rustup-${rustupVersion}.tar.gz"
local rustupTarballPath="${DOCKER_DIR}/${rustupTarball}" local rustupTarballPath="${DOCKER_DIR}/${rustupTarball}"
if [[ ! -f ${rustupTarballPath} ]]; then if [[ ! -f ${rustupTarballPath} ]]; then
@@ -169,19 +166,40 @@ docker_build_image() {
fi fi
echo "ADD ${rustupTarball} /tmp/" echo "ADD ${rustupTarball} /tmp/"
local cargoInst="\ echo "RUN cd /tmp/rustup-${rustupVersion} && bash rustup-init.sh -y --default-toolchain=${rustcVersion}"
cd /tmp/rustup-${rustupVersion} \
&& bash rustup-init.sh -y --default-toolchain=${rustcVersion}"
echo "RUN ${cargoInst}"
# install cargo-binstall # install cargo-binstall
echo "RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash" echo "RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash"
# install cargo-c # install cargo-c
echo "RUN cargo-binstall -y cargo-c" echo "RUN cargo-binstall -y cargo-c"
# final mods for PS1
echo
echo 'USER root'
echo "RUN echo \"PS1='id=\\\$(id -u)@${image}:\w\\$ '\" >> /etc/bash.bashrc"
echo 'USER 65534:65534'
echo
# embed dockerfile into docker image itself
# shellcheck disable=SC2094
echo "COPY $(bash_basename "${dockerfile}") ${embedPath}"
echo "WORKDIR ${DOCKER_WORKDIR}" echo "WORKDIR ${DOCKER_WORKDIR}"
} >"${dockerfile}" } >"${dockerfile}"
# docker buildx is too aggressive with invalidating
# build layer caches. Instead of relying on docker
# to check for when to rebuild, compare the to-build
# dockerfile with the embedded dockerfile
local oldDockerfile="${dockerfile}.old"
docker_run_image "${image}" cp "${embedPath}" "${oldDockerfile}"
if diff "${dockerfile}" "${oldDockerfile}"; then
echo_pass "no dockerfile changes detected, skipping rebuild"
return 0
else
echo_warn "dockerfile changes detected, proceeding with build"
fi
image_tag="$(set_distro_image_tag "${image}")" image_tag="$(set_distro_image_tag "${image}")"
docker buildx build \ docker buildx build \
--platform "${PLATFORM}" \ --platform "${PLATFORM}" \
@@ -199,9 +217,6 @@ docker_build_image() {
-f "${dockerfile}" \ -f "${dockerfile}" \
"${DOCKER_DIR}" || return 1 "${DOCKER_DIR}" || return 1
fi fi
# FIXME uncomment
# docker system prune -f
} }
FB_FUNC_NAMES+=('docker_save_image') FB_FUNC_NAMES+=('docker_save_image')
@@ -229,8 +244,7 @@ docker_load_image() {
echo_info "loading docker image for ${image_tag}" echo_info "loading docker image for ${image_tag}"
local archive="${DOCKER_DIR}/$(docker_image_archive_name "${image_tag}")" local archive="${DOCKER_DIR}/$(docker_image_archive_name "${image_tag}")"
test -f "$archive" || return 1 test -f "$archive" || return 1
zstdcat -T0 "$archive" | zstdcat -T0 "$archive" | docker load || return 1
docker load || return 1
docker system prune -f docker system prune -f
} }
@@ -251,7 +265,7 @@ docker_run_image() {
runCmd+=("${cmd[@]}") runCmd+=("${cmd[@]}")
fi fi
image_tag="$(set_distro_image_tag "${image}")" local image_tag="$(set_distro_image_tag "${image}")"
# if a docker registry is defined, pull from it # if a docker registry is defined, pull from it
if [[ ${DOCKER_REGISTRY} != '' ]]; then if [[ ${DOCKER_REGISTRY} != '' ]]; then
@@ -261,16 +275,16 @@ docker_run_image() {
docker tag "${DOCKER_REGISTRY}/${image_tag}" "${image_tag}" docker tag "${DOCKER_REGISTRY}/${image_tag}" "${image_tag}"
fi fi
echo_info "running ffmpeg build with ${image_tag}" echo_info "running docker image ${image_tag}"
docker run \ docker run \
"${DOCKER_RUN_FLAGS[@]}" \ "${DOCKER_RUN_FLAGS[@]}" \
-u "$(id -u):$(id -g)" \ -u "$(id -u):$(id -g)" \
"${image_tag}" \ "${image_tag}" \
"${runCmd[@]}" || return 1 "${runCmd[@]}"
docker system prune -f local rv=$?
docker image prune -f
return 0 return ${rv}
} }
FB_FUNC_NAMES+=('build_with_docker') FB_FUNC_NAMES+=('build_with_docker')

View File

@@ -2,6 +2,7 @@
efg_usage() { efg_usage() {
echo "efg -i input [options]" echo "efg -i input [options]"
echo -e "\t[-P NUM] set preset (default: ${PRESET})"
echo -e "\t[-l NUM] low value (default: ${LOW})" echo -e "\t[-l NUM] low value (default: ${LOW})"
echo -e "\t[-s NUM] step value (default: ${STEP})" echo -e "\t[-s NUM] step value (default: ${STEP})"
echo -e "\t[-h NUM] high value (default: ${HIGH})" echo -e "\t[-h NUM] high value (default: ${HIGH})"
@@ -12,10 +13,11 @@ efg_usage() {
} }
set_efg_opts() { set_efg_opts() {
local opts='pl:s:h:i:IU' local opts='P:pl:s:h:i:IU'
local numOpts=${#opts} local numOpts=${#opts}
# default values # default values
unset INPUT unset INPUT
PRESET=10
LOW=0 LOW=0
STEP=1 STEP=1
HIGH=30 HIGH=30
@@ -30,18 +32,25 @@ set_efg_opts() {
local OPTARG OPTIND local OPTARG OPTIND
while getopts "${opts}" flag; do while getopts "${opts}" flag; do
case "${flag}" in case "${flag}" in
P)
if ! is_positive_integer "${OPTARG}"; then
efg_usage
return 1
fi
PRESET="${OPTARG}"
;;
I) I)
echo_warn "attempting install" echo_warn "attempting install"
sudo ln -sf "${SCRIPT_DIR}/efg.sh" \ sudo ln -sf "${SCRIPT_DIR}/efg.sh" \
"${EFG_INSTALL_PATH}" || return 1 "${EFG_INSTALL_PATH}" || return 1
echo_pass "succesfull install" echo_pass "succesfull install"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
U) U)
echo_warn "attempting uninstall" echo_warn "attempting uninstall"
sudo rm "${EFG_INSTALL_PATH}" || return 1 sudo rm "${EFG_INSTALL_PATH}" || return 1
echo_pass "succesfull uninstall" echo_pass "succesfull uninstall"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
i) i)
if [[ $# -lt 2 ]]; then if [[ $# -lt 2 ]]; then
@@ -126,8 +135,7 @@ efg_segment() {
local segmentBitrates=() local segmentBitrates=()
# clean workspace # clean workspace
test -d "${EFG_DIR}" && rm -rf "${EFG_DIR}" recreate_dir "${EFG_DIR}" || return 1
mkdir -p "${EFG_DIR}"
# split up video into segments based on start times # split up video into segments based on start times
for ((time = 0; time < duration; time += timeBetweenSegments)); do for ((time = 0; time < duration; time += timeBetweenSegments)); do
@@ -170,20 +178,26 @@ efg_segment() {
} }
efg_encode() { efg_encode() {
echo -n >"${GRAIN_LOG}" local grainLogWIP="${GRAIN_LOG}.wip"
echo -n >"${grainLogWIP}"
for vid in "${EFG_DIR}/"*.mkv; do for vid in "${EFG_DIR}/"*.mkv; do
echo "file: ${vid}" >>"${GRAIN_LOG}" echo "file: ${vid}" >>"${grainLogWIP}"
for ((grain = LOW; grain <= HIGH; grain += STEP)); do for ((grain = LOW; grain <= HIGH; grain += STEP)); do
local file="$(bash_basename "${vid}")" local file="$(bash_basename "${vid}")"
local out="${EFG_DIR}/grain-${grain}-${file}" local out="${EFG_DIR}/grain-${grain}-${file}"
echo_info "encoding ${file} with grain ${grain}" echo_info "encoding ${file} with grain ${grain}"
echo_if_fail encode -P 10 -g ${grain} -i "${vid}" "${out}" echo_if_fail encode -P "${PRESET}" -g ${grain} -i "${vid}" "${out}" || return 1
echo -e "\tgrain: ${grain}, bitrate: $(get_avg_bitrate "${out}")" >>"${GRAIN_LOG}" echo -e "\tgrain: ${grain}, bitrate: $(get_avg_bitrate "${out}")" >>"${grainLogWIP}"
rm "${out}" rm "${out}" || return 1
done done
# remove segment once complete
rm "${vid}" || return 1
done done
less "${GRAIN_LOG}" # atomic move of grain log
mv "${grainLogWIP}" "${GRAIN_LOG}" || return 1
echo "$(<"${GRAIN_LOG}")"
} }
efg_plot() { efg_plot() {
@@ -245,8 +259,14 @@ efg() {
# encode N highest-bitrate segments # encode N highest-bitrate segments
ENCODE_SEGMENTS=5 ENCODE_SEGMENTS=5
set_efg_opts "$@" || return 1 set_efg_opts "$@"
test -d "${EFG_DIR}" || mkdir "${EFG_DIR}" local ret=$?
if [[ ${ret} -eq ${FUNC_EXIT_SUCCESS} ]]; then
return 0
elif [[ ${ret} -ne 0 ]]; then
return ${ret}
fi
ensure_dir "${EFG_DIR}"
GRAIN_LOG="${EFG_DIR}/${LOW}-${STEP}-${HIGH}-grains.txt" GRAIN_LOG="${EFG_DIR}/${LOW}-${STEP}-${HIGH}-grains.txt"

View File

@@ -99,11 +99,11 @@ get_encode_versions() {
# shellcheck disable=SC2155 # shellcheck disable=SC2155
local output="$(ffmpeg -version 2>&1)" local output="$(ffmpeg -version 2>&1)"
while read -r line; do while read -r line; do
if line_contains "${line}" 'ffmpeg='; then if line_starts_with "${line}" 'ffmpeg='; then
ffmpegVersion="${line}" ffmpegVersion="${line}"
elif line_contains "${line}" 'libsvtav1_psy=' || line_contains "${line}" 'libsvtav1='; then elif line_starts_with "${line}" 'libsvtav1'; then
videoEncVersion="${line}" videoEncVersion="${line}"
elif line_contains "${line}" 'libopus='; then elif line_starts_with "${line}" 'libopus='; then
audioEncVersion="${line}" audioEncVersion="${line}"
fi fi
done <<<"${output}" done <<<"${output}"
@@ -154,7 +154,7 @@ encode_usage() {
echo -e "\t[-d] enable dolby vision (default: ${DV_TOGGLE})" echo -e "\t[-d] enable dolby vision (default: ${DV_TOGGLE})"
echo -e "\t[-v] print relevant version info" echo -e "\t[-v] print relevant version info"
echo -e "\t[-s] use same container as input, default is convert to mkv" echo -e "\t[-s] use same container as input, default is convert to mkv"
echo -e "\n\t[output] if unset, defaults to \${HOME}/av1-input-file-name.mkv" echo -e "\n\t[output] if unset, defaults to \${PWD}/av1-input-file-name.mkv"
echo -e "\n\t[-u] update script (git pull ffmpeg-builder)" echo -e "\n\t[-u] update script (git pull ffmpeg-builder)"
echo -e "\t[-I] system install at ${ENCODE_INSTALL_PATH}" echo -e "\t[-I] system install at ${ENCODE_INSTALL_PATH}"
echo -e "\t[-U] uninstall from ${ENCODE_INSTALL_PATH}" echo -e "\t[-U] uninstall from ${ENCODE_INSTALL_PATH}"
@@ -188,25 +188,25 @@ set_encode_opts() {
while getopts "${opts}" flag; do while getopts "${opts}" flag; do
case "${flag}" in case "${flag}" in
u) u)
encode_update encode_update || return 1
exit $? return ${FUNC_EXIT_SUCCESS}
;; ;;
I) I)
echo_warn "attempting install" echo_warn "attempting install"
sudo ln -sf "${SCRIPT_DIR}/encode.sh" \ sudo ln -sf "${SCRIPT_DIR}/encode.sh" \
"${ENCODE_INSTALL_PATH}" || return 1 "${ENCODE_INSTALL_PATH}" || return 1
echo_pass "succesfull install" echo_pass "succesfull install"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
U) U)
echo_warn "attempting uninstall" echo_warn "attempting uninstall"
sudo rm "${ENCODE_INSTALL_PATH}" || return 1 sudo rm "${ENCODE_INSTALL_PATH}" || return 1
echo_pass "succesfull uninstall" echo_pass "succesfull uninstall"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
v) v)
get_encode_versions print get_encode_versions print || return 1
exit $? return ${FUNC_EXIT_SUCCESS}
;; ;;
i) i)
if [[ $# -lt 2 ]]; then if [[ $# -lt 2 ]]; then
@@ -253,7 +253,7 @@ set_encode_opts() {
if ! is_positive_integer "${OPTARG}" || test ${OPTARG} -gt 63; then if ! is_positive_integer "${OPTARG}" || test ${OPTARG} -gt 63; then
echo_fail "${OPTARG} is not a valid CRF value (0-63)" echo_fail "${OPTARG} is not a valid CRF value (0-63)"
encode_usage encode_usage
exit 1 return 1
fi fi
CRF="${OPTARG}" CRF="${OPTARG}"
OPTS_USED=$((OPTS_USED + 2)) OPTS_USED=$((OPTS_USED + 2))
@@ -271,7 +271,7 @@ set_encode_opts() {
OUTPUT="${*: -1}" OUTPUT="${*: -1}"
else else
local basename="$(bash_basename "${INPUT}")" local basename="$(bash_basename "${INPUT}")"
OUTPUT="${HOME}/av1-${basename}" OUTPUT="${PWD}/av1-${basename}"
fi fi
# use same container for output # use same container for output
@@ -339,11 +339,13 @@ gen_encode_script() {
"spy-rd=1" "spy-rd=1"
"psy-rd=1" "psy-rd=1"
"sharpness=3" "sharpness=3"
"enable-overlays=1" "enable-overlays=0"
"hbd-mds=1"
"scd=1" "scd=1"
"fast-decode=1" "fast-decode=1"
"enable-variance-boost=1" "enable-variance-boost=1"
"enable-qm=1" "enable-qm=1"
"chroma-qm-min-10"
"qm-min=4" "qm-min=4"
"qm-max=15" "qm-max=15"
) )
@@ -447,7 +449,7 @@ gen_encode_script() {
echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1' echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1'
# track-stats and clear title # track-stats and clear title
if [[ ${FILE_EXT} == 'mkv' ]]; then if [[ ${FILE_EXT} == 'mkv' ]] && has_cmd mkvpropedit; then
{ {
echo echo
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags' echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags'
@@ -471,6 +473,12 @@ FB_FUNC_NAMES+=('encode')
# shellcheck disable=SC2034 # shellcheck disable=SC2034
FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus' FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus'
encode() { encode() {
set_encode_opts "$@" || return 1 set_encode_opts "$@"
local ret=$?
if [[ ${ret} -eq ${FUNC_EXIT_SUCCESS} ]]; then
return 0
elif [[ ${ret} -ne 0 ]]; then
return ${ret}
fi
gen_encode_script || return 1 gen_encode_script || return 1
} }

View File

@@ -126,3 +126,44 @@ get_stream_lang() {
-of default=noprint_wrappers=1:nokey=1 \ -of default=noprint_wrappers=1:nokey=1 \
"${file}" "${file}"
} }
gen_video() {
local outFile="$1"
local addFlags=()
shift
local vf="format=yuv420p10le"
for arg in "$@"; do
case "${arg}" in
'1080p') resolution='1920x1080' ;;
'2160p') resolution='3840x2160' ;;
'grain=yes') vf+=",noise=alls=15:allf=t+u" ;;
'hdr=yes')
local colorPrimaries='bt2020'
local colorTrc='smpte2084'
local colorspace='bt2020nc'
vf+=",setparams=color_primaries=${colorPrimaries}:color_trc=${colorTrc}:colorspace=${colorspace}"
addFlags+=(
-color_primaries "${colorPrimaries}"
-color_trc "${colorTrc}"
-colorspace "${colorspace}"
-metadata:s:v:0 "mastering_display_metadata=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)"
-metadata:s:v:0 "content_light_level=1000,400"
)
;;
*) echo_fail "bad arg ${arg}" && return 1 ;;
esac
done
echo_if_fail ffmpeg -y \
-hide_banner \
-f lavfi \
-i "testsrc2=size=${resolution}:rate=24:duration=5" \
-vf "${vf}" \
-c:v ffv1 \
-level 3 \
-g 1 \
-color_range tv \
"${addFlags[@]}" \
"${outFile}"
}

View File

@@ -67,12 +67,14 @@ print_req_pkgs() {
"${common_linux_pkgs[@]}" pipx "${common_linux_pkgs[@]}" pipx
build-essential libssl-dev gobjc++ build-essential libssl-dev gobjc++
mawk libc6-dev mediainfo ninja-build mawk libc6-dev mediainfo ninja-build
mkvtoolnix libgtest-dev mkvtoolnix libgtest-dev lld
libfontconfig-dev libglib2.0-dev
) )
# shellcheck disable=SC2034 # shellcheck disable=SC2034
local pacman_pkgs=( local pacman_pkgs=(
"${common_linux_pkgs[@]}" base-devel "${common_linux_pkgs[@]}" base-devel
python-pipx ninja python-pipx ninja lld mkvtoolnix-cli
glib2-devel
) )
# shellcheck disable=SC2034 # shellcheck disable=SC2034
local dnf_pkgs=( local dnf_pkgs=(
@@ -82,6 +84,7 @@ print_req_pkgs() {
libstdc++-static libstdc++-devel libstdc++-static libstdc++-devel
llvm-cmake-utils llvm-devel llvm-cmake-utils llvm-devel
llvm-static compiler-rt lld llvm-static compiler-rt lld
mkvtoolnix glib2-static
) )
# shellcheck disable=SC2034 # shellcheck disable=SC2034
local pkg_pkgs=( local pkg_pkgs=(
@@ -91,6 +94,10 @@ print_req_pkgs() {
git gnuplot bison rsync ragel git gnuplot bison rsync ragel
zip unzip gperf build-essential zip unzip gperf build-essential
binutils ninja ndk-multilib-native-static binutils ninja ndk-multilib-native-static
libandroid-posix-semaphore
libandroid-posix-semaphore-static
libandroid-shmem
libandroid-shmem-static
) )
# shellcheck disable=SC2034 # shellcheck disable=SC2034
local msys_ucrt_pkgs=( local msys_ucrt_pkgs=(
@@ -157,6 +164,7 @@ check_for_req_pkgs() {
echo_pass "packages from ${pkg_mgr} installed" echo_pass "packages from ${pkg_mgr} installed"
has_cmd pipx || echo_if_fail python3 -m pip install --user pipx || return 1 has_cmd pipx || echo_if_fail python3 -m pip install --user pipx || return 1
has_cmd pipx || echo_if_fail python3 -m pipx ensurepath && source ~/.bashrc || return 1
echo_if_fail pipx install virtualenv || return 1 echo_if_fail pipx install virtualenv || return 1
echo_if_fail pipx ensurepath || return 1 echo_if_fail pipx ensurepath || return 1
has_cmd meson || echo_if_fail pipx install meson || return 1 has_cmd meson || echo_if_fail pipx install meson || return 1

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
check_for_package_cfg() { check_for_package_cfg() {
local requiredCfg='ON:ON:3' local requiredCfg='ON:ON:ON:3'
local currentCfg="${STATIC}:${LTO}:${OPT}" local currentCfg="${STATIC}:${LTO}:${PGO}:${OPT}"
if [[ ${currentCfg} == "${requiredCfg}" ]]; then if [[ ${currentCfg} == "${requiredCfg}" ]]; then
return 0 return 0
else else
@@ -14,12 +14,10 @@ FB_FUNC_NAMES+=('package')
FB_FUNC_DESCS['package']='package ffmpeg build' FB_FUNC_DESCS['package']='package ffmpeg build'
package() { package() {
local pkgDir="${IGN_DIR}/package" local pkgDir="${IGN_DIR}/package"
test -d "${pkgDir}" && rm -rf "${pkgDir}" recreate_dir "${pkgDir}" || return 1
check_for_package_cfg || return 0 check_for_package_cfg || return 0
echo_info "packaging" echo_info "packaging"
mkdir "${pkgDir}" || return 1
set_compile_opts || return 1 set_compile_opts || return 1
cp "${PREFIX}/bin/ff"* "${pkgDir}/" cp "${PREFIX}/bin/ff"* "${pkgDir}/"

60
lib/pgo.sh Normal file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env bash
PGO_DIR="${IGN_DIR}/pgo"
PGO_PROFDATA="${PGO_DIR}/prof.profdata"
gen_profdata() {
recreate_dir "${PGO_DIR}" || return 1
cd "${PGO_DIR}" || return 1
setup_pgo_clips || return 1
for vid in *.mkv; do
local args=()
# add precalculated grain amount based off of filename
line_contains "${vid}" 'grain' && args+=(-g 16)
# make fhd preset 2
line_contains "${vid}" 'fhd' && args+=(-P 2)
echo_info "encoding pgo vid: ${vid}"
LLVM_PROFILE_FILE="${PGO_DIR}/default_%p.profraw" \
echo_if_fail encode -i "${vid}" "${args[@]}" "encoded-${vid}" || return 1
done
# merge profraw into profdata
local mergeCmd=()
# darwin needs special invoke
if is_darwin; then
mergeCmd+=(xcrun)
fi
mergeCmd+=(
llvm-profdata
merge
"--output=${PGO_PROFDATA}"
)
"${mergeCmd[@]}" default*.profraw || return 1
return 0
}
setup_pgo_clips() {
local clips=(
"fhd-grainy.mkv 1080p,grain=yes"
"uhd.mkv 2160p"
"uhd-hdr.mkv 2160p,hdr=yes"
)
for clip in "${clips[@]}"; do
local genVid genVidArgs pgoFile genVidArgsArr
IFS=' ' read -r genVid genVidArgs <<<"${clip}"
# pgo path is separate
pgoFile="${PGO_DIR}/${genVid}"
genVid="${TMP_DIR}/${genVid}"
# create array of args split with ,
genVidArgsArr=(${genVidArgs//,/ })
# create generated vid without any profiling if needed
test -f "${genVid}" ||
LLVM_PROFILE_FILE='/dev/null' gen_video "${genVid}" "${genVidArgsArr[@]}" || return 1
# and move to the pgo directory
test -f "${pgoFile}" ||
cp "${genVid}" "${pgoFile}" || return 1
done
}

View File

@@ -1,350 +0,0 @@
#!/usr/bin/env bash
# shellcheck disable=SC2034
# ANSI colors
RED='\e[0;31m'
CYAN='\e[0;36m'
GREEN='\e[0;32m'
YELLOW='\e[0;33m'
NC='\e[0m'
# echo wrappers
echo_wrapper() {
local args
if [[ $1 == '-n' ]]; then
args=("$1")
shift
fi
# COLOR is override for using ${color}
# shellcheck disable=SC2153
if [[ ${COLOR} == 'OFF' ]]; then
color=''
endColor=''
else
endColor="${NC}"
fi
echo -e "${args[@]}" "${color}${word:-''}${endColor}" "$@"
}
echo_fail() { color="${RED}" word="FAIL" echo_wrapper "$@"; }
echo_info() { color="${CYAN}" word="INFO" echo_wrapper "$@"; }
echo_pass() { color="${GREEN}" word="PASS" echo_wrapper "$@"; }
echo_warn() { color="${YELLOW}" word="WARN" echo_wrapper "$@"; }
echo_exit() {
echo_fail "$@"
exit 1
}
void() { echo "$@" >/dev/null; }
echo_if_fail() {
local cmd=("$@")
local logName="${LOGNAME:-${RANDOM}}-"
local out="${TMP_DIR}/${logName}stdout"
local err="${TMP_DIR}/${logName}stderr"
# set trace to the cmdEvalTrace and open file descriptor
local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace"
exec 5>"${cmdEvalTrace}"
export BASH_XTRACEFD=5
set -x
"${cmd[@]}" >"${out}" 2>"${err}"
local retval=$?
# unset and close file descriptor
set +x
exec 5>&-
# parse out relevant part of the trace
local cmdEvalLines=()
while IFS= read -r line; do
line="${line/${PS4}/}"
test "${line}" == 'set +x' && continue
test "${line}" == '' && continue
cmdEvalLines+=("${line}")
done <"${cmdEvalTrace}"
if ! test ${retval} -eq 0; then
echo
echo_fail "command failed:"
printf "%s\n" "${cmdEvalLines[@]}"
echo_warn "command stdout:"
tail -n 32 "${out}"
echo_warn "command stderr:"
tail -n 32 "${err}"
echo
fi
if [[ -z ${LOGNAME} ]]; then
rm "${out}" "${err}" "${cmdEvalTrace}"
fi
return ${retval}
}
is_root_owned() {
local path=$1
local uid
if stat --version >/dev/null 2>&1; then
# GNU coreutils (Linux)
uid=$(stat -c '%u' "$path")
else
# BSD/macOS
uid=$(stat -f '%u' "$path")
fi
test "$uid" -eq 0
}
dump_arr() {
local arrayNames=("$@")
for arrayName in "${arrayNames[@]}"; do
declare -n array="${arrayName}"
arrayExpanded=("${array[@]}")
# skip showing single element arrays by default
if [[ ! ${#arrayExpanded[@]} -gt 1 ]]; then
if [[ ${SHOW_SINGLE} == true ]]; then
echo_info "${arrayName}='${arrayExpanded[*]}'"
else
continue
fi
fi
echo
# don't care that the variable has "ARR"
echo_info "${arrayName//"_ARR"/}"
printf "\t%s\n" "${arrayExpanded[@]}"
done
}
has_cmd() {
local cmds=("$@")
local rv=0
for cmd in "${cmds[@]}"; do
command -v "${cmd}" >/dev/null 2>&1 || rv=1
done
return ${rv}
}
missing_cmd() {
local cmds=("$@")
local rv=1
for cmd in "${cmds[@]}"; do
if ! has_cmd "${cmd}"; then
echo_warn "missing ${cmd}"
rv=0
fi
done
return ${rv}
}
bash_dirname() {
local tmp=${1:-.}
[[ $tmp != *[!/]* ]] && {
printf '/\n'
return
}
tmp=${tmp%%"${tmp##*[!/]}"}
[[ $tmp != */* ]] && {
printf '.\n'
return
}
tmp=${tmp%/*}
tmp=${tmp%%"${tmp##*[!/]}"}
printf '%s\n' "${tmp:-/}"
}
bash_basename() {
local tmp
path="$1"
suffix="${2:-''}"
tmp=${path%"${path##*[!/]}"}
tmp=${tmp##*/}
tmp=${tmp%"${suffix/"$tmp"/}"}
printf '%s\n' "${tmp:-/}"
}
bash_realpath() {
local file=$1
local dir
# If the file is already absolute
[[ $file == /* ]] && {
printf '%s\n' "$file"
return
}
# Otherwise: split into directory + basename
dir="$(bash_dirname "${file}")"
file="$(bash_basename "${file}")"
# If no directory component, use current directory
if [[ $dir == "$file" ]]; then
dir="$PWD"
else
# Save current dir, move into target dir, capture $PWD, then return
local oldpwd="$PWD"
cd "$dir" || return 1
dir="$PWD"
cd "$oldpwd" || return 1
fi
printf '%s/%s\n' "$dir" "$file"
}
line_contains() {
local line="$1"
local substr="$2"
if [[ $line == *"${substr}"* ]]; then
return 0
else
return 1
fi
}
line_starts_with() {
local line="$1"
local substr="$2"
if [[ $line == "${substr}"* ]]; then
return 0
else
return 1
fi
}
is_linux() {
line_contains "${OSTYPE}" 'linux'
}
is_darwin() {
line_contains "$(print_os)" darwin
}
is_windows() {
line_contains "$(print_os)" windows
}
is_android() {
line_contains "$(print_os)" android
}
print_os() {
# cached response
if [[ -n ${FB_OS} ]]; then
echo "${FB_OS}"
return 0
fi
unset FB_OS
if [[ -f /etc/os-release ]]; then
source /etc/os-release
FB_OS="${ID}"
if [[ ${VERSION_ID} != '' ]]; then
FB_OS+="-${VERSION_ID}"
fi
if line_starts_with "${FB_OS}" 'arch'; then
FB_OS='archlinux'
fi
else
FB_OS="$(uname -o)"
fi
# lowercase
FB_OS="${FB_OS,,}"
# special treatment for windows
if line_contains "${FB_OS}" 'windows' || line_contains "${FB_OS}" 'msys'; then
FB_OS='windows'
fi
echo "${FB_OS}"
}
is_positive_integer() {
local input="$1"
if [[ ${input} != ?(-)+([[:digit:]]) || ${input} -lt 0 ]]; then
echo_fail "${input} is not a positive integer"
return 1
fi
return 0
}
replace_line() {
local file="$1"
local search="$2"
local newLine="$3"
local newFile="${TMP_DIR}/$(bash_basename "${file}")"
test -f "${newFile}" && rm "${newFile}"
while read -r line; do
if line_contains "${line}" "${search}"; then
echo -en "${newLine}" >>"${newFile}"
continue
fi
echo "${line}" >>"${newFile}"
done <"${file}"
cp "${newFile}" "${file}"
}
remove_line() {
local file="$1"
local search="$2"
replace_line "${file}" "${search}" ''
}
bash_sort() {
local arr=("$@")
local n=${#arr[@]}
local i j val1 val2
# Bubble sort, numeric comparison
for ((i = 0; i < n; i++)); do
for ((j = 0; j < n - i - 1; j++)); do
read -r val1 _ <<<"${arr[j]}"
read -r val2 _ <<<"${arr[j + 1]}"
if (("${val1}" > "${val2}")); then
local tmp=${arr[j]}
arr[j]=${arr[j + 1]}
arr[j + 1]=$tmp
fi
done
done
printf '%s\n' "${arr[@]}"
}
spinner() {
if [[ $1 == 'reset' ]]; then
echo -ne ' \n'
return 0
fi
local spinChars=(
"-"
'\'
"|"
"/"
)
while true; do
for ((ind = 0; ind < "${#spinChars[@]}"; ind++)); do
echo -ne "${spinChars[${ind}]}" '\b\b'
sleep .25
done
done
}
get_pkgconfig_version() {
local pkg="$1"
pkg-config --modversion "${pkg}"
}

View File

@@ -15,6 +15,11 @@ DOCKER_DIR="${IGN_DIR}/docker"
PATCHES_DIR="${REPO_DIR}/patches" PATCHES_DIR="${REPO_DIR}/patches"
export REPO_DIR IGN_DIR TMP_DIR DL_DIR BUILD_DIR CCACHE_DIR DOCKER_DIR PATCHES_DIR export REPO_DIR IGN_DIR TMP_DIR DL_DIR BUILD_DIR CCACHE_DIR DOCKER_DIR PATCHES_DIR
# some functions need a way to signal early
# returns instead of failures, so if a function
# returns ${FUNC_EXIT_SUCCESS}, stop processing
test -v FUNC_EXIT_SUCCESS || readonly FUNC_EXIT_SUCCESS=9
# make paths if needed # make paths if needed
IGN_DIRS=( IGN_DIRS=(
"${TMP_DIR}" "${TMP_DIR}"

View File

@@ -0,0 +1,11 @@
# https://sourceforge.net/p/lame/mailman/message/36081038/
diff --git a/include/libmp3lame.sym b/include/libmp3lame.sym
index ff7d318..fd120f5 100644
--- a/include/libmp3lame.sym
+++ b/include/libmp3lame.sym
@@ -1,5 +1,4 @@
lame_init
-lame_init_old
lame_set_num_samples
lame_get_num_samples
lame_set_in_samplerate

View File

@@ -0,0 +1,24 @@
diff --git a/vorbis.pc.in b/vorbis.pc.in
index f5ca77d..50cad9e 100644
--- a/vorbis.pc.in
+++ b/vorbis.pc.in
@@ -10,6 +10,6 @@ Description: vorbis is the primary Ogg Vorbis library
Version: @VERSION@
Requires.private: ogg
Conflicts:
-Libs: -L${libdir} -lvorbis
-Libs.private: @VORBIS_LIBS@
+Libs: -L${libdir} -lvorbis
+Libs.private: @VORBIS_LIBS@ -lm
Cflags: -I${includedir}
diff --git a/vorbisenc.pc.in b/vorbisenc.pc.in
index a412b7a..4222daf 100644
--- a/vorbisenc.pc.in
+++ b/vorbisenc.pc.in
@@ -10,5 +10,5 @@ Description: vorbisenc is a library that provides a convenient API for setting u
Version: @VERSION@
Requires.private: vorbis
Conflicts:
-Libs: -L${libdir} -lvorbisenc
+Libs: -L${libdir} -lvorbisenc -lm
Cflags: -I${includedir}

View File

@@ -0,0 +1,13 @@
diff --git a/build/make/configure.sh b/build/make/configure.sh
index cc5bf6c..c229965 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -16,8 +16,6 @@
die_unknown(){
echo "Unknown option \"$1\"."
echo "See $0 --help for available options."
- clean_temp_files
- exit 1
}
die() {

View File

@@ -6,10 +6,10 @@ inotifywait -m -r \
-e close_write \ -e close_write \
-e moved_to \ -e moved_to \
--format '%w%f' \ --format '%w%f' \
"$base/lib" \ "${base}/lib" \
"$base/scripts" \ "${base}/scripts" \
"$base/main.sh" | while read -r file; do "${base}/main.sh" | while read -r file; do
if [[ -f $file && $file =~ .sh ]]; then if [[ -f $file && $file =~ .sh ]]; then
shfmt --write --simplify "$file" shfmt --indent 4 --write --simplify "${file}"
fi fi
done done