summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md26
-rwxr-xr-xtranscode.sh147
-rw-r--r--transcode.sh.154
-rw-r--r--transcode.sh.bash-completion12
4 files changed, 194 insertions, 45 deletions
diff --git a/README.md b/README.md
index 720e0d5..c937595 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,8 @@ replaces the original atomically on success.
- **Size report** (`-s`) — print per-file size feedback, show a batch
summary, and write a status TSV log for encoded, skipped, and failed files.
- **Dry-run** (`-n`) — preview what would happen without touching any files.
+- **Selectable video probe stream** (`--video-stream`) — choose which input
+ video stream is probed for preset helper variables.
- **Backup original** (`--backup-dir DIR`) — copy originals to an existing
backup directory before replacing them.
- **Nice** — runs ffmpeg at niceness 19 by default to avoid starving other
@@ -82,8 +84,10 @@ Presets live in:
${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets/<name>.sh
```
-Each preset is sourced as Bash and must define an array named `ffargs`.
-The following variables are available to presets at source time:
+Each preset is sourced as Bash and must define an array named `ffargs`. The
+following variables are available to presets at source time. They are derived
+from the selected video probe stream, which defaults to `v:0` and can be
+changed with `--video-stream` or `[encoding] video_stream`:
| Variable | Description |
|----------|-------------|
@@ -104,6 +108,12 @@ these base arguments to `ffmpeg`:
-c copy # default to stream copy for every stream
```
+`--video-stream` only controls which input stream is probed for helper
+variables such as `input_codec`, `input_pixel_format`, `input_frame_rate`,
+`input_fps`, `output_pixel_format`, and `output_gop_size`. It does not rewrite
+the preset's `ffargs`; presets remain responsible for selecting which ffmpeg
+stream to encode.
+
A preset therefore only needs to specify the streams it wishes to
re-encode (typically `-c:v:0`) and any associated encoder options.
All other streams — audio, subtitles, attachments — are passed through
@@ -156,6 +166,7 @@ Requires `tomlq` when the file is present.
preset = "av1"
nice = 10
backup_dir = "backups"
+video_stream = "v:0"
[skip]
codecs = ["av1", "hevc"]
@@ -176,6 +187,7 @@ quiet = false
| `[encoding]` | `nice` | integer | `-N` |
| `[encoding]` | `preset` | string | `-p` |
| `[encoding]` | `verify_output` | boolean | `--verify-output` |
+| `[encoding]` | `video_stream` | string | `--video-stream` |
| `[output]` | `quiet` | boolean | `-q` |
| `[output]` | `verbose` | boolean | `-v` |
| `[output]` | `ffmpeg_loglevel` | string | `--ffmpeg-loglevel` |
@@ -195,6 +207,12 @@ quiet = false
> **Note:** `[encoding] backup_dir` must point to an existing directory. CLI
> `--backup-dir` always takes precedence.
+> **Note:** `[encoding] video_stream` selects the input video stream that is
+> probed for preset helper variables. It defaults to `"v:0"`. Invalid config
+> values are ignored with a warning and the default is used. CLI
+> `--video-stream` always takes precedence. This setting does not change ffmpeg
+> stream mapping in presets.
+
### Codec skip list (deprecated)
The legacy `skip.conf` file is no longer read. If it still exists, a
@@ -228,6 +246,7 @@ transcode.sh [OPTION] [--] FILE...
| `-l`, `--only-if-smaller` | Only replace original if new file is smaller |
| `--no-only-if-smaller` | Do replace original even if new file is bigger |
| `-p NAME`, `--preset NAME`, `--preset=NAME` | Preset to use (default: `default`) |
+| `--video-stream STREAM_SELECTOR`, `--video-stream=STREAM_SELECTOR` | Select the input video stream to probe for preset helper variables, e.g. `v:0` or `v:1` (default: `v:0`) |
| `--ffmpeg-loglevel LEVEL`, `--ffmpeg-loglevel=LEVEL` | Specify the loglevel to pass to ffmpeg (default: `fatal`) |
| `-q`, `--quiet` | Suppress all output (overrides `-v`) |
| `-v`, `--verbose` | More detailed output |
@@ -262,6 +281,9 @@ transcode.sh --nice 10 --continue *.mp4
# Load an alternative config file
transcode.sh --config-file ~/profiles/fast.toml input.mp4
+
+# Probe the second video stream for preset helper variables
+transcode.sh --video-stream v:1 --dry-run --verbose input.mkv
```
When `--backup-dir` is used, the directory must already exist. Backups preserve
diff --git a/transcode.sh b/transcode.sh
index 7f40e3b..817d8e2 100755
--- a/transcode.sh
+++ b/transcode.sh
@@ -164,6 +164,7 @@ PRESET_NAME="default"
SIZE_REPORT=0
SIZE_REPORT_FILE="transcode_size_report"
VERIFY_OUTPUT=1
+VIDEO_STREAM="v:0"
declare -A SKIP_CODECS
REMAINING_ARGS=()
@@ -192,6 +193,7 @@ _CLI_SKIP_CODECS=()
_CLI_SKIP_CODECS_OVERRIDE=0
_CLI_VERBOSE=0
_CLI_VERIFY_OUTPUT=0
+_CLI_VIDEO_STREAM=0
# Values for size report
_REPORT_ENCODING_FAILED=0
@@ -284,44 +286,45 @@ ${BOLD}${BLUE}Usage:${ALL_OFF} ${BOLD}${MAGENTA}%s${ALL_OFF} ${BOLD}${YELLOW}[OP
Long options that take a value also accept ${BOLD}${YELLOW}--option${ALL_OFF}${BOLD}${CYAN}=${ALL_OFF}${BOLD}${GREEN}VALUE${ALL_OFF} syntax.
${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 adjustment 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} --backup-dir${ALL_OFF} ${BOLD}${GREEN}DIR${ALL_OFF} backup original files to DIR instead of overwriting them
- ${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
- ${BOLD}${YELLOW}--no-continue${ALL_OFF} do not continue with the next file if ffmpeg fails
- ${BOLD}${YELLOW}--verify-output${ALL_OFF} probe output with ffprobe before replacing original (default)
- ${BOLD}${YELLOW}--no-verify-output${ALL_OFF} skip the post-encode integrity check
+ ${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 adjustment 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} --backup-dir${ALL_OFF} ${BOLD}${GREEN}DIR${ALL_OFF} backup original files to DIR instead of overwriting them
+ ${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}--video-stream${ALL_OFF} ${BOLD}${GREEN}STREAM_SELECTOR${ALL_OFF} video stream to probe for preset helper variables (default: ${BOLD}${RED}v:0${ALL_OFF})
+ ${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
+ ${BOLD}${YELLOW}--no-continue${ALL_OFF} do not continue with the next file if ffmpeg fails
+ ${BOLD}${YELLOW}--verify-output${ALL_OFF} probe output with ffprobe before replacing original (default)
+ ${BOLD}${YELLOW}--no-verify-output${ALL_OFF} skip the post-encode integrity check
${BOLD}${BLUE}Input options:${ALL_OFF}
- ${BOLD}${YELLOW}--config-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} load configuration from FILE instead of the default path
- ${BOLD}${YELLOW}-f, --encode-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} file containing a list of files to encode
- ${BOLD}${YELLOW}-S, --skip-codec${ALL_OFF} ${BOLD}${GREEN}LIST${ALL_OFF} skip files with these codecs;
- ${BOLD}${GREEN}LIST${ALL_OFF} is comma, space, or colon separated
- ${BOLD}${YELLOW}--skip-codec-override${ALL_OFF} use only codecs from --skip-codec,
- ignoring [skip].codecs from config
+ ${BOLD}${YELLOW}--config-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} load configuration from FILE instead of the default path
+ ${BOLD}${YELLOW}-f, --encode-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} file containing a list of files to encode
+ ${BOLD}${YELLOW}-S, --skip-codec${ALL_OFF} ${BOLD}${GREEN}LIST${ALL_OFF} skip files with these codecs;
+ ${BOLD}${GREEN}LIST${ALL_OFF} is comma, space, or colon separated
+ ${BOLD}${YELLOW}--skip-codec-override${ALL_OFF} use only codecs from --skip-codec,
+ ignoring [skip].codecs from config
${BOLD}${BLUE}Size report options:${ALL_OFF}
- ${BOLD}${YELLOW}-s, --size-report${ALL_OFF} print size feedback and write a status TSV log
- ${BOLD}${YELLOW}--no-size-report${ALL_OFF} disable size reporting from config.toml
- ${BOLD}${YELLOW}--size-report-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} path for the size report log (default: ${BOLD}${RED}%s${ALL_OFF})
+ ${BOLD}${YELLOW}-s, --size-report${ALL_OFF} print size feedback and write a status TSV log
+ ${BOLD}${YELLOW}--no-size-report${ALL_OFF} disable size reporting from config.toml
+ ${BOLD}${YELLOW}--size-report-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} path for the size report log (default: ${BOLD}${RED}%s${ALL_OFF})
${BOLD}${BLUE}Output options:${ALL_OFF}
- ${BOLD}${YELLOW}--ffmpeg-loglevel${ALL_OFF} specify the loglevel to pass to ffmpeg (default: ${BOLD}${RED}fatal${ALL_OFF})
- ${BOLD}${YELLOW}-q, --quiet${ALL_OFF} suppress all output; takes precedence over ${BOLD}${YELLOW}-v${ALL_OFF}
- ${BOLD}${YELLOW}-v, --verbose${ALL_OFF} explain what is being done
- ${BOLD}${YELLOW}--color${ALL_OFF} force colored output
- ${BOLD}${YELLOW}--no-color${ALL_OFF} disable colored output
+ ${BOLD}${YELLOW}--ffmpeg-loglevel${ALL_OFF} specify the loglevel to pass to ffmpeg (default: ${BOLD}${RED}fatal${ALL_OFF})
+ ${BOLD}${YELLOW}-q, --quiet${ALL_OFF} suppress all output; takes precedence over ${BOLD}${YELLOW}-v${ALL_OFF}
+ ${BOLD}${YELLOW}-v, --verbose${ALL_OFF} explain what is being done
+ ${BOLD}${YELLOW}--color${ALL_OFF} force colored output
+ ${BOLD}${YELLOW}--no-color${ALL_OFF} disable colored output
${BOLD}${BLUE}General options:${ALL_OFF}
- ${BOLD}${YELLOW}-h, --help${ALL_OFF} display this help and exit
- ${BOLD}${YELLOW}--version${ALL_OFF} output version information and exit
- ${BOLD}${YELLOW}--list-presets${ALL_OFF} list available presets and exit
+ ${BOLD}${YELLOW}-h, --help${ALL_OFF} display this help and exit
+ ${BOLD}${YELLOW}--version${ALL_OFF} output version information and exit
+ ${BOLD}${YELLOW}--list-presets${ALL_OFF} list available presets and exit
${BOLD}${BLUE}Configuration files:${ALL_OFF}
${BOLD}${CYAN}%s/<NAME>.sh${ALL_OFF}
@@ -347,9 +350,14 @@ ${BOLD}${BLUE}Examples:${ALL_OFF}
%s -n -N 10 my_movie.mkv\n" \
"$SCRIPTNAME" "$VERSION" "$DESCRIPTION" \
"$SCRIPTNAME" \
- "$PRESET_NAME" "$NICE_VALUE" "$SIZE_REPORT_FILE" \
- "$PRESET_DIR" "$CONFIG_FILE" \
- "$SCRIPTNAME" "$SCRIPTNAME" "$SCRIPTNAME"
+ "$PRESET_NAME" \
+ "$NICE_VALUE" \
+ "$SIZE_REPORT_FILE" \
+ "$PRESET_DIR" \
+ "$CONFIG_FILE" \
+ "$SCRIPTNAME" \
+ "$SCRIPTNAME" \
+ "$SCRIPTNAME"
}
print_version() {
@@ -594,6 +602,20 @@ load_config() {
fi
fi
+ # [encoding] video_stream
+ if [[ $_CLI_VIDEO_STREAM -eq 0 ]]; then
+ val=$(_tomlq_get '.encoding.video_stream // empty')
+ if [[ -n "$val" ]]; then
+ debug "Config: encoding.video_stream =" "$val"
+ if ! validate_stream_selector "$val"; then
+ warning "Ignoring invalid config value for encoding.video_stream:" "$val"
+ warning "Falling back to default video stream:" "$VIDEO_STREAM"
+ else
+ VIDEO_STREAM="$val"
+ fi
+ fi
+ fi
+
if [[ $_CLI_BACKUP_DIR -eq 0 ]]; then
val=$(_tomlq_get '.encoding.backup_dir // empty')
if [[ -n "$val" ]]; then
@@ -702,6 +724,22 @@ parse_skip_codec_parameter() {
}
###############################################################################
+# STREAM SELECTOR HANDLING
+###############################################################################
+
+validate_stream_selector() {
+ local stream_selector="$1"
+
+ # Accept only simple video stream indexes for metadata probing. This is not a
+ # general ffmpeg stream selector parser.
+ if [[ ! "$stream_selector" =~ ^((v|V):)?([0-9]|[1-9][0-9]+)$ ]]; then
+ return 1
+ fi
+
+ return 0
+}
+
+###############################################################################
# PRESET HANDLING
###############################################################################
@@ -1109,9 +1147,14 @@ encode_one() {
# Probe codec, pixel format and frame rate in a single ffprobe invocation to
# decrease the startup overhead on large batches.
local probe_out
- probe_out=$(ffprobe -v error -select_streams v:0 \
- -show_entries stream=codec_name,pix_fmt,r_frame_rate \
- -of default=nk=1:nw=1 "file:$input_file" 2>/dev/null)
+ probe_out=$(
+ ffprobe \
+ -v error \
+ -select_streams "$VIDEO_STREAM" \
+ -show_entries stream=codec_name,pix_fmt,r_frame_rate \
+ -of default=nk=1:nw=1 \
+ "file:$input_file" 2>/dev/null
+ )
local input_codec input_pixel_format input_frame_rate input_fps
@@ -1267,6 +1310,7 @@ encode_one() {
if [[ $DRY_RUN -eq 1 ]]; then
msg "DRY RUN:" "Would encode with preset $PRESET_NAME"
+ verbose "Video stream:" "$VIDEO_STREAM"
verbose "Input codec:" "$input_codec"
verbose "Input pixel format:" "$input_pixel_format"
verbose "Output pixel format:" "$output_pixel_format"
@@ -1675,6 +1719,36 @@ while [[ $# -gt 0 ]]; do
_CLI_FFMPEG_LOGLEVEL=1
shift
;;
+ --video-stream)
+ 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
+ if ! validate_stream_selector "$2"; then
+ error "Invalid stream selector:" "$2"
+ exit $EXIT_USAGE_ERROR
+ fi
+ VIDEO_STREAM="$2"
+ _CLI_VIDEO_STREAM=1
+ shift 2
+ ;;
+ --video-stream=*)
+ if [[ ! -n "${1#*=}" ]]; then
+ error "Value for --video-stream must not be empty"
+ exit $EXIT_USAGE_ERROR
+ fi
+ if ! validate_stream_selector "${1#*=}"; then
+ error "Invalid stream selector:" "${1#*=}"
+ exit $EXIT_USAGE_ERROR
+ fi
+ VIDEO_STREAM="${1#*=}"
+ _CLI_VIDEO_STREAM=1
+ shift
+ ;;
--)
shift
REMAINING_ARGS+=("$@")
@@ -1722,6 +1796,7 @@ debug " size-report:" "$SIZE_REPORT"
debug " skip-codecs:" "${joined# }"
debug " verbose:" "$VERBOSE"
debug " verify-output:" "$VERIFY_OUTPUT"
+debug " video-stream:" "$VIDEO_STREAM"
command -v ffmpeg >/dev/null 2>&1 || {
error "ffmpeg not found."
diff --git a/transcode.sh.1 b/transcode.sh.1
index bc3639c..e0b7f3c 100644
--- a/transcode.sh.1
+++ b/transcode.sh.1
@@ -24,9 +24,13 @@ containing the extra arguments passed to
.PP
The script probes every input file with
.BR ffprobe (1)
-to detect the input video codec and pixel format. Files whose codec
-appears in the skip list are silently skipped. The output pixel format
-is derived automatically so that chroma subsampling (4:2:0, 4:2:2,
+to detect the input video codec, pixel format and frame rate of the selected
+video probe stream. The selected stream defaults to
+.B v:0
+and can be changed with
+.BR \-\-video\-stream .
+Files whose codec appears in the skip list are silently skipped. The output
+pixel format is derived automatically so that chroma subsampling (4:2:0, 4:2:2,
4:4:4) and bit depth (8, 10, 12, 16\-bit) are preserved.
.PP
All streams, metadata and chapter markers from the input are retained by
@@ -84,7 +88,8 @@ Print what would be done without actually invoking
.BR ffmpeg (1).
Combine with
.B \-v
-to see the detected codec and pixel format information.
+to see the selected video stream and detected codec, pixel format and frame
+rate information.
.TP
.BR \-\-backup\-dir " \fIDIR\fR, " \-\-backup\-dir= \fIDIR\fR
Copy originals to \fIDIR\fR before replacing them after successful encoding.
@@ -123,6 +128,17 @@ to
Use this on hosts where hardware acceleration causes compatibility or
stability issues.
.TP
+.BR \-\-video\-stream " \fISTREAM_SELECTOR\fR, " \-\-video\-stream= \fISTREAM_SELECTOR\fR
+Select the input video stream that is probed for preset helper variables.
+Defaults to
+.BR v:0 .
+The selector must be a conservative video stream selector such as
+.B v:0
+or
+.BR v:1 .
+This option does not change ffmpeg stream mapping; presets remain responsible
+for selecting which stream to encode.
+.TP
.BR \-N " \fIVALUE\fR, " \-\-nice " \fIVALUE\fR, " \-\-nice= \fIVALUE\fR
Run
.BR ffmpeg (1)
@@ -195,8 +211,8 @@ Suppress all normal output. Takes precedence over
.BR \-v / \-\-verbose .
.TP
.BR \-v ", " \-\-verbose
-Emit additional informational messages (detected codec, pixel format,
-etc.).
+Emit additional informational messages, including the selected video stream and
+detected codec, pixel format and frame rate.
.TP
.B \-\-version
Print version, author and license information and exit.
@@ -294,7 +310,15 @@ array variable named
.B ffargs
containing additional arguments for
.BR ffmpeg (1).
-The following variables are available to presets at source time:
+These variables are derived from the selected video probe stream, which
+defaults to
+.B v:0
+and can be changed with
+.BR \-\-video\-stream
+or
+.B [encoding] video_stream
+in
+.BR config.toml .
.RS
.TP
.B input_codec
@@ -418,6 +442,14 @@ encoding and before replacement. Equivalent to
.BR \-\-backup\-dir .
CLI \fB--backup-dir\fR takes precedence.
.TP
+.B [encoding] video_stream
+String. Input video stream to probe for preset helper variables. Defaults to
+.BR v:0 .
+Equivalent to
+.BR \-\-video\-stream .
+Invalid configured values are ignored with a warning and the default is used.
+This setting does not change ffmpeg stream mapping in presets.
+.TP
.B [skip] codecs
Array of strings. Merged with any codecs from
.BR \-S
@@ -538,6 +570,14 @@ Load an alternative configuration file:
transcode.sh \-\-config\-file ~/profiles/fast.toml input.mp4
.fi
.RE
+.PP
+Probe the second video stream for preset helper variables:
+.PP
+.RS
+.nf
+transcode.sh \-\-video\-stream v:1 \-n \-v input.mkv
+.fi
+.RE
.SH SEE ALSO
.BR ffmpeg (1),
.BR ffprobe (1),
diff --git a/transcode.sh.bash-completion b/transcode.sh.bash-completion
index 716995e..c980081 100644
--- a/transcode.sh.bash-completion
+++ b/transcode.sh.bash-completion
@@ -39,6 +39,7 @@ _transcode_sh() {
local nice_vals='0 5 10 15 19'
local hwaccel_methods='auto cuda vaapi dxva2 d3d11va videotoolbox qsv'
local ffmpeg_loglevels='quiet panic fatal error warning info verbose debug trace'
+ local video_streams='v:0 v:1 v:2 v:3'
# ---------------------------------------------------------------------------
# Handle --option=VALUE: cur contains the entire "--opt=val" token.
@@ -91,6 +92,11 @@ _transcode_sh() {
COMPREPLY=($(compgen -W "$ffmpeg_loglevels" -- "$cur"))
return
;;
+ --video-stream=*)
+ cur="${cur#*=}"
+ COMPREPLY=($(compgen -W "$video_streams" -- "$cur"))
+ return
+ ;;
esac
# ---------------------------------------------------------------------------
@@ -135,6 +141,10 @@ _transcode_sh() {
COMPREPLY=($(compgen -W "$ffmpeg_loglevels" -- "$cur"))
return
;;
+ --video-stream)
+ COMPREPLY=($(compgen -W "$video_streams" -- "$cur"))
+ return
+ ;;
esac
# ---------------------------------------------------------------------------
@@ -183,6 +193,8 @@ _transcode_sh() {
--verbose
--verify-output
--version
+ --video-stream
+ --video-stream=
'
COMPREPLY=($(compgen -W "$longopts" -- "$cur"))
# Suppress the trailing space when the only completion ends with '='