diff options
| -rw-r--r-- | README.md | 7 | ||||
| -rwxr-xr-x | transcode.sh | 74 | ||||
| -rw-r--r-- | transcode.sh.1 | 45 | ||||
| -rw-r--r-- | transcode.sh.bash-completion | 297 |
4 files changed, 274 insertions, 149 deletions
@@ -146,6 +146,7 @@ quiet = false | `[encoding]` | `preset` | string | `-p` | | `[encoding]` | `nice` | integer | `-N` | | `[encoding]` | `verify_output` | boolean | `--verify-output` | +| `[encoding]` | `hwaccel` | string or boolean | `--hwaccel` / `--no-hwaccel` | | `[skip]` | `codecs` | array of strings | `-S` (merged with CLI) | | `[saving]` | `enabled` | boolean | `-s` | | `[saving]` | `file` | string | `--saving-file` | @@ -155,6 +156,10 @@ quiet = false > **Note:** `[skip] codecs` from the config file and `--skip-codec` from the > CLI are **merged** — both sources contribute to the skip list. +> **Note:** `[encoding] hwaccel` accepts `false` (disable), `true` (use `auto`), +> or a method string such as `"vaapi"` or `"cuda"`. CLI `--hwaccel`/`--no-hwaccel` +> always takes precedence. + ### Codec skip list (deprecated) The legacy `skip.conf` file is no longer read. If it still exists, a @@ -177,6 +182,8 @@ transcode.sh [OPTION] [--] FILE... | `-f PATH`, `--encode-file PATH`, `--encodefile=PATH` | Read file list from PATH (one per line) | | `-n`, `--dry-run` | Show what would be done; don't run ffmpeg | | `-N VALUE`, `--nice VALUE`, `--nice=VALUE` | Niceness value for ffmpeg (default: 19) | +| `--hwaccel [METHOD]`, `--hwaccel=METHOD` | Enable hardware acceleration; METHOD defaults to `auto` if omitted (e.g. `cuda`, `vaapi`, `videotoolbox`); enabled by default | +| `--no-hwaccel` | Disable hardware acceleration (omit `-hwaccel` from ffmpeg invocation) | | `-s`, `--saving` | Log filesize savings after each encode | | `--saving-file PATH`, `--saving-file=PATH` | Savings log path (default: `transcode_savings`) | | `-S LIST`, `--skip-codec LIST`, `--skip-codec=LIST` | Codecs to skip (comma/space/colon separated) | diff --git a/transcode.sh b/transcode.sh index 807495d..41a22ab 100755 --- a/transcode.sh +++ b/transcode.sh @@ -135,6 +135,8 @@ VERBOSE=0 CONTINUE_ON_FAIL=0 DRY_RUN=0 ENCODE_FILE="" +HWACCEL=1 +HWACCEL_VALUE="auto" NICE_VALUE=19 ONLY_IF_SMALLER=0 PRESET_NAME="default" @@ -157,6 +159,7 @@ readonly SKIP_CODECS_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/skip.c # knows which values have already been provided and must not be overridden. _CLI_CONFIG_FILE=0 _CLI_CONTINUE=0 +_CLI_HWACCEL=0 _CLI_NICE=0 _CLI_ONLY_IF_SMALLER=0 _CLI_PRESET=0 @@ -234,6 +237,9 @@ ${BOLD}${BLUE}Encoding options:${ALL_OFF} ${BOLD}${YELLOW}-p, --preset${ALL_OFF} ${BOLD}${GREEN}NAME${ALL_OFF} load ffmpeg arguments from a preset (default: ${BOLD}${RED}%s${ALL_OFF}) ${BOLD}${YELLOW}-N, --nice${ALL_OFF} ${BOLD}${GREEN}VALUE${ALL_OFF} nice value for ffmpeg (default: ${BOLD}${RED}%d${ALL_OFF}) ${BOLD}${YELLOW}-n, --dry-run${ALL_OFF} show what would be done, do not run ffmpeg + ${BOLD}${YELLOW} --hwaccel${ALL_OFF} ${BOLD}${GREEN}[METHOD]${ALL_OFF} enable hardware acceleration; METHOD defaults to ${BOLD}${RED}auto${ALL_OFF} + if omitted + ${BOLD}${YELLOW} --no-hwaccel${ALL_OFF} disable hardware acceleration (do not pass ${BOLD}${YELLOW}-hwaccel${ALL_OFF} to ffmpeg) ${BOLD}${YELLOW}-l, --only-if-smaller${ALL_OFF} only replace original if new file is smaller ${BOLD}${YELLOW}--no-only-if-smaller${ALL_OFF} do replace original even if new file is bigger ${BOLD}${YELLOW}-c, --continue${ALL_OFF} continue with the next file even if ffmpeg fails @@ -495,6 +501,22 @@ load_config() { } fi + # [encoding] hwaccel + if [[ $_CLI_HWACCEL -eq 0 ]]; then + val=$(_tomlq_get '.encoding.hwaccel // empty') && [[ -n "$val" ]] && { + debug "Config: encoding.hwaccel =" "$val" + if [[ "$val" == "false" ]]; then + HWACCEL=0 + else + HWACCEL=1 + # A bare `hwaccel = true` keeps "auto"; any other string is the METHOD. + if [[ "$val" != "true" ]]; then + HWACCEL_VALUE="$val" + fi + fi + } + fi + # [skip] codecs (TOML array → one element per line via tomlq -r '.skip.codecs[]') # CLI --skip-codec entries are additive, so we always load config codecs # regardless of _CLI_SKIP_CODEC. Both sources merge into SKIP_CODECS. @@ -802,6 +824,34 @@ while [[ $# -gt 0 ]]; do _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#*=}" + [[ -n "$HWACCEL_VALUE" ]] || { + error "Value for --hwaccel must not be empty" + exit $EXIT_USAGE_ERROR + } + _CLI_HWACCEL=1 + shift + ;; + --no-hwaccel) + HWACCEL=0 + _CLI_HWACCEL=1 + shift + ;; -p | --preset) [[ $# -ge 2 ]] || { error "Missing value for $1" @@ -847,18 +897,20 @@ load_config printf -v joined ' %s' "${!SKIP_CODECS[@]}" debug "Effective configuration:" -debug " preset:" "$PRESET_NAME" -debug " nice:" "$NICE_VALUE" +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 " verify-output:" "$VERIFY_OUTPUT" -debug " saving:" "$SAVING" +debug " preset:" "$PRESET_NAME" +debug " quiet:" "$QUIET" debug " saving-file:" "$SAVING_FILE" +debug " saving:" "$SAVING" debug " skip-codecs:" "${joined# }" debug " verbose:" "$VERBOSE" -debug " quiet:" "$QUIET" -debug " config-file:" "$CONFIG_FILE" -debug " encode-file:" "$ENCODE_FILE" +debug " verify-output:" "$VERIFY_OUTPUT" command -v ffmpeg >/dev/null 2>&1 || { error "ffmpeg not found." @@ -1065,13 +1117,21 @@ encode_one() { # Build ffmpeg command: # - Map all streams, metadata, and chapters # - Default to stream copy for everything + # - Prepend -hwaccel before -i when hardware acceleration is requested # - Let the preset override specific streams (usually video) via ffargs + + local hwaccel_args=() + if [[ $HWACCEL -eq 1 ]]; then + hwaccel_args=(-hwaccel "$HWACCEL_VALUE") + fi + local cmd=(ffmpeg -nostdin -y -hide_banner -v error -stats + "${hwaccel_args[@]}" -i "file:$file" -map 0 -map_metadata 0 diff --git a/transcode.sh.1 b/transcode.sh.1 index edeaae8..46b7526 100644 --- a/transcode.sh.1 +++ b/transcode.sh.1 @@ -86,6 +86,37 @@ Combine with .B \-v to see the detected codec and pixel format information. .TP +.BR \-\-hwaccel " [\fIMETHOD\fR], " \-\-hwaccel= \fIMETHOD\fR +Pass +.BI \-hwaccel " METHOD" +to +.BR ffmpeg (1) +before the input file, enabling hardware-accelerated decoding. +\fIMETHOD\fR is optional; when omitted it defaults to +.BR auto , +which lets +.BR ffmpeg (1) +select the best available hardware decoder and fall back to software +automatically. +Common values include +.BR cuda , +.BR vaapi , +.BR dxva2 , +and +.BR videotoolbox . +Hardware acceleration is +.B enabled by default +(method +.BR auto ). +.TP +.B \-\-no\-hwaccel +Do not pass +.B \-hwaccel +to +.BR ffmpeg (1). +Use this on hosts where hardware acceleration causes compatibility or +stability issues. +.TP .BR \-N " \fIVALUE\fR, " \-\-nice " \fIVALUE\fR, " \-\-nice= \fIVALUE\fR Run .BR ffmpeg (1) @@ -287,6 +318,20 @@ String. Default preset name. Equivalent to Integer. Default niceness value. Equivalent to .BR \-N . .TP +.B [encoding] hwaccel +String or boolean. +.B false +disables hardware acceleration. +.B true +enables it with method +.BR auto . +Any other string (e.g.\& +.IR vaapi , +.IR cuda ) +enables it with that specific method. +Equivalent to +.BR \-\-hwaccel " / " \-\-no\-hwaccel . +.TP .B [encoding] verify_output Boolean. Equivalent to .BR \-\-verify\-output / \-\-no\-verify\-output . diff --git a/transcode.sh.bash-completion b/transcode.sh.bash-completion index 9fc4701..1cae90e 100644 --- a/transcode.sh.bash-completion +++ b/transcode.sh.bash-completion @@ -14,155 +14,168 @@ # long equals --encode-file=list.txt _transcode_sh() { - local cur prev words cword - _init_completion || return + local cur prev words cword + _init_completion || return - local -r preset_dir="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets" + local -r preset_dir="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets" - # --------------------------------------------------------------------------- - # Helper: collect preset names from the preset directory - # --------------------------------------------------------------------------- - _transcode_presets() { - local presets=() - if [[ -d "$preset_dir" ]]; then - local f - while IFS= read -r f; do - f="${f##*/}" # basename - f="${f%.sh}" # strip .sh extension - presets+=("$f") - done < <(find "$preset_dir" -maxdepth 1 -name '*.sh' -type f 2>/dev/null) - fi - printf '%s\n' "${presets[@]}" - } + # --------------------------------------------------------------------------- + # Helper: collect preset names from the preset directory + # --------------------------------------------------------------------------- + _transcode_presets() { + local presets=() + if [[ -d "$preset_dir" ]]; then + local f + while IFS= read -r f; do + f="${f##*/}" # basename + f="${f%.sh}" # strip .sh extension + presets+=("$f") + done < <(find "$preset_dir" -maxdepth 1 -name '*.sh' -type f 2>/dev/null) + fi + printf '%s\n' "${presets[@]}" + } - local codecs='h264 hevc av1 vp8 vp9 mpeg2video mpeg4 mjpeg theora' - local nice_vals='0 5 10 15 19' + local codecs='h264 hevc av1 vp8 vp9 mpeg2video mpeg4 mjpeg theora' + local nice_vals='0 5 10 15 19' + local hwaccel_methods='auto cuda vaapi dxva2 d3d11va videotoolbox qsv' - # --------------------------------------------------------------------------- - # Handle --option=VALUE: cur contains the entire "--opt=val" token. - # Strip the "opt=" prefix and delegate to the appropriate completer. - # This must be checked before the $prev dispatch below. - # --------------------------------------------------------------------------- - case "$cur" in - --config-file=*) - cur="${cur#*=}" - _filedir - return - ;; - --encode-file=*) - cur="${cur#*=}" - _filedir - return - ;; - --saving-file=*) - cur="${cur#*=}" - _filedir - return - ;; - --nice=*) - cur="${cur#*=}" - COMPREPLY=( $(compgen -W "$nice_vals" -- "$cur") ) - return - ;; - --skip-codec=*) - cur="${cur#*=}" - COMPREPLY=( $(compgen -W "$codecs" -- "$cur") ) - return - ;; - --preset=*) - cur="${cur#*=}" - COMPREPLY=( $(compgen -W "$(_transcode_presets)" -- "$cur") ) - return - ;; - esac + # --------------------------------------------------------------------------- + # Handle --option=VALUE: cur contains the entire "--opt=val" token. + # Strip the "opt=" prefix and delegate to the appropriate completer. + # This must be checked before the $prev dispatch below. + # --------------------------------------------------------------------------- + case "$cur" in + --config-file=*) + cur="${cur#*=}" + _filedir + return + ;; + --encode-file=*) + cur="${cur#*=}" + _filedir + return + ;; + --saving-file=*) + cur="${cur#*=}" + _filedir + return + ;; + --nice=*) + cur="${cur#*=}" + COMPREPLY=($(compgen -W "$nice_vals" -- "$cur")) + return + ;; + --skip-codec=*) + cur="${cur#*=}" + COMPREPLY=($(compgen -W "$codecs" -- "$cur")) + return + ;; + --preset=*) + cur="${cur#*=}" + COMPREPLY=($(compgen -W "$(_transcode_presets)" -- "$cur")) + return + ;; + --hwaccel=*) + cur="${cur#*=}" + COMPREPLY=($(compgen -W "$hwaccel_methods" -- "$cur")) + return + ;; + esac - # --------------------------------------------------------------------------- - # Handle VALUE after short form (-f, -N, -S, -p) and - # long space form (--encode-file, --nice, --saving-file, --skip-codec, --preset). - # $prev is the option word, $cur is the value being typed. - # --------------------------------------------------------------------------- - case "$prev" in - --config-file) - _filedir - return - ;; - -f|--encode-file) - _filedir - return - ;; - -N|--nice) - COMPREPLY=( $(compgen -W "$nice_vals" -- "$cur") ) - return - ;; - --saving-file) - _filedir - return - ;; - -S|--skip-codec) - COMPREPLY=( $(compgen -W "$codecs" -- "$cur") ) - return - ;; - -p|--preset) - COMPREPLY=( $(compgen -W "$(_transcode_presets)" -- "$cur") ) - return - ;; - esac + # --------------------------------------------------------------------------- + # Handle VALUE after short form (-f, -N, -S, -p) and + # long space form (--encode-file, --nice, --saving-file, --skip-codec, --preset). + # $prev is the option word, $cur is the value being typed. + # --------------------------------------------------------------------------- + case "$prev" in + --config-file) + _filedir + return + ;; + -f | --encode-file) + _filedir + return + ;; + -N | --nice) + COMPREPLY=($(compgen -W "$nice_vals" -- "$cur")) + return + ;; + --saving-file) + _filedir + return + ;; + -S | --skip-codec) + COMPREPLY=($(compgen -W "$codecs" -- "$cur")) + return + ;; + -p | --preset) + COMPREPLY=($(compgen -W "$(_transcode_presets)" -- "$cur")) + return + ;; + --hwaccel) + COMPREPLY=($(compgen -W "$hwaccel_methods" -- "$cur")) + return + ;; + esac - # --------------------------------------------------------------------------- - # Complete option names themselves. - # For options that accept an argument we list both the bare long form - # (--nice) and the equals form (--nice=) so the user can choose their - # preferred style. compopt -o nospace is applied when the sole match - # ends with '=' to avoid an unwanted trailing space in that case. - # --------------------------------------------------------------------------- - case "$cur" in - --*) - local longopts=' - --continue - --no-continue - --verify-output - --no-verify-output - --config-file - --config-file= - --encode-file - --encode-file= - --dry-run - --nice - --nice= - --saving - --no-saving - --saving-file - --saving-file= - --skip-codec - --skip-codec= - --only-if-smaller - --no-only-if-smaller - --preset - --preset= - --help - --quiet - --verbose - --version - --color - --no-color - ' - COMPREPLY=( $(compgen -W "$longopts" -- "$cur") ) - # Suppress the trailing space when the only completion ends with '=' - [[ ${#COMPREPLY[@]} -eq 1 && "${COMPREPLY[0]}" == *= ]] \ - && compopt -o nospace - return - ;; - -*) - local shortopts='-c -f -n -N -s -S -l -p -h -? -q -v --' - COMPREPLY=( $(compgen -W "$shortopts" -- "$cur") ) - return - ;; - esac + # --------------------------------------------------------------------------- + # Complete option names themselves. + # For options that accept an argument we list both the bare long form + # (--nice) and the equals form (--nice=) so the user can choose their + # preferred style. compopt -o nospace is applied when the sole match + # ends with '=' to avoid an unwanted trailing space in that case. + # --------------------------------------------------------------------------- + case "$cur" in + --*) + local longopts=' + --color + --config-file + --config-file= + --continue + --dry-run + --encode-file + --encode-file= + --help + --hwaccel + --hwaccel= + --nice + --nice= + --no-color + --no-continue + --no-hwaccel + --no-only-if-smaller + --no-saving + --no-verify-output + --only-if-smaller + --preset + --preset= + --quiet + --saving + --saving-file + --saving-file= + --skip-codec + --skip-codec= + --verbose + --verify-output + --version + ' + COMPREPLY=($(compgen -W "$longopts" -- "$cur")) + # Suppress the trailing space when the only completion ends with '=' + [[ ${#COMPREPLY[@]} -eq 1 && "${COMPREPLY[0]}" == *= ]] && + compopt -o nospace + return + ;; + -*) + local shortopts='-c -f -n -N -s -S -l -p -h -? -q -v --' + COMPREPLY=($(compgen -W "$shortopts" -- "$cur")) + return + ;; + esac - # --------------------------------------------------------------------------- - # Default: complete positional FILE arguments with common media extensions - # --------------------------------------------------------------------------- - _filedir '@(mkv|mp4|mov|avi|webm|flv|wmv|m4v|ts|mts|m2ts|mpg|mpeg|ogv|3gp|rm|rmvb)' + # --------------------------------------------------------------------------- + # Default: complete positional FILE arguments with common media extensions + # --------------------------------------------------------------------------- + _filedir '@(mkv|mp4|mov|avi|webm|flv|wmv|m4v|ts|mts|m2ts|mpg|mpeg|ogv|3gp|rm|rmvb)' } complete -F _transcode_sh transcode.sh |
