aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Fink2026-05-16 07:59:48 +0200
committerDennis Fink2026-05-16 07:59:48 +0200
commit13b50b5faae3d46e1b23ccc4922b098b7feaf709 (patch)
tree8d4da0b3fbbd537a82d67210890edc0ae79e56b3
parent27173868947c0ad00cf207cf5c80c256f6da4989 (diff)
downloadtranscode.sh-13b50b5faae3d46e1b23ccc4922b098b7feaf709.tar.gz
transcode.sh-13b50b5faae3d46e1b23ccc4922b098b7feaf709.zip
refactor: improve script structure readability
Add a file structure overview and split the script into clearer section headers so related functions are easier to find. Move main execution below all function definitions and add local subsection comments inside encode_one without changing the script behavior.
Diffstat (limited to '')
-rwxr-xr-xtranscode.sh731
1 files changed, 402 insertions, 329 deletions
diff --git a/transcode.sh b/transcode.sh
index 1283ca3..33794bf 100755
--- a/transcode.sh
+++ b/transcode.sh
@@ -59,6 +59,24 @@
# Dennis Fink <me+coding@dennisfink.me>
###############################################################################
+###############################################################################
+# FILE STRUCTURE
+#
+# 1. Header, metadata, globals and exit codes
+# 2. Function definitions
+# - Output helpers
+# - Help/version output
+# - Small utility functions
+# - Terminal color handling
+# - Configuration handling
+# - Codec skip-list handling
+# - Preset handling
+# - Cleanup handling
+# - Size report handling
+# - Encoding
+# 3. Main execution
+###############################################################################
+
# TRACE enables bash execution tracing and is intended for debugging control
# flow / expansions. DEBUG enable structured debug messages (see debug()) and
# is intended for high-level state reporting.
@@ -107,6 +125,7 @@ set -o pipefail
# for informational messages. They are marked readonly to prevent accidental
# modification at runtime.
###############################################################################
+
readonly SCRIPTNAME=${0##*/}
readonly DESCRIPTION="Batch transcode helper for media files using ffmpeg."
readonly DATE_OF_CREATION=2025-08-06
@@ -189,12 +208,8 @@ EXIT_CONFIG_ERROR=3
EXIT_MISSING_DEPENDENCY=127
readonly EXIT_OK EXIT_RUNTIME_FAILURE EXIT_USAGE_ERROR EXIT_CONFIG_ERROR EXIT_MISSING_DEPENDENCY
-##############################################################################
-# FUNCTIONS
-#
-# This section defines the helper functions used throughout the script. They
-# handle formatted output, error reporting, version information, utilities
-# functions and runtime behaviour such as displaying usage instructions.
+###############################################################################
+# OUTPUT HELPERS
###############################################################################
emit() {
@@ -251,6 +266,10 @@ debug() {
fi
}
+###############################################################################
+# HELP AND VERSION OUTPUT
+###############################################################################
+
print_help() {
printf "${BOLD}${MAGENTA}%s${ALL_OFF} - ${BOLD}${CYAN}%s${ALL_OFF} - ${BOLD}%s${ALL_OFF}
@@ -362,6 +381,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" \
"$DATE_OF_REVISION" "$LICENSE"
}
+###############################################################################
+# SMALL UTILITY FUNCTIONS
+###############################################################################
+
# Return the size of a file in bytes.
# Uses GNU stat -c on Linux with a fallback to BSD/macOS stat -f.
filesize() {
@@ -381,35 +404,17 @@ format_filesize() {
}
###############################################################################
-# TERMINAL COLOR SETUP
+# TERMINAL COLOR HANDLING
#
# Colors and style escape sequences are configured dynamically through the
-# `setup_colors` function, which enables or disables color output based on the
-# value of ENABLE_COLOR. When enabled, terminal capabilities are detected via
-# `tput`, falling back to ANSI escapes if unavailable.
+# setup_colors function. Runtime color detection happens in MAIN EXECUTION so
+# all function definitions stay together before the executable flow.
#
# This script respects the NO_COLOR standard (https://no-color.org/). If the
# environment variable NO_COLOR is set (to any value), all color output is
# disabled. If FORCE_COLOR is set, colors are always enabled.
###############################################################################
-# NOTE: This block calls debug() and reads $DEBUG. Both must be defined before
-# this point. Do not move this block above the GLOBAL VARIABLES or FUNCTIONS
-# sections without adjusting those dependencies.
-if [[ -n "${NO_COLOR:-}" ]]; then
- debug "Colors are disabled via NO_COLOR"
- ENABLE_COLOR=0
-elif [[ -n "${FORCE_COLOR:-}" ]]; then
- debug "Colors are forced via FORCE_COLOR"
- ENABLE_COLOR=1
-elif [[ -t 1 ]]; then
- debug "Colors are enabled via interactive terminal"
- ENABLE_COLOR=1
-else
- debug "Colors are disabled"
- ENABLE_COLOR=0
-fi
-
setup_colors() {
if [[ "$ENABLE_COLOR" -eq 1 ]]; then
if tput setaf 0 >/dev/null 2>&1; then
@@ -446,14 +451,9 @@ setup_colors() {
CYAN=""
fi
}
-setup_colors
###############################################################################
-# MAIN EXECUTION
-###############################################################################
-
-###############################################################################
-# CONFIGURATION FILE
+# CONFIGURATION HANDLING
#
# Load defaults from config.toml if it exists. Values are only applied when the
# corresponding CLI flag has NOT already been set (CLI takes precedence).
@@ -635,11 +635,14 @@ load_config() {
fi
}
+###############################################################################
+# CODEC SKIP-LIST HANDLING
+###############################################################################
+
# Add a codec name to the SKIP_CODECS associative array.
# - Normalizes to lowercase
# - Ignores empty tokens
# - Used both for CLI --skip-codec and for codecs defined
-# in the config file
add_skip_codec_token() {
local token="${1,,}" # lowercase
if [[ ! -v SKIP_CODECS["$token"] ]]; then
@@ -662,6 +665,10 @@ parse_skip_codec_parameter() {
done
}
+###############################################################################
+# PRESET HANDLING
+###############################################################################
+
# Load ffmpeg argument preset by name.
#
# Security:
@@ -792,300 +799,9 @@ list_presets() {
done
}
-if [[ $# -eq 0 ]]; then
- debug "No parameters were specified"
- printf "${BOLD}${BLUE}Usage:${ALL_OFF} ${BOLD}${MAGENTA}%s${ALL_OFF} ${BOLD}${YELLOW}[OPTION] [--]${ALL_OFF} ${BOLD}${GREEN}FILE...${ALL_OFF}
-Run ${BOLD}${MAGENTA}%s${ALL_OFF} ${BOLD}${YELLOW}--help${ALL_OFF} for full usage information.\n" "$SCRIPTNAME" "$SCRIPTNAME" >&2
- exit $EXIT_USAGE_ERROR
-fi
-
-while [[ $# -gt 0 ]]; do
- case "$1" in
- -h | --help | -\?)
- print_help
- exit $EXIT_OK
- ;;
- --version)
- print_version
- exit $EXIT_OK
- ;;
- --list-presets)
- list_presets
- exit $EXIT_OK
- ;;
- -q | --quiet)
- QUIET=1
- _CLI_QUIET=1
- shift
- ;;
- -v | --verbose)
- VERBOSE=1
- _CLI_VERBOSE=1
- shift
- ;;
- --color)
- ENABLE_COLOR=1
- setup_colors
- shift
- ;;
- --no-color)
- ENABLE_COLOR=0
- setup_colors
- shift
- ;;
- -c | --continue)
- CONTINUE_ON_FAIL=1
- _CLI_CONTINUE=1
- shift
- ;;
- --no-continue)
- CONTINUE_ON_FAIL=0
- _CLI_CONTINUE=1
- shift
- ;;
- --verify-output)
- VERIFY_OUTPUT=1
- _CLI_VERIFY_OUTPUT=1
- shift
- ;;
- --no-verify-output)
- VERIFY_OUTPUT=0
- _CLI_VERIFY_OUTPUT=1
- shift
- ;;
- --config-file)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- if [[ ! -n "$2" ]]; then
- error "Value for $1 must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- CONFIG_FILE="$2"
- _CLI_CONFIG_FILE=1
- shift 2
- ;;
- --config-file=*)
- if [[ ! -n "${1#*=}" ]]; then
- error "Value for --config-file must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- CONFIG_FILE="${1#*=}"
- _CLI_CONFIG_FILE=1
- shift
- ;;
- --no-config)
- CONFIG_FILE="/dev/null"
- _CLI_CONFIG_FILE=1
- shift
- ;;
- -f | --encode-file)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- if [[ ! -n "$2" ]]; then
- error "Value for $1 must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- ENCODE_FILE="$2"
- shift 2
- ;;
- --encode-file=*)
- if [[ ! -n "${1#*=}" ]]; then
- error "Value for --encode-file must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- ENCODE_FILE="${1#*=}"
- shift
- ;;
- -n | --dry-run)
- DRY_RUN=1
- shift
- ;;
- -N | --nice)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- NICE_VALUE="$2"
- _CLI_NICE=1
- shift 2
- ;;
- --nice=*)
- NICE_VALUE="${1#*=}"
- _CLI_NICE=1
- shift
- ;;
- -s | --size-report)
- SIZE_REPORT=1
- _CLI_SIZE_REPORT=1
- shift
- ;;
- --no-size-report)
- SIZE_REPORT=0
- _CLI_SIZE_REPORT=1
- shift
- ;;
- --size-report-file)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- if [[ ! -n "$2" ]]; then
- error "Value for $1 must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- SIZE_REPORT_FILE="$2"
- _CLI_SIZE_REPORT_FILE=1
- shift 2
- ;;
- --size-report-file=*)
- if [[ ! -n "${1#*=}" ]]; then
- error "Value for --size-report-file must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- SIZE_REPORT_FILE="${1#*=}"
- _CLI_SIZE_REPORT_FILE=1
- shift
- ;;
- -S | --skip-codec)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- parse_skip_codec_parameter "$2"
- shift 2
- ;;
- --skip-codec=*)
- parse_skip_codec_parameter "${1#*=}"
- shift
- ;;
- -l | --only-if-smaller)
- ONLY_IF_SMALLER=1
- _CLI_ONLY_IF_SMALLER=1
- shift
- ;;
- --no-only-if-smaller)
- ONLY_IF_SMALLER=0
- _CLI_ONLY_IF_SMALLER=1
- shift
- ;;
- --hwaccel)
- HWACCEL=1
- # Peek at the next argument: use it as the METHOD only if it is
- # non-empty and does not look like an option flag.
- if [[ $# -ge 2 && -n "$2" && "$2" != -* ]]; then
- HWACCEL_VALUE="$2"
- shift 2
- else
- HWACCEL_VALUE="auto"
- shift
- fi
- _CLI_HWACCEL=1
- ;;
- --hwaccel=*)
- HWACCEL=1
- HWACCEL_VALUE="${1#*=}"
- if [[ ! -n "$HWACCEL_VALUE" ]]; then
- error "Value for --hwaccel must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- _CLI_HWACCEL=1
- shift
- ;;
- --no-hwaccel)
- HWACCEL=0
- _CLI_HWACCEL=1
- shift
- ;;
- -p | --preset)
- if [[ $# -lt 2 ]]; then
- error "Missing value for $1"
- exit $EXIT_USAGE_ERROR
- fi
- if [[ ! -n "$2" ]]; then
- error "Value for $1 must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- PRESET_NAME="$2"
- _CLI_PRESET=1
- shift 2
- ;;
- --preset=*)
- if [[ ! -n "${1#*=}" ]]; then
- error "Value for --preset must not be empty"
- exit $EXIT_USAGE_ERROR
- fi
- PRESET_NAME="${1#*=}"
- _CLI_PRESET=1
- shift
- ;;
- --)
- shift
- REMAINING_ARGS+=("$@")
- break
- ;;
- -*)
- error "Unknown option: $1"
- exit $EXIT_USAGE_ERROR
- ;;
- *)
- REMAINING_ARGS+=("$1")
- shift
- ;;
- esac
-done
-
-# Apply config file defaults. Must run after CLI parsing so _CLI_* sentinels
-# are set, but before validation so config-supplied values are validated too.
-load_config
-
-printf -v joined ' %s' "${!SKIP_CODECS[@]}"
-
-debug "Effective configuration:"
-debug " config-file:" "$CONFIG_FILE"
-debug " dry-run:" "$DRY_RUN"
-debug " encode-file:" "$ENCODE_FILE"
-debug " hwaccel:" "$HWACCEL"
-debug " hwaccel_value:" "$HWACCEL_VALUE"
-debug " nice:" "$NICE_VALUE"
-debug " only-if-smaller:" "$ONLY_IF_SMALLER"
-debug " preset:" "$PRESET_NAME"
-debug " quiet:" "$QUIET"
-debug " size-report-file:" "$SIZE_REPORT_FILE"
-debug " size-report:" "$SIZE_REPORT"
-debug " skip-codecs:" "${joined# }"
-debug " verbose:" "$VERBOSE"
-debug " verify-output:" "$VERIFY_OUTPUT"
-
-command -v ffmpeg >/dev/null 2>&1 || {
- error "ffmpeg not found."
- exit $EXIT_MISSING_DEPENDENCY
-}
-command -v ffprobe >/dev/null 2>&1 || {
- error "ffprobe not found."
- exit $EXIT_MISSING_DEPENDENCY
-}
-command -v nice >/dev/null 2>&1 || {
- error "nice not found."
- exit $EXIT_MISSING_DEPENDENCY
-}
-
-if [[ $_CLI_SIZE_REPORT_FILE -eq 1 && $SIZE_REPORT -eq 0 ]]; then
- warn "--size-report-file has no effect without --size-report"
-fi
-
-if [[ ! "$NICE_VALUE" =~ ^-?[0-9]+$ || $NICE_VALUE -lt -20 || $NICE_VALUE -gt 19 ]]; then
- error "Invalid nice value (must be an integer between -20 and 19):" "$NICE_VALUE"
- exit $EXIT_USAGE_ERROR
-fi
-
-if [[ ! -z "${joined# }" ]]; then
- verbose "Skipping files with codecs:" "${joined# }"
-fi
-unset joined
+###############################################################################
+# CLEANUP HANDLING
+###############################################################################
# Remove temporary output files created during encoding.
# Registered via trap EXIT so it runs on normal exit and on failures
@@ -1100,7 +816,10 @@ cleanup() {
fi
done
}
-trap cleanup EXIT
+
+###############################################################################
+# SIZE REPORT HANDLING
+###############################################################################
# Calculate integer percentage saved from original/new byte counts.
calculate_saved_percentage() {
@@ -1187,6 +906,10 @@ print_size_report_summary() {
printf "${BOLD}${BLUE}Average saved:${ALL_OFF} %s%%\n" "$average_saved_pct"
}
+###############################################################################
+# ENCODING
+###############################################################################
+
# Encode a single media file according to PRESET_NAME.
#
# Arguments:
@@ -1210,6 +933,10 @@ encode_one() {
local current_file_index="$2"
local amount_total_files="$3"
+ # ---------------------------------------------------------------------------
+ # Validate input file
+ # ---------------------------------------------------------------------------
+
# Ignore empty input entries so callers can safely pass filtered file lists
# without treating blank lines as errors.
if [[ -z "$input_file" ]]; then
@@ -1242,6 +969,10 @@ encode_one() {
return $EXIT_RUNTIME_FAILURE
fi
+ # ---------------------------------------------------------------------------
+ # Probe input stream metadata
+ # ---------------------------------------------------------------------------
+
# Probe codec, pixel format and frame rate in a single ffprobe invocation to
# decrease the startup overhead on large batches.
local probe_out
@@ -1286,6 +1017,10 @@ encode_one() {
return $EXIT_RUNTIME_FAILURE
fi
+ # ---------------------------------------------------------------------------
+ # Derive output pixel format and GOP size
+ # ---------------------------------------------------------------------------
+
# Some files report "yuvj*" formats (full-range JPEG-style). For encoding
# purposes we normalize to the equivalent "yuv*" formats.
input_pixel_format="${input_pixel_format/yuvj/yuv}"
@@ -1342,6 +1077,10 @@ encode_one() {
load_preset "$PRESET_NAME"
+ # ---------------------------------------------------------------------------
+ # Build temporary output path and ffmpeg command
+ # ---------------------------------------------------------------------------
+
local extension directory temporary_output_file base stem
base="${input_file##*/}"
@@ -1389,6 +1128,10 @@ encode_one() {
"${ffargs[@]}"
"file:$temporary_output_file")
+ # ---------------------------------------------------------------------------
+ # Dry-run output
+ # ---------------------------------------------------------------------------
+
if [[ $DRY_RUN -eq 1 ]]; then
msg "DRY RUN:" "Would encode with preset $PRESET_NAME"
verbose "Input codec:" "$input_codec"
@@ -1401,6 +1144,10 @@ encode_one() {
return $EXIT_OK
fi
+ # ---------------------------------------------------------------------------
+ # Run encode, verify output, and replace original
+ # ---------------------------------------------------------------------------
+
msg "Encoding:" "$input_file"
if nice -n "$NICE_VALUE" "${encode_cmd[@]}"; then
@@ -1467,6 +1214,332 @@ encode_one() {
fi
}
+###############################################################################
+# MAIN EXECUTION
+###############################################################################
+
+# Configure terminal colors before any user-facing output.
+#
+# NOTE: This block calls debug() and reads $DEBUG. Both must be defined before
+# this point. Do not move this block above the GLOBAL VARIABLES or FUNCTION
+# DEFINITIONS sections without adjusting those dependencies.
+if [[ -n "${NO_COLOR:-}" ]]; then
+ debug "Colors are disabled via NO_COLOR"
+ ENABLE_COLOR=0
+elif [[ -n "${FORCE_COLOR:-}" ]]; then
+ debug "Colors are forced via FORCE_COLOR"
+ ENABLE_COLOR=1
+elif [[ -t 1 ]]; then
+ debug "Colors are enabled via interactive terminal"
+ ENABLE_COLOR=1
+else
+ debug "Colors are disabled"
+ ENABLE_COLOR=0
+fi
+setup_colors
+
+# Reject calls without any positional arguments or options before doing more
+# setup work.
+if [[ $# -eq 0 ]]; then
+ debug "No parameters were specified"
+ printf "${BOLD}${BLUE}Usage:${ALL_OFF} ${BOLD}${MAGENTA}%s${ALL_OFF} ${BOLD}${YELLOW}[OPTION] [--]${ALL_OFF} ${BOLD}${GREEN}FILE...${ALL_OFF}
+Run ${BOLD}${MAGENTA}%s${ALL_OFF} ${BOLD}${YELLOW}--help${ALL_OFF} for full usage information.\n" "$SCRIPTNAME" "$SCRIPTNAME" >&2
+ exit $EXIT_USAGE_ERROR
+fi
+
+# Parse command-line options. CLI flags are recorded in _CLI_* sentinel
+# variables so load_config() can respect CLI-over-config precedence.
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h | --help | -\?)
+ print_help
+ exit $EXIT_OK
+ ;;
+ --version)
+ print_version
+ exit $EXIT_OK
+ ;;
+ --list-presets)
+ list_presets
+ exit $EXIT_OK
+ ;;
+ -q | --quiet)
+ QUIET=1
+ _CLI_QUIET=1
+ shift
+ ;;
+ -v | --verbose)
+ VERBOSE=1
+ _CLI_VERBOSE=1
+ shift
+ ;;
+ --color)
+ ENABLE_COLOR=1
+ setup_colors
+ shift
+ ;;
+ --no-color)
+ ENABLE_COLOR=0
+ setup_colors
+ shift
+ ;;
+ -c | --continue)
+ CONTINUE_ON_FAIL=1
+ _CLI_CONTINUE=1
+ shift
+ ;;
+ --no-continue)
+ CONTINUE_ON_FAIL=0
+ _CLI_CONTINUE=1
+ shift
+ ;;
+ --verify-output)
+ VERIFY_OUTPUT=1
+ _CLI_VERIFY_OUTPUT=1
+ shift
+ ;;
+ --no-verify-output)
+ VERIFY_OUTPUT=0
+ _CLI_VERIFY_OUTPUT=1
+ shift
+ ;;
+ --config-file)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ if [[ ! -n "$2" ]]; then
+ error "Value for $1 must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ CONFIG_FILE="$2"
+ _CLI_CONFIG_FILE=1
+ shift 2
+ ;;
+ --config-file=*)
+ if [[ ! -n "${1#*=}" ]]; then
+ error "Value for --config-file must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ CONFIG_FILE="${1#*=}"
+ _CLI_CONFIG_FILE=1
+ shift
+ ;;
+ --no-config)
+ CONFIG_FILE="/dev/null"
+ _CLI_CONFIG_FILE=1
+ shift
+ ;;
+ -f | --encode-file)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ if [[ ! -n "$2" ]]; then
+ error "Value for $1 must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ ENCODE_FILE="$2"
+ shift 2
+ ;;
+ --encode-file=*)
+ if [[ ! -n "${1#*=}" ]]; then
+ error "Value for --encode-file must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ ENCODE_FILE="${1#*=}"
+ shift
+ ;;
+ -n | --dry-run)
+ DRY_RUN=1
+ shift
+ ;;
+ -N | --nice)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ NICE_VALUE="$2"
+ _CLI_NICE=1
+ shift 2
+ ;;
+ --nice=*)
+ NICE_VALUE="${1#*=}"
+ _CLI_NICE=1
+ shift
+ ;;
+ -s | --size-report)
+ SIZE_REPORT=1
+ _CLI_SIZE_REPORT=1
+ shift
+ ;;
+ --no-size-report)
+ SIZE_REPORT=0
+ _CLI_SIZE_REPORT=1
+ shift
+ ;;
+ --size-report-file)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ if [[ ! -n "$2" ]]; then
+ error "Value for $1 must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ SIZE_REPORT_FILE="$2"
+ _CLI_SIZE_REPORT_FILE=1
+ shift 2
+ ;;
+ --size-report-file=*)
+ if [[ ! -n "${1#*=}" ]]; then
+ error "Value for --size-report-file must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ SIZE_REPORT_FILE="${1#*=}"
+ _CLI_SIZE_REPORT_FILE=1
+ shift
+ ;;
+ -S | --skip-codec)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ parse_skip_codec_parameter "$2"
+ shift 2
+ ;;
+ --skip-codec=*)
+ parse_skip_codec_parameter "${1#*=}"
+ shift
+ ;;
+ -l | --only-if-smaller)
+ ONLY_IF_SMALLER=1
+ _CLI_ONLY_IF_SMALLER=1
+ shift
+ ;;
+ --no-only-if-smaller)
+ ONLY_IF_SMALLER=0
+ _CLI_ONLY_IF_SMALLER=1
+ shift
+ ;;
+ --hwaccel)
+ HWACCEL=1
+ # Peek at the next argument: use it as the METHOD only if it is
+ # non-empty and does not look like an option flag.
+ if [[ $# -ge 2 && -n "$2" && "$2" != -* ]]; then
+ HWACCEL_VALUE="$2"
+ shift 2
+ else
+ HWACCEL_VALUE="auto"
+ shift
+ fi
+ _CLI_HWACCEL=1
+ ;;
+ --hwaccel=*)
+ HWACCEL=1
+ HWACCEL_VALUE="${1#*=}"
+ if [[ ! -n "$HWACCEL_VALUE" ]]; then
+ error "Value for --hwaccel must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ _CLI_HWACCEL=1
+ shift
+ ;;
+ --no-hwaccel)
+ HWACCEL=0
+ _CLI_HWACCEL=1
+ shift
+ ;;
+ -p | --preset)
+ if [[ $# -lt 2 ]]; then
+ error "Missing value for $1"
+ exit $EXIT_USAGE_ERROR
+ fi
+ if [[ ! -n "$2" ]]; then
+ error "Value for $1 must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ PRESET_NAME="$2"
+ _CLI_PRESET=1
+ shift 2
+ ;;
+ --preset=*)
+ if [[ ! -n "${1#*=}" ]]; then
+ error "Value for --preset must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ PRESET_NAME="${1#*=}"
+ _CLI_PRESET=1
+ shift
+ ;;
+ --)
+ shift
+ REMAINING_ARGS+=("$@")
+ break
+ ;;
+ -*)
+ error "Unknown option: $1"
+ exit $EXIT_USAGE_ERROR
+ ;;
+ *)
+ REMAINING_ARGS+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# Apply config file defaults. Must run after CLI parsing so _CLI_* sentinels
+# are set, but before validation so config-supplied values are validated too.
+load_config
+
+printf -v joined ' %s' "${!SKIP_CODECS[@]}"
+
+debug "Effective configuration:"
+debug " config-file:" "$CONFIG_FILE"
+debug " dry-run:" "$DRY_RUN"
+debug " encode-file:" "$ENCODE_FILE"
+debug " hwaccel:" "$HWACCEL"
+debug " hwaccel_value:" "$HWACCEL_VALUE"
+debug " nice:" "$NICE_VALUE"
+debug " only-if-smaller:" "$ONLY_IF_SMALLER"
+debug " preset:" "$PRESET_NAME"
+debug " quiet:" "$QUIET"
+debug " size-report-file:" "$SIZE_REPORT_FILE"
+debug " size-report:" "$SIZE_REPORT"
+debug " skip-codecs:" "${joined# }"
+debug " verbose:" "$VERBOSE"
+debug " verify-output:" "$VERIFY_OUTPUT"
+
+command -v ffmpeg >/dev/null 2>&1 || {
+ error "ffmpeg not found."
+ exit $EXIT_MISSING_DEPENDENCY
+}
+command -v ffprobe >/dev/null 2>&1 || {
+ error "ffprobe not found."
+ exit $EXIT_MISSING_DEPENDENCY
+}
+command -v nice >/dev/null 2>&1 || {
+ error "nice not found."
+ exit $EXIT_MISSING_DEPENDENCY
+}
+
+if [[ $_CLI_SIZE_REPORT_FILE -eq 1 && $SIZE_REPORT -eq 0 ]]; then
+ warn "--size-report-file has no effect without --size-report"
+fi
+
+if [[ ! "$NICE_VALUE" =~ ^-?[0-9]+$ || $NICE_VALUE -lt -20 || $NICE_VALUE -gt 19 ]]; then
+ error "Invalid nice value (must be an integer between -20 and 19):" "$NICE_VALUE"
+ exit $EXIT_USAGE_ERROR
+fi
+
+if [[ ! -z "${joined# }" ]]; then
+ verbose "Skipping files with codecs:" "${joined# }"
+fi
+unset joined
+
+# Remove temporary output files on normal exit and on failures.
+trap cleanup EXIT
+
STATUS=$EXIT_OK
if [[ -n $ENCODE_FILE ]]; then
if [[ ! -f "$ENCODE_FILE" ]]; then