mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-19 22:09:13 +00:00
304 lines
13 KiB
Bash
Executable File
304 lines
13 KiB
Bash
Executable File
#!/bin/sh -eu
|
|
# shellcheck disable=SC2059 # use of $bold et al. in printf format str
|
|
|
|
# defaults
|
|
use_bundled_libva_default=0
|
|
|
|
# if not run from AppImage (eg. extracted), use default values
|
|
APPIMAGE=${APPIMAGE-none}
|
|
ARGV0=${ARGV0-$0}
|
|
|
|
bold=$(tput bold || true)
|
|
red=$(tput setaf 1 || true)
|
|
reset=$(tput sgr0 || true)
|
|
|
|
DIR=$(dirname "$0")
|
|
AI_LIB_PATH=$DIR/usr/lib
|
|
orig_ld_library_path=${LD_LIBRARY_PATH-}
|
|
export LD_LIBRARY_PATH="$AI_LIB_PATH"${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}
|
|
LD_PRELOAD=${LD_PRELOAD-}
|
|
# there is an issue with running_from_path() which evaluates this executable
|
|
# as being system-installed
|
|
#export PATH=$DIR/usr/bin:$PATH
|
|
export QT_QPA_FONTDIR="$DIR/usr/share/fonts"
|
|
export UG_FONT_DIR="$DIR/usr/share/fonts"
|
|
QT_PLUGIN_PATH=$(set -- "$DIR"/usr/lib/qt?/plugins; echo "$1")
|
|
export QT_PLUGIN_PATH
|
|
export QT_QPA_PLATFORM_PLUGIN_PATH="$QT_PLUGIN_PATH/platforms"
|
|
|
|
if [ -z "${SDL_SOUNDFONTS-}" ] && [ -d "$DIR/usr/share/soundfonts" ]; then
|
|
SDL_SOUNDFONTS=$(find "$DIR/usr/share/soundfonts" -mindepth 1 | head -n 1)
|
|
export SDL_SOUNDFONTS
|
|
export SDL_FORCE_SOUNDFONTS=1
|
|
fj_env="--env=SDL_SOUNDFONTS=${SDL_SOUNDFONTS} --env=SDL_FORCE_SOUNDFONTS=1"
|
|
fi
|
|
|
|
get_tools() {(
|
|
LD_LIBRARY_PATH=$orig_ld_library_path
|
|
find "$DIR/usr/bin" -mindepth 1 -exec basename {} \; | tr '\n' ' '
|
|
)}
|
|
|
|
usage() {
|
|
printf "usage:\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}[--gui [args]]${reset}\n" "$ARGV0"
|
|
printf "\t\tinvokes GUI\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}--appimage-help${reset}\n" "$ARGV0"
|
|
printf "\t\tprints AppImage related options\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}-h | --help | --fullhelp${reset}\n" "$ARGV0"
|
|
printf "\t\tprints this help (extended version with ${bold}--fullhelp${reset})\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}-m|--man [uv|hd-rum-transcode]${reset}\n" "$ARGV0"
|
|
printf "\t\tprints manual page\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}-u|--update [args]${reset}\n" "$ARGV0"
|
|
printf "\t\tupdates AppImage (args will be passed to appimageupdatetool)\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}-o|--tool uv --help${reset}\n" "$ARGV0"
|
|
printf "\t\tprints command-line UltraGrid help\n"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}-o|--tool <t> [args]${reset}\n" "$ARGV0"
|
|
printf "\t\tinvokes specified tool\n"
|
|
printf "\t\ttool may be one of: ${bold}%s${reset}\n" "$(get_tools)"
|
|
printf "\n"
|
|
printf "\t${bold}${red}%s${reset} ${bold}args${reset}\n" "$ARGV0"
|
|
printf "\t\tinvokes command-line UltraGrid\n"
|
|
printf "\n"
|
|
}
|
|
|
|
usage_aux() {
|
|
printf "environment variables:\n"
|
|
printf "\tULTRAGRID_AUTOUPDATE: autoupdate interval in days (0 - check always); -1 - disable update advice\n"
|
|
printf "\tULTRAGRID_BUNDLED_LIBVA: 1 - use bundled libva; 0 - use system libva (if available), default %d\n" $use_bundled_libva_default
|
|
printf "\tULTRAGRID_USE_FIREJAIL: run the UltraGrid executable with firejail. If\n"
|
|
printf "\t the variable contains a profile path (ends with\n"
|
|
printf "\t '.profile'), it will be used.\n"
|
|
printf "\n"
|
|
}
|
|
|
|
update_check_days=90
|
|
## Trigger update if $ULTRAGRID_AUTOUPDATE days passed.
|
|
## If $ULTRAGRID_AUTOUPDATE unset or empty, print update hint if UG binary is older than $update_check_days days.
|
|
handle_updates() {(
|
|
if [ "${ULTRAGRID_AUTOUPDATE-0}" -eq -1 ]; then
|
|
return
|
|
fi
|
|
# shellcheck disable=SC2030 # intentional
|
|
LD_LIBRARY_PATH=$orig_ld_library_path
|
|
if [ "$APPIMAGE" = none ]; then
|
|
return
|
|
fi
|
|
if expr "$APPIMAGE" : '.*continuous' > /dev/null; then
|
|
update_check_days=30
|
|
fi
|
|
if [ "${ULTRAGRID_AUTOUPDATE-}" ] && [ "$ULTRAGRID_AUTOUPDATE" -ge 0 ]; then
|
|
update_check_days=$ULTRAGRID_AUTOUPDATE
|
|
fi
|
|
appimage_mtime=$(stat -c %Y "$APPIMAGE")
|
|
curr_timestamp=$(date +%s)
|
|
if [ "$curr_timestamp" -lt $((appimage_mtime + update_check_days * 24 * 60 * 60)) ]; then
|
|
return
|
|
fi
|
|
if [ "${ULTRAGRID_AUTOUPDATE-}" ] && [ "$ULTRAGRID_AUTOUPDATE" -ge 0 ]; then
|
|
if ! "$DIR/appimageupdatetool" -j "$APPIMAGE" && "$DIR/appimageupdatetool" "$APPIMAGE"; then
|
|
ULTRAGRID_AUTOUPDATE=-1 # prevent update loops if the new version not stored for some reason
|
|
exec "$APPIMAGE" "$@" # launch the updated version
|
|
fi
|
|
touch "$APPIMAGE" # update AppImage mtime otherwise if there are no updates after elapsing the interval, the check would run always
|
|
return
|
|
fi
|
|
printf "UltraGrid binary older than %d days, consider checking updates:\n" "$update_check_days"
|
|
printf "\n"
|
|
printf "%s -u\n" "$ARGV0"
|
|
printf "\t- updates AppImage\n"
|
|
printf "%s -u -j; [ \$? -eq 1 ] && echo Update available || echo No update available\n" "$ARGV0"
|
|
printf "\t- check for update without actually updating\n"
|
|
printf "%s -u -h\n" "$ARGV0"
|
|
printf "\t- prints update options\n"
|
|
printf "\n"
|
|
printf "Hint: you can set environment variable ULTRAGRID_AUTOUPDATE to 1 for daily automatic update or -1 to suppress the above message.\n"
|
|
printf "\n"
|
|
)}
|
|
|
|
## Tries to find system libva. If found it is preloaded (+libva-drm+libva-x11)
|
|
## @retval 0 if preloaded; 1 otherwise
|
|
set_libva_ld_preload() {
|
|
if [ ! -f "$AI_LIB_PATH/ultragrid/ultragrid_vcompress_libavcodec.so" ]; then
|
|
return 0
|
|
fi
|
|
LOADER=$(get_loader)
|
|
if [ ! -x "$LOADER" ]; then
|
|
return 1
|
|
fi
|
|
AI_LIBAVCODEC_LIB=$(LD_TRACE_LOADED_OBJECTS=1 "$LOADER" "$AI_LIB_PATH/ultragrid/ultragrid_vcompress_libavcodec.so" | grep libavcodec.so | grep -v 'not found' | awk '{print $3}')
|
|
if [ -z "$AI_LIBAVCODEC_LIB" ]; then
|
|
return 1
|
|
fi
|
|
# shellcheck disable=SC2031 # invalid?
|
|
S_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
|
|
LD_LIBRARY_PATH=$orig_ld_library_path
|
|
LIBVA_LIB=$(LD_TRACE_LOADED_OBJECTS=1 "$LOADER" "$AI_LIBAVCODEC_LIB" | grep libva.so | grep -v 'not found' | awk '{print $3}')
|
|
if [ -z "$LIBVA_LIB" ]; then
|
|
LD_LIBRARY_PATH=$S_LD_LIBRARY_PATH
|
|
return 1
|
|
fi
|
|
libva_libs=$LIBVA_LIB
|
|
# add also libva-drm, libva-x11 if present
|
|
for n in libva-drm libva-x11; do
|
|
NAME=$(echo "$LIBVA_LIB" | sed s/libva/$n/)
|
|
if [ -f "$NAME" ]; then
|
|
libva_libs=$libva_libs:$NAME
|
|
fi
|
|
done
|
|
LD_LIBRARY_PATH=$S_LD_LIBRARY_PATH
|
|
export LD_PRELOAD="$libva_libs${LD_PRELOAD:+:$LD_PRELOAD}"
|
|
}
|
|
|
|
## Tries to set LD_PRELOAD to system libva (see set_libva_ld_preload()). If failed, sets path to bundled libva drivers.
|
|
setup_vaapi() {
|
|
ULTRAGRID_BUNDLED_LIBVA=${ULTRAGRID_BUNDLED_LIBVA:-$use_bundled_libva_default}
|
|
if [ "$ULTRAGRID_BUNDLED_LIBVA" -ne 1 ]; then
|
|
if ! set_libva_ld_preload; then
|
|
echo "${bold}${red}Could not set system libva, using bundled libraries instead!${reset}" >&2
|
|
ULTRAGRID_BUNDLED_LIBVA=1
|
|
fi
|
|
fi
|
|
if [ "$ULTRAGRID_BUNDLED_LIBVA" -eq 1 ]; then
|
|
if [ -d "$DIR/usr/lib/va" ] && [ -z "${LIBVA_DRIVERS_PATH:-}" ]; then
|
|
export LIBVA_DRIVERS_PATH="$AI_LIB_PATH/va"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
setup_wayland() {
|
|
# use bundled Wayland libs only when not running on Wayland, otherwise system ones
|
|
if [ -z "${WAYLAND_DISPLAY-}" ]; then
|
|
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$AI_LIB_PATH/wayland"
|
|
fi
|
|
}
|
|
|
|
add_whitelist() {
|
|
if expr "$1" : /tmp >/dev/null; then
|
|
printf -- "$separator--read-write=%s --mkdir=%s" "$1" "$1"
|
|
else
|
|
printf -- "$separator--whitelist=%s" "$1"
|
|
fi
|
|
separator=' '
|
|
}
|
|
|
|
## Parse params to get custom rules like whitelists that may be needed to add
|
|
## @todo spaces inside paths doesn't work
|
|
get_custom_firejail_rules() {
|
|
separator=''
|
|
playback_path=$(echo "$@" | sed -n 's/.*--playback \([^ :]*\).*/\1/p')
|
|
if [ -n "$playback_path" ]; then
|
|
add_whitelist "$(realpath "$playback_path")"
|
|
fi
|
|
# print every argument of "filename=", "file=", "dump:" or "--record=" pattern
|
|
for n in "$@"; do
|
|
file_path=$(echo "$n" | sed -n -e 's/.*filename=\([^:]*\).*/\1/p' -e 's/.*file=\([^:]*\).*/\1/p' -e 's/dump:\([^:]*\).*/\1/p' -e 's/^--record=\([^:]*\).*/\1/p')
|
|
if [ -n "$file_path" ]; then
|
|
abs_path=$(realpath "$file_path")
|
|
add_whitelist "$abs_path"
|
|
if expr "$n" : 'dump:' >/dev/null || expr "$n" : '--record' >/dev/null; then
|
|
printf -- "$separator--mkdir=%s" "$abs_path" # dir may not exist
|
|
fi
|
|
if expr "$n" : '.*file=' >/dev/null || expr "$n" : '.*filename' >/dev/null; then
|
|
parent_dir=$(dirname "$abs_path")
|
|
printf -- "$separator--whitelist=%s" "$parent_dir" # to create the file
|
|
fi
|
|
fi
|
|
done
|
|
# -d dump or -d dummy:dump_to_file
|
|
if expr "$*" : '.*dump' >/dev/null || expr "$*" : '.*record' >/dev/null; then
|
|
add_whitelist "$(pwd)"
|
|
fi
|
|
if ! expr "$DIR" : /tmp >/dev/null; then # add AppRun path if not in tmp (== extracted AppImage)
|
|
add_whitelist "$(realpath "$DIR")"
|
|
fi
|
|
if [ -z "$separator" ]; then # no whitelist was set
|
|
printf -- "--private"
|
|
fi
|
|
# screen pw - requires root (could be disabled by default.profile) and dbus
|
|
if expr "$*" : '.*screen' >/dev/null; then
|
|
printf " --ignore=noroot"
|
|
elif firejail --version | grep -iq "d-\{0,1\}bus.*enabled"; then
|
|
printf " --dbus-user=none --dbus-system=none"
|
|
fi
|
|
}
|
|
|
|
# shellcheck source=/dev/null
|
|
. "$DIR/scripts/preload.sh"
|
|
setup_vaapi
|
|
setup_wayland
|
|
# ultragrid_aplay_jack.so is not used because it loads JACK with dlopen,
|
|
# while portaudio is linked directly to JACK library
|
|
set_ld_preload ultragrid_aplay_portaudio.so libjack
|
|
set_ld_preload ultragrid_vidcap_screen_pipewire.so libpipewire
|
|
|
|
RUN=
|
|
if [ -n "${ULTRAGRID_USE_FIREJAIL-}" ] && [ "$ULTRAGRID_USE_FIREJAIL" != 0 ] && [ "$ULTRAGRID_USE_FIREJAIL" != no ]; then
|
|
command -v firejail >/dev/null || { echo "Firejail not present in system!"; exit 1; }
|
|
if expr "$ULTRAGRID_USE_FIREJAIL" : '.*\.profile' >/dev/null; then
|
|
FIREJAIL_OPTS="--profile=$ULTRAGRID_USE_FIREJAIL"
|
|
else
|
|
FJ_TMPDIR=${TMPDIR-/tmp/ultragrid-$(id -u)}
|
|
FIREJAIL_OPTS="--caps.drop=all --ipc-namespace --nonewprivs --protocol=unix,inet,inet6,netlink --seccomp --disable-mnt --private-bin=none --private-opt=none --mkdir=$FJ_TMPDIR --read-write=$FJ_TMPDIR --writable-var"
|
|
FIREJAIL_OPTS="$FIREJAIL_OPTS $(get_custom_firejail_rules "$@") --private-etc=alsa,group,hostname,ld.so.conf,ld.so.cache,ld.so.conf.d,nsswitch.conf,passwd,resolv.conf --ignore=novideo"
|
|
if ! expr "$FIREJAIL_OPTS" : '.*--read-write=/tmp ' > /dev/null; then
|
|
FIREJAIL_OPTS="--read-only=/tmp $FIREJAIL_OPTS"
|
|
fi
|
|
fi
|
|
if firejail --help | grep -q -- --keep-var-tmp; then
|
|
FIREJAIL_OPTS="$FIREJAIL_OPTS --keep-var-tmp"
|
|
fi
|
|
RUN="firejail --env=LD_PRELOAD=${LD_PRELOAD} --env=LD_LIBRARY_PATH=${LD_LIBRARY_PATH}${FJ_TMPDIR+ --env=TMPDIR=${FJ_TMPDIR}} --env=UG_FONT_DIR=${UG_FONT_DIR} ${fj_env-} $FIREJAIL_OPTS "
|
|
if [ "${FIREJAIL_DEBUG:-}" ]; then
|
|
printf "Firejail arguments:\n\t$RUN\n\n"
|
|
fi
|
|
fi
|
|
|
|
if [ $# -eq 0 ] || [ "${1-}" = "--gui" ]; then
|
|
handle_updates "$@"
|
|
if [ $# -eq 0 ]; then usage; else shift; fi
|
|
if [ -x "$DIR/usr/bin/uv-qt" ]; then
|
|
"$DIR/usr/bin/uv-qt" --with-uv "$DIR/usr/bin/uv" "$@"
|
|
else
|
|
echo "GUI was not compiled in!" >&2
|
|
exit 1
|
|
fi
|
|
elif [ "$1" = "-o" ] || [ "$1" = "--tool" ]; then
|
|
handle_updates "$@"
|
|
TOOL=$2
|
|
shift 2
|
|
if [ "$TOOL" = help ]; then
|
|
printf "available tools: ${bold}%s${reset}\n" "$(get_tools)"
|
|
exit 0
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
${RUN}"$DIR/usr/bin/$TOOL" "$@"
|
|
elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
|
usage
|
|
exit 0
|
|
elif [ "$1" = "--fullhelp" ]; then
|
|
usage
|
|
usage_aux
|
|
exit 0
|
|
elif { [ $# -eq 1 ] || [ $# -eq 2 ]; } && { [ "$1" = "-m" ] || [ "$1" = "--man" ]; }; then
|
|
PAGE=${2:-uv}
|
|
man -l "$DIR/usr/share/man/man1/$PAGE.1"
|
|
elif [ "$1" = "-u" ] || [ "$1" = "--update" ]; then
|
|
shift
|
|
unset LD_LIBRARY_PATH
|
|
if [ -d "$DIR/appimageupdatetool-lib" ]; then
|
|
export LD_LIBRARY_PATH="$DIR/appimageupdatetool-lib"
|
|
fi
|
|
touch "$APPIMAGE" # update AppImage mtime to avoid update notices if there are no updates avalable but were checked for
|
|
"$DIR/appimageupdatetool" ${1+"$@" }"$APPIMAGE"
|
|
else
|
|
handle_updates "$@"
|
|
# shellcheck disable=SC2086
|
|
${RUN}"$DIR/usr/bin/uv" "$@"
|
|
fi
|