summaryrefslogtreecommitdiffstats
path: root/Completion/Unix/Command/_ffmpeg
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Unix/Command/_ffmpeg')
-rw-r--r--Completion/Unix/Command/_ffmpeg1649
1 files changed, 1487 insertions, 162 deletions
diff --git a/Completion/Unix/Command/_ffmpeg b/Completion/Unix/Command/_ffmpeg
index 9c91fe386..2cdeb02fe 100644
--- a/Completion/Unix/Command/_ffmpeg
+++ b/Completion/Unix/Command/_ffmpeg
@@ -1,200 +1,1525 @@
#compdef ffmpeg
-local curcontext="$curcontext" state line expl
-typeset -A opt_args
+# notes:
+# - stream/file options modify the input/output file argument that follows, so
+# ideally their arguments would be limited accordingly (e.g. -c would only
+# show encoders before an output file). but it seemed like being too 'smart'
+# about this could be very confusing/annoying. so we don't do that
-(( $+functions[_ffmpeg_presets] )) || _ffmpeg_presets() {
- local presets
- presets=(~/.ffmpeg/*.ffpreset(:t:r) "$FFMPEG_DATADIR"/*.ffpreset(:t:r))
- _wanted ffmpeg-presets expl 'preset' compadd -a presets
+# complete numeric argument
+(( $+functions[_ffmpeg_numbers] )) ||
+_ffmpeg_numbers() {
+ # most numeric args support these suffixes, even when it's nonsensical, e.g.
+ # -framerate 1KiB specifies 8192 fps. and most options that only accept
+ # integer args nonetheless need -f here because of this
+ _numbers -f "$@" {K,M,G}{,i}{,B}
}
-(( $+functions[_ffmpeg_acodecs] )) || _ffmpeg_acodecs() {
- local acodecs
- acodecs=(copy ${${(M)${(f)"$(_call_program audio-codecs $words[1] -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]A[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]})
- _wanted ffmpeg-audio-codecs expl 'force audio codec (''copy'' to copy stream)' compadd -a acodecs
+# `compadd -R` helper for _ffmpeg_flags
+(( $+functions[_ffmpeg_flags_remf] )) ||
+_ffmpeg_flags_remf() {
+ [[ $1 == 0 ]] || return
+ # swallow last char of inserted match if it was typed again
+ [[ $LBUFFER[-1] == $KEYS ]] && LBUFFER=${LBUFFER%?}
}
-(( $+functions[_ffmpeg_vcodecs] )) || _ffmpeg_vcodecs() {
- local vcodecs
- vcodecs=(copy ${${(M)${(f)"$(_call_program video-codecs $words[1] -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]V[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]})
- _wanted ffmpeg-video-codecs expl 'force video codec (''copy'' to copy stream)' compadd -a vcodecs
+# complete flag argument (flag1+flag2-flag3)
+# $1 ... => flag
+(( $+functions[_ffmpeg_flags] )) ||
+_ffmpeg_flags() {
+ local ret=1 tag=${curtag:-flags}
+ local -a expl ca_opts ca_x_opts flags
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ M+:=ca_opts {x+:,X+:}=ca_x_opts 1 2 F: J: n o: q r: R: s: S: V: \
+ || return
+
+ flags=( ${@:#${PREFIX//:/\\:}(|:*)} )
+
+ compset -S '[+-]*'
+ compset -P '*[+-]'
+
+ _describe -t $tag flag flags "${(@)ca_opts}" "${(@)ca_x_opts}" -S '' && ret=0
+
+ [[ $IPREFIX$PREFIX == *[+-] ]] || {
+ compset -P '*'
+ _wanted operators expl operator \
+ compadd "${(@)ca_opts}" -R _ffmpeg_flags_remf -S '' - + - && ret=0
+ }
+
+ return ret
}
-(( $+functions[_ffmpeg_scodecs] )) || _ffmpeg_scodecs() {
- local scodecs
- scodecs=(copy ${${(M)${(f)"$(_call_program subtitle-codecs $words[1] -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]S[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]})
- _wanted ffmpeg-subtitle-codecs expl 'force subtitle codec (''copy'' to copy stream)' compadd -a scodecs
+# helper to get stream type char from stream specifier in previous word. this
+# isn't quite accurate, but probably fine for most purposes
+# $1 => param to assign to
+(( $+functions[_ffmpeg_prev_ss_type] )) ||
+_ffmpeg_prev_ss_type() {
+ [[ $1 == (-|--) ]] && shift
+ case ${9::=${(Q)words[CURRENT-1]}} in
+ -[adsv]codec|-[av]f)
+ : ${(P)1::=${(U)9[2]}}
+ ;;
+ -(c|codec):(|*:*:)[adstvV](|:*)) ;&
+ -filter:(|*:*:)[avV](|:*))
+ 8=${(M)9##*:[adstvV](:|)}
+ 8=${${8%:}##*:}
+ : ${(P)1::=${(U)8}}
+ ;;
+ *) return 1 ;;
+ esac
}
-(( $+functions[_ffmpeg_formats] )) || _ffmpeg_formats() {
- local formats
- formats=(${(ou)${=${(s:,:)${${(M)${(f)"$(_call_program formats $words[1] -formats 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]][[:space:]][^[:space:]]##*}//(#b)????([^[:space:]]##)*/$match[1]}}}})
- _wanted ffmpeg-formats expl 'force format' compadd -a formats
+# complete stream specifier, usually after a colon-option like -c:
+(( $+functions[_ffmpeg_stream_specs] )) ||
+_ffmpeg_stream_specs() {
+ # does it make sense to allow e.g. -c:a:a:... ?
+ if compset -P '([adstvV]|g:([^i:]*|i:*)|(p|disp):*):'; then
+ _ffmpeg_stream_specs
+ elif compset -P 'g:(\#|\\\#|i:)'; then
+ _message 'group ID'
+ elif compset -P g:; then
+ _message 'group specifier'
+ elif compset -P p:; then
+ _message 'program ID'
+ elif compset -P '(\#|\\\#|i:)'; then
+ _message 'stream ID'
+ elif compset -P m:; then
+ _message 'metadata tag key[:value]'
+ elif compset -P disp:; then
+ _sequence -s+ _ffmpeg_dispositions -I
+ else
+ local ret=1
+ local -a ca_opts
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:}=ca_opts J: V: x: X: \
+ || return
+
+ _describe -t stream-specifier-types 'stream-type specifier' '(
+ a:"audio"
+ d:"data"
+ s:"subtitle"
+ t:"attachment"
+ v:"video (all)"
+ V:"video (not images)"
+ )' -qS: "${(@)ca_opts}" && ret=0
+ _describe -t stream-specifier-others 'other stream specifier' \
+ '(
+ g:"group index or ID"
+ i:"stream ID"
+ p:"program ID"
+ m:"metadata tag"
+ disp:"dispositions"
+ )' -qS: "${(@)ca_opts}" \
+ -- \
+ '(
+ u:"usable configuration"
+ )' "${(@)ca_opts}" && ret=0
+
+ return ret
+ fi
}
-(( $+functions[_ffmpeg_pix_fmts] )) || _ffmpeg_pix_fmts() {
- local pix_fmts
- _wanted ffmpeg-pix-fmts expl 'pixel format' compadd "$@" - \
- ${${${(M)${(f)"$(_call_program formats $words[1] -pix_fmts 2>/dev/null)"}:#[I.][O.][H.][P.][B.] [^=[:space:]]*}#* }%% *}
+# complete metadata specifier
+(( $+functions[_ffmpeg_metadata_specs] )) ||
+_ffmpeg_metadata_specs() {
+ if compset -P s:; then
+ _ffmpeg_stream_specs
+ elif compset -P c:; then
+ _message 'chapter index'
+ elif compset -P p:; then
+ _message 'program index'
+ else
+ _describe -t metadata-specs 'metadata specifier' \
+ '(
+ c:"per-chapter metadata"
+ p:"per-program metadata"
+ s:"per-stream metadata"
+ )' -qS: \
+ -- \
+ '(
+ g:"global metadata"
+ )'
+ fi
}
-(( $+functions[_ffmpeg_bsfs] )) || _ffmpeg_bsfs() {
- local bsfs
- bsfs=(${${(f)"$(_call_program bsfs $words[1] -bsfs 2>/dev/null)"}:#*:})
- _wanted ffmpeg-bsfs expl 'set bitstream filter' compadd -a bsfs
+# complete preset name
+(( $+functions[_ffmpeg_presets] )) ||
+_ffmpeg_presets() {
+ local -a presets=(
+ ~/.ffmpeg
+ $FFMPEG_DATADIR
+ ${${${${(Q)words[1]}:c}%/bin/*}:-/usr}/share/ffmpeg
+ )
+ presets=( $^presets/*.ffpreset(N:t:r) )
+ _wanted presets expl preset compadd "$@" -a presets
}
-typeset -A _ffmpeg_flags
+# complete codec or encoder/decoder (-codec et al accept either)
+# -D => decoders, -E => encoders, -T => type (audio, video, etc)
+(( $+functions[_ffmpeg_codecs] )) ||
+_ffmpeg_codecs() {
+ local ret=1 de=DE de_desc=encoder/decoder type=ADSTV type_desc
+ local -a ca_opts codecs encdecs
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,x+:,X+:}=ca_opts J: V: \
+ D E T: \
+ || return
+
+ case ${(L)opth[-T]} in
+ a|aud*) type=A ;;
+ d|dat*) type=D ;;
+ s|sub*) type=S ;;
+ t|att*) type=T ;;
+ v|vid*) type=V ;;
+ *) _ffmpeg_prev_ss_type type ;;
+ esac
+ case $type in
+ A) type_desc=audio ;;
+ D) type_desc=data ;;
+ S) type_desc=subtitle ;;
+ T) type_desc=attachment ;;
+ V) type_desc=video ;;
+ esac
+
+ if (( ${+opth[-D]} )); then
+ de=D de_desc=decoder
+ elif (( ${+opth[-E]} )); then
+ de=E de_desc=encoder
+ fi
+
+ codecs=( ${(f)"$( _call_program codecs $words[1] -codecs )"} )
+ codecs=( ${(M)codecs:# [ADILSTV. ](#c6) [^=]* *} )
+ [[ $de == *D* ]] || codecs=( ${codecs:# D?*} )
+ [[ $de == *E* ]] || codecs=( ${codecs:# ?E*} )
+ codecs=( ${(M)codecs:# ??[$type]??? *} )
+ codecs=( ${codecs# ?????? } )
+
+ # -decoders and -encoders don't include data/attachment
+ [[ $type == *[ASV]* ]] && {
+ [[ $de == *D* ]] &&
+ encdecs+=( ${(f)"$( _call_program decoders $words[1] -decoders )"} )
+ [[ $de == *E* ]] &&
+ encdecs+=( ${(f)"$( _call_program encoders $words[1] -encoders )"} )
+
+ encdecs=( ${(M)encdecs:# [$type][ABDFSVX. ](#c5) [^=]* *} )
+ encdecs=( ${encdecs# ?????? } )
+ }
+
+ if zstyle -t ":completion:$curcontext:$tag" verbose; then
+ codecs=( ${codecs%%[[:space:]]##\((decoders#|encoders#):*} )
+ codecs=( ${${(@)codecs//:/\\:}/[[:space:]]##/:} )
+ # _describe doesn't remove duplicates when there are descriptions
+ encdecs=( ${(u)encdecs} )
+ encdecs=( ${${(@)encdecs//:/\\:}/[[:space:]]##/:} )
+ else
+ codecs=( ${codecs%%[[:space:]]*} )
+ encdecs=( ${encdecs%%[[:space:]]*} )
+ fi
-(( $+functions[_ffmpeg_flag_options] )) || _ffmpeg_flag_options() {
- local expl
- _wanted options expl 'flag' compadd -S '' -- {-,+}${^flag_options}
+ _describe -t codecs "${type_desc:+$type_desc }codec" \
+ codecs "${(@)ca_opts}" && ret=0
+ _describe -t encoders-decoders "${type_desc:+$type_desc }$de_desc" \
+ encdecs "${(@)ca_opts}" && ret=0
+ [[ $de == *E* && ${(Q)words[CURRENT-1]} == -(c|[adsv]#codec)(|:*) ]] &&
+ _describe -t codecs-special 'copy option' '( copy:"copy stream" )' && ret=0
+
+ return ret
}
-(( $+functions[_ffmpeg_more_flag_options] )) || _ffmpeg_more_flag_options() {
- compset -p $1 && _ffmpeg_flag_options
+# complete format/muxer/demuxer/device
+# -D => demuxer, -E => muxer, -v => device
+(( $+functions[_ffmpeg_formats] )) ||
+_ffmpeg_formats() {
+ local dde=dDE tag=formats desc=format
+ local -a ca_opts tmp formats
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ D E v \
+ || return
+
+ if (( ${+opth[-D]} )); then
+ dde=D tag=demuxers desc=demuxer
+ elif (( ${+opth[-E]} )); then
+ dde=E tag=muxers desc=muxer
+ elif (( ${+opth[-v]} )); then
+ dde=d tag=devices desc=device
+ fi
+
+ tmp=( ${(f)"$( _call_program formats $words[1] -formats )"} )
+ tmp=( ${(M)tmp:# [dDE. ](#c3) [^=]* *} )
+ [[ $dde == *D* ]] && formats+=( ${(M)tmp:# D?? *} )
+ [[ $dde == *E* ]] && formats+=( ${(M)tmp:# ?E? *} )
+ [[ $dde == *d* ]] && formats+=( ${(M)tmp:# ??d *} )
+ formats=( ${formats# ??? } )
+
+ # some formats have multiple descriptions, e.g. 'matroska:Matroska' and
+ # 'matroska:Matroska / WebM'. ideally we would merge these together somehow
+ if zstyle -t ":completion:$curcontext:$tag" verbose; then
+ local f d
+ tmp=( ${${(@)formats//:/\\:}/[[:space:]]##/:} )
+ formats=( )
+ for f in $tmp; do
+ d=${f#*:} f=${f%%:*}
+ formats+=( ${^${(@s<,>)f}}:$d )
+ done
+ formats=( ${(u)formats} )
+
+ else
+ formats=( ${(@s<,>)${(@)formats%%[[:space:]]*}} )
+ fi
+
+ _describe -t $tag $desc formats "${(@)ca_opts}"
}
-(( $+functions[_ffmpeg_new_flag_options] )) || _ffmpeg_new_flag_options() {
- compset -P '*' && _ffmpeg_flag_options
+# complete bitstream filter
+# -I => single bsf
+(( $+functions[_ffmpeg_bsfs] )) ||
+_ffmpeg_bsfs() {
+ local tag=bsfs desc='bitstream filter'
+ local -a ca_opts expl bsfs
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ I \
+ || return
+
+ bsfs=( ${(f)"$( _call_program $tag $words[1] -bsfs )"} )
+ bsfs=( ${bsfs##[[:space:]]##} )
+ bsfs=( ${bsfs:#*:} )
+
+ if (( ${+opth[-I]} )); then
+ _describe -t $tag $desc bsfs "${(@)ca_opts}"
+ else
+ _wanted $tag expl '' _values -s, -S= $desc \
+ $^bsfs':bsf option (opt1=val1\:opt2=val2\:...):'
+ fi
}
-(( $+functions[_ffmpeg_flags] )) || _ffmpeg_flags() {
- local -a flag_options
- eval "flag_options=(\${=_ffmpeg_flags[$1]})"
+# complete pixel format / hwaccel output format
+# -H => hwaccel formats only
+(( $+functions[_ffmpeg_pix_fmts] )) ||
+_ffmpeg_pix_fmts() {
+ local tag=pixel-formats desc='pixel format'
+ local -a ca_opts pixfmts
+ local -A opth
- local match mbegin mend
- integer ret=1
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ H \
+ || return
- if [[ $PREFIX = (#b)(*)[-+]([^-+]#) ]]; then
- if [[ -n ${flag_options[(R)$match[2]]} ]]; then
- _ffmpeg_new_flag_options && ret=0
- fi
- if [[ -n ${flag_options[(R)$match[2]?*]} ]]; then
- _ffmpeg_more_flag_options ${#match[1]} && ret=0
- fi
- else
- _ffmpeg_flag_options && ret=0
- fi
+ pixfmts=( ${(f)"$( _call_program $tag $words[1] -pix_fmts )"} )
+ pixfmts=( ${(M)pixfmts:#[BHIOP. ](#c5) [^=]* *} )
- return ret
+ (( ${+opth[-H]} )) && {
+ tag=hwaccel-formats desc='output format'
+ pixfmts=( ${(M)pixfmts:#??H?? *} )
+ }
+
+ pixfmts=( ${pixfmts#????? *} )
+ pixfmts=( ${pixfmts%%[[:space:]]*} )
+
+ (( ${+opth[-H]} )) || {
+ compset -P + || pixfmts+=( + )
+ }
+
+ _describe -t $tag $desc pixfmts "${(@)ca_opts}"
}
-(( $+functions[_ffmpeg_register_lastopt_values] )) || _ffmpeg_register_lastopt_values() {
- if (( lastopt_takesargs )); then
- lastopt+=":$lastopt_description:"
- if (( $#lastopt_values )); then
- if [[ $lastopt_type == flags ]]; then
- lastopt="*$lastopt"
- flagtype=${${lastopt%%:*}#-}
- lastopt+="->$flagtype"
- _ffmpeg_flags[$flagtype]="${lastopt_values[*]}"
- else
- lastopt+="(${lastopt_values[*]})"
- fi
- fi
- fi
- _ffmpeg_argspecs+=$lastopt
+# complete filter
+(( $+functions[_ffmpeg_filters] )) ||
+_ffmpeg_filters() {
+ local MATCH MBEGIN MEND x y z tag=filters desc=filter type=AV
+ local -a ca_opts tmp filters
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ T: \
+ || return
+
+ case ${(L)opth[-T]} in
+ a|aud*) type=A ;;
+ v|vid*) type=V ;;
+ *) _ffmpeg_prev_ss_type type ;;
+ esac
+ case $type in
+ A) tag=audio-$tag desc="audio $desc" ;;
+ V) tag=video-$tag desc="video $desc" ;;
+ esac
+
+ tmp=( ${(f)"$( _call_program filters $words[1] -filters )"} )
+ tmp=( ${(M)tmp:#*-\>*} )
+ tmp=( ${tmp# ?? } )
+ tmp=( ${tmp/[ ]##/$'\t'} )
+ tmp=( ${tmp/[ ]##/$'\t'} )
+
+ for x y z in "${(@ps<\t>)tmp}"; do
+ [[ ${y//[N$type]/} == $y ]] ||
+ filters+=( $x:${z//:/\\:} )
+ done
+
+ if zstyle -t ":completion:$curcontext:$tag" verbose; then
+ # undo sentence case/punctuation
+ filters=( ${filters%.} )
+ filters=( ${filters/(#m):[A-Z][a-z]/${(L)MATCH}} )
+ else
+ filters=( ${filters%%:*} )
+ fi
+
+ _describe -t $tag $desc filters "${(@)ca_opts}"
+}
+
+# complete filtergraph spec
+(( $+functions[_ffmpeg_filtergraphs] )) ||
+_ffmpeg_filtergraphs() {
+ # [link][link] fltr@id=val:key=val:val, fltr@id [link]; fltr=val; ...
+ compset -P '*[];,]'
+ compset -P '[[:space:]]##'
+ compset -S '[;,[]*'
+ compset -S '[[:space:]]##'
+
+ if compset -P '*\['; then
+ _message 'link label'
+ elif compset -P '*='; then
+ _message 'filter arguments ([key=]val:[key=]val:...)'
+ elif compset -P '*@'; then
+ _message 'filter ID'
+ else
+ _ffmpeg_filters -r$'@=,[; \t\n\-' -S,
+ fi
+}
+
+# complete protocol
+(( $+functions[_ffmpeg_protocols] )) ||
+_ffmpeg_protocols() {
+ local tag=protocols desc=protocol
+ local -a protocols
+
+ protocols=( ${(f)"$( _call_program $tag $words[1] -protocols )"} )
+ protocols=( ${protocols:#*:*} )
+ protocols=( ${protocols##[[:space:]]##} )
+
+ _describe -t $tag $desc protocols "$@"
+}
+
+# complete standard or custom channel layout
+(( $+functions[_ffmpeg_layouts] )) ||
+_ffmpeg_layouts() {
+ local ret=1
+ local -a tmp names layouts
+
+ tmp=( ${(f)"$( _call_program layouts $words[1] -layouts )"} )
+ tmp=( ${tmp##[[:space:]]##} )
+
+ names=( ${tmp[1,(R)*(#i)layouts*:*]} )
+ names=( ${names:#(#i)*(NAME[[:space:]]##D|(channel|layout)*:)*} )
+ names=( ${^${names/[[:space:]]##/\[}}\] )
+ names=( $^names':custom name' )
+
+ layouts=( ${tmp[(R)*(#i)layouts*:*,-1]} )
+ layouts=( ${layouts:#(#i)*(NAME[[:space:]]##D|layouts*:)*} )
+ layouts=( ${layouts//:/\\:} )
+ layouts=( ${layouts/[[:space:]]##/:} )
+
+ [[ $PREFIX == *[@+]* ]] || {
+ _describe -t channel-layouts 'standard channel layout' layouts && ret=0
+ }
+ _values -s+ -S@ 'channel name' $names && ret=0
+
+ return ret
}
-local -a _ffmpeg_argspecs
-{
- local lastopt REPLY
- local lastopt_description
- local lastopt_takesargs
- local lastopt_type
- local -a lastopt_values
+# complete sample format
+(( $+functions[_ffmpeg_sample_fmts] )) ||
+_ffmpeg_sample_fmts() {
+ local tag=sample-formats desc='sample format'
+ local -a sample_fmts
+
+ sample_fmts=( ${(f)"$( _call_program $tag $words[1] -sample_fmts )"} )
+ sample_fmts=( ${sample_fmts:#*(:|name[[:space:]]##desc)*} )
+ sample_fmts=( ${sample_fmts##[[:space:]]##} )
+ sample_fmts=( ${sample_fmts%%[[:space:]]*} )
+
+ _describe -t $tag $desc sample_fmts "$@"
+}
+
+# complete hardware acceleration method
+# -T => types only
+(( $+functions[_ffmpeg_hwaccels] )) ||
+_ffmpeg_hwaccels() {
+ local tag=hwaccels desc='hardware acceleration method'
+ local -a ca_opts hwaccels
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ T \
+ || return
+
+ hwaccels=( ${(f)"$( _call_program $tag $words[1] -hwaccels )"} )
+ hwaccels=( ${hwaccels##[[:space:]]##} )
+ hwaccels=( ${hwaccels:#*:*} )
+
+ (( ${+opth[-T]} )) || hwaccels+=( none auto )
+
+ _describe -t $tag $desc hwaccels "${(@)ca_opts}"
+}
+
+# complete hardware devices
+(( $+functions[_ffmpeg_hw_devices] )) ||
+_ffmpeg_hw_devices() {
+ local i tag=hardware-devices desc='hardware device'
+ local -a ca_opts devices
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,x+:,X+:}=ca_opts J: V: \
+ || return
+
+ for (( i = 2; i <= CURRENT; i++ )); do
+ [[ ${(Q)words[i]} == -init_hw_device ]] || continue
+ devices+=( ${${${(Q)words[i+1]}#*=}%@*} )
+ (( i++ ))
+ done
+
+ # exclude name in current arg
+ [[ ${(Q)words[CURRENT-1]} == -init_hw_device ]] &&
+ [[ ${i::=$IPREFIX$PREFIX} == *=* ]] &&
+ devices=( ${devices:#${${i%%[@:,]*}#*=}} )
- _call_program options $words[1] -h 2>/dev/null | while IFS=$'\n' read -r; do
- if [[ $REPLY == -* ]]; then
- [[ -n $lastopt ]] && _ffmpeg_register_lastopt_values
- lastopt=${REPLY%%[[:space:]]*}
- lastopt_description=${REPLY##-[^[:space:]]##[[:space:]]##}
- if [[ $lastopt_description == (#b)'<'(?##)'>'* ]]; then
- lastopt_type=$match[1]
- lastopt_description=${lastopt_description##<[^[:space:]]##>[[:space:]]##[^[:space:]]##[[:space:]]#}
- if [[ -z $lastopt_description ]]; then
- lastopt_description=$lastopt
- fi
- lastopt_description=${lastopt_description//:/\\:}
- elif [[ $lastopt_description == [^[:space:]]##[[:space:]][[:space:]]* ]]; then
- local example=${lastopt_description%% *}
- example=${example//:/\\:}
- lastopt_description=${lastopt_description##[^[:space:]]##[[:space:]]##}
- lastopt_description=${lastopt_description//:/\\:}
- if [[ $example == filename ]]; then
- lastopt_takesargs=0
- lastopt+=":${lastopt_description}:_files"
- elif [[ $lastopt == -[asv]pre ]]; then
- lastopt_takesargs=0
- lastopt="*$lastopt"
- lastopt+=": :_ffmpeg_presets"
- elif [[ $lastopt == -acodec ]]; then
- lastopt_takesargs=0
- lastopt+=": :_ffmpeg_acodecs"
- elif [[ $lastopt == -vcodec ]]; then
- lastopt_takesargs=0
- lastopt+=": :_ffmpeg_vcodecs"
- elif [[ $lastopt == -scodec ]]; then
- lastopt_takesargs=0
- lastopt+=": :_ffmpeg_scodecs"
- elif [[ $lastopt == -f ]]; then
- lastopt_takesargs=0
- lastopt="*$lastopt"
- lastopt+=": :_ffmpeg_formats"
- elif [[ $lastopt == -pix_fmt ]]; then
- lastopt_takesargs=0
- lastopt="*$lastopt"
- lastopt+=":set pixel format:_ffmpeg_pix_fmts"
- elif [[ $example == bitstream_filter ]]; then
- lastopt_takesargs=0
- lastopt+=": :_ffmpeg_bsfs"
- else
- lastopt_takesargs=1
- lastopt_description+=" ($example)"
- fi
- else
- lastopt_takesargs=0
- if [[ $lastopt == -vfilters ]]; then
- lastopt+=": :->vfilters"
- fi
- fi
- lastopt_values=()
- elif [[ $REPLY == ' '* ]]; then
- REPLY=${REPLY##[[:space:]]##}
- REPLY=${REPLY%%[[:space:]]##*}
- lastopt_takesargs=1
- lastopt_values+=$REPLY
- fi
+ _alternative -O ca_opts \
+ "$tag:$desc:( ${(j< >)${(@q+)devices}} )" \
+ "$tag:$desc:_ffmpeg_hwaccels -T"
+}
+
+# complete hardware devices init spec
+(( $+functions[_ffmpeg_hw_device_inits] )) ||
+_ffmpeg_hw_device_inits() {
+ local -a expl
+ if compset -P '*,*=' && [[ $PREFIX != *,* ]]; then
+ _wanted values expl 'device parameter value' _files -qS,
+ elif compset -P '*,'; then
+ _message 'device parameter (key=val)'
+ elif compset -P '*@'; then
+ _ffmpeg_hw_devices
+ elif compset -P '*:'; then
+ _wanted devices expl device _files -qS,
+ elif compset -P '*='; then
+ _message 'hardware device name'
+ else
+ _ffmpeg_hwaccels -T -qS=
+ fi
+}
+
+# complete input/output devices
+(( $+functions[_ffmpeg_devices] )) ||
+_ffmpeg_devices() {
+ local de=DE tag=devices desc=device
+ local -a ca_opts tmp devices
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ D E \
+ || return
+
+ if (( ${+opth[-D]} )); then
+ de=D tag=input-$tag desc="input $desc"
+ elif (( ${+opth[-E]} )); then
+ de=E tag=output-$tag desc="output $desc"
+ fi
+
+ tmp=( ${(f)"$( _call_program devices $words[1] -devices )"} )
+ tmp=( ${(M)tmp:# [DE. ](#c2) [^=]* *} )
+
+ [[ $de == *D* ]] && devices+=( ${(M)tmp:# D? *} )
+ [[ $de == *E* ]] && devices+=( ${(M)tmp:# ?E *} )
+ devices=( ${devices# ?? } )
+
+ if zstyle -t ":completion:$curcontext:$tag" verbose; then
+ local f d
+ tmp=( ${${(@)devices//:/\\:}/[[:space:]]##/:} )
+ devices=( )
+ for f in $tmp; do
+ d=${f#*:} f=${f%%:*}
+ devices+=( ${^${(@s<,>)f}}:$d )
done
- [[ -n $lastopt ]] && _ffmpeg_register_lastopt_values
+ devices=( ${(u)devices} )
+
+ else
+ devices=( ${(@s<,>)${(@)devices%%[[:space:]]*}} )
+ fi
+
+ _describe -t $tag $desc devices "${(@)ca_opts}"
+}
+
+# complete disposition flags
+# -I => single disposition
+(( $+functions[_ffmpeg_dispositions] )) ||
+_ffmpeg_dispositions() {
+ local tag=dispositions desc='disposition flag'
+ local -a ca_opts expl dispositions
+ local -A opth
+
+ zparseopts -A opth -D -F - \
+ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \
+ I \
+ || return
+
+ dispositions=( ${(f)"$( _call_program $tag $words[1] -dispositions )"} )
+ dispositions=( ${dispositions:#*:*} )
+ dispositions=( ${dispositions##[[:space:]]##} )
+
+ if (( ${+opth[-I]} )); then
+ _describe -t $tag $desc dispositions "${(@)ca_opts}"
+ else
+ _wanted $tag expl $desc _ffmpeg_flags "${(@)ca_opts}" - $dispositions
+ fi
+}
+
+# complete stats format spec
+(( $+functions[_ffmpeg_stats_fmt_specs] )) ||
+_ffmpeg_stats_fmt_specs() {
+ local bs
+
+ compset -S '[{[[:space:]]*'
+ compset -P '*[}[[:space:]]'
+
+ [[ -n $compstate[quote] ]] || bs=\\
+
+ argv=( -r'}\-' -S"$bs}" "$@" )
+ compset -P '*{' || argv=( -P"$bs{" "$@" )
+
+ _describe -t stats-format-spec-directives 'stats format spec directive' '(
+ fidx:"index of output file"
+ sidx:"index of output stream in file"
+ n:"frame number"
+ ni:"input frame number"
+ tb:"time base for time stamps of frame/packet"
+ tbi:"timebase for ptsi"
+ pts:"presentation time stamp of frame/packet"
+ ptsi:"presentation time stamp of input frame (ni)"
+ t:"presentation time of frame/packet"
+ ti:"presentation time of input frame (ni)"
+ dts:"decoding time stamp of packet"
+ dt:"decoding time of frame/packet (dts*tb)"
+ sn:"number of audio samples sent to encoder"
+ samp:"number of audio samples in frame"
+ size:"size of packet (bytes)"
+ br:"current bit rate (bps)"
+ abr:"average bit rate of whole stream (bps)"
+ key:"K if packet contains key frame, N otherwise"
+ )' "$@"
+}
+
+# complete vsync method / frame-rate mode
+(( $+functions[_ffmpeg_fps_modes] )) ||
+_ffmpeg_fps_modes() {
+ _describe -t fps-modes 'frame-rate mode [auto]' '(
+ passthrough:"pass through frames unmodified"
+ cfr:"duplicate or drop frames to achieve constant frame rate"
+ vfr:"pass through or drop frames to achieve variable frame rate"
+ auto:"choose cfr or vfr based on muxer capabilities"
+ )' "$@"
+}
+
+# complete video-size abbreviation
+(( $+functions[_ffmpeg_video_sizes] )) ||
+_ffmpeg_video_sizes() {
+ _describe -t video-sizes 'video size abbreviation (or WxH)' '(
+ ntsc:720x480 pal:720x576 qntsc:352x240 qpal:352x288
+ sntsc:640x480 spal:768x576 film:352x240 ntsc-film:352x240
+ sqcif:128x96 qcif:176x144 cif:352x288 4cif:704x576
+ 16cif:1408x1152 qqvga:160x120 qvga:320x240 vga:640x480
+ svga:800x600 xga:1024x768 uxga:1600x1200 qxga:2048x1536
+ sxga:1280x1024 qsxga:2560x2048 hsxga:5120x4096 wvga:852x480
+ wxga:1366x768 wsxga:1600x1024 wuxga:1920x1200 woxga:2560x1600
+ wqsxga:3200x2048 wquxga:3840x2400 whsxga:6400x4096
+ whuxga:7680x4800 cga:320x200 ega:640x350 hd480:852x480
+ hd720:1280x720 hd1080:1920x1080 2k:2048x1080 2kflat:1998x1080
+ 2kscope:2048x858 4k:4096x2160 4kflat:3996x2160
+ 4kscope:4096x1716 nhd:640x360 hqvga:240x160 wqvga:400x240
+ fwqvga:432x240 hvga:480x320 qhd:960x540 2kdci:2048x1080
+ 4kdci:4096x2160 uhd2160:3840x2160 uhd4320:7680x4320
+ )' "$@"
}
-_arguments -C -S \
- "${_ffmpeg_argspecs[@]}" \
- '*:output file:_files' \
- && return
+# complete map data source
+(( $+functions[_ffmpeg_map_sources] )) ||
+_ffmpeg_map_sources() {
+ compset -P -
+
+ if compset -P '*:view:'; then
+ _message 'view ID'
+ elif compset -P '*:vidx:'; then
+ _message 'view index'
+ elif compset -P '*:vpos:'; then
+ _describe -t view-positions 'view position' '(left right)'
+ elif compset -P 1 '*:'; then
+ local ret=1
+ # this isn't quite right
+ compset -P '<->:' ||
+ compset -P '[astvV](:(?|[\\#]##[^:]##))#:' ||
+ compset -P 'g:(i:|)[\\#]#[^:]##:' ||
+ compset -P 'p:[^:]##(|:(?|[\\#]##[^:]##))#:' ||
+ compset -P '([\\#]##|i:)[^:]##:' ||
+ compset -P 'm:[^:]##:' || # how can this have a value here?
+ compset -P 'disp:[^:]##:' ||
+ compset -P u:
+ _ffmpeg_stream_specs -qS: && ret=0
+ _describe -t view-specifiers 'view specifier' '(
+ view:"view ID"
+ vidx:"view index"
+ vpos:"view position"
+ )' -qS: && ret=0
+ return ret
+ else
+ _message \
+ 'map source ([-]input_file_id[:stream_specifier][:view_specifier][:?])'
+ fi
+}
+
+# complete program spec
+(( $+functions[_ffmpeg_program_specs] )) ||
+_ffmpeg_program_specs() {
+ local x
+ local -a kvs keys=(
+ 'title:program title'
+ 'program_num:program number'
+ 'st:stream index'
+ )
+ for x in $keys; do
+ kvs+=( "${x%%:*}[${${x#*:}%%:*}]:${x#*:}" )
+ done
+
+ # it doesn't seem like these need to be given in order
+ compset -P '*:'
+ _values -s: -S= 'program specifier (key=val:key=val:...)' $kvs
+}
+
+# complete stream-group spec
+(( $+functions[_ffmpeg_stream_group_specs] )) ||
+_ffmpeg_stream_group_specs() {
+ local x
+ local -a kvs keys=(
+ 'map:input-group mapping'
+ 'type:stream-group type:( iamf_audio_element iamf_mix_presentation )'
+ 'st:stream index'
+ 'stg:stream group'
+ 'id:stream-group ID'
+ )
+ for x in $keys; do
+ kvs+=( "${x%%:*}[${${x#*:}%%:*}]:${x#*:}" )
+ done
+
+ # @todo we should complete these. it's annoying because some use ':' for their
+ # own values
+ compset -P '*,' && {
+ _message 'type option'
+ return
+ }
+
+ # it doesn't seem like these need to be given in order. except maybe the type
+ # options?
+ compset -P '*:'
+ _values -s: -S= 'stream-group specifier (key=val:key=val:...)' $kvs
+}
+
+# complete key-frame force condition
+(( $+functions[_ffmpeg_kf_force_conds] )) ||
+_ffmpeg_kf_force_conds() {
+ if compset -P expr:; then
+ _message expression
+ elif compset -P '*[0-9,]*'; then
+ _message 'time stamps (time[,time...])'
+ else
+ _describe -t kf-force-conditions 'when to force key frame (or time stamps)' \
+ '(
+ source:"when source frame is marked as key frame"
+ scd_metadata:"when frame has metadata entry lavfi.scd.time"
+ )' \
+ -- \
+ '( expr:"when evaluated expression is non-zero" )' -qS:
+ fi
+}
+
+# complete log-level flag
+(( $+functions[_ffmpeg_loglevels] )) ||
+_ffmpeg_loglevels() {
+ local -a levels=(
+ quiet panic fatal error warning info verbose debug trace
+ )
+ compset -P "(|*+)(${(j<|>)${(@b)levels}})" && return
+ _alternative \
+ "levels:logging level:_ffmpeg_flags - ${(j< >)${(@q+)levels}}" \
+ 'flags: :_ffmpeg_flags - repeat level time datetime'
+}
+
+# complete date spec
+(( $+functions[_ffmpeg_dates] )) ||
+_ffmpeg_dates() {
+ _message -e dates \
+ 'date ([(YYYY-MM-DD|YYYYMMDD)[T|t| ]]((HH:MM:SS[.m]]])|(HHMMSS[.m]]]))[Z]) (or now)'
+}
+
+# complete duration spec
+(( $+functions[_ffmpeg_durations] )) ||
+_ffmpeg_durations() {
+ _message -e durations 'duration ([-][HH:]MM:SS[.m] or [-]S+[.m][s|ms|us])'
+}
+
+# complete compare functions
+(( $+functions[_ffmpeg_cmp_functions] )) ||
+_ffmpeg_cmp_functions() {
+ _describe -t compare-functions 'compare function' '(
+ sad sse satd dct psnr bit rd zero vsad vsse nsse w53 w97 dctmax
+ chroma msad
+ )' "$@"
+}
+
+# complete frame discard methods
+(( $+functions[_ffmpeg_discard_methods] )) ||
+_ffmpeg_discard_methods() {
+ _describe -t discard-methods 'frame discard method' '(
+ none:"no frames"
+ default:"useless frames"
+ noref:"non-reference frames"
+ bidir:"bi-directional frames"
+ nointra:"all except I frames"
+ nokey:"all except key frames"
+ all:"all frames"
+ )' "$@"
+}
+
+# complete -help topic
+(( $+functions[_ffmpeg_help_topics] )) ||
+_ffmpeg_help_topics() {
+ if compset -P decoder=; then
+ _ffmpeg_codecs -D
+ elif compset -P encoder=; then
+ _ffmpeg_codecs -E
+ elif compset -P demuxer=; then
+ _ffmpeg_formats -D
+ elif compset -P muxer=; then
+ _ffmpeg_formats -E
+ elif compset -P filter=; then
+ _ffmpeg_filters
+ elif compset -P bsf=; then
+ _ffmpeg_bsfs -I
+ elif compset -P protocol=; then
+ _ffmpeg_protocols
+ else
+ _describe -t help-topics 'help topic' \
+ '(
+ long:"basic and advanced tool options"
+ full:"all options"
+ )' \
+ -- \
+ '(
+ decoder:"specified decoder"
+ encoder:"specified encoder"
+ demuxer:"specified demuxer"
+ muxer:"specified muxer"
+ filter:"specified filter"
+ bsf:"specified bitstream filter"
+ protocol:"specified protocol"
+ )' -qS=
+ fi
+}
+
+local MATCH MBEGIN MEND x y z no
+local -a ss_opts ms_opts basic_opts expert_opts gen_avo_opts opts tmp
+
+# names of options that support optional :stream_specifier form
+ss_opts=(
+ ac apad apply_cropping ar aspect autorotate autoscale b
+ bits_per_raw_sample bsf c canvas_size ch_layout channel_layout
+ chroma_intra_matrix codec copyinkf copypriorss discard
+ display_hflip display_rotation display_vflip disposition
+ drop_changed dump_attachment enc_time_base filter filter_script
+ fix_sub_duration fix_sub_duration_heartbeat force_fps
+ force_key_frames fps_mode fpsmax frames guess_layout_max hwaccel
+ hwaccel_device hwaccel_output_format inter_matrix intra_matrix
+ itsscale max_muxing_queue_size muxing_queue_data_threshold pass
+ passlogfile pix_fmt pre q qscale r rc_override reinit_filter s
+ sample_fmt stats_enc_post stats_enc_post_fmt stats_enc_pre
+ stats_enc_pre_fmt stats_mux_pre stats_mux_pre_fmt tag threads
+ time_base top
+)
+
+# names of options that support optional :metadata_specifier form
+ms_opts=( metadata map_metadata )
+
+# option specs are grouped and ordered per `ffmpeg -help full` output. the
+# separate arrays probably aren't necessary, but i was keeping track of it
+# anyway, and maybe it'll be useful in the future
+
+# note: in order for the replacements below to work reliably, all specs must
+# have descriptions ('-o[desc]'), and colons must not be omitted after optarg
+# descriptions: '-o[desc]:argdesc:', NOT '-o[desc]:argdesc'
+
+# basic information/capability options
+basic_opts+=(
+ '(- : *)'{-L,-license}'[display licence information]'
+ '(- : *)'{-h,-help,--help}'[display help information]:: :_ffmpeg_help_topics'
+ '!(- : *)-?[]:: :_ffmpeg_help_topics' # annoying
+ '(- : *)-version[display version information]'
+ '(- : *)-muxers[display available muxers]'
+ '(- : *)-demuxers[display available demuxers]'
+ '(- : *)-devices[display available devices]'
+ '(- : *)-decoders[display available decoders]'
+ '(- : *)-encoders[display available encoders]'
+ '(- : *)-filters[display available filters]'
+ '(- : *)-pix_fmts[display available pixel formats]'
+ '(- : *)-layouts[display channel names and standard channel layouts]'
+ '(- : *)-sample_fmts[display available sample formats]'
+)
+# advanced information/capability options
+expert_opts+=(
+ '(- : *)-buildconf[display build configuration]'
+ '(- : *)-formats[display available formats]'
+ '(- : *)-codecs[display available codecs]'
+ '(- : *)-bsfs[display available bitstream filters]'
+ '(- : *)-protocols[display available protocols]'
+ '(- : *)-dispositions[display stream dispositions]'
+ '(- : *)-colors[display recognised colours]'
+ '(- : *)-sources[display input sources (specify device)]:: :{
+ compset -S ",*"
+ if compset -P "*,"; then
+ _message "input device option (opt1=val1,opt2=val2,...)"
+ else
+ _ffmpeg_devices -D -qS,
+ fi
+ }'
+ '(- : *)-sinks[display output sinks (specify device)]:: :{
+ compset -S ",*"
+ if compset -P "*,"; then
+ _message "output device option (opt1=val1,opt2=val2,...)"
+ else
+ _ffmpeg_devices -E -qS,
+ fi
+ }'
+ '(- : *)-hwaccels[display available hardware-acceleration methods]'
+)
+# basic global options
+basic_opts+=(
+ '(-v -loglevel)'{-v,-loglevel}'[set logging level]: :_ffmpeg_loglevels'
+ '(-n)-y[overwrite output files without asking]'
+ '(-y)-n[never overwrite output files]'
+ '-print_graphs[print execution graph data to stderr]'
+ '-print_graphs_file[write execution graph data to specified file]:execution graph file:_files'
+ '-print_graphs_format[specify execution graph format]:execution graph format:(
+ default compact csv flat ini json xml mermaid mermaidhtml
+ )'
+ '-stats[print encoding progress and statistics]'
+)
+# advanced global options
+expert_opts+=(
+ '-report[generate report]'
+ '-max_alloc[specify heap allocation size limit]: :\
+ _ffmpeg_numbers -u bytes "max heap allocation block size"
+ '
+ # we could check these against $MACHTYPE but i don't think it matters
+ '-cpuflags[specify CPU flags]:CPU flag:_ffmpeg_flags - \
+ mmx mmxext \
+ sse sse2 sse2slow sse3 sse3slow ssse3 sse4.1 sse4.2 \
+ atom \
+ avx avx2 \
+ xop \
+ fma3 fma4 \
+ 3dnow 3dnowext \
+ bmi1 bmi2 \
+ cmov \
+ pentium2 pentium3 pentium4 k6 k62 athlon athlonxp k8 \
+ armv5te armv6 armv6t2 vfp vfpv3 neon setend \
+ armv8 vfp neon \
+ altivec
+ '
+ '-cpucount[specify CPU count]: :_ffmpeg_numbers "CPU count"'
+ '-hide_banner[suppress banner]'
+ '(-copy_unknown)-ignore_unknown[ignore unknown stream types]'
+ '(-ignore_unknown)-copy_unknown[copy unknown stream types]'
+ '-recast_media[allow forcing decoder of different media type]'
+ '-benchmark[show benchmark information at end of encode]'
+ '-benchmark_all[show benchmark information during encode]'
+ '-progress[write progress information to specified URL]: :{
+ if compset -P pipe\:; then
+ _describe "file descriptor" "(0 1 2)"
+ else
+ _alternative "urls\: \:_urls" "files\: \:_files"
+ fi
+ }'
+ '-stdin[enable interaction on standard input]'
+ '-timelimit[specify max run time]: :\
+ _ffmpeg_numbers -u seconds "max CPU user time"
+ '
+ '-dump[dump each input packet to stderr]'
+ '-hex[also dump payload (with -dump)]'
+ '-frame_drop_threshold[specify frame-drop threshold]: :\
+ _ffmpeg_numbers -u frames -N -d-1.1 "frame-drop threshold"
+ '
+ '-copyts[copy timestamps]'
+ '-start_at_zero[shift input timestamps to start at 0 (with -copyts)]'
+ '-copytb[specify how to set encoder time base when copying stream]:mode:((
+ -1\:"decide automatically"
+ 0\:"use decoder time base"
+ 1\:"use demuxer time base"
+ ))'
+ '-dts_delta_threshold[specify timestamp discontinuity delta threshold]: :\
+ _ffmpeg_numbers -u seconds -d10 "timestamp discontinuity delta threshold"
+ '
+ '-dts_error_threshold[specify timestamp error delta threshold]: :\
+ _ffmpeg_numbers -u seconds -d108000 "timestamp error delta threshold"
+ '
+ '-xerror[exit on error]'
+ '-abort_on[abort on specified condition flags]:condition flag:\
+ _ffmpeg_flags - empty_output empty_output_stream
+ '
+ '-filter_threads[specify number of threads used for each filter pipeline]: :\
+ _ffmpeg_numbers threads
+ '
+ '-filter_buffered_frames[specify max buffered frames in a filtergraph]: :\
+ _ffmpeg_numbers -d0 "max buffered frames"
+ '
+ '*'{-filter_complex,-lavfi}'[define specified complex filtergraph]: :_ffmpeg_filtergraphs'
+ '-filter_complex_threads[specify number of threads used for each complex filtergraph]: :\
+ _ffmpeg_numbers threads
+ '
+ '!*-filter_complex_script[]:-filter_complex script:_files' # deprecated
+ '-auto_conversion_filters[enable automatic conversion filters globally]'
+ '-stats_period[specify progress/statistics update interval]: :\
+ _ffmpeg_numbers -u seconds -d0.5 "update interval"
+ '
+ '-debug_ts[print timestamp/latency information]'
+ '-max_error_rate[specify max decoding error ratio]: :\
+ _ffmpeg_numbers -l0 -m1 -d0.67 "max decoding error ratio"
+ '
+ '-sdp_file[write sdp information to specified file]:sdp file:_files'
+ '*-init_hw_device[initialise specified hardware device]: :_ffmpeg_hw_device_inits'
+ '-filter_hw_device[specify hardware device for filtering]: :_ffmpeg_hw_devices'
+ '!-adrift_threshold[]:threshold:' # deprecated
+ '!-qphist[]' # deprecated
+ # deprecated in favour of -fps_mode, but still used in documentation, so no !
+ '-vsync[specify video sync method globally]: :_ffmpeg_fps_modes'
+)
+# basic per-file options (input and output)
+basic_opts+=(
+ '*-f[force specified container format]: :_ffmpeg_formats'
+ '*-t[stop after specified duration]: :_ffmpeg_durations'
+ '*-to[stop at specified time]: :_ffmpeg_durations'
+ '*-ss[start at specified time]: :_ffmpeg_durations'
+)
+# advanced per-file options (input and output)
+expert_opts+=(
+ '*-bitexact[enable bitexact mode]'
+ '*-thread_queue_size[specified max queued packets for demuxer]: :\
+ _ffmpeg_numbers "max queued packets"
+ '
+)
+# advanced per-file options (input only)
+expert_opts+=(
+ '*-sseof[start at specified time relative to EOF]: :_ffmpeg_durations'
+ '*-seek_timestamp[seek by timestamp (with -ss/-sseof)]'
+ '*-accurate_seek[enable accurate seeking (with -ss/-sseof)]'
+ '*-isync[specify input index for sync reference]: :\
+ _ffmpeg_numbers -N -d-1 "input index"
+ '
+ '*-itsoffset[specify input time offset]: :_ffmpeg_durations'
+ '*-re[read input at native frame rate (like -readrate 1)]'
+ '*-readrate[specify input read speed limit]: :\
+ _ffmpeg_numbers -u seconds -l0 -d0 "max input read duration per 1s of wall time"
+ '
+ '*-readrate_initial_burst[specify initial read burst time (with -readrate)]: :\
+ _ffmpeg_numbers -u seconds "initial read burst time"
+ '
+ '*-readrate_catchup[specify catch-up read speed limit if blocked (with -readrate)]: :\
+ _ffmpeg_numbers -u seconds "max input read duration per 1s of wall time"
+ '
+ '*-dump_attachment[extract matching attachment into specified file]:attachment output file:_files'
+ '*-stream_loop[specify number of times to loop input stream]: :\
+ _ffmpeg_numbers -N -d0 "input-stream loops"
+ '
+ '*-find_stream_info[decode streams to fill missing info with heuristics]'
+)
+# basic per-file options (output only)
+basic_opts+=(
+ '*-metadata[add specified metadata to output]:metadata key=value:'
+)
+# advanced per-file options (output only)
+expert_opts+=(
+ '*-map[specify stream mapping from input to output]: :_ffmpeg_map_sources'
+ '*-map_metadata[set metadata mapping from input to output]: :{
+ if compset -P 1 "*\:"; then
+ _ffmpeg_metadata_specs
+ else
+ _message "input file index[\:metadata specifier]"
+ fi
+ }'
+ '*-map_chapters[specify chapter mapping from input to output]: :\
+ _ffmpeg_numbers -N "input index"
+ '
+ '*-fs[specify output file size limit]: :\
+ _ffmpeg_numbers -u bytes "output file size limit"
+ '
+ '*-timestamp[specify recording timestamp]: :_ffmpeg_dates'
+ '*-program[add program with specified streams]: :_ffmpeg_program_specs'
+ '*-stream_group[add stream group with specified streams]: :_ffmpeg_stream_group_specs'
+ '*-dframes[specify max data frames to output (-like -frames\:d)]: :\
+ _ffmpeg_numbers "max data frames"
+ '
+ '*-target[specify target file type]:file type:(
+ {film-,ntsc-,pal-,}{vcd,svcd,dvd,dv,dv50}
+ )'
+ '*-shortest[finish encoding when shortest output stream ends]'
+ '*-shortest_buf_duration[specify buffer duration for -shortest]: :\
+ _ffmpeg_numbers -u seconds -d10 "max duration of buffered frames"
+ '
+ '*'{-q,-qscale}'[specify VBR quality]: :\
+ _ffmpeg_numbers "quality scale value"
+ '
+ # this is codec-specific, but here are some we know about
+ '*-profile[specify codec profile]:codec profile:(
+ # avcodeccontext
+ unknown main10
+ # dnxhd
+ dnxhd dnxhr_444 dnxhr_hqx dnxhr_hq dnxhr_sq dnxhr_lb
+ # prores
+ auto proxy lt standard hq 4444 4444xq
+ # x264
+ baseline main high high10 high422 high444
+ # h264 videotoolbox
+ baseline constrained_baseline main high constrained_high extended
+ # hevc videotoolbox
+ main main10 main42210 rext
+ # prores videotoolbox
+ auto proxy lt standard hq 4444 xq
+ )'
+ '*-attach[add attachment]:file to attach:_files'
+ '*-muxdelay[specify max demux-decode delay]: :\
+ _ffmpeg_numbers -u seconds "max demux-decode delay"
+ '
+ '*-muxpreload[specify initial demux-decode delay]: :\
+ _ffmpeg_numbers -u seconds "demux-decode delay"
+ '
+ '*-fpre[set options from specified preset file]:preset file:_files' \
+)
+# basic per-stream options
+basic_opts+=(
+ '*'{-c,-codec}'[specify encoder or decoder]: :_ffmpeg_codecs'
+ '*-filter[apply specified filtergraph]: :_ffmpeg_filtergraphs'
+)
+# advanced per-stream options
+expert_opts+=(
+ '*-pre[specify preset]: :_ffmpeg_presets'
+ '*-itsscale[specify input timestamp scale]: :_ffmpeg_numbers scale'
+ '*-copyinkf[copy initial non-key frames]'
+ '*-copypriorss[copy or discard frames before start time]'
+ '*-frames[specify max frames to output]: :\
+ _ffmpeg_numbers "max frames"
+ '
+ # there are hundreds of these so i'm not sure it makes sense to complete them
+ '*-tag[force specified codec tag/fourcc]:codec fourcc:'
+ '!*-filter_script[]:-filter script:_files' # deprecated
+ '*-reinit_filter[specify whether to re-initialise filtergraph on input parameter change]:re-initialise mode:((
+ 0\:disabled
+ 1\:enabled
+ ))'
+ '*-drop_changed[specify whether to drop frame on input parameter change]:drop mode:((
+ 0\:disabled
+ 1\:enabled
+ ))'
+ '*-discard[specify frames to discard]: :_ffmpeg_discard_methods'
+ '*-disposition[specify disposition flags]: :_ffmpeg_dispositions'
+ '*-bits_per_raw_sample[specify bits per raw sample]: :\
+ _ffmpeg_numbers "bits per raw sample"
+ '
+ '*-stats_enc_pre[write pre-encoding frame stats to specified file]:stats file:_files'
+ '*-stats_enc_post[write post-encoding frame stats to specified file]:stats file:_files'
+ '*-stats_mux_pre[write pre-muxing frame stats to specified file]:stats file:_files'
+ '*-stats_enc_pre_fmt[specify format for -stats_enc_pre]: :_ffmpeg_stats_fmt_specs'
+ '*-stats_enc_post_fmt[specify format for -stats_enc_post]: :_ffmpeg_stats_fmt_specs'
+ '*-stats_mux_pre_fmt[specify format for -stats_mux_pre]: :_ffmpeg_stats_fmt_specs'
+ '*-time_base[specify time base for output stream]:time base (num\:den or float):'
+ '*-enc_time_base[specify time base for encoder]:encoder time base (or num\:den or float):((
+ 0\:"assign default value according to media type"
+ demux\:"use time base from demuxer"
+ filter\:"use time base from filtergraph"
+ ))'
+ '*-bsf[specify bitstream filters]: :_ffmpeg_bsfs'
+ '*-max_muxing_queue_size[specify max packets in muxing queue]: :\
+ _ffmpeg_numbers "max packets in muxing queue"
+ '
+ '*-muxing_queue_data_threshold[specify minimum threshold for -max_muxing_queue_size]: :\
+ _ffmpeg_numbers -u bytes -d50M "minimum threshold for muxing queue size"
+ '
+)
+# basic video options
+basic_opts+=(
+ '*-r[specify frame rate]: :\
+ _ffmpeg_numbers -u "Hz, fraction, or abbreviation" "frame rate"
+ '
+ '*-aspect[specify aspect ratio]: :\
+ _ffmpeg_numbers -u "float or num:den" "aspect ratio"
+ '
+ '*-vn[disable video]'
+ '*-vcodec[force specified video codec (like -c\:v)]: :_ffmpeg_codecs -Tv'
+ '*-vf[apply specified filtergraph to video (like -filter\:v)]: :_ffmpeg_filtergraphs'
+ # this is actually not a video option, it has to be used like -b:a or -b:v.
+ # but this is where it's listed in the help output
+ '*-b[specify bit rate]: :_ffmpeg_numbers -u bps "bit rate"'
+ # this isn't in the help output for some reason
+ '*-s[specify video frame size]: :_ffmpeg_video_sizes'
+)
+# advanced video options
+expert_opts+=(
+ '*-vframes[specify max video frames to output (like -frames\:v)]: :\
+ _ffmpeg_numbers "max video frames"
+ '
+ '*-fpsmax[specify max video frame rate]: :\
+ _ffmpeg_numbers -u "Hz, fraction, or abbreviation" "frame rate"
+ '
+ '*-pix_fmt[specify pixel format]: :_ffmpeg_pix_fmts'
+ '*-display_rotation[specify video rotation]: :\
+ _ffmpeg_numbers -u degrees "anti-clockwise video rotation"
+ '
+ '*-display_hflip[flip video horizontally]'
+ '*-display_vflip[flip video vertically]'
+ '*-rc_override[specify rate-control override]:rate control (beg,end,quant):'
+ '*-timecode[specify timecode]:timecode (hh\:mm\:ss[\:;.]ff)'
+ '*-pass[specify pass number for two-pass video encoding]:pass:(1 2)'
+ '*-passlogfile[specify two-pass log-file prefix]:log-file prefix [ffmpeg2pass]:'
+ '*-intra_matrix[specify intra quantisation matrix]:intra quantisation matrix:'
+ '*-inter_matrix[specify inter quantisation matrix]:inter quantisation matrix:'
+ '*-chroma_intra_matrix[specify chroma intra quantisation matrix]:intra quantisation matrix:'
+ '*-vtag[force specified video codec tag/fourcc (like -tag\:v)]:video codec fourcc:'
+ '*-fps_mode[specify frame-rate mode]: :_ffmpeg_fps_modes'
+ '*-force_fps[force selected frame rate]'
+ '*-streamid[specify stream identifier]:output-stream-index\:new-value:'
+ '*-force_key_frames[force key frames at specified timestamps]: :_ffmpeg_kf_force_conds'
+ '*-hwaccel[specify hardware acceleration for decoding]: :_ffmpeg_hwaccels'
+ '*-hwaccel_device[specify hardware-acceleration device (with -hwaccel)]: :_ffmpeg_hw_devices'
+ '*-hwaccel_output_format[specify hardware-acceleration output format (with -hwaccel)]: :_ffmpeg_pix_fmts -H'
+ '*-autorotate[automatically rotate video]'
+ '*-autoscale[automatically scale video]'
+ '*-apply_cropping[automatically crop video using specified method]:crop method [all]:((
+ none\:"don'\''t apply cropping"
+ all\:"apply codec- and container-level cropping"
+ codec\:"apply codec-level cropping"
+ container\:"apply container-level cropping"
+ ))'
+ '*-fix_sub_duration_heartbeat[set stream as heartbeat stream (with -fix_sub_duration)]'
+ '*-vpre[specify video preset]: :_ffmpeg_presets'
+ '!*-top[]:top:' # deprecated
+)
+# basic audio options
+basic_opts+=(
+ '*-aq[specify audio VBR quality (like -q\:a)]: :\
+ _ffmpeg_numbers "quality scale value"
+ '
+ '*-ar[specify audio sampling rate]: :\
+ _ffmpeg_numbers -u Hz "audio sampling rate"
+ '
+ '*-ac[specify number of audio channels]: :\
+ _ffmpeg_numbers "audio channels"
+ '
+ '*-an[disable audio]'
+ '*-acodec[force specified audio codec (like -c\:a)]: :_ffmpeg_codecs -Ta'
+ '*-ab[specify audio bit rate]: :_ffmpeg_numbers -u bps "audio bit rate"'
+ '*-af[apply specified filtergraph to audio (like -filter\:a)]: :_ffmpeg_filtergraphs'
+)
+# advanced audio options
+expert_opts+=(
+ '*-aframes[specify max audio frames to output (like -frames\:a)]: :\
+ _ffmpeg_numbers "max audio frames"
+ '
+ '*-apad[pad audio stream with specified parameters (like -af apad) (with -shortest)]:apad filter parameters ([key=]val\:[key=]val\:...):'
+ '*-atag[force specified audio codec tag/fourcc (like -tag\:a)]:audio codec fourcc:'
+ '*-sample_fmt[specify audio sample format]: :_ffmpeg_sample_fmts'
+ '*'{-channel_layout,-ch_layout}'[specify audio channel layout]: :_ffmpeg_layouts'
+ '*-guess_layout_max[specify max channels for guessing channel layout]: :\
+ _ffmpeg_numbers "max audio channels"
+ '
+ '*-apre[specify audio preset]: :_ffmpeg_presets'
+)
+# basic subtitle options
+basic_opts+=(
+ '*-sn[disable subtitles]'
+ '*-scodec[force specified subtitle codec (like -c\:s)]: :_ffmpeg_codecs -Ts'
+)
+# advanced subtitle options
+expert_opts+=(
+ '*-stag[force specified subtitle codec tag/fourcc (like -tag\:s)]:subtitle codec fourcc:'
+ '*-fix_sub_duration[fix subtitle durations]'
+ '*-canvas_size[specify size of canvas for rendering subtitles]: :_ffmpeg_video_sizes'
+ '*-spre[specify subtitle preset]: :_ffmpeg_presets'
+)
+# basic data-stream options
+basic_opts+=(
+ '*-dcodec[force specified data codec (like -c\:d)]: :_ffmpeg_codecs -Td'
+ '*-dn[disable data]'
+)
+# generic codec AVOptions. my assumption is that these are rarely used, so i
+# haven't put much effort into them
+gen_avo_opts+=(
+ '!*-bt[]: :_ffmpeg_numbers -u bps "bit-rate tolerance"'
+ '!*-flags[]: :_ffmpeg_flags - \
+ unaligned mv4qpel loop gray psnr ildct low_delay global_header \
+ bitexact aic ilme cgop output_corrupt
+ '
+ '!*-flags2[]: :_ffmpeg_flags - \
+ fast noout ignorecrop local_header chunks showall export_mvs \
+ skip_manual ass_ro_flush_noop icc_profiles
+ '
+ '!*-export_side_data[]: :_ffmpeg_flags - \
+ mvs prft venc_params film_grain enhancements
+ '
+ '*-g[specify GOP (group of pictures) length]: :\
+ _ffmpeg_numbers -u frames "GOP length"
+ '
+ '*-cutoff[specify audio cut-off frequency]: :\
+ _ffmpeg_numbers -u Hz "cut-off frequency"
+ '
+ '*-frame_size[specify audio frame size]: :\
+ _ffmpeg_numbers -u samples/channel "frame size"
+ '
+ '!*-qcomp[]:float:'
+ '!*-qblur[]:float:'
+ '!*-qmin[]:int:'
+ '!*-qmax[]:int:'
+ '!*-qdiff[]:int:'
+ '!*-bf[]:int:'
+ '!*-b_qfactor[]:float:'
+ '!*-bug[]: :_ffmpeg_flags - \
+ autodetect xvid_ilace ump4 no_padding amv qpel_chroma std_qpel \
+ qpel_chroma2 direct_blocksize edge hpel_chroma dc_clip ms trunc \
+ iedge
+ '
+ '*-strict[specify how strictly to follow standards]:strictness level:(
+ very strict normal unofficial experimental
+ )'
+ '!*-b_qoffset[]:float:'
+ '!*-err_detect[]: :_ffmpeg_flags - \
+ crccheck bitstream buffer explode ignore_err careful compliant
+ aggressive
+ '
+ '!*-maxrate[]:int64:'
+ '!*-minrate[]:int64:'
+ '!*-bufsize[]:int:'
+ '!*-i_qfactor[]:float:'
+ '!*-i_qoffset[]:float:'
+ '!*-lumi_mask[]:float:'
+ '!*-tcplx_mask[]:float:'
+ '!*-scplx_mask[]:float:'
+ '!*-p_mask[]:float:'
+ '!*-dark_mask[]:float:'
+ '!*-dct[]:algorithm:(auto fastint int mmx altivec faan neon)'
+ '!*-idct[]:algorithm:(
+ auto int simple simplemmx arm altivec simplearm simplearmv5te
+ simplearmv6 simpleneon xvid xvidmmx faani simpleauto
+ )'
+ '!*-ec[]: :_ffmpeg_flags - guess_mvs deblock favor_inter'
+ '!*-sar[]:rational:'
+ '!*-debug[]: :_ffmpeg_flags - \
+ pict rc bitstream mb_type qp dct_coeff green_metadata skip \
+ startcode er mmco bugs buffers thread_ops nomc
+ '
+ '!*-dia_size[]:int:'
+ '!*-last_pred[]:int:'
+ '!*-pre_dia_size[]:int:'
+ '!*-subq[]:int:'
+ '!*-me_range[]:int:'
+ '!*-global_quality[]:int:'
+ '!*-mdb[]:macroblock decision algorithm [simple]:(simple bits rd)'
+ '!*-rc_init_occupancy[]:int:'
+ '*-threads[specify number of threads to use]: :\
+ _ffmpeg_numbers -d1 "threads (or auto)"
+ '
+ '!*-dc[]:int:'
+ '!*-nssew[]:int:'
+ '!*-skip_top[]:int:'
+ '!*-skip_bottom[]:int:'
+ '!*-level[]:int:'
+ '!*-lowres[]:int:'
+ '!*-cmp[]: :_ffmpeg_cmp_functions'
+ '!*-subcmp[]: :_ffmpeg_cmp_functions'
+ '!*-mbcmp[]: :_ffmpeg_cmp_functions'
+ '!*-ildctcmp[]: :_ffmpeg_cmp_functions'
+ '!*-precmp[]: :_ffmpeg_cmp_functions'
+ '!*-mblmin[]:int:'
+ '!*-mblmax[]:int:'
+ '!*-skip_loop_filter[]: :_ffmpeg_discard_methods'
+ '!*-skip_idct[]: :_ffmpeg_discard_methods'
+ '!*-skip_frame[]: :_ffmpeg_discard_methods'
+ '!*-bidir_refine[]:int:'
+ '!*-keyint_min[]:int:'
+ '!*-refs[]:int:'
+ '!*-trellis[]:int:'
+ '!*-mv0_threshold[]:int:'
+ '!*-compression_level[]:int:'
+ '!*-rc_max_vbv_use[]:float:'
+ '!*-rc_min_vbv_use[]:float:'
+ '!*-color_primaries[]:colour primary [unknown]:(
+ bt709 unknown bt470m bt470bg smpte170m smpte240m film bt2020
+ smpte428 smpte428_1 smpte431 smpte432 jedec-p22 ebu3213
+ unspecified
+ )'
+ '!*-color_trc[]:colour transfer characteristic [unknown]:(
+ bt709 unknown gamma22 gamma28 smpte170m smpte240m linear log100
+ log316 iec61966-2-4 bt1361e iec61966-2-1 bt2020-10 bt2020-12
+ smpte2084 smpte428 arib-std-b67 unspecified log log_sqrt
+ iec61966_2_4 bt1361 iec61966_2_1 bt2020_10bit bt2020_12bit
+ smpte428_1
+ )'
+ '!*-colorspace[]:colour space [unknown]:(
+ rgb bt709 unknown fcc bt470bg smpte170m smpte240m ycgco bt2020nc
+ bt2020c smpte2085 chroma-derived-nc chroma-derived-c ictcp ipt-c2
+ unspecified ycocg ycgco-re ycgco-ro bt2020_ncl bt2020_cl
+ )'
+ '!*-color_range[]:colour range [unknown]:(
+ unknown tv pc unspecified mpeg jpeg limited full
+ )'
+ '!*-chroma_sample_location[]:sample location [unknown]:(
+ unknown left center topleft top bottomleft bottom unspecified
+ )'
+ '!*-alpha_mode[]:alpha mode [unknown]:(
+ unknown unspecified premultiplied straight
+ )'
+ '!*-slices[]:int:'
+ '!*-thread_type[]:thread-type flag [slice+frame]:_ffmpeg_flags - slice frame'
+ '!*-audio_service_type[]:audio service type [ma]:(ma ef vi hi di co em vo ka)'
+ '!*-request_sample_fmt[]: :_ffmpeg_sample_fmts'
+ '!*-sub_charenc[specify subtitle character encoding]:subtitle character encoding:'
+ '!*-sub_charenc_mode[]:subtitle character encoding mode flag [0]:\
+ _ffmpeg_flags - do_nothing auto pre_decoder ignore
+ '
+ '!*-skip_alpha[]'
+ '!*-field_order[]:field order [0]:(progressive tt bb tb bt)'
+ '!*-dump_separator[specify information dump field separator]:field separator:'
+ '!*-codec_whitelist[]: :_sequence -s, _ffmpeg_codecs -D'
+ '!*-max_pixels[]:int64:'
+ '!*-max_samples[]:int64:'
+ '!*-hwaccel_flags[]:hardware-acceleration flag [ignore_level]:\
+ _ffmpeg_flags - \
+ ignore_level allow_high_depth allow_profile_mismatch \
+ unsafe_output
+ '
+ '!*-extra_hw_frames[]:int:'
+ '!*-discard_damaged_percentage[]:int:'
+ '!*-side_data_prefer_packet[]: : _values -s, "side data type" \
+ replaygain displaymatrix spherical stereo3d audio_service_type \
+ mastering_display_metadata content_light_level icc_profile exif
+ '
+)
+# generic format AVOptions. see above
+gen_avo_opts+=(
+ '!*-avioflags[]: :_ffmpeg_flags - direct'
+ '!*-probesize[]:int64:'
+ '!*-formatprobesize[]:int:'
+ '!*-packetsize[]:int:'
+ '!*-fflags[]: :_ffmpeg_flags - \
+ flush_packets ignidx genpts nofillin noparse igndts \
+ discardcorrupt sortdts fastseek nobuffer bitexact autobsf
+ '
+ '!*-seek2any[]'
+ '!*-analyzeduration[]:int64:'
+ '!*-cryptokey[]:binary:'
+ '!*-indexmem[]:int:'
+ '!*-rtbufsize[]:int:'
+ '!*-fdebug[]: :_ffmpeg_flags - ts'
+ '!*-max_delay[]:int:'
+ '!*-start_time_realtime[]:int64:'
+ '!*-fsprobesize[]:int:'
+ '!*-audio_preload[]:int:'
+ '!*-chunk_duration[]:int:'
+ '!*-chunk_size[]:int:'
+ '!*'{-f_err_detect,-err_detect}'[]: :_ffmpeg_flags - \
+ crccheck bitstream buffer explode ignore_err careful compliant \
+ aggressive
+ ' # -f_err_detect is deprecated
+ '!*-use_wallclock_as_timestamps[]'
+ '!*-skip_initial_bytes[]:int64:'
+ '!*-correct_ts_overflow[]'
+ '!*-flush_packets[]:int:'
+ '!*-metadata_header_padding[]:int:'
+ '!*-output_ts_offset[]: :_ffmpeg_durations'
+ '!*-max_interleave_delta[]:int64:'
+ # deprecated. see -strict
+ '!*-f_strict[]:strictness level:(very strict normal unofficial experimental)'
+ '!*-max_ts_probe[]:int:'
+ '!*-avoid_negative_ts[]:time-stamp shift method:(
+ auto disabled make_non_negative make_zero
+ )'
+ '!*-format_whitelist[]: :_sequence -s, _ffmpeg_formats -D'
+ '!*-protocol_whitelist[]: :_sequence -s, _ffmpeg_protocols'
+ '!*-protocol_blacklist[]: :_sequence -s, _ffmpeg_protocols'
+ '!*-max_streams[]:int:'
+ '!*-skip_estimate_duration_from_pts[]'
+ '!*-max_probe_packets[]:int:'
+ '!*-duration_probesize[]:int64:'
+)
+# and... this
+basic_opts+=(
+ '*-i[input file or URL]:input file:_files'
+)
+
+# previous iterations of this function only completed basic options. not sure if
+# that's specifically desirable, but we can support it
+opts=( $basic_opts )
+if zstyle -t ":completion:$curcontext:$curtag" basic; then
+ opts+=( ${expert_opts/#(#m)[^!]/!$MATCH} ${gen_avo_opts/#(#m)[^!]/!$MATCH} )
+else
+ opts+=( $expert_opts $gen_avo_opts )
+fi
+
+# --help looks annoying in the list
+[[ -n $words[(r)--*] ]] || opts=( ${opts:#(|\(*\))\*#--*} )
+
+# support -no variants of boolean options
+[[ $PREFIX == -no* ]] &&
+for x in ${opts:#*\]:*}; do
+ [[ $x == \([' *:-']##\)* ]] && continue # skip -version etc
+ # skip some others that are stupid
+ [[ $x == (|\(*\))-(hide_banner|n|y)\[* ]] && continue
+ # turn '-foo[do bar]' into "-nofoo[don't do bar]"
+ [[ $x == \(* ]] && x=${x/\)-/\)-no} || x=${x/-/-no}
+ x=${x/\[/\[don\'t }
+ opts+=( $x )
+done
-[[ "$state" == "vfilters" ]] &&
- _values -s , -S = 'video filter' \
- 'aspect:set aspect ratio (rational number X\:Y or decimal number):' \
- 'crop:crop input video (x\:y\:width\:height):' \
- 'format: :_sequence -s : _ffmpeg_pix_fmts' \
- 'noformat: :_sequence -s : _ffmpeg_pix_fmts' \
- 'null' \
- 'pad:add pads to the input image (width\:height\:x\:y\:color_string):' \
- 'pixelaspect:set pixel aspect ratio (rational number X\:Y or decimal number):' \
- 'scale:scale input video (width\:height):' \
- 'slicify:output slice height ("random" or a number of pixels):' \
- 'unsharp:luma_x\:luma_y\:luma_amount\:chroma_x\:chroma_y\:chroma_amount:' \
- 'vflip' \
- 'buffer' \
- 'nullsrc' \
- 'nullsink' \
- && return
+# support optional stream/metadata spec, e.g. -codec:a or -metadata:s:a
+[[ $words[CURRENT] == -/#*:* || $words[CURRENT-1] == -/#*:* ]] &&
+for x y in ss_opts _ffmpeg_stream_specs ms_opts _ffmpeg_metadata_specs; do
+ for z in ${(P)x}; do
+ [[ $words[CURRENT] == -/#$z:* || $words[CURRENT-1] == -/#$z:* ]] || continue
+ tmp=( ${(M)opts:#(|\(*\))\*#-$z\[*} )
+ opts=( ${opts:#$tmp} )
+ # turn '-c:x:y' into '-c\:-: :_ffmpeg_stream_specs:x:y'
+ tmp=( ${tmp/\[/\\:-\[} )
+ tmp=( ${tmp/%(#m):([^:]|\\:)##(|:([^:]|\\:)#)/: :$y$MATCH} )
+ opts+=( $tmp )
+ break
+ done
+done
-[[ -n $state && -n $_ffmpeg_flags[$state] ]] &&
- _ffmpeg_flags $state && return
+# support -/ variant (-/filter:v filter.script) of options with args
+[[ $words[CURRENT] == -/* || $words[CURRENT-1] == -/?* ]] &&
+for (( x = 1; x <= $#opts; x++ )); do
+ [[ $opts[x] == *\]:* ]] || continue
+ [[ $opts[x] == \([' *:-']##\)* ]] && continue # skip -help etc
+ y=${${${${opts[x]#\!}#\(*\)}#\*}%%(\\:|)(-|)\[*} # option name for desc
+ # turn '-c:x:y' into '-/c:...:_files'
+ [[ $opts[x] == \(* ]] && opts[x]=${opts[x]/\)-/\)-/} || opts[x]=${opts[x]/-/-/}
+ opts[x]=${opts[x]/%:([^:]|\\:)##(|:([^:]|\\:)#)/:$y argument value file:_files}
+done
-return 1
+_arguments -S : $opts '*:output file:_files'