mirror of
https://github.com/levogevo/ffmpeg-builder.git
synced 2026-03-16 19:20:11 +00:00
Compare commits
26 Commits
2bde1d7d01
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 852d7e3795 | |||
| 18815854f5 | |||
| 5261b67a18 | |||
| c2be0112fb | |||
| f1b2a0d534 | |||
| 64c7f358fc | |||
| 73bb7338f4 | |||
| a56d4adb27 | |||
| 037a008c1b | |||
| b21d2bfdd8 | |||
| 00c4415e15 | |||
| d13143815d | |||
| 1462bb12bc | |||
| a9703ac87e | |||
| 717410b632 | |||
| 09ea4e24fb | |||
| 8d9c670b6c | |||
| 78e35b734d | |||
| a8f2ad82fd | |||
| a54dec7174 | |||
| 41cbb42a88 | |||
| ec60ce73af | |||
| d9bd413d9c | |||
| ee06f96221 | |||
| fe42f66ce6 | |||
| 7ffd989330 |
@@ -13,7 +13,7 @@ Tested on:
|
||||
With these scripts you can:
|
||||
1. install required dependencies using `./scripts/install_deps.sh`
|
||||
2. build ffmpeg with the desired configuration using `./scripts/build.sh`
|
||||
3. encode a file using libsvtav1_psy and libopus using `./scripts/encode.sh`
|
||||
3. encode a file using libsvtav1 and libopus using `./scripts/encode.sh`
|
||||
4. estimate the film grain of a given file using `./scripts/efg.sh`
|
||||
|
||||
# Building
|
||||
@@ -24,7 +24,7 @@ Configuration is done through environment variables.
|
||||
By default, this project will build a static `ffmpeg` binary in `./gitignore/sysroot/bin/ffmpeg`.
|
||||
|
||||
The user-overridable compile options are:
|
||||
- `ENABLE`: configure what ffmpeg enables (default: libaom libass libvpx libxml2 libvmaf libx264 libx265 libwebp libopus librav1e libdav1d libvorbis libmp3lame libfribidi libfreetype libharfbuzz libsvtav1_psy libfontconfig )
|
||||
- `ENABLE`: configure what ffmpeg enables (default: libaom libass libvpx libxml2 libvmaf libx264 libx265 libwebp libopus librav1e libdav1d libvorbis libmp3lame libfribidi libfreetype libharfbuzz libopenjpeg libsvtav1_hdr libfontconfig )
|
||||
- `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local)
|
||||
- `STATIC`: static or shared build (default: ON)
|
||||
- `LTO`: enable link time optimization (default: ON)
|
||||
@@ -78,6 +78,7 @@ encode -i input [options] output
|
||||
- Skips re-encoding av1/opus streams.
|
||||
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
||||
- Only maps english subtitle streams.
|
||||
- Crop PGS subtitles to match video dimensions.
|
||||
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
||||
```
|
||||
ENCODE : aa4d7e6
|
||||
|
||||
152
lib/0-utils.sh
152
lib/0-utils.sh
@@ -37,24 +37,55 @@ echo_exit() {
|
||||
}
|
||||
void() { echo "$@" >/dev/null; }
|
||||
|
||||
echo_if_fail() {
|
||||
trace_cmd_to_file() {
|
||||
local cmd=("$@")
|
||||
local logName="${LOGNAME:-${RANDOM}}-"
|
||||
local out="${TMP_DIR}/${logName}stdout"
|
||||
local err="${TMP_DIR}/${logName}stderr"
|
||||
test -n "${OUT}" && test -n "${ERR}" && test -n "${TRACE}" || return 1
|
||||
local out="${OUT}"
|
||||
local err="${ERR}"
|
||||
local trace="${TRACE}"
|
||||
local fd=6
|
||||
|
||||
# get current trace status
|
||||
local set
|
||||
if [[ $- == *x* ]]; then
|
||||
set='-x'
|
||||
else
|
||||
set='+x'
|
||||
fi
|
||||
|
||||
# stop tracing before new trace file
|
||||
set +x
|
||||
|
||||
# set trace to the cmdEvalTrace and open file descriptor
|
||||
local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace"
|
||||
exec 5>"${cmdEvalTrace}"
|
||||
export BASH_XTRACEFD=5
|
||||
eval "exec ${fd}>\"${trace}\""
|
||||
export BASH_XTRACEFD=${fd}
|
||||
|
||||
set -x
|
||||
"${cmd[@]}" >"${out}" 2>"${err}"
|
||||
local retval=$?
|
||||
|
||||
# unset and close file descriptor
|
||||
# unset BASH_XTRACEFD first
|
||||
set +x
|
||||
exec 5>&-
|
||||
unset BASH_XTRACEFD
|
||||
eval "exec ${fd}>&-"
|
||||
|
||||
# reset previous state
|
||||
set ${set}
|
||||
|
||||
return ${retval}
|
||||
}
|
||||
|
||||
echo_if_fail() {
|
||||
local cmd=("$@")
|
||||
local logName="${LOGNAME:-${RANDOM}}-"
|
||||
local out="${TMP_DIR}/${logName}stdout"
|
||||
local err="${TMP_DIR}/${logName}stderr"
|
||||
local trace="${TMP_DIR}/${logName}trace"
|
||||
|
||||
OUT="${out}" ERR="${err}" TRACE="${trace}" trace_cmd_to_file \
|
||||
"${cmd[@]}"
|
||||
local retval=$?
|
||||
|
||||
# parse out relevant part of the trace
|
||||
local cmdEvalLines=()
|
||||
@@ -63,7 +94,7 @@ echo_if_fail() {
|
||||
test "${line}" == 'set +x' && continue
|
||||
test "${line}" == '' && continue
|
||||
cmdEvalLines+=("${line}")
|
||||
done <"${cmdEvalTrace}"
|
||||
done <"${trace}"
|
||||
|
||||
if ! test ${retval} -eq 0; then
|
||||
echo
|
||||
@@ -76,7 +107,7 @@ echo_if_fail() {
|
||||
echo
|
||||
fi
|
||||
if [[ -z ${LOGNAME} ]]; then
|
||||
rm "${out}" "${err}" "${cmdEvalTrace}"
|
||||
rm "${out}" "${err}" "${trace}"
|
||||
fi
|
||||
return ${retval}
|
||||
}
|
||||
@@ -85,7 +116,7 @@ is_root_owned() {
|
||||
local path=$1
|
||||
local uid
|
||||
|
||||
if stat --version >/dev/null 2>&1; then
|
||||
if stat --version &>/dev/null; then
|
||||
# GNU coreutils (Linux)
|
||||
uid=$(stat -c '%u' "$path")
|
||||
else
|
||||
@@ -122,7 +153,7 @@ has_cmd() {
|
||||
local cmds=("$@")
|
||||
local rv=0
|
||||
for cmd in "${cmds[@]}"; do
|
||||
command -v "${cmd}" >/dev/null 2>&1 || rv=1
|
||||
command -v "${cmd}" &>/dev/null || rv=1
|
||||
done
|
||||
|
||||
return ${rv}
|
||||
@@ -333,19 +364,14 @@ bash_sort() {
|
||||
}
|
||||
|
||||
_start_spinner() {
|
||||
local spinChars=(
|
||||
"-"
|
||||
'\'
|
||||
"|"
|
||||
"/"
|
||||
)
|
||||
local spinChars=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏")
|
||||
|
||||
sleep 1
|
||||
|
||||
while true; do
|
||||
for ((ind = 0; ind < "${#spinChars[@]}"; ind++)); do
|
||||
echo -ne "${spinChars[${ind}]}" '\b\b'
|
||||
sleep .25
|
||||
sleep .125
|
||||
done
|
||||
done
|
||||
}
|
||||
@@ -355,7 +381,8 @@ spinner() {
|
||||
local spinPidFile="${TMP_DIR}/.spinner-pid"
|
||||
case "${action}" in
|
||||
start)
|
||||
test -f "${spinPidFile}" && rm "${spinPidFile}"
|
||||
# if there is already a pidfile, we're spinning
|
||||
test -f "${spinPidFile}" && return
|
||||
|
||||
# don't want to clutter logs if running headless
|
||||
test "${HEADLESS}" == '1' && return
|
||||
@@ -364,7 +391,11 @@ spinner() {
|
||||
echo $! >"${spinPidFile}"
|
||||
;;
|
||||
stop)
|
||||
test -f "${spinPidFile}" && kill "$(<"${spinPidFile}")"
|
||||
if [[ -f ${spinPidFile} ]]; then
|
||||
local pid="$(<"${spinPidFile}")"
|
||||
kill -0 "${pid}" &>/dev/null && kill "${pid}"
|
||||
rm "${spinPidFile}"
|
||||
fi
|
||||
echo -ne ' \n'
|
||||
;;
|
||||
esac
|
||||
@@ -375,10 +406,10 @@ get_pkgconfig_version() {
|
||||
pkg-config --modversion "${pkg}"
|
||||
}
|
||||
|
||||
using_cmake_4() {
|
||||
using_cmake3() {
|
||||
local cmakeVersion
|
||||
IFS=$' \t' read -r _ _ cmakeVersion <<<"$(command cmake --version)"
|
||||
line_starts_with "${cmakeVersion}" 4
|
||||
line_starts_with "${cmakeVersion}" 3
|
||||
}
|
||||
|
||||
have_req_meson_version() {
|
||||
@@ -412,11 +443,29 @@ ensure_dir() {
|
||||
done
|
||||
}
|
||||
|
||||
get_date() {
|
||||
printf '%(%Y-%m-%d)T\n' -1
|
||||
}
|
||||
|
||||
get_remote_head() {
|
||||
local url="$1"
|
||||
local remoteHEAD=''
|
||||
# ${build} is magically populated from get_build_conf
|
||||
local remoteCommitFile="${TMP_DIR}/${build}-remote-head.txt"
|
||||
local date="$(get_date)"
|
||||
# want to cache the remote head for faster retrieval
|
||||
# and only get it once per day
|
||||
local remoteHEAD
|
||||
if [[ -f ${remoteCommitFile} ]]; then
|
||||
IFS=' ' read -r prevDate prevBuild prevCommit <"${remoteCommitFile}"
|
||||
fi
|
||||
|
||||
if [[ "${date}:${build}" == "${prevDate}:${prevBuild}" ]]; then
|
||||
remoteHEAD="${prevCommit}"
|
||||
else
|
||||
IFS=$' \t' read -r remoteHEAD _ <<< \
|
||||
"$(git ls-remote "${url}" HEAD)"
|
||||
echo "${date} ${build} ${remoteHEAD}" >"${remoteCommitFile}"
|
||||
fi
|
||||
echo "${remoteHEAD}"
|
||||
}
|
||||
|
||||
@@ -436,3 +485,58 @@ print_padded() {
|
||||
echo -n ' '
|
||||
done
|
||||
}
|
||||
|
||||
benchmark_command() {
|
||||
local cmd=("$@")
|
||||
local out='/dev/null'
|
||||
local err='/dev/null'
|
||||
local trace="${TMP_DIR}/benchmark-trace.txt"
|
||||
|
||||
# note this marker around the awk parsing
|
||||
local traceMarker='TRACEOUTPUT ; '
|
||||
|
||||
echo_warn "tracing ${cmd[*]}"
|
||||
PS4='$EPOCHREALTIME TRACEOUTPUT ; ' OUT="${out}" ERR="${err}" TRACE="${trace}" trace_cmd_to_file \
|
||||
"${cmd[@]}" || return 1
|
||||
echo_pass "done tracing ${cmd[*]}"
|
||||
|
||||
awk '
|
||||
BEGIN {
|
||||
# Use a regex for the marker to handle leading/trailing whitespace cleanly
|
||||
marker = "TRACEOUTPUT ; "
|
||||
}
|
||||
|
||||
# Match lines starting with a timestamp followed by the marker
|
||||
$0 ~ /^[0-9.]+[ ]+TRACEOUTPUT ; / {
|
||||
# 1. Calculate duration for the PREVIOUS command now that we have a new timestamp
|
||||
if (prev_time != "") {
|
||||
duration = $1 - prev_time
|
||||
# Output for the system sort: [duration] | [command]
|
||||
printf "%012.6f | %s\n", duration, prev_cmd
|
||||
}
|
||||
|
||||
# 2. Start tracking the NEW command
|
||||
prev_time = $1
|
||||
|
||||
# Extract everything after "TRACEOUTPUT ; "
|
||||
# match() finds the position, substr() grabs the rest
|
||||
match($0, /TRACEOUTPUT ; /)
|
||||
prev_cmd = substr($0, RSTART + RLENGTH)
|
||||
next
|
||||
}
|
||||
|
||||
# If the line does not match the timestamp pattern, it is a newline in a variable
|
||||
{
|
||||
if (prev_time != "") {
|
||||
prev_cmd = prev_cmd "\n" $0
|
||||
}
|
||||
}
|
||||
' "${trace}" | sort -rn | head -n 20
|
||||
}
|
||||
|
||||
# make sure supmover is built
|
||||
# and set SUPMOVER
|
||||
check_for_supmover() {
|
||||
SUPMOVER="${LOCAL_PREFIX}/bin/supmover"
|
||||
test -f "${SUPMOVER}" || do_build supmover || return 1
|
||||
}
|
||||
|
||||
303
lib/build.sh
303
lib/build.sh
@@ -166,6 +166,9 @@ fi' >"${compilerDir}/which"
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
||||
"-DCMAKE_VERBOSE_MAKEFILE=ON"
|
||||
"-G" "Ninja"
|
||||
"-DENABLE_STATIC=${STATIC}"
|
||||
"-DBUILD_STATIC_LIBS=${STATIC}"
|
||||
"-DBUILD_TESTING=OFF"
|
||||
)
|
||||
CARGO_CINSTALL_FLAGS=(
|
||||
"--release"
|
||||
@@ -175,11 +178,6 @@ fi' >"${compilerDir}/which"
|
||||
)
|
||||
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
|
||||
# TODO use cygpath for windows
|
||||
CPPFLAGS_ARR+=("-I${PREFIX}/include")
|
||||
@@ -224,6 +222,9 @@ fi' >"${compilerDir}/which"
|
||||
SHARED_LIB_SUFF='so'
|
||||
fi
|
||||
|
||||
# least problematic place to set this
|
||||
CMAKE_FLAGS+=("-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}")
|
||||
|
||||
# static/shared linking
|
||||
if [[ ${STATIC} == 'ON' ]]; then
|
||||
BUILD_TYPE=static
|
||||
@@ -233,17 +234,14 @@ fi' >"${compilerDir}/which"
|
||||
)
|
||||
MESON_FLAGS+=('--default-library=static')
|
||||
CMAKE_FLAGS+=(
|
||||
"-DENABLE_STATIC=${STATIC}"
|
||||
"-DENABLE_SHARED=OFF"
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
)
|
||||
# darwin does not support -static
|
||||
if is_darwin; then
|
||||
FFMPEG_EXTRA_FLAGS+=("--extra-ldflags=${LDFLAGS_ARR[*]}")
|
||||
CMAKE_FLAGS+=("-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}")
|
||||
else
|
||||
FFMPEG_EXTRA_FLAGS+=("--extra-ldflags=${LDFLAGS_ARR[*]} -static")
|
||||
CMAKE_FLAGS+=("-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]} -static")
|
||||
fi
|
||||
FFMPEG_EXTRA_FLAGS+=("--pkg-config-flags=--static")
|
||||
# remove shared libraries for static builds
|
||||
@@ -252,12 +250,10 @@ fi' >"${compilerDir}/which"
|
||||
else
|
||||
BUILD_TYPE=shared
|
||||
CMAKE_FLAGS+=(
|
||||
"-DENABLE_STATIC=${STATIC}"
|
||||
"-DENABLE_SHARED=ON"
|
||||
"-DBUILD_SHARED_LIBS=ON"
|
||||
"-DCMAKE_INSTALL_RPATH=${LIBDIR}"
|
||||
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON"
|
||||
"-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}"
|
||||
)
|
||||
if is_darwin; then
|
||||
CMAKE_FLAGS+=(
|
||||
@@ -286,15 +282,18 @@ fi' >"${compilerDir}/which"
|
||||
else
|
||||
arch_flags+=("-march=${ARCH}")
|
||||
fi
|
||||
CFLAGS_ARR+=("${arch_flags[@]}")
|
||||
RUSTFLAGS_ARR+=(-C "target-cpu=${ARCH}")
|
||||
|
||||
# can fail static builds with -fpic
|
||||
# warning: too many GOT entries for -fpic, please recompile with -fPIC
|
||||
CFLAGS_ARR+=("${arch_flags[@]}" "-fPIC")
|
||||
RUSTFLAGS_ARR+=("-C target-cpu=${ARCH}")
|
||||
CFLAGS_ARR+=("-fPIC")
|
||||
# add preprocessor flags
|
||||
CFLAGS_ARR+=("${CPPFLAGS_ARR[@]}")
|
||||
|
||||
# set exported env names to stringified arrays
|
||||
CPPFLAGS="${CPPFLAGS_ARR[*]}"
|
||||
CFLAGS="${CFLAGS_ARR[*]} ${CPPFLAGS}"
|
||||
CFLAGS="${CFLAGS_ARR[*]}"
|
||||
CXXFLAGS="${CFLAGS}"
|
||||
LDFLAGS="${LDFLAGS_ARR[*]}"
|
||||
RUSTFLAGS="${RUSTFLAGS_ARR[*]}"
|
||||
@@ -325,6 +324,7 @@ fi' >"${compilerDir}/which"
|
||||
|
||||
get_build_conf() {
|
||||
local getBuild="${1}"
|
||||
local getBuildValue="${2:-}"
|
||||
|
||||
local longestBuild=0
|
||||
local longestVer=0
|
||||
@@ -336,12 +336,13 @@ get_build_conf() {
|
||||
local BUILDS_CONF='
|
||||
ffmpeg 8.0.1 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
|
||||
|
||||
libsvtav1_hdr 4.0.1 tar.gz https://github.com/juliobbv-p/svt-av1-hdr/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.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}
|
||||
cpuinfo latest git https://github.com/pytorch/cpuinfo/
|
||||
|
||||
libsvtav1 3.1.2 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${ver}/SVT-AV1-v${ver}.${ext}
|
||||
libsvtav1 4.0.1 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${ver}/SVT-AV1-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}
|
||||
libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext}
|
||||
@@ -349,15 +350,20 @@ libopus 1.6 tar.gz https://github.com/xiph/opus/archive/re
|
||||
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
|
||||
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}
|
||||
libvpx 1.16.0 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
|
||||
libvorbis 1.3.7 tar.xz https://github.com/xiph/vorbis/releases/download/v${ver}/libvorbis-${ver}.${ext} libogg,cmake3
|
||||
libogg 1.3.6 tar.xz https://github.com/xiph/ogg/releases/download/v${ver}/libogg-${ver}.${ext}
|
||||
|
||||
libopenjpeg 2.5.4 tar.gz https://github.com/uclouvain/openjpeg/archive/refs/tags/v${ver}.${ext} libtiff,lcms2
|
||||
lcms2 2.18 tar.gz https://github.com/mm2/Little-CMS/archive/refs/tags/lcms${ver}.${ext} libtiff,libjpeg
|
||||
libtiff 4.7.1 tar.gz https://github.com/libsdl-org/libtiff/archive/refs/tags/v${ver}.${ext} libwebp,libdeflate,xz,zstd
|
||||
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}
|
||||
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}
|
||||
libdeflate 1.25 tar.gz https://github.com/ebiggers/libdeflate/archive/refs/tags/v${ver}.${ext} zlib
|
||||
zstd 1.5.7 tar.gz https://github.com/facebook/zstd/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
|
||||
glslang 16.0.0 tar.gz https://github.com/KhronosGroup/glslang/archive/refs/tags/${ver}.${ext} spirv_tools
|
||||
@@ -365,12 +371,14 @@ spirv_tools 2025.4 tar.gz https://github.com/KhronosGroup/SPIRV-T
|
||||
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}
|
||||
|
||||
libx265 4.1 tar.gz https://bitbucket.org/multicoreware/x265_git/downloads/x265_${ver}.${ext} libnuma
|
||||
libx265 4.1 tar.gz http://ftp.videolan.org/pub/videolan/x265/x265_${ver}.${ext} libnuma,cmake3
|
||||
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} libfreetype,libharfbuzz,libfribidi,libunibreak,libxml2,xz
|
||||
libass 0.17.4 tar.xz https://github.com/libass/libass/releases/download/${ver}/libass-${ver}.${ext} libfontconfig,libfreetype,libharfbuzz,libfribidi,libunibreak,libxml2,xz
|
||||
libfontconfig 2.17.1 tar.xz https://gitlab.freedesktop.org/api/v4/projects/890/packages/generic/fontconfig/${ver}/fontconfig-${ver}.${ext} libharfbuzz,expat,brotli
|
||||
libfreetype 2.14.1 tar.xz https://downloads.sourceforge.net/freetype/freetype-${ver}.${ext} bzip,libpng,zlib,brotli
|
||||
libfreetype 2.14.1 tar.xz https://downloads.sourceforge.net/freetype/freetype-${ver}.${ext} bzip,libpng,zlib,brotli,libharfbuzzNFTP
|
||||
libharfbuzzNFTP 12.3.0 tar.xz https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.${ext}
|
||||
libharfbuzz 12.3.0 tar.xz https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.${ext} libfreetype
|
||||
libunibreak 6.1 tar.gz https://github.com/adah1972/libunibreak/releases/download/libunibreak_${ver//./_}/libunibreak-${ver}.${ext}
|
||||
libxml2 2.15.1 tar.gz https://github.com/GNOME/libxml2/archive/refs/tags/v${ver}.${ext}
|
||||
@@ -379,6 +387,8 @@ libfribidi 1.0.16 tar.xz https://github.com/fribidi/fribidi/rele
|
||||
bzip latest git https://github.com/libarchive/bzip2.git
|
||||
brotli 1.2.0 tar.gz https://github.com/google/brotli/archive/refs/tags/v${ver}.${ext}
|
||||
expat 2.7.3 tar.xz https://github.com/libexpat/libexpat/releases/download/R_${ver//./_}/expat-${ver}.${ext}
|
||||
|
||||
supmover 2.4.3 tar.gz https://github.com/MonoS/SupMover/archive/refs/tags/v${ver}.${ext}
|
||||
'
|
||||
local supported_builds=()
|
||||
unset ver ext url deps extractedDir
|
||||
@@ -406,7 +416,7 @@ expat 2.7.3 tar.xz https://github.com/libexpat/libexpat/re
|
||||
fi
|
||||
|
||||
# special arg to print BUILDS_CONF but formatted with spaces
|
||||
if [[ ${getBuild} == 'format-builds-conf' ]]; then
|
||||
if [[ ${getBuild} == 'formatted' ]]; then
|
||||
echo "local BUILDS_CONF='"
|
||||
while read -r line; do
|
||||
IFS=$' \t' read -r build ver ext url deps <<<"${line}"
|
||||
@@ -428,8 +438,15 @@ expat 2.7.3 tar.xz https://github.com/libexpat/libexpat/re
|
||||
# url uses ver and extension
|
||||
eval "url=\"$url\""
|
||||
# set dependencies array
|
||||
# ffmpeg dependencies are everything enabled
|
||||
if [[ ${build} == 'ffmpeg' ]]; then
|
||||
# shellcheck disable=SC2206
|
||||
# shellcheck disable=SC2153
|
||||
deps=(${ENABLE})
|
||||
else
|
||||
# shellcheck disable=SC2206
|
||||
deps=(${deps//,/ })
|
||||
fi
|
||||
# set version based off of remote head
|
||||
# and set extracted directory
|
||||
if [[ ${ext} == 'git' ]]; then
|
||||
@@ -439,6 +456,11 @@ expat 2.7.3 tar.xz https://github.com/libexpat/libexpat/re
|
||||
extractedDir="${BUILD_DIR}/${build}-v${ver}"
|
||||
fi
|
||||
|
||||
if [[ -n ${getBuildValue} ]]; then
|
||||
declare -n value=${getBuildValue}
|
||||
echo "${value}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -499,12 +521,12 @@ download_release() {
|
||||
else
|
||||
# for git downloads
|
||||
test -d "${download}" ||
|
||||
git clone --recursive "${url}" "${download}" || return 1
|
||||
git clone --depth 1 --recursive "${url}" "${download}" || return 1
|
||||
(
|
||||
cd "${download}" || exit 1
|
||||
local localHEAD remoteHEAD
|
||||
localHEAD="$(git rev-parse HEAD)"
|
||||
remoteHEAD="$(get_remote_head "$(git config --get remote.origin.url)")"
|
||||
remoteHEAD="$(get_remote_head "${url}")"
|
||||
if [[ ${localHEAD} != "${remoteHEAD}" ]]; then
|
||||
git stash
|
||||
git pull --ff-only
|
||||
@@ -522,6 +544,29 @@ download_release() {
|
||||
fi
|
||||
}
|
||||
|
||||
# given a build, topologically sort
|
||||
# a build and its dependencies
|
||||
# to minimize rebuilds
|
||||
_generate_build_order() (
|
||||
local build="$1"
|
||||
local depMap=("${build} ${build}")
|
||||
get_build_conf "${build}" || return 1
|
||||
for dep in "${deps[@]}"; do
|
||||
_generate_build_order "${dep}" || return 1
|
||||
depMap+=("${dep} ${build}")
|
||||
done
|
||||
printf '%s\n' "${depMap[@]}"
|
||||
)
|
||||
generate_build_order() {
|
||||
local build="$1"
|
||||
local order
|
||||
while read -r line; do
|
||||
order+="${line} "
|
||||
done <<<"$(_generate_build_order "${build}" | tsort)"
|
||||
# remove self-inclusive build from order list
|
||||
echo "${order// ${build}/}"
|
||||
}
|
||||
|
||||
FB_FUNC_NAMES+=('do_build')
|
||||
# shellcheck disable=SC2034
|
||||
FB_FUNC_DESCS['do_build']='build a specific project'
|
||||
@@ -530,14 +575,22 @@ FB_FUNC_COMPLETION['do_build']="$(get_build_conf supported)"
|
||||
do_build() {
|
||||
local build="${1:-''}"
|
||||
get_build_conf "${build}" || return 1
|
||||
download_release || return 1
|
||||
|
||||
set_compile_opts || return 1
|
||||
for dep in "${deps[@]}"; do
|
||||
do_build "${dep}" || return 1
|
||||
|
||||
# set BUILD_ORDER only if unset
|
||||
# this recursive function needs to be able
|
||||
# to control its callstack to minimize re-calls
|
||||
if [[ ${BUILD_ORDER} == '' ]]; then
|
||||
BUILD_ORDER="$(generate_build_order "${build}")" || return 1
|
||||
for b in ${BUILD_ORDER}; do
|
||||
test "${b}" == "${build}" && continue
|
||||
do_build "${b}" || return 1
|
||||
done
|
||||
unset BUILD_ORDER
|
||||
fi
|
||||
|
||||
get_build_conf "${build}" || return 1
|
||||
download_release || return 1
|
||||
|
||||
# save the metadata for a build to skip re-building identical builds
|
||||
local oldMetadataFile="${TMP_DIR}/${build}-old-metadata"
|
||||
@@ -557,6 +610,10 @@ do_build() {
|
||||
echo "ver: ${ver}"
|
||||
echo "url: ${url}"
|
||||
echo "LOCAL_PREFIX: ${LOCAL_PREFIX}"
|
||||
for patch in "${PATCHES_DIR}/${build}"/*.patch; do
|
||||
test -f "${patch}" || continue
|
||||
echo -e "patch:${patch}\n$(<"${patch}")"
|
||||
done
|
||||
COLOR=OFF SHOW_SINGLE=true dump_arr "${BUILD_ENV_NAMES[@]}"
|
||||
} >"${newMetadataFile}"
|
||||
|
||||
@@ -567,20 +624,20 @@ do_build() {
|
||||
type add_project_versioning_to_ffmpeg >>"${newMetadataFile}"
|
||||
fi
|
||||
|
||||
# prepare build
|
||||
pushd "${extractedDir}" >/dev/null || return 1
|
||||
# check for any patches
|
||||
for patch in "${PATCHES_DIR}/${build}"/*.patch; do
|
||||
test -f "${patch}" || continue
|
||||
echo_if_fail patch -p1 -i "${patch}" || return 1
|
||||
echo "patch:${patch}" >>"${newMetadataFile}"
|
||||
done
|
||||
|
||||
# rebuild if new metadata is different
|
||||
local newMetadata="$(<"${newMetadataFile}")"
|
||||
local oldMetadata=''
|
||||
test -f "${oldMetadataFile}" && oldMetadata="$(<"${oldMetadataFile}")"
|
||||
if [[ ${oldMetadata} != "${newMetadata}" || -n ${REQUIRES_REBUILD} ]]; then
|
||||
# prepare build
|
||||
download_release || return 1
|
||||
pushd "${extractedDir}" >/dev/null || return 1
|
||||
# check for any patches
|
||||
for patch in "${PATCHES_DIR}/${build}"/*.patch; do
|
||||
test -f "${patch}" || continue
|
||||
echo_if_fail patch -p1 -i "${patch}" || return 1
|
||||
done
|
||||
|
||||
echo_info -n "building ${build} "
|
||||
# build in background
|
||||
local timeBefore=${EPOCHSECONDS}
|
||||
@@ -603,7 +660,6 @@ do_build() {
|
||||
# indicate that build chain will require rebuild
|
||||
REQUIRES_REBUILD=1
|
||||
else
|
||||
popd >/dev/null || return 1
|
||||
echo_info "re-using identical previous build for ${build}"
|
||||
fi
|
||||
}
|
||||
@@ -622,11 +678,6 @@ build() {
|
||||
|
||||
set_compile_opts || return 1
|
||||
|
||||
for build in ${ENABLE}; do
|
||||
do_build "${build}" || return 1
|
||||
# reset whether build chain requires a rebuild
|
||||
unset REQUIRES_REBUILD
|
||||
done
|
||||
do_build ffmpeg || return 1
|
||||
|
||||
# skip packaging on PGO generate run
|
||||
@@ -795,21 +846,21 @@ build_cpuinfo() {
|
||||
sanitize_sysroot_libs libcpuinfo || return 1
|
||||
}
|
||||
|
||||
build_libsvtav1() {
|
||||
meta_cmake_build \
|
||||
-DENABLE_AVX512=ON \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DCOVERAGE=OFF || return 1
|
||||
sanitize_sysroot_libs libSvtAv1Enc || return 1
|
||||
build_libsvtav1_hdr() {
|
||||
build_libsvtav1_psy
|
||||
}
|
||||
|
||||
build_libsvtav1_psy() {
|
||||
meta_cmake_build \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DENABLE_AVX512=ON \
|
||||
-DCOVERAGE=OFF \
|
||||
build_libsvtav1 \
|
||||
-DLIBDOVI_FOUND=1 \
|
||||
-DLIBHDR10PLUS_RS_FOUND=1 || return 1
|
||||
-DLIBHDR10PLUS_RS_FOUND=1
|
||||
}
|
||||
|
||||
build_libsvtav1() {
|
||||
meta_cmake_build \
|
||||
-DSVT_AV1_LTO=OFF \
|
||||
-DENABLE_AVX512=ON \
|
||||
-DCOVERAGE=OFF "$@" || return 1
|
||||
sanitize_sysroot_libs libSvtAv1Enc || return 1
|
||||
}
|
||||
|
||||
@@ -825,7 +876,12 @@ build_libopus() {
|
||||
}
|
||||
|
||||
build_libvorbis() {
|
||||
meta_cmake_build || return 1
|
||||
local modPath
|
||||
if ! using_cmake3; then
|
||||
modPath="${LOCAL_PREFIX}/bin:"
|
||||
fi
|
||||
|
||||
PATH="${modPath}${PATH}" meta_cmake_build || return 1
|
||||
sanitize_sysroot_libs \
|
||||
libvorbis libvorbisenc libvorbisfile || return 1
|
||||
}
|
||||
@@ -842,7 +898,16 @@ build_libwebp() {
|
||||
"if(FALSE)\n"
|
||||
fi
|
||||
|
||||
meta_cmake_build || return 1
|
||||
meta_cmake_build \
|
||||
-DWEBP_BUILD_ANIM_UTILS=OFF \
|
||||
-DWEBP_BUILD_CWEBP=OFF \
|
||||
-DWEBP_BUILD_DWEBP=OFF \
|
||||
-DWEBP_BUILD_VWEBP=OFF \
|
||||
-DWEBP_BUILD_GIF2WEBP=OFF \
|
||||
-DWEBP_BUILD_IMG2WEBP=OFF \
|
||||
-DWEBP_BUILD_WEBPINFO=OFF \
|
||||
-DWEBP_BUILD_WEBPMUX=OFF \
|
||||
-DWEBP_BUILD_EXTRAS=OFF || return 1
|
||||
sanitize_sysroot_libs libwebp libsharpyuv || return 1
|
||||
}
|
||||
|
||||
@@ -858,6 +923,18 @@ build_libpng() {
|
||||
sanitize_sysroot_libs libpng || return 1
|
||||
}
|
||||
|
||||
build_libdeflate() {
|
||||
meta_cmake_build \
|
||||
-DLIBDEFLATE_BUILD_GZIP=OFF || return 1
|
||||
sanitize_sysroot_libs libdeflate || return 1
|
||||
}
|
||||
|
||||
build_zstd() {
|
||||
meta_cmake_build \
|
||||
-S build/cmake || return 1
|
||||
sanitize_sysroot_libs libzstd || return 1
|
||||
}
|
||||
|
||||
build_zlib() {
|
||||
meta_cmake_build \
|
||||
-DZLIB_BUILD_EXAMPLES=OFF || return 1
|
||||
@@ -874,23 +951,79 @@ build_spirv_tools() {
|
||||
meta_cmake_build \
|
||||
-DSPIRV-Headers_SOURCE_DIR="${PREFIX}" \
|
||||
-DSPIRV_WERROR=OFF \
|
||||
-DSPIRV_SKIP_TESTS=ON \
|
||||
-G Ninja || return 1
|
||||
-DSPIRV_SKIP_TESTS=ON || return 1
|
||||
}
|
||||
|
||||
build_spirv_headers() {
|
||||
meta_cmake_build \
|
||||
-G Ninja || return 1
|
||||
meta_cmake_build || return 1
|
||||
}
|
||||
|
||||
build_libx265() {
|
||||
# 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
|
||||
build_libopenjpeg() {
|
||||
meta_cmake_build || return 1
|
||||
sanitize_sysroot_libs libopenjp2 || return 1
|
||||
}
|
||||
|
||||
build_libtiff() {
|
||||
meta_cmake_build \
|
||||
-Dtiff-tools=OFF \
|
||||
-Dtiff-tests=OFF \
|
||||
-Dtiff-contrib=OFF || return 1
|
||||
sanitize_sysroot_libs libtiff || return 1
|
||||
}
|
||||
|
||||
build_supmover() (
|
||||
# clean build environment
|
||||
unset "${BUILD_ENV_NAMES[@]}"
|
||||
|
||||
# manual install to sysroot
|
||||
make || return 1
|
||||
cp supmover "${LOCAL_PREFIX}/bin/supmover" || return 1
|
||||
)
|
||||
|
||||
build_cmake3() (
|
||||
# clean build environment
|
||||
unset "${BUILD_ENV_NAMES[@]}"
|
||||
|
||||
# don't need to rebuild if already using cmake3
|
||||
if using_cmake3; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
meta_cmake_build \
|
||||
# don't need to rebuild if already built
|
||||
if PATH="${LOCAL_PREFIX}/bin:${PATH}" using_cmake3; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_android; then
|
||||
CMAKE_FLAGS+=(
|
||||
"-DCMAKE_USE_SYSTEM_LIBUV=ON"
|
||||
"-DCMAKE_USE_SYSTEM_LIBARCHIVE=ON"
|
||||
)
|
||||
fi
|
||||
|
||||
CMAKE_FLAGS+=(
|
||||
"-DCMAKE_PREFIX_PATH=${LOCAL_PREFIX}"
|
||||
"-DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX}"
|
||||
"-DCMAKE_INSTALL_LIBDIR=lib"
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_C_COMPILER_LAUNCHER=ccache"
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
||||
"-DCMAKE_VERBOSE_MAKEFILE=ON"
|
||||
"-G" "Ninja"
|
||||
"-DENABLE_STATIC=ON"
|
||||
"-DENABLE_SHARED=OFF"
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
)
|
||||
meta_cmake_build || return 1
|
||||
)
|
||||
|
||||
build_libx265() {
|
||||
local modPath
|
||||
if ! using_cmake3; then
|
||||
modPath="${LOCAL_PREFIX}/bin:"
|
||||
fi
|
||||
|
||||
PATH="${modPath}${PATH}" meta_cmake_build \
|
||||
-DHIGH_BIT_DEPTH=ON \
|
||||
-DENABLE_HDR10_PLUS=OFF \
|
||||
-S source || return 1
|
||||
@@ -1007,10 +1140,20 @@ build_libfontconfig() {
|
||||
sanitize_sysroot_libs libfontconfig || return 1
|
||||
}
|
||||
|
||||
# harfbuzz No FreeType
|
||||
build_libharfbuzzNFTP() {
|
||||
DISABLE_FREETYPE=1 build_libharfbuzz
|
||||
}
|
||||
|
||||
build_libharfbuzz() {
|
||||
meta_meson_build \
|
||||
-D tests=disabled \
|
||||
local addFlag
|
||||
test "${DISABLE_FREETYPE}" -eq 1 && addFlag="-Dfreetype=disabled"
|
||||
|
||||
meta_meson_build ${addFlag} \
|
||||
-D glib=disabled \
|
||||
-D docs=disabled \
|
||||
-D tests=disabled \
|
||||
-D utilities=disabled \
|
||||
-D doc_tests=false || return 1
|
||||
sanitize_sysroot_libs libharfbuzz || return 1
|
||||
}
|
||||
@@ -1021,6 +1164,11 @@ build_libfribidi() {
|
||||
sanitize_sysroot_libs libfribidi || return 1
|
||||
}
|
||||
|
||||
build_lcms2() {
|
||||
meta_meson_build || return 1
|
||||
sanitize_sysroot_libs liblcms2 || return 1
|
||||
}
|
||||
|
||||
### PYTHON ###
|
||||
build_glad() {
|
||||
true
|
||||
@@ -1066,7 +1214,9 @@ meta_configure_build() {
|
||||
}
|
||||
|
||||
build_libvpx() {
|
||||
meta_configure_build \
|
||||
# remove preprocessor flags to not break the build
|
||||
# when including old pre-built headers
|
||||
CFLAGS="${CFLAGS//${CPPFLAGS}/}" meta_configure_build \
|
||||
--disable-examples \
|
||||
--disable-tools \
|
||||
--disable-docs \
|
||||
@@ -1077,6 +1227,7 @@ build_libvpx() {
|
||||
--enable-vp9 \
|
||||
--enable-vp9-highbitdepth \
|
||||
--enable-better-hw-compatibility \
|
||||
--enable-runtime-cpu-detect \
|
||||
--enable-webm-io \
|
||||
--enable-libyuv || return 1
|
||||
sanitize_sysroot_libs libvpx || return 1
|
||||
@@ -1126,14 +1277,11 @@ add_project_versioning_to_ffmpeg() {
|
||||
'' # pad with empty line
|
||||
"ffmpeg-builder=$(git -C "${REPO_DIR}" rev-parse HEAD)"
|
||||
)
|
||||
for build in ${ENABLE}; do
|
||||
for build in ${ENABLE} ffmpeg; do
|
||||
get_build_conf "${build}" || return 1
|
||||
# add build configuration info
|
||||
FFMPEG_BUILDER_INFO+=("${build}=${ver}")
|
||||
done
|
||||
# and finally for ffmpeg itself
|
||||
get_build_conf ffmpeg || return 1
|
||||
FFMPEG_BUILDER_INFO+=("${build}=${ver}")
|
||||
|
||||
local fname='opt_common.c'
|
||||
local optFile="fftools/${fname}"
|
||||
@@ -1151,9 +1299,18 @@ add_project_versioning_to_ffmpeg() {
|
||||
build_ffmpeg() {
|
||||
add_project_versioning_to_ffmpeg || return 1
|
||||
|
||||
# libsvtav1_psy real name is libsvtav1
|
||||
# libsvtav1_* patch and enable name change
|
||||
for enable in ${ENABLE}; do
|
||||
test "${enable}" == 'libsvtav1_psy' && enable='libsvtav1'
|
||||
if line_starts_with "${enable}" libsvtav1; then
|
||||
# libsvtav1 v4 is breaking API
|
||||
if [[ "$(get_build_conf "${enable}" ver)" == '4'* ]]; then
|
||||
replace_line \
|
||||
libavcodec/libsvtav1.c \
|
||||
'param->enable_adaptive_quantization = 0;' \
|
||||
'param->aq_mode = 0;' || return 1
|
||||
fi
|
||||
enable=libsvtav1
|
||||
fi
|
||||
CONFIGURE_FLAGS+=("--enable-${enable}")
|
||||
done
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ libmp3lame \
|
||||
libfribidi \
|
||||
libfreetype \
|
||||
libharfbuzz \
|
||||
libsvtav1_psy \
|
||||
libopenjpeg \
|
||||
libsvtav1_hdr \
|
||||
libfontconfig \
|
||||
"
|
||||
|
||||
|
||||
365
lib/encode.sh
365
lib/encode.sh
@@ -1,25 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# sets unmapStreams
|
||||
DESIRED_SUB_LANG=eng
|
||||
|
||||
# sets UNMAP_STREAMS
|
||||
set_unmap_streams() {
|
||||
local file="$1"
|
||||
local unmapFilter='bin_data|jpeg|png'
|
||||
local streamsStr
|
||||
unmapStreams=()
|
||||
UNMAP_STREAMS=()
|
||||
streamsStr="$(get_num_streams "${file}")" || return 1
|
||||
mapfile -t streams <<<"${streamsStr}" || return 1
|
||||
for stream in "${streams[@]}"; do
|
||||
if [[ "$(get_stream_codec "${file}" "${stream}")" =~ ${unmapFilter} ]]; then
|
||||
unmapStreams+=("-map" "-0:${stream}")
|
||||
UNMAP_STREAMS+=("-map" "-0:${stream}")
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# sets audioParams
|
||||
# sets AUDIO_PARAMS
|
||||
set_audio_params() {
|
||||
local file="$1"
|
||||
local videoLang
|
||||
audioParams=()
|
||||
AUDIO_PARAMS=()
|
||||
videoLang="$(get_stream_lang "${file}" 'v:0')" || return 1
|
||||
for stream in $(get_num_streams "${file}" 'a'); do
|
||||
local numChannels codec lang
|
||||
@@ -32,18 +34,18 @@ set_audio_params() {
|
||||
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
||||
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
||||
if [[ ${videoLang} != '' && ${videoLang} != "${lang}" ]]; then
|
||||
audioParams+=(
|
||||
AUDIO_PARAMS+=(
|
||||
'-map'
|
||||
"-0:${stream}"
|
||||
)
|
||||
elif [[ ${codec} == 'opus' ]]; then
|
||||
audioParams+=(
|
||||
AUDIO_PARAMS+=(
|
||||
"-c:${OUTPUT_INDEX}"
|
||||
"copy"
|
||||
)
|
||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||
else
|
||||
audioParams+=(
|
||||
AUDIO_PARAMS+=(
|
||||
"-filter:${OUTPUT_INDEX}"
|
||||
"aformat=channel_layouts=7.1|5.1|stereo|mono"
|
||||
"-c:${OUTPUT_INDEX}"
|
||||
@@ -56,11 +58,10 @@ set_audio_params() {
|
||||
done
|
||||
}
|
||||
|
||||
# sets subtitleParams
|
||||
# sets SUBTITLE_PARAMS
|
||||
set_subtitle_params() {
|
||||
local file="$1"
|
||||
local convertCodec='eia_608'
|
||||
local keepLang='eng'
|
||||
|
||||
local defaultTextCodec
|
||||
if [[ ${SAME_CONTAINER} == false && ${FILE_EXT} == 'mkv' ]]; then
|
||||
@@ -71,18 +72,27 @@ set_subtitle_params() {
|
||||
convertCodec+='|srt'
|
||||
fi
|
||||
|
||||
subtitleParams=()
|
||||
SUBTITLE_PARAMS=()
|
||||
for stream in $(get_num_streams "${file}" 's'); do
|
||||
local codec lang
|
||||
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
||||
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
||||
if [[ ${lang} != '' && ${keepLang} != "${lang}" ]]; then
|
||||
subtitleParams+=(
|
||||
if [[ ${lang} != '' && ${DESIRED_SUB_LANG} != "${lang}" ]]; then
|
||||
SUBTITLE_PARAMS+=(
|
||||
'-map'
|
||||
"-0:${stream}"
|
||||
)
|
||||
elif [[ ${codec} =~ ${convertCodec} ]]; then
|
||||
subtitleParams+=("-c:${OUTPUT_INDEX}" "${defaultTextCodec}")
|
||||
SUBTITLE_PARAMS+=("-c:${OUTPUT_INDEX}" "${defaultTextCodec}")
|
||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||
elif [[ ${codec} == 'hdmv_pgs_subtitle' ]]; then
|
||||
PGS_SUB_STREAMS+=("${stream}")
|
||||
SUBTITLE_PARAMS+=(
|
||||
'-map'
|
||||
"-0:${stream}"
|
||||
)
|
||||
else
|
||||
# map -0 covers the stream but still want to increment the index
|
||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||
fi
|
||||
done
|
||||
@@ -91,59 +101,228 @@ set_subtitle_params() {
|
||||
get_encode_versions() {
|
||||
action="${1:-}"
|
||||
|
||||
encodeVersion="encode=$(git -C "${REPO_DIR}" rev-parse --short HEAD)"
|
||||
ffmpegVersion=''
|
||||
videoEncVersion=''
|
||||
audioEncVersion=''
|
||||
ENCODE_VERSION="encode=$(git -C "${REPO_DIR}" rev-parse --short HEAD)"
|
||||
FFMPEG_VERSION=''
|
||||
VIDEO_ENC_VERSION=''
|
||||
AUDIO_ENC_VERSION=''
|
||||
|
||||
# shellcheck disable=SC2155
|
||||
local output="$(ffmpeg -version 2>&1)"
|
||||
while read -r line; do
|
||||
if line_starts_with "${line}" 'ffmpeg='; then
|
||||
ffmpegVersion="${line}"
|
||||
FFMPEG_VERSION="${line}"
|
||||
elif line_starts_with "${line}" 'libsvtav1'; then
|
||||
videoEncVersion="${line}"
|
||||
VIDEO_ENC_VERSION="${line}"
|
||||
elif line_starts_with "${line}" 'libopus='; then
|
||||
audioEncVersion="${line}"
|
||||
AUDIO_ENC_VERSION="${line}"
|
||||
fi
|
||||
done <<<"${output}"
|
||||
|
||||
local version
|
||||
if [[ ${ffmpegVersion} == '' ]]; then
|
||||
if [[ ${FFMPEG_VERSION} == '' ]]; then
|
||||
while read -r line; do
|
||||
if line_starts_with "${line}" 'ffmpeg version '; then
|
||||
read -r _ _ version _ <<<"${line}"
|
||||
ffmpegVersion="ffmpeg=${version}"
|
||||
FFMPEG_VERSION="ffmpeg=${version}"
|
||||
break
|
||||
fi
|
||||
done <<<"${output}"
|
||||
fi
|
||||
|
||||
if [[ ${videoEncVersion} == '' ]]; then
|
||||
if [[ ${VIDEO_ENC_VERSION} == '' ]]; then
|
||||
version="$(get_pkgconfig_version SvtAv1Enc)"
|
||||
test "${version}" == '' && return 1
|
||||
videoEncVersion="libsvtav1=${version}"
|
||||
VIDEO_ENC_VERSION="libsvtav1=${version}"
|
||||
fi
|
||||
|
||||
if [[ ${audioEncVersion} == '' ]]; then
|
||||
if [[ ${AUDIO_ENC_VERSION} == '' ]]; then
|
||||
version="$(get_pkgconfig_version opus)"
|
||||
test "${version}" == '' && return 1
|
||||
audioEncVersion="libopus=${version}"
|
||||
AUDIO_ENC_VERSION="libopus=${version}"
|
||||
fi
|
||||
|
||||
test "${ffmpegVersion}" == '' && return 1
|
||||
test "${videoEncVersion}" == '' && return 1
|
||||
test "${audioEncVersion}" == '' && return 1
|
||||
test "${FFMPEG_VERSION}" == '' && return 1
|
||||
test "${VIDEO_ENC_VERSION}" == '' && return 1
|
||||
test "${AUDIO_ENC_VERSION}" == '' && return 1
|
||||
|
||||
if [[ ${action} == 'print' ]]; then
|
||||
echo "${encodeVersion}"
|
||||
echo "${ffmpegVersion}"
|
||||
echo "${videoEncVersion}"
|
||||
echo "${audioEncVersion}"
|
||||
echo "${ENCODE_VERSION}"
|
||||
echo "${FFMPEG_VERSION}"
|
||||
echo "${VIDEO_ENC_VERSION}"
|
||||
echo "${AUDIO_ENC_VERSION}"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# given an input mkv/sup file,
|
||||
# output a new mkv file with
|
||||
# input metadata preserved
|
||||
replace_mkv_sup() {
|
||||
local mkvIn="$1"
|
||||
local supIn="$2"
|
||||
local mkvOut="$3"
|
||||
local stream="${4:-0}"
|
||||
|
||||
local json
|
||||
json="$(get_stream_json "${mkvIn}" "${stream}")" || return 1
|
||||
|
||||
# x:y
|
||||
# x = stream json variable name
|
||||
# y = mkvmerge option name
|
||||
local optionMap=(
|
||||
disposition.default:--default-track-flag
|
||||
disposition.original:--original-flag
|
||||
disposition.comment:--commentary-flag
|
||||
disposition.forced:--forced-display-flag
|
||||
disposition.hearing_impaired:--hearing-impaired-flag
|
||||
tags.language:--language
|
||||
tags.title:--track-name
|
||||
)
|
||||
|
||||
# start building mkvmerge command
|
||||
local mergeCmd=(
|
||||
mkvmerge
|
||||
-o "${mkvOut}"
|
||||
)
|
||||
for line in "${optionMap[@]}"; do
|
||||
IFS=: read -r key option <<<"${line}"
|
||||
local val
|
||||
val="$(jq -r ".streams[].${key}" <<<"${json}")" || return 1
|
||||
# skip undefined values
|
||||
test "${val}" == null && continue
|
||||
# always track 0 for single track
|
||||
mergeCmd+=("${option}" "0:${val}")
|
||||
done
|
||||
mergeCmd+=("${supIn}")
|
||||
|
||||
"${mergeCmd[@]}"
|
||||
}
|
||||
|
||||
crop_sup() {
|
||||
local inSup="$1"
|
||||
local outSup="$2"
|
||||
local left="$3"
|
||||
local top="$4"
|
||||
local right="$5"
|
||||
local bottom="$6"
|
||||
local warnMsg='Window is outside new screen area'
|
||||
local maxAcceptableWarn=5
|
||||
local offset=5
|
||||
|
||||
# skip cropping if not needed
|
||||
if [[ "${left}${top}${right}${bottom}" == "0000" ]]; then
|
||||
cp "${inSup}" "${outSup}" || return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
for ((try = 0; try < 30; try++)); do
|
||||
echo_info "cropping sup with ${left} ${top} ${right} ${bottom}"
|
||||
"${SUPMOVER}" \
|
||||
"${inSup}" \
|
||||
"${outSup}" \
|
||||
--crop \
|
||||
"${left}" "${top}" "${right}" "${bottom}" &>"${outSup}.out" || return 1
|
||||
# supmover does not error for out-of-bounds subtitles
|
||||
# so adjust crop value until there is most certainly no issue
|
||||
if [[ "$(grep -c "${warnMsg}" "${cropSup}.out")" -gt ${maxAcceptableWarn} ]]; then
|
||||
echo_warn "${warnMsg}, retrying... (try ${try})"
|
||||
test "${left}" -gt ${offset} && left=$((left - offset))
|
||||
test "${top}" -gt ${offset} && top=$((top - offset))
|
||||
test "${right}" -gt ${offset} && right=$((right - offset))
|
||||
test "${bottom}" -gt ${offset} && bottom=$((bottom - offset))
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
# if we got here, all tries were had, so indicate failure
|
||||
return 1
|
||||
}
|
||||
|
||||
# extract PGS_SUB_STREAMS from INPUT
|
||||
# and crop using CROP_VALUE
|
||||
setup_pgs_mkv() {
|
||||
local pgsMkvOut="$1"
|
||||
|
||||
if [[ ${#PGS_SUB_STREAMS[@]} -eq 0 ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
check_for_supmover || return 1
|
||||
|
||||
# setup tempdir
|
||||
local ogSup cropSup cropMkv tmpdir
|
||||
tmpdir="${pgsMkvOut}-dir"
|
||||
recreate_dir "${tmpdir}" || return 1
|
||||
|
||||
# get video resolution
|
||||
local vidRes vidWidth vidHeight
|
||||
vidRes="$(get_resolution "${INPUT}")"
|
||||
IFS=x read -r vidWidth vidHeight <<<"${vidRes}"
|
||||
|
||||
for stream in "${PGS_SUB_STREAMS[@]}"; do
|
||||
# extract sup from input
|
||||
ogSup="${tmpdir}/${stream}.sup"
|
||||
cropSup="${tmpdir}/${stream}-cropped.sup"
|
||||
cropMkv="${tmpdir}/${stream}.mkv"
|
||||
mkvextract "${INPUT}" tracks "${stream}:${ogSup}" || return 1
|
||||
|
||||
# check sup resolution
|
||||
local supRes
|
||||
supRes="$(get_sup_resolution "${ogSup}")" || return 1
|
||||
local supWidth supHeight
|
||||
IFS=x read -r supWidth supHeight <<<"${supRes}"
|
||||
local left top right bottom
|
||||
# determine crop values
|
||||
# if the supfile is smaller than the video stream
|
||||
# crop using aspect ratio instead of resolution
|
||||
if [[ ${vidWidth} -gt ${supWidth} || ${vidHeight} -gt ${supHeight} ]]; then
|
||||
echo_warn "PGS sup (stream=${stream}) is somehow smaller than initial video stream"
|
||||
echo_warn "cropping based off of aspect ratio instead of resolution"
|
||||
left=0
|
||||
# (supHeight - ((vidHeight/vidWidth) * supWidth)) / 2
|
||||
top="$(awk '{ print int(($1 - ($2 / $3 * $4)) / 2) }' <<<"${supHeight} ${vidHeight} ${vidWidth} ${supWidth}")"
|
||||
right=${left}
|
||||
bottom=${top}
|
||||
# otherwise crop using the crop value
|
||||
elif [[ ${CROP_VALUE} != '' ]]; then
|
||||
# determine supmover crop based off of crop
|
||||
local res w h x y
|
||||
# extract ffmpeg crop value ("crop=w:h:x:y")
|
||||
IFS='=' read -r _ res <<<"${CROP_VALUE}"
|
||||
IFS=':' read -r w h x y <<<"${res}"
|
||||
|
||||
# ffmpeg crop value
|
||||
# is different than supmover crop inputs
|
||||
left=${x}
|
||||
top=${y}
|
||||
right=$((supWidth - w - left))
|
||||
bottom=$((supHeight - h - top))
|
||||
# fallback to just the video resolution
|
||||
else
|
||||
left=$(((supWidth - vidWidth) / 2))
|
||||
top=$(((supHeight - vidHeight) / 2))
|
||||
right=${left}
|
||||
bottom=${top}
|
||||
fi
|
||||
|
||||
if ! crop_sup "${ogSup}" "${cropSup}" "${left}" "${top}" "${right}" "${bottom}"; then
|
||||
rm -r "${tmpdir}" || return 1
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! replace_mkv_sup "${INPUT}" "${cropSup}" "${cropMkv}" "${stream}"; then
|
||||
echo_fail "could not replace mkv sup for ${stream}"
|
||||
rm -r "${tmpdir}" || return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# merge all single mkv into one
|
||||
mkvmerge -o "${pgsMkvOut}" "${tmpdir}/"*.mkv
|
||||
local mergeRet=$?
|
||||
rm -r "${tmpdir}" || return 1
|
||||
return ${mergeRet}
|
||||
}
|
||||
|
||||
encode_usage() {
|
||||
echo "encode -i input [options] output"
|
||||
echo -e "\t[-P NUM] set preset (default: ${PRESET})"
|
||||
@@ -238,7 +417,7 @@ set_encode_opts() {
|
||||
encode_usage
|
||||
return 1
|
||||
fi
|
||||
GRAIN="film-grain=${OPTARG}:film-grain-denoise=1:"
|
||||
GRAIN="film-grain=${OPTARG}:film-grain-denoise=1:adaptive-film-grain=1:"
|
||||
optsUsed=$((optsUsed + 2))
|
||||
;;
|
||||
P)
|
||||
@@ -299,18 +478,26 @@ set_encode_opts() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ${PRINT_OUT} == false ]]; then
|
||||
echo
|
||||
echo_info "INPUT: ${INPUT}"
|
||||
echo_info "GRAIN: ${GRAIN}"
|
||||
echo_info "OUTPUT: ${OUTPUT}"
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
# shellcheck disable=SC2155
|
||||
# shellcheck disable=SC2016
|
||||
gen_encode_script() {
|
||||
local genScript="${TMP_DIR}/$(bash_basename "${OUTPUT}").sh"
|
||||
if missing_cmd mkvpropedit; then
|
||||
echo_fail "use: ${REPO_DIR}/scripts/install_deps.sh"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local outputBasename="$(bash_basename "${OUTPUT}")"
|
||||
local genScript="${TMP_DIR}/${outputBasename}.sh"
|
||||
|
||||
# global output index number to increment
|
||||
OUTPUT_INDEX=0
|
||||
@@ -321,17 +508,15 @@ gen_encode_script() {
|
||||
OUTPUT
|
||||
PRESET
|
||||
CRF
|
||||
crop
|
||||
encodeVersion
|
||||
ffmpegVersion
|
||||
videoEncVersion
|
||||
audioEncVersion
|
||||
CROP_VALUE
|
||||
ENCODE_VERSION
|
||||
FFMPEG_VERSION
|
||||
VIDEO_ENC_VERSION
|
||||
AUDIO_ENC_VERSION
|
||||
svtAv1Params
|
||||
pgsMkv
|
||||
muxxedPgsMkv
|
||||
)
|
||||
local crop=''
|
||||
if [[ $CROP == "true" ]]; then
|
||||
crop="$(get_crop "${INPUT}")" || return 1
|
||||
fi
|
||||
|
||||
svtAv1ParamsArr=(
|
||||
"tune=0"
|
||||
@@ -345,7 +530,7 @@ gen_encode_script() {
|
||||
"fast-decode=1"
|
||||
"enable-variance-boost=1"
|
||||
"enable-qm=1"
|
||||
"chroma-qm-min-10"
|
||||
"chroma-qm-min=10"
|
||||
"qm-min=4"
|
||||
"qm-max=15"
|
||||
)
|
||||
@@ -355,15 +540,18 @@ gen_encode_script() {
|
||||
|
||||
# arrays
|
||||
local arrays=(
|
||||
unmapStreams
|
||||
audioParams
|
||||
UNMAP_STREAMS
|
||||
AUDIO_PARAMS
|
||||
SUBTITLE_PARAMS
|
||||
videoParams
|
||||
metadata
|
||||
subtitleParams
|
||||
ffmpegParams
|
||||
PGS_SUB_STREAMS
|
||||
)
|
||||
local "${arrays[@]}"
|
||||
|
||||
local videoParams=(
|
||||
"-crf" '${CRF}' "-preset" '${PRESET}' "-g" "240"
|
||||
"-crf" '${CRF}' "-preset" '${PRESET}'
|
||||
)
|
||||
local ffmpegParams=(
|
||||
'-hide_banner'
|
||||
@@ -374,51 +562,72 @@ gen_encode_script() {
|
||||
)
|
||||
|
||||
# set video params
|
||||
get_encode_versions || return 1
|
||||
local inputVideoCodec="$(get_stream_codec "${INPUT}" 'v:0')"
|
||||
if [[ ${inputVideoCodec} == 'av1' ]]; then
|
||||
ffmpegParams+=(
|
||||
"-c:v:${OUTPUT_INDEX}" 'copy'
|
||||
)
|
||||
# can't crop if copying codec
|
||||
CROP=false
|
||||
else
|
||||
ffmpegParams+=(
|
||||
'-pix_fmt' 'yuv420p10le'
|
||||
"-c:v:${OUTPUT_INDEX}" 'libsvtav1' '${videoParams[@]}'
|
||||
'-svtav1-params' '${svtAv1Params}'
|
||||
)
|
||||
metadata+=(
|
||||
'-metadata' '${VIDEO_ENC_VERSION}'
|
||||
'-metadata' 'svtav1_params=${svtAv1Params}'
|
||||
'-metadata' 'video_params=${videoParams[*]}'
|
||||
)
|
||||
fi
|
||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||
|
||||
# these values may be empty
|
||||
local unmapStr audioParamsStr subtitleParamsStr
|
||||
set_unmap_streams "${INPUT}" || return 1
|
||||
set_audio_params "${INPUT}" || return 1
|
||||
set_subtitle_params "${INPUT}" || return 1
|
||||
|
||||
if [[ ${unmapStreams[*]} != '' ]]; then
|
||||
ffmpegParams+=('${unmapStreams[@]}')
|
||||
if [[ ${UNMAP_STREAMS[*]} != '' ]]; then
|
||||
ffmpegParams+=('${UNMAP_STREAMS[@]}')
|
||||
fi
|
||||
|
||||
if [[ ${audioParams[*]} != '' ]]; then
|
||||
ffmpegParams+=('${audioParams[@]}')
|
||||
if [[ ${AUDIO_PARAMS[*]} != '' ]]; then
|
||||
ffmpegParams+=('${AUDIO_PARAMS[@]}')
|
||||
fi
|
||||
|
||||
if [[ ${subtitleParams[*]} != '' ]]; then
|
||||
ffmpegParams+=('${subtitleParams[@]}')
|
||||
if [[ ${SUBTITLE_PARAMS[*]} != '' ]]; then
|
||||
ffmpegParams+=('${SUBTITLE_PARAMS[@]}')
|
||||
fi
|
||||
|
||||
if [[ ${crop} != '' ]]; then
|
||||
ffmpegParams+=('-vf' '${crop}')
|
||||
fi
|
||||
|
||||
get_encode_versions || return 1
|
||||
local metadata=(
|
||||
'-metadata' '${encodeVersion}'
|
||||
'-metadata' '${ffmpegVersion}'
|
||||
'-metadata' '${videoEncVersion}'
|
||||
'-metadata' '${audioEncVersion}'
|
||||
'-metadata' 'svtav1_params=${svtAv1Params}'
|
||||
'-metadata' 'video_params=${videoParams[*]}'
|
||||
metadata+=(
|
||||
'-metadata' '${ENCODE_VERSION}'
|
||||
'-metadata' '${FFMPEG_VERSION}'
|
||||
)
|
||||
|
||||
# in the case all audio streams are copied,
|
||||
# don't add libopus metadata
|
||||
if line_contains "${AUDIO_PARAMS[*]}" 'libopus'; then
|
||||
metadata+=(
|
||||
'-metadata' '${AUDIO_ENC_VERSION}')
|
||||
fi
|
||||
|
||||
local CROP_VALUE
|
||||
if [[ ${CROP} == true ]]; then
|
||||
CROP_VALUE="$(get_crop "${INPUT}")" || return 1
|
||||
ffmpegParams+=('-vf' '${CROP_VALUE}')
|
||||
metadata+=(
|
||||
'-metadata' '${CROP_VALUE}'
|
||||
'-metadata' "og_res=$(get_resolution "${INPUT}")"
|
||||
)
|
||||
fi
|
||||
|
||||
# separate processing step for pkg subs
|
||||
local pgsMkv="${TMP_DIR}/pgs-${outputBasename// /.}.mkv"
|
||||
local muxxedPgsMkv='${OUTPUT}.muxxed'
|
||||
setup_pgs_mkv "${pgsMkv}" 1>&2 || return 1
|
||||
|
||||
ffmpegParams+=('${metadata[@]}')
|
||||
|
||||
{
|
||||
@@ -449,11 +658,19 @@ gen_encode_script() {
|
||||
echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1'
|
||||
|
||||
# track-stats and clear title
|
||||
if [[ ${FILE_EXT} == 'mkv' ]] && has_cmd mkvpropedit; then
|
||||
if [[ ${FILE_EXT} == 'mkv' ]]; then
|
||||
{
|
||||
# ffmpeg does not copy PGS subtitles without breaking them
|
||||
# use mkvmerge to extract and supmover to crop
|
||||
if [[ ${#PGS_SUB_STREAMS[@]} -gt 0 ]]; then
|
||||
echo
|
||||
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags'
|
||||
echo 'mkvpropedit "${OUTPUT}" --edit info --set "title="'
|
||||
echo 'mkvmerge -o "${muxxedPgsMkv}" "${pgsMkv}" "${OUTPUT}" || exit 1'
|
||||
echo 'rm "${pgsMkv}" || exit 1'
|
||||
echo 'mv "${muxxedPgsMkv}" "${OUTPUT}" || exit 1'
|
||||
fi
|
||||
|
||||
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags || exit 1'
|
||||
echo 'mkvpropedit "${OUTPUT}" --edit info --set "title=" || exit 1'
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -461,7 +678,7 @@ gen_encode_script() {
|
||||
} >"${genScript}"
|
||||
|
||||
if [[ ${PRINT_OUT} == true ]]; then
|
||||
echo_info "${genScript} contents:"
|
||||
echo_info "${genScript} contents:" 1>&2
|
||||
echo "$(<"${genScript}")"
|
||||
else
|
||||
bash -x "${genScript}" || return 1
|
||||
@@ -471,7 +688,7 @@ gen_encode_script() {
|
||||
|
||||
FB_FUNC_NAMES+=('encode')
|
||||
# shellcheck disable=SC2034
|
||||
FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus'
|
||||
FB_FUNC_DESCS['encode']='encode a file using libsvtav1 and libopus'
|
||||
encode() {
|
||||
set_encode_opts "$@"
|
||||
local ret=$?
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_ffprobe_wrapper() {
|
||||
local stderr="${TMP_DIR}/ffprobe-stderr"
|
||||
if ! ffprobe "$@" 2>"${TMP_DIR}/ffprobe-stderr"; then
|
||||
cat "${stderr}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
get_duration() {
|
||||
local file="$1"
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-show_entries format=duration \
|
||||
-of default=noprint_wrappers=1:nokey=1 \
|
||||
@@ -11,7 +20,7 @@ get_duration() {
|
||||
|
||||
get_avg_bitrate() {
|
||||
local file="$1"
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-select_streams v:0 \
|
||||
-show_entries format=bit_rate \
|
||||
@@ -43,7 +52,7 @@ get_crop() {
|
||||
# don't care about decimal points
|
||||
IFS='.' read -r duration _ <<<"${duration}"
|
||||
# get crop value for first half of input
|
||||
local timeEnc=$((duration / 2))
|
||||
local timeEnc=$((duration / 20))
|
||||
ffmpeg \
|
||||
-y \
|
||||
-hide_banner \
|
||||
@@ -55,7 +64,7 @@ get_crop() {
|
||||
-filter:v:0 'cropdetect=limit=100:round=16:skip=2:reset_count=0' \
|
||||
-codec:v 'wrapped_avframe' \
|
||||
-f 'null' '/dev/null' 2>&1 |
|
||||
grep -o crop=.* |
|
||||
grep -o 'crop=.*' |
|
||||
sort -bh |
|
||||
uniq -c |
|
||||
sort -bh |
|
||||
@@ -63,10 +72,31 @@ get_crop() {
|
||||
grep -o "crop=.*"
|
||||
}
|
||||
|
||||
# output '1920x1080'
|
||||
get_resolution() {
|
||||
local file="$1"
|
||||
get_stream_json "${file}" 0 |
|
||||
jq -r '.streams[0] | "\(.width)x\(.height)"'
|
||||
}
|
||||
|
||||
# same as get_resolution
|
||||
get_sup_resolution() {
|
||||
local supfile="$1"
|
||||
check_for_supmover || return 1
|
||||
if [[ "$(get_file_format "${supfile}")" != 'sup' ]]; then
|
||||
echo_fail "${supfile} is not a sup file"
|
||||
return 1
|
||||
fi
|
||||
local trace res
|
||||
trace="$("${SUPMOVER}" "${supfile}" --trace)" || return 1
|
||||
res="$(grep 'Video size' <<<"${trace}" | sort -u | awk '{print $NF}')" || return 1
|
||||
echo "${res}"
|
||||
}
|
||||
|
||||
get_stream_codec() {
|
||||
local file="$1"
|
||||
local stream="$2"
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-select_streams "${stream}" \
|
||||
-show_entries stream=codec_name \
|
||||
@@ -74,18 +104,31 @@ get_stream_codec() {
|
||||
"${file}"
|
||||
}
|
||||
|
||||
get_stream_json() {
|
||||
local file="$1"
|
||||
local stream="$2"
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-select_streams "${stream}" \
|
||||
-show_entries stream \
|
||||
-of json \
|
||||
"${file}"
|
||||
}
|
||||
|
||||
get_file_format() {
|
||||
local file="$1"
|
||||
local probe
|
||||
probe="$(ffprobe \
|
||||
probe="$(_ffprobe_wrapper \
|
||||
-v error \
|
||||
-show_entries format=format_name \
|
||||
-of default=noprint_wrappers=1:nokey=1 \
|
||||
"${file}")" || return 1
|
||||
if line_contains "${probe}" 'matroska'; then
|
||||
echo mkv
|
||||
else
|
||||
elif line_contains "${probe}" 'mp4'; then
|
||||
echo mp4
|
||||
else
|
||||
echo "${probe}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -98,7 +141,7 @@ get_num_streams() {
|
||||
select=("-select_streams" "${type}")
|
||||
fi
|
||||
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error "${select[@]}" \
|
||||
-show_entries stream=index \
|
||||
-of default=noprint_wrappers=1:nokey=1 \
|
||||
@@ -108,7 +151,7 @@ get_num_streams() {
|
||||
get_num_audio_channels() {
|
||||
local file="$1"
|
||||
local stream="$2"
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-select_streams "${stream}" \
|
||||
-show_entries stream=channels \
|
||||
@@ -119,7 +162,7 @@ get_num_audio_channels() {
|
||||
get_stream_lang() {
|
||||
local file="$1"
|
||||
local stream="$2"
|
||||
ffprobe \
|
||||
_ffprobe_wrapper \
|
||||
-v error \
|
||||
-select_streams "${stream}" \
|
||||
-show_entries stream_tags=language \
|
||||
|
||||
@@ -55,7 +55,7 @@ print_req_pkgs() {
|
||||
# shellcheck disable=SC2034
|
||||
local brew_pkgs=(
|
||||
"${common_pkgs[@]}" pkgconf
|
||||
mkvtoolnix pipx uutils-coreutils
|
||||
mkvtoolnix pipx coreutils
|
||||
llvm lld
|
||||
)
|
||||
local common_linux_pkgs=(
|
||||
@@ -98,6 +98,7 @@ print_req_pkgs() {
|
||||
libandroid-posix-semaphore-static
|
||||
libandroid-shmem
|
||||
libandroid-shmem-static
|
||||
cargo-c
|
||||
)
|
||||
# shellcheck disable=SC2034
|
||||
local msys_ucrt_pkgs=(
|
||||
@@ -151,7 +152,7 @@ check_for_req_pkgs() {
|
||||
for pkg in $(print_req_pkgs); do
|
||||
# pkg_check has ${pkg} unexpanded
|
||||
eval "pkg_check=\"${pkg_check}\""
|
||||
${pkg_check} "${pkg}" >/dev/null 2>&1 || missing_pkgs+=("${pkg}")
|
||||
${pkg_check} "${pkg}" &>/dev/null || missing_pkgs+=("${pkg}")
|
||||
done
|
||||
|
||||
if [[ ${#missing_pkgs[@]} -gt 0 ]]; then
|
||||
|
||||
@@ -79,6 +79,7 @@ $(encode)
|
||||
- Skips re-encoding av1/opus streams.
|
||||
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
||||
- Only maps english subtitle streams.
|
||||
- Crop PGS subtitles to match video dimensions.
|
||||
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
||||
\`\`\`
|
||||
ENCODE : aa4d7e6
|
||||
|
||||
59
main.sh
59
main.sh
@@ -33,11 +33,6 @@ for dir in "${IGN_DIRS[@]}"; do
|
||||
done
|
||||
unset IGN_DIRS
|
||||
|
||||
# function names, descriptions, completions
|
||||
unset FB_FUNC_NAMES FB_FUNC_DESCS FB_FUNC_COMPLETION
|
||||
FB_FUNC_NAMES=()
|
||||
declare -A FB_FUNC_DESCS FB_FUNC_COMPLETION
|
||||
|
||||
# can't have recursive generation
|
||||
FB_RUNNING_AS_SCRIPT=${FB_RUNNING_AS_SCRIPT:-0}
|
||||
|
||||
@@ -46,10 +41,34 @@ FB_COMPILE_OPTS_SET=0
|
||||
|
||||
SCRIPT_DIR="${REPO_DIR}/scripts"
|
||||
ENTRY_SCRIPT="${SCRIPT_DIR}/entry.sh"
|
||||
src_scripts() {
|
||||
local SCRIPT_DIR="${REPO_DIR}/scripts"
|
||||
|
||||
if [[ $FB_RUNNING_AS_SCRIPT -eq 0 ]]; then
|
||||
src_scripts() {
|
||||
# function names, descriptions, completions
|
||||
unset FB_FUNC_NAMES FB_FUNC_DESCS FB_FUNC_COMPLETION
|
||||
FB_FUNC_NAMES=()
|
||||
declare -gA FB_FUNC_DESCS FB_FUNC_COMPLETION
|
||||
for script in "${REPO_DIR}/lib/"*.sh; do
|
||||
# shellcheck disable=SC1090
|
||||
source "${script}"
|
||||
done
|
||||
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
||||
(cd "${SCRIPT_DIR}" && ln -sf "entry.sh" "${funcName}.sh")
|
||||
done
|
||||
}
|
||||
src_scripts || return 1
|
||||
|
||||
FB_FUNC_NAMES+=('print_cmds')
|
||||
FB_FUNC_DESCS['print_cmds']='print usable commands'
|
||||
print_cmds() {
|
||||
echo -e "~~~ Usable Commands ~~~\n"
|
||||
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
||||
color="${CYAN}" word="${funcName}:" echo_wrapper "\n\t${FB_FUNC_DESCS[${funcName}]}"
|
||||
done
|
||||
echo -e "\n"
|
||||
}
|
||||
|
||||
gen_links() {
|
||||
if [[ ${FB_RUNNING_AS_SCRIPT} -eq 0 ]]; then
|
||||
rm "${SCRIPT_DIR}"/*.sh
|
||||
# shellcheck disable=SC2016
|
||||
echo '#!/usr/bin/env bash
|
||||
@@ -62,26 +81,15 @@ cmd="${scr_name//.sh/}"
|
||||
if [[ $DEBUG == 1 ]]; then set -x; fi
|
||||
$cmd "$@"' >"${ENTRY_SCRIPT}"
|
||||
chmod +x "${ENTRY_SCRIPT}"
|
||||
fi
|
||||
|
||||
for script in "${REPO_DIR}/lib/"*.sh; do
|
||||
# shellcheck disable=SC1090
|
||||
source "${script}"
|
||||
done
|
||||
}
|
||||
|
||||
FB_FUNC_NAMES+=('print_cmds')
|
||||
FB_FUNC_DESCS['print_cmds']='print usable commands'
|
||||
print_cmds() {
|
||||
echo -e "~~~ Usable Commands ~~~\n"
|
||||
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
||||
color="${CYAN}" word="${funcName}:" echo_wrapper "\n\t${FB_FUNC_DESCS[${funcName}]}"
|
||||
if [[ $FB_RUNNING_AS_SCRIPT -eq 0 ]]; then
|
||||
(cd "$SCRIPT_DIR" && ln -sf entry.sh "${funcName}.sh")
|
||||
fi
|
||||
(cd "${SCRIPT_DIR}" && ln -sf "entry.sh" "${funcName}.sh")
|
||||
done
|
||||
echo -e "\n"
|
||||
fi
|
||||
}
|
||||
gen_links || return 1
|
||||
|
||||
# allow calling entry.sh with arguments as execution
|
||||
entry() { "$@" ; }
|
||||
|
||||
set_completions() {
|
||||
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
||||
@@ -89,7 +97,6 @@ set_completions() {
|
||||
done
|
||||
}
|
||||
|
||||
src_scripts || return 1
|
||||
determine_pkg_mgr || return 1
|
||||
check_compile_opts_override || return 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user