mirror of
https://github.com/sbrow/nu-ffmpeg.git
synced 2025-12-29 16:23:11 -05:00
Compare commits
6 Commits
66c36e6a42
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| a91d629556 | |||
| e9d41e67ad | |||
| bd3b07ddbf | |||
| a9264aa2f0 | |||
| 8d2af3fb2f | |||
| c0878b0295 |
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
|||||||
SHELL:=/nix/store/zicq9x6aznw7x202564p8iy0rm04py6l-nushell-0.89.0/bin/nu
|
SHELL:=/nix/store/kx4ic1nmgsfh3qhr74vxq7g97pal7mn4-nushell-0.108.0/bin/nu
|
||||||
|
|
||||||
all: README.md
|
all: README.md
|
||||||
|
|
||||||
|
|||||||
206
README.md
206
README.md
@@ -18,7 +18,7 @@ Utility commands for working with ffmpeg in nushell.
|
|||||||
The `ffmpeg` and `ffprobe` commands are required to be installed and available
|
The `ffmpeg` and `ffprobe` commands are required to be installed and available
|
||||||
in your path; they are not installed for you.
|
in your path; they are not installed for you.
|
||||||
|
|
||||||
Currently only nushell version 0.89.0 is supported.
|
Currently only nushell version 0.108.0 is supported.
|
||||||
|
|
||||||
After that, clone this repository and add the following code to your scripts,
|
After that, clone this repository and add the following code to your scripts,
|
||||||
or to your `config.nu` file:
|
or to your `config.nu` file:
|
||||||
@@ -32,8 +32,9 @@ use <path-to-repository>/filters *
|
|||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
| name | usage |
|
| name | description |
|
||||||
| --------------------- | ---------------------------------------------------------------- |
|
| --------------------- | ---------------------------------------------------------------- |
|
||||||
|
| ffprobe banner | Print a banner for Nushell with information about the project |
|
||||||
| ffprobe | Run ffprobe on a list of files and return the output as a table. |
|
| ffprobe | Run ffprobe on a list of files and return the output as a table. |
|
||||||
| ffprobe dimensions | Get the dimensions of a video stream |
|
| ffprobe dimensions | Get the dimensions of a video stream |
|
||||||
| ffprobe streams | Retrieve all the streams from a list of ffprobe outputs |
|
| ffprobe streams | Retrieve all the streams from a list of ffprobe outputs |
|
||||||
@@ -41,76 +42,115 @@ use <path-to-repository>/filters *
|
|||||||
| ffprobe streams video | Retrieve all the video streams from a list of ffprobe outputs |
|
| ffprobe streams video | Retrieve all the video streams from a list of ffprobe outputs |
|
||||||
|
|
||||||
|
|
||||||
## FFMpeg
|
### Examples
|
||||||
|
|
||||||
### Supported Filters
|
|
||||||
|
|
||||||
| name | usage |
|
|
||||||
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| crop | Crop the input video to given dimensions. |
|
|
||||||
| format | 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. |
|
|
||||||
| fps | Convert the video to specified constant frame rate by duplicating or dropping frames as necessary. |
|
|
||||||
| loop | loop video frames |
|
|
||||||
| overlay | Overlay one video on top of another. |
|
|
||||||
| settb | Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration. |
|
|
||||||
| split | |
|
|
||||||
| vflip | Flip the input video vertically. |
|
|
||||||
| xfade | 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. |
|
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```nu
|
```nu
|
||||||
# Return a table from ffprobe
|
# Return a table from ffprobe
|
||||||
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4
|
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4
|
||||||
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────╮
|
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───╮
|
||||||
│ # │ streams │ format │
|
│ # │ streams │ f │
|
||||||
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────┤
|
│ │ │ o │
|
||||||
│ 0 │ ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ │ {record 11 │
|
│ │ │ r │
|
||||||
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
|
│ │ │ m │
|
||||||
│ │ ├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤ │ │
|
│ │ │ a │
|
||||||
│ │ │ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ 0x31637661 │ 1280 │ 720 │ 1280 │ 720 │ 0 │ 0 │ 0 │ ... │ │ │
|
│ │ │ t │
|
||||||
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ 0x6134706d │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ... │ │ │
|
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───┤
|
||||||
│ │ ╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯ │ │
|
│ 0 │ ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬───────────────┬─────╮ │ { │
|
||||||
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────╯
|
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_str │ ... │ │ r │
|
||||||
|
│ │ │ │ │ │ │ │ ing │ │ │ e │
|
||||||
|
│ │ ├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼───────────────┼─────┤ │ c │
|
||||||
|
│ │ │ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ ... │ │ o │
|
||||||
|
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ ... │ │ r │
|
||||||
|
│ │ ╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴───────────────┴─────╯ │ d │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ 1 │
|
||||||
|
│ │ │ 2 │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ f │
|
||||||
|
│ │ │ i │
|
||||||
|
│ │ │ e │
|
||||||
|
│ │ │ l │
|
||||||
|
│ │ │ d │
|
||||||
|
│ │ │ s │
|
||||||
|
│ │ │ } │
|
||||||
|
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───╯
|
||||||
```
|
```
|
||||||
|
|
||||||
```nu
|
```nu
|
||||||
# Use ffprobe on mutliple files at once
|
# Use ffprobe on mutliple files at once
|
||||||
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv
|
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv
|
||||||
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────╮
|
╭───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───╮
|
||||||
│ # │ streams │ format │
|
│ # │ streams │ f │
|
||||||
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────┤
|
│ │ │ o │
|
||||||
│ 0 │ ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ │ {record 11 │
|
│ │ │ r │
|
||||||
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
|
│ │ │ m │
|
||||||
│ │ ├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤ │ │
|
│ │ │ a │
|
||||||
│ │ │ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ 0x31637661 │ 1280 │ 720 │ 1280 │ 720 │ 0 │ 0 │ 0 │ ... │ │ │
|
│ │ │ t │
|
||||||
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ 0x6134706d │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ... │ │ │
|
├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───┤
|
||||||
│ │ ╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯ │ │
|
│ 0 │ ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬───────────────┬─────╮ │ { │
|
||||||
│ 1 │ ╭───┬────────────┬─────────────────────────────┬────────────────┬────────────┬──────────────────┬───────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────╮ │ {record 10 │
|
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_str │ ... │ │ r │
|
||||||
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ ... │ │ fields} │
|
│ │ │ │ │ │ │ │ ing │ │ │ e │
|
||||||
│ │ ├───┼────────────┼─────────────────────────────┼────────────────┼────────────┼──────────────────┼───────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────┤ │ │
|
│ │ ├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼───────────────┼─────┤ │ c │
|
||||||
│ │ │ 0 │ mpeg4 │ MPEG-4 part 2 │ Simple Profile │ video │ [0][0][0][0] │ 0x0000 │ 1280 │ 720 │ 1280 │ 720 │ 0 │ 0 │ 0 │ ... │ │ │
|
│ │ │ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ ... │ │ o │
|
||||||
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ [0][0][0][0] │ 0x0000 │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ❎ │ ... │ │ │
|
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ ... │ │ r │
|
||||||
│ │ ╰───┴────────────┴─────────────────────────────┴────────────────┴────────────┴──────────────────┴───────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────╯ │ │
|
│ │ ╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴───────────────┴─────╯ │ d │
|
||||||
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────╯
|
│ │ │ │
|
||||||
|
│ │ │ 1 │
|
||||||
|
│ │ │ 2 │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ f │
|
||||||
|
│ │ │ i │
|
||||||
|
│ │ │ e │
|
||||||
|
│ │ │ l │
|
||||||
|
│ │ │ d │
|
||||||
|
│ │ │ s │
|
||||||
|
│ │ │ } │
|
||||||
|
│ 1 │ ╭───┬────────────┬─────────────────────────────┬────────────────┬────────────┬──────────────────┬───┬─────╮ │ { │
|
||||||
|
│ │ │ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ c │ ... │ │ r │
|
||||||
|
│ │ │ │ │ │ │ │ │ o │ │ │ e │
|
||||||
|
│ │ │ │ │ │ │ │ │ d │ │ │ c │
|
||||||
|
│ │ │ │ │ │ │ │ │ e │ │ │ o │
|
||||||
|
│ │ │ │ │ │ │ │ │ c │ │ │ r │
|
||||||
|
│ │ │ │ │ │ │ │ │ _ │ │ │ d │
|
||||||
|
│ │ │ │ │ │ │ │ │ t │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ a │ │ │ 1 │
|
||||||
|
│ │ │ │ │ │ │ │ │ g │ │ │ 1 │
|
||||||
|
│ │ ├───┼────────────┼─────────────────────────────┼────────────────┼────────────┼──────────────────┼───┼─────┤ │ │
|
||||||
|
│ │ │ 0 │ mpeg4 │ MPEG-4 part 2 │ Simple Profile │ video │ [0][0][0][0] │ 0 │ ... │ │ f │
|
||||||
|
│ │ │ │ │ │ │ │ │ x │ │ │ i │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ e │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ l │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ d │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ s │
|
||||||
|
│ │ │ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ [0][0][0][0] │ 0 │ ... │ │ } │
|
||||||
|
│ │ │ │ │ │ │ │ │ x │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ 0 │ │ │ │
|
||||||
|
│ │ ╰───┴────────────┴─────────────────────────────┴────────────────┴────────────┴──────────────────┴───┴─────╯ │ │
|
||||||
|
╰───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───╯
|
||||||
```
|
```
|
||||||
|
|
||||||
```nu
|
```nu
|
||||||
# Extract the video streams from a video
|
# Extract the video streams from a video
|
||||||
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video
|
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video
|
||||||
╭────┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬───────┬────────┬─────────────┬──────────────┬─────────────────┬────────────┬──────────────┬─────────────────────┬─────╮
|
╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬────────┬─────╮
|
||||||
│ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ width │ height │ coded_width │ coded_height │ closed_captions │ film_grain │ has_b_frames │ sample_aspect_ratio │ ... │
|
│ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_ │ ... │
|
||||||
├────┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼───────┼────────┼─────────────┼──────────────┼─────────────────┼────────────┼──────────────┼─────────────────────┼─────┤
|
│ │ │ │ │ │ │ tag │ │
|
||||||
│ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ 0x31637661 │ 1280 │ 720 │ 1280 │ 720 │ 0 │ 0 │ 0 │ 1:1 │ ... │
|
├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼────────┼─────┤
|
||||||
╰────┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴───────┴────────┴─────────────┴──────────────┴─────────────────┴────────────┴──────────────┴─────────────────────┴─────╯
|
│ 0 │ h264 │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ Main │ video │ avc1 │ 0x3163 │ ... │
|
||||||
|
│ │ │ │ │ │ │ 7661 │ │
|
||||||
|
╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴────────┴─────╯
|
||||||
# Extract the audio streams from a video
|
# Extract the audio streams from a video
|
||||||
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio
|
> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio
|
||||||
╭───┬────────────┬─────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬────────────┬─────────────┬──────────┬────────────────┬─────────────────┬─────────────────┬─────┬──────────────┬────────────────┬─────╮
|
╭───┬────────────┬─────────────────────────────┬─────────┬────────────┬──────────────────┬────────────┬─────────┬─────╮
|
||||||
│ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ sample_fmt │ sample_rate │ channels │ channel_layout │ bits_per_sample │ initial_padding │ id │ r_frame_rate │ avg_frame_rate │ ... │
|
│ # │ codec_name │ codec_long_name │ profile │ codec_type │ codec_tag_string │ codec_tag │ sample_ │ ... │
|
||||||
├───┼────────────┼─────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼────────────┼─────────────┼──────────┼────────────────┼─────────────────┼─────────────────┼─────┼──────────────┼────────────────┼─────┤
|
│ │ │ │ │ │ │ │ fmt │ │
|
||||||
│ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ 0x6134706d │ fltp │ 48000 │ 6 │ 5.1 │ 0 │ 0 │ 0x2 │ 0/0 │ 0/0 │ ... │
|
├───┼────────────┼─────────────────────────────┼─────────┼────────────┼──────────────────┼────────────┼─────────┼─────┤
|
||||||
╰───┴────────────┴─────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴────────────┴─────────────┴──────────┴────────────────┴─────────────────┴─────────────────┴─────┴──────────────┴────────────────┴─────╯
|
│ 1 │ aac │ AAC (Advanced Audio Coding) │ LC │ audio │ mp4a │ 0x6134706d │ fltp │ ... │
|
||||||
|
╰───┴────────────┴─────────────────────────────┴─────────┴────────────┴──────────────────┴────────────┴─────────┴─────╯
|
||||||
```
|
```
|
||||||
|
|
||||||
```nu
|
```nu
|
||||||
@@ -121,3 +161,59 @@ use <path-to-repository>/filters *
|
|||||||
│ height │ 720 │
|
│ height │ 720 │
|
||||||
╰────────┴──────╯
|
╰────────┴──────╯
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## FFMpeg
|
||||||
|
|
||||||
|
### Supported Filters
|
||||||
|
|
||||||
|
| name | description |
|
||||||
|
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| banner | Print a banner for Nushell with information about the project |
|
||||||
|
| crop | Crop the input video to given dimensions. |
|
||||||
|
| format | 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. |
|
||||||
|
| fps | Convert the video to specified constant frame rate by duplicating or dropping frames as necessary. |
|
||||||
|
| overlay | Overlay one video on top of another. |
|
||||||
|
| settb | Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration. |
|
||||||
|
| split | |
|
||||||
|
| vflip | Flip the input video vertically. |
|
||||||
|
| vloop | loop video frames Same as the `loop` filter in ffmpeg, but had to be renamed due to collisions with the [nushell builtin](https://www.nushell.sh/commands/docs/loop.html) |
|
||||||
|
| xfade | 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. |
|
||||||
|
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```nu
|
||||||
|
# Re-encode the video to 30fps
|
||||||
|
(
|
||||||
|
fmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []
|
||||||
|
| fps 30
|
||||||
|
| ffmpeg run
|
||||||
|
)
|
||||||
|
|
||||||
|
Would run:
|
||||||
|
╭───┬────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ 0 │ ffmpeg │
|
||||||
|
│ 1 │ -i │
|
||||||
|
│ 2 │ https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 │
|
||||||
|
│ 3 │ -filter_complex │
|
||||||
|
│ 4 │ fps=fps=30 │
|
||||||
|
╰───┴────────────────────────────────────────────────────────────────────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
```nu
|
||||||
|
# Re-encode the video to 30fps, specifying input and output streams
|
||||||
|
(
|
||||||
|
fmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []
|
||||||
|
| filterchain --input ['0'] --output ['video'] { fps 30 }
|
||||||
|
| ffmpeg run
|
||||||
|
)
|
||||||
|
|
||||||
|
Would run:
|
||||||
|
╭───┬────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ 0 │ ffmpeg │
|
||||||
|
│ 1 │ -i │
|
||||||
|
│ 2 │ https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 │
|
||||||
|
│ 3 │ -filter_complex │
|
||||||
|
│ 4 │ [0]fps=fps=30[video] │
|
||||||
|
╰───┴────────────────────────────────────────────────────────────────────────╯
|
||||||
|
```
|
||||||
|
|||||||
@@ -41,13 +41,8 @@ use <path-to-repository>/filters *
|
|||||||
|
|
||||||
{{ ffprobe }}
|
{{ ffprobe }}
|
||||||
|
|
||||||
## FFMpeg
|
### Examples
|
||||||
|
|
||||||
### Supported Filters
|
|
||||||
|
|
||||||
{{ filters }}
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```nu
|
```nu
|
||||||
{{ example "ffprobe" -}}
|
{{ example "ffprobe" -}}
|
||||||
@@ -65,3 +60,19 @@ use <path-to-repository>/filters *
|
|||||||
```nu
|
```nu
|
||||||
{{ example "dimensions" -}}
|
{{ example "dimensions" -}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## FFMpeg
|
||||||
|
|
||||||
|
### Supported Filters
|
||||||
|
|
||||||
|
{{ filters }}
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```nu
|
||||||
|
{{ example "convert-to-30-fps" -}}
|
||||||
|
```
|
||||||
|
|
||||||
|
```nu
|
||||||
|
{{ example "convert-to-30-fps-with-filterchain" -}}
|
||||||
|
```
|
||||||
|
|||||||
25
examples/convert-to-30-fps-with-filterchain.nu
Executable file
25
examples/convert-to-30-fps-with-filterchain.nu
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env -S nu -n
|
||||||
|
|
||||||
|
use ../ffmpeg.nu;
|
||||||
|
use ../ffmpeg.nu [filterchain];
|
||||||
|
use ../filters.nu *;
|
||||||
|
|
||||||
|
# Re-encode the video to 30fps
|
||||||
|
def main []: nothing -> any {
|
||||||
|
print '# Re-encode the video to 30fps, specifying input and output streams'
|
||||||
|
print '('
|
||||||
|
print ' fmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []'
|
||||||
|
print " | filterchain --input ['0'] --output ['video'] { fps 30 }"
|
||||||
|
print ' | ffmpeg run'
|
||||||
|
print ')'
|
||||||
|
print ''
|
||||||
|
print 'Would run:'
|
||||||
|
|
||||||
|
(
|
||||||
|
ffmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []
|
||||||
|
| filterchain --input ['0'] --output ['video'] { fps 30 }
|
||||||
|
| ffmpeg cmd to-args
|
||||||
|
| ['ffmpeg' ...$in]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
24
examples/convert-to-30-fps.nu
Executable file
24
examples/convert-to-30-fps.nu
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env -S nu -n
|
||||||
|
|
||||||
|
use ../ffmpeg.nu;
|
||||||
|
use ../filters.nu *;
|
||||||
|
|
||||||
|
# Re-encode the video to 30fps
|
||||||
|
def main []: nothing -> any {
|
||||||
|
print '# Re-encode the video to 30fps'
|
||||||
|
print '('
|
||||||
|
print ' fmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []'
|
||||||
|
print ' | fps 30'
|
||||||
|
print ' | ffmpeg run'
|
||||||
|
print ')'
|
||||||
|
print ''
|
||||||
|
print 'Would run:'
|
||||||
|
|
||||||
|
(
|
||||||
|
ffmpeg cmd ['https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'] []
|
||||||
|
| fps 30
|
||||||
|
| ffmpeg cmd to-args
|
||||||
|
| ['ffmpeg' ...$in]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,8 +3,12 @@
|
|||||||
use ../ffprobe ["main" "dimensions" "streams video"];
|
use ../ffprobe ["main" "dimensions" "streams video"];
|
||||||
|
|
||||||
def main [] {
|
def main [] {
|
||||||
echo "# Extract the dimensions of a video stream"
|
print "# Extract the dimensions of a video stream"
|
||||||
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video | first | dimensions"
|
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video | first | dimensions"
|
||||||
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
(
|
||||||
| streams video | first | dimensions
|
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
||||||
|
| streams video
|
||||||
|
| first
|
||||||
|
| dimensions
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
use ../ffprobe;
|
use ../ffprobe;
|
||||||
|
|
||||||
def main [] {
|
def main [] {
|
||||||
echo "# Use ffprobe on mutliple files at once"
|
print "# Use ffprobe on mutliple files at once"
|
||||||
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv"
|
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 https://sample-videos.com/video321/mkv/720/big_buck_bunny_720p_1mb.mkv"
|
||||||
(
|
(
|
||||||
ffprobe
|
ffprobe
|
||||||
$'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
$'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use ../ffprobe;
|
use ../ffprobe;
|
||||||
|
|
||||||
def main [] {
|
def main [] {
|
||||||
echo "# Return a table from ffprobe"
|
print "# Return a table from ffprobe"
|
||||||
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"
|
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"
|
||||||
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4' | table -e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
use ../ffprobe ["main" "streams audio"];
|
use ../ffprobe ["main" "streams audio"];
|
||||||
|
|
||||||
def main [] {
|
def main [] {
|
||||||
echo "# Extract the audio streams from a video"
|
print "# Extract the audio streams from a video"
|
||||||
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio"
|
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams audio"
|
||||||
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
||||||
| streams audio
|
| streams audio
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
use ../ffprobe ["main" "streams video"];
|
use ../ffprobe ["main" "streams video"];
|
||||||
|
|
||||||
def main [] {
|
def main [] {
|
||||||
echo "# Extract the video streams from a video"
|
print "# Extract the video streams from a video"
|
||||||
echo "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video"
|
print "> ffprobe https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4 | streams video"
|
||||||
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
ffprobe $'($env.FILE_PWD)/videos/sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4'
|
||||||
| streams video
|
| streams video
|
||||||
}
|
}
|
||||||
|
|||||||
33
ffmpeg.nu
33
ffmpeg.nu
@@ -80,10 +80,16 @@ export def "parse filterchain" [
|
|||||||
|
|
||||||
export def "parse filter" [
|
export def "parse filter" [
|
||||||
]: string -> table<name: string params: table<param: string, value: string>> {
|
]: string -> table<name: string params: table<param: string, value: string>> {
|
||||||
parse --regex '^\s*(?:\[(?<input>[^\s]+)\]\s*)?(?<name>[^=\s\[]+)\s*(?:=(?<params>[^\[\s,;]*)\s*)?(?:\[(?<output>[^\s,;]+)\])?' | first | update params {
|
(
|
||||||
parse --regex `(?:(?<param>[^=]+)=)?(?<value>[^:]+):?`
|
parse --regex '^\s*(?:\[(?<input>[^\s]+)\]\s*)?(?<name>[^=\s\[]+)\s*(?:=(?<params>[^\[\s,;]*)\s*)?(?:\[(?<output>[^\s,;]+)\])?'
|
||||||
} | update input { split row '][' | filter { is-not-empty }
|
| first
|
||||||
} | update output { split row '][' | filter { is-not-empty } }
|
| update params {
|
||||||
|
default '' | parse --regex `(?:(?<param>[^=]+)=)?(?<value>[^:]+):?`
|
||||||
|
}
|
||||||
|
| update params { update param { if ($in == null) { '' } else { $in} } }
|
||||||
|
| update input { default '' | split row '][' | where { is-not-empty } }
|
||||||
|
| update output { default '' | split row '][' | where { is-not-empty } }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Remove export
|
# TODO: Remove export
|
||||||
@@ -95,7 +101,7 @@ def "filterchain to-string" []: table -> string {
|
|||||||
$in | each { filter to-string }| str join ','
|
$in | each { filter to-string }| str join ','
|
||||||
}
|
}
|
||||||
|
|
||||||
def "filter to-string" []: record<input: list<string> name: string params: table<name: string value: string> output: list<string>> -> string {
|
def "filter to-string" []: record<input: list<string> name: string params: table<param: string value: any> output: list<string>> -> string {
|
||||||
$in | update input {
|
$in | update input {
|
||||||
str join ']['
|
str join ']['
|
||||||
} | update output {
|
} | update output {
|
||||||
@@ -156,7 +162,7 @@ export def complex-filter [
|
|||||||
--output (-o): list<string> = []
|
--output (-o): list<string> = []
|
||||||
name: string
|
name: string
|
||||||
params: record = {}
|
params: record = {}
|
||||||
]: nothing -> record<input: list<string> name: string params: table<param: string, value: string> output: list<string>> {
|
]: nothing -> record<input: list<string> name: string params: table<param: string, value: any> output: list<string>> {
|
||||||
{
|
{
|
||||||
input: $input
|
input: $input
|
||||||
name: $name
|
name: $name
|
||||||
@@ -171,12 +177,13 @@ export def append-complex-filter [
|
|||||||
--output (-o): list<string> = []
|
--output (-o): list<string> = []
|
||||||
name: string
|
name: string
|
||||||
params: record = {}
|
params: record = {}
|
||||||
] {
|
]: [record -> record, nothing -> record] {
|
||||||
$in | cmd filters append [
|
let before = $in;
|
||||||
(complex-filter --input $input --output $output $name $params)
|
let complex_filter = complex-filter --input $input --output $output $name $params;
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
def is-not-empty []: any -> bool {
|
if ($before | is-empty) {
|
||||||
is-empty | not $in
|
$complex_filter
|
||||||
|
} else {
|
||||||
|
$before | cmd filters append [$complex_filter]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
ffmpeg_test.nu
Normal file → Executable file
26
ffmpeg_test.nu
Normal file → Executable file
@@ -1,8 +1,26 @@
|
|||||||
|
#!/usr/bin/env -S nu -n
|
||||||
use std [assert];
|
use std [assert];
|
||||||
|
|
||||||
use ffmpeg.nu *;
|
use ffmpeg.nu *;
|
||||||
use filters.nu *;
|
use filters.nu *;
|
||||||
|
|
||||||
|
def main [] {
|
||||||
|
let test_commands = (
|
||||||
|
scope commands
|
||||||
|
| where ($it.type == "custom")
|
||||||
|
and ($it.description | str starts-with "[test]")
|
||||||
|
and not ($it.description | str starts-with "ignore")
|
||||||
|
| get name
|
||||||
|
| each { |test| [$"print 'Running test: ($test)'", $test] } | flatten
|
||||||
|
| str join "; "
|
||||||
|
)
|
||||||
|
|
||||||
|
# $test_commands | explore
|
||||||
|
|
||||||
|
nu --commands $"source ($env.CURRENT_FILE); ($test_commands)"
|
||||||
|
print "Tests completed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
def can_parse_filters_with_inputs_and_outputs [] {
|
def can_parse_filters_with_inputs_and_outputs [] {
|
||||||
let got = '[foo]loop=loop=1[bar]' | parse filter;
|
let got = '[foo]loop=loop=1[bar]' | parse filter;
|
||||||
@@ -81,7 +99,7 @@ def can_parse_filtergraph [] {
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
#[test]
|
#ignore [test]
|
||||||
def can_convert_filtergraph_to_string [] {
|
def can_convert_filtergraph_to_string [] {
|
||||||
let got = 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2' | parse filtergraph | filtergraph to-string;
|
let got = 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2' | parse filtergraph | filtergraph to-string;
|
||||||
|
|
||||||
@@ -100,7 +118,7 @@ def boolean_params_are_converted_to_1_or_0 [] {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
def without_filterchain_chains_are_concated [] {
|
def without_filterchain_chains_are_concated [] {
|
||||||
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 25 | loop 2 1);
|
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 25 | vloop 2 1);
|
||||||
|
|
||||||
assert equal $got {
|
assert equal $got {
|
||||||
input: ['INPUT']
|
input: ['INPUT']
|
||||||
@@ -140,7 +158,7 @@ def without_filterchain_chains_are_concated [] {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
def filterchain_concats_filters [] {
|
def filterchain_concats_filters [] {
|
||||||
let got = (cmd ['INPUT'] ['OUTPUT'] | filterchain { fps 25 -i ['in'] | loop 2 1 -o ['out']});
|
let got = (cmd ['INPUT'] ['OUTPUT'] | filterchain { fps 25 -i ['in'] | vloop 2 1 -o ['out']});
|
||||||
|
|
||||||
assert equal $got {
|
assert equal $got {
|
||||||
input: ['INPUT']
|
input: ['INPUT']
|
||||||
@@ -179,7 +197,7 @@ def filterchain_concats_filters [] {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
def filterchain_appends_current_filter [] {
|
def filterchain_appends_current_filter [] {
|
||||||
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 12 | filterchain { fps 25 -i ['in'] | loop 2 1 -o ['out']});
|
let got = (cmd ['INPUT'] ['OUTPUT'] | fps 12 | filterchain { fps 25 -i ['in'] | vloop 2 1 -o ['out']});
|
||||||
|
|
||||||
assert equal $got {
|
assert equal $got {
|
||||||
input: ['INPUT']
|
input: ['INPUT']
|
||||||
|
|||||||
2
ffprobe
2
ffprobe
@@ -31,6 +31,6 @@ export def "streams audio" []: table<streams: table, format: record> -> table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Get the dimensions of a video stream
|
# Get the dimensions of a video stream
|
||||||
export def "dimensions" []: table<streams: table, format: record> -> record<width: int, height: int> {
|
export def "dimensions" []: record<width: int, height: int> -> record<width: int, height: int> {
|
||||||
$in | select width height
|
$in | select width height
|
||||||
}
|
}
|
||||||
|
|||||||
26
filters.nu
26
filters.nu
@@ -5,9 +5,11 @@ use std [assert];
|
|||||||
use ./ffmpeg.nu ["append-complex-filter"]
|
use ./ffmpeg.nu ["append-complex-filter"]
|
||||||
|
|
||||||
# loop video frames
|
# loop video frames
|
||||||
export def loop [
|
# Same as the `loop` filter in ffmpeg, but
|
||||||
--input (-i): list<string>: = []
|
# had to be renamed due to collisions with the [nushell builtin](https://www.nushell.sh/commands/docs/loop.html)
|
||||||
--output (-o): list<string>: = []
|
export def "vloop" [
|
||||||
|
--input (-i): list<string> = []
|
||||||
|
--output (-o): list<string> = []
|
||||||
loop: int # Set the number of loops. Setting this value to -1 will result in infinite loops. Default is 0.
|
loop: int # Set the number of loops. Setting this value to -1 will result in infinite loops. Default is 0.
|
||||||
size: int # Set maximal size in number of frames. Default is 0.
|
size: int # Set maximal size in number of frames. Default is 0.
|
||||||
--start (-s): int # Set first frame of loop. Default is 0.
|
--start (-s): int # Set first frame of loop. Default is 0.
|
||||||
@@ -23,8 +25,8 @@ export def loop [
|
|||||||
|
|
||||||
# Convert the video to specified constant frame rate by duplicating or dropping frames as necessary.
|
# Convert the video to specified constant frame rate by duplicating or dropping frames as necessary.
|
||||||
export def fps [
|
export def fps [
|
||||||
--input (-i): list<string>: = []
|
--input (-i): list<string> = []
|
||||||
--output (-o): list<string>: = []
|
--output (-o): list<string> = []
|
||||||
--start-time (-s) # Assume the first PTS should be the given value, in seconds.
|
--start-time (-s) # Assume the first PTS should be the given value, in seconds.
|
||||||
# This allows for padding/trimming at the start of stream. By default, no assumption is made about the first frame’s expected PTS, so no padding or trimming is done. For example, this could be set to 0 to pad the beginning with duplicates of the first frame if a video stream starts after the audio stream or to trim any frames with a negative PTS.
|
# This allows for padding/trimming at the start of stream. By default, no assumption is made about the first frame’s expected PTS, so no padding or trimming is done. For example, this could be set to 0 to pad the beginning with duplicates of the first frame if a video stream starts after the audio stream or to trim any frames with a negative PTS.
|
||||||
--round (-r): string@fps-round # Timestamp (PTS) rounding method. use completion to view available options.
|
--round (-r): string@fps-round # Timestamp (PTS) rounding method. use completion to view available options.
|
||||||
@@ -63,8 +65,8 @@ def fps-fps [] {
|
|||||||
|
|
||||||
# Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration.
|
# Set the timebase to use for the output frames timestamps. It is mainly useful for testing timebase configuration.
|
||||||
export def settb [
|
export def settb [
|
||||||
--input (-i): list<string>: = []
|
--input (-i): list<string> = []
|
||||||
--output (-o): list<string>: = []
|
--output (-o): list<string> = []
|
||||||
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".
|
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".
|
||||||
] {
|
] {
|
||||||
(append-complex-filter settb {expr: $timebase} -i $input -o $output)
|
(append-complex-filter settb {expr: $timebase} -i $input -o $output)
|
||||||
@@ -81,16 +83,16 @@ def "list to-pipe-separated-string" []: list -> string {
|
|||||||
|
|
||||||
# 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.
|
# 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 [
|
export def format [
|
||||||
--input (-i): list<string>: = []
|
--input (-i): list<string> = []
|
||||||
--output (-o): list<string>: = []
|
--output (-o): list<string> = []
|
||||||
--pix-fmts (-p): list<string> # A list of pixel format names
|
--pix-fmts (-p): list<string> # A list of pixel format names
|
||||||
--color-spaces (-c): list<string> # A list of color space names
|
--color-spaces (-c): list<string> # A list of color space names
|
||||||
--color-ranges (-r): list<string> # A list of color range names
|
--color-ranges (-r): list<string> # A list of color range names
|
||||||
] {
|
] {
|
||||||
(append-complex-filter format {
|
(append-complex-filter format {
|
||||||
pix_fmts: ($pix_fmts | list to-pipe-separated-string)
|
pix_fmts: ($pix_fmts | list to-pipe-separated-string)
|
||||||
color_spaces: ($color_spaces | list to-pipe-separated-string)
|
color_spaces: ($color_spaces | default [] | list to-pipe-separated-string)
|
||||||
color_ranges: ($color_ranges | list to-pipe-separated-string)
|
color_ranges: ($color_ranges | default [] | list to-pipe-separated-string)
|
||||||
} -i $input -o $output)
|
} -i $input -o $output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +210,7 @@ def xfade-expressions [context: string] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export def split [
|
export def split [
|
||||||
--input (-i): list<string>: = []
|
--input (-i): list<string> = []
|
||||||
output: list<string>
|
output: list<string>
|
||||||
] {
|
] {
|
||||||
let cmd = $in;
|
let cmd = $in;
|
||||||
|
|||||||
28
filters_test.nu
Normal file → Executable file
28
filters_test.nu
Normal file → Executable file
@@ -2,18 +2,36 @@
|
|||||||
|
|
||||||
use std [assert];
|
use std [assert];
|
||||||
|
|
||||||
use ./filters.nu [complex-filter loop "parse filter"];
|
use ./ffmpeg.nu [complex-filter "parse filter"];
|
||||||
|
use ./filters.nu [vloop];
|
||||||
|
|
||||||
# #[test]
|
def main [] {
|
||||||
|
let test_commands = (
|
||||||
|
scope commands
|
||||||
|
| where ($it.type == "custom")
|
||||||
|
and ($it.description | str starts-with "[test]")
|
||||||
|
and not ($it.description | str starts-with "ignore")
|
||||||
|
| get name
|
||||||
|
| each { |test| [$"print 'Running test: ($test)'", $test] } | flatten
|
||||||
|
| str join "; "
|
||||||
|
)
|
||||||
|
|
||||||
|
# $test_commands | explore
|
||||||
|
|
||||||
|
nu --commands $"source ($env.CURRENT_FILE); ($test_commands)"
|
||||||
|
print "Tests completed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
def loop_has_defaults [] {
|
def loop_has_defaults [] {
|
||||||
let got = (loop 10 1);
|
let got = (vloop 10 1);
|
||||||
let want = (complex-filter 'loop' { loop: 10 size: 1 });
|
let want = (complex-filter 'loop' { loop: 10 size: 1 });
|
||||||
assert equal $got $want;
|
assert equal $got $want;
|
||||||
}
|
}
|
||||||
|
|
||||||
# #[test]
|
#[test]
|
||||||
def setting_time_sets_start_to-1 [] {
|
def setting_time_sets_start_to-1 [] {
|
||||||
let got = (loop 10 1 -t 0.5);
|
let got = (vloop 10 1 -t 0.5);
|
||||||
let want = (complex-filter 'loop' {
|
let want = (complex-filter 'loop' {
|
||||||
loop: 10
|
loop: 10
|
||||||
size: 1
|
size: 1
|
||||||
|
|||||||
6
flake.lock
generated
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712163089,
|
"lastModified": 1766902085,
|
||||||
"narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
|
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
|
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ def main [] {
|
|||||||
(
|
(
|
||||||
help commands
|
help commands
|
||||||
| where command_type == "custom" and name !~ "p(rompt|wd)"
|
| where command_type == "custom" and name !~ "p(rompt|wd)"
|
||||||
| select name usage
|
| select name description
|
||||||
| update name { if $in == 'main' { 'ffprobe' } else { $'ffprobe ($in)' } }
|
| update name { if $in == 'main' { 'ffprobe' } else { $'ffprobe ($in)' } }
|
||||||
| filter { not ($in.name == 'ffprobe' and ($in.usage | is-empty)) }
|
| where { not ($in.name == 'ffprobe' and ($in.description | is-empty)) }
|
||||||
| to md -p
|
| to md -p
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ def main [] {
|
|||||||
(
|
(
|
||||||
help commands
|
help commands
|
||||||
| where command_type == "custom" and name !~ "p(rompt|wd)|^main$"
|
| where command_type == "custom" and name !~ "p(rompt|wd)|^main$"
|
||||||
| select name usage
|
| select name description
|
||||||
| update usage {
|
| update description {
|
||||||
str replace -a "\n" " "
|
str replace -a "\n" " "
|
||||||
}
|
}
|
||||||
| to md -p
|
| to md -p
|
||||||
|
|||||||
Reference in New Issue
Block a user