aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rwxr-xr-xtranscode.sh74
-rw-r--r--transcode.sh.145
-rw-r--r--transcode.sh.bash-completion297
4 files changed, 274 insertions, 149 deletions
diff --git a/README.md b/README.md
index 09ee1d3..a3adaf4 100644
--- a/README.md
+++ b/README.md
@@ -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