#compdef ffmpeg # 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 # 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} } # `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%?} } # 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 } # 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 } # 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" )' -r: -S: "${(@)ca_opts}" \ -- \ '( u:"usable configuration" )' "${(@)ca_opts}" && ret=0 return ret fi } # 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" )' -r: -S: \ -- \ '( g:"global metadata" )' fi } # 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 } # 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 _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 } # 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}" } # 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 } # 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 zparseopts -A opth -D -F - \ {1+,2+,F+:,J+:,M+:,n+,o+:,q+,r+:,R+:,s+:,S+:,V+:,x+:,X+:}=ca_opts \ H \ || return pixfmts=( ${(f)"$( _call_program $tag $words[1] -pix_fmts )"} ) pixfmts=( ${(M)pixfmts:#[BHIOP. ](#c5) [^=]* *} ) (( ${+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}" } # 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 } # 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%%[@:,]*}#*=}} ) _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 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 )' "$@" } # 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" )' -r: -S: 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" )' -r= -S= 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 # 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 # 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 _arguments -S : $opts '*:output file:_files'