diff --git a/ffmpeg.nu b/ffmpeg.nu index 6b664a5..02fe1b1 100644 --- a/ffmpeg.nu +++ b/ffmpeg.nu @@ -67,8 +67,8 @@ export def "parse filter" [ ]: string -> table> { parse --regex '^\s*(?:\[(?[^\s]+)\]\s*)?(?[^=\s\[]+)\s*(?:=(?[^\[\s,;]*)\s*)?(?:\[(?[^\s,;]+)\])?' | first | update params { parse --regex `(?:(?[^=]+)=)?(?[^:]+):?` - } | update input { split row '][' | filter { not ($in | is-empty) } - } | update output { split row '][' | filter { not ($in | is-empty) } } + } | update input { split row '][' | filter { is-not-empty } + } | update output { split row '][' | filter { is-not-empty } } } # TODO: Remove export @@ -115,14 +115,14 @@ export def filterchain [ } } | do $filter - | if ($input | is-empty | not $in) { + | if ($input | is-not-empty) { update filters { update (($in | length) - 1) { update 0.input $input } } } else { $in } - | if ($output | is-empty | not $in) { + | if ($output | is-not-empty) { update filters { update (($in | length) - 1) { update (($in | length) - 1) { @@ -149,3 +149,19 @@ export def complex-filter [ output: $output } } + +# Appends a single complex-filter to the end of the command's filtergraph +export def append-complex-filter [ + --input (-i): list = [] + --output (-o): list = [] + name: string + params: record = {} +] { + $in | cmd filters append [ + (complex-filter --input $input --output $output $name $params) + ] +} + +def is-not-empty []: any -> bool { + is-empty | not $in +} diff --git a/filters.nu b/filters.nu index f0457ef..654c677 100755 --- a/filters.nu +++ b/filters.nu @@ -52,6 +52,124 @@ def fps-round-options [] { 'near' ] } + +# Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration. +export def settb [ + --input (-i): list: = [] + --output (-o): list: = [] + timebase # The value for tb is an arithmetic expression representing a rational. The expression can contain the constants "AVTB" (the default timebase), "intb" (the input timebase) and "sr" (the sample rate, audio only). Default value is "intb". + ] { + cmd filters append [ + (complex-filter settb {expr: $timebase} -i $input -o $output) + ] +} + +# TODO: Refactor "list to-pipe-separated-string" +def "list to-pipe-separated-string" []: list -> string { + let list = $in; + + if ($list | length) > 0 { + $list | str join '|' + } +} + +# Convert the input video to one of the specified pixel formats. Libavfilter will try to pick one that is suitable as input to the next filter. +export def format [ + --input (-i): list: = [] + --output (-o): list: = [] + --pix-fmts (-p): list # A list of pixel format names + --color-spaces (-c): list # A list of color space names + --color-ranges (-r): list # A list of color range names + ] { + cmd filters append [ + (complex-filter format { + pix_fmts: ($pix_fmts | list to-pipe-separated-string) + color_spaces: ($color_spaces | list to-pipe-separated-string) + color_ranges: ($color_ranges | list to-pipe-separated-string) + } -i $input -o $output) + ] +} + +# Apply cross fade from one input video stream to another input video stream. The cross fade is applied for specified duration. +# Both inputs must be constant frame-rate and have the same resolution, pixel format, frame rate and timebase. +export def xfade [ + --input (-i): list = [] + --output (-o): list = [] + --transition (-t): string@xfade-transitions = fade # Set one of available transition effects (activate completion to view) + --duration (-d): float = 1.0 # Set cross fade duration in seconds. Range is 0 to 60 seconds. Default duration is 1 second. + --offset (-O): float = 0.0 # Set cross fade start relative to first input stream in seconds. Default offset is 0. + --expr (-e): string +] { + cmd filters append [ + (complex-filter xfade -i $input -o $output { transition: $transition duration: $duration offset: $offset expr: $expr }) + ] +} + +# List of available transition effects +def xfade-transitions [] { + [ + 'custom' + 'fade' + 'wipeleft' + 'wiperight' + 'wipeup' + 'wipedown' + 'slideleft' + 'slideright' + 'slideup' + 'slidedown' + 'circlecrop' + 'rectcrop' + 'distance' + 'fadeblack' + 'fadewhite' + 'radial' + 'smoothleft' + 'smoothright' + 'smoothup' + 'smoothdown' + 'circleopen' + 'circleclose' + 'vertopen' + 'vertclose' + 'horzopen' + 'horzclose' + 'dissolve' + 'pixelize' + 'diagtl' + 'diagtr' + 'diagbl' + 'diagbr' + 'hlslice' + 'hrslice' + 'vuslice' + 'vdslice' + 'hblur' + 'fadegrays' + 'wipetl' + 'wipetr' + 'wipebl' + 'wipebr' + 'squeezeh' + 'squeezev' + 'zoomin' + 'fadefast' + 'fadeslow' + 'hlwind' + 'hrwind' + 'vuwind' + 'vdwind' + 'coverleft' + 'coverright' + 'coverup' + 'coverdown' + 'revealleft' + 'revealright' + 'revealup' + 'revealdown' + ] +} + export def split [ --input (-i): list: = [] output: list