Skip to main content

ffswak

A Python wrapper for ffmpeg that simplifies common video editing tasks.

Things you can do:

  • Scale the video so that it isn't too large
  • Extract a short clip from a long video
  • Rotate the video, automatically zooming so that there are no black spaces on the sides
  • Stabilize a shaky video
  • Crop to zoom in on part of the video
  • Re-encode the video using the HEVC encoder (h265)

Getting Started

Make sure you have ffmpeg and ffprobe installed, and that you have Python 3.11 or newer:

ffmpeg -version
ffprobe -version
python3 --version

Install uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

Or on macOS:

brew install uv

Then install ffswak from PyPI:

uv tool install ffswak

Alternatively, with pipx:

pipx install ffswak

Or with pip in a virtual environment:

python3 -m pip install ffswak

To try ffswak without installing a persistent command, run it in uv's isolated, cached environment:

uvx ffswak --help

FFmpeg and ffprobe must still be installed separately. On macOS, use ffmpeg-full for stabilization support; see the FFmpeg setup instructions.

Use -D to choose output dimensions and -O to choose the output directory.

Test it out:

ffswak --help

Usage Examples

Example 1: Scale and re-encode one video

ffswak input.mov

Scale down the video to fit in 1920x1080 (or 1080x1920 if it's a portrait video). Re-encode with the HEVC codec, using the same video bitrate. Re-encode the audio using the AAC codec, if the bitrate is higher than 192k. Save the output to ~/Pictures/Import, generating a new filename if the file already exists. Keep the pixel format, bit depth, frame rate, etc. the same.

If the resulting file is less than 10% smaller, issue a warning. If it's less than 2% smaller (or even larger!) copy the input file to the output location and issue a warning.

Example 2: Join clips from two videos, with a fade transition

ffswak input1.mov -10 input2.mp4 0:15-1:10

Same as above, but join portions of two videos with a .5s fade transition. When possible, the time ranges will be increased by .5s so that the part you care about isn't lost in the transition. If a time is omitted, such as -10 or 10-, it implies the start or end of the input. You can also specify multiple time ranges for a single input, such as input.mov 5-10 15-20.

If one video is 1280x720 and the other is 720x1280, the resulting output will be 1280x1080, with black bars. (1280 wide because the 1280x720 is less than 1920x1080, but only 1080 high because 720x1280 is taller than the default max size of 1920x1080.) The output frame rate, pixel format, video/audio bitrates, etc. will be the maximum of the values from the input files.

Example 3: Stabilize and join multiple videos

ffswak -s input1.mov input2.mov

Stabilize all the videos and join them. The output file will be named input1-input2.mp4.

Example 4: Global versus per-input options

ffswak -O ~/Desktop -v 2 -- input1.mov -s input2.mov

Increase the volume of all the videos by 100%, but stabilize only the second video. Write the output file to the ~/Desktop directory.

Use the -- syntax whenever you need to specify per-input options. Global options go before the --. Per-input options go before the file name, and any time ranges go after the file name.

Example 5: Cropping and slowing one clip

ffswak -- input.mov 0-10 -cs .5 -cl bc -s .5 input.mov 10-15 input.mov 15-20

For a 5-second clip in the middle, slow it down 50% and crop it to be 50% of the original size, centered on the bottom center of the original image.

All Options

This help message shows all of the options

usage: ffswak [global options] -- [per-file options] input_file [time_ranges ...] [ [per-file options] input_file [time_ranges... ] ... ]

A Python wrapper for ffmpeg that simplifies common video editing tasks.

TIME FORMAT is [[HH:]MM:]SS[.frac] or NNN[.frac] or .frac. Time ranges do not include
transition times. A warning will be issued if the end of an input file requires the transition to
include part of the specified time range.

Global options apply to all files. Video options override global options for a specific
file. "--" can be omitted if there are no per-video options.

Global-Only Options:
  General options, and options for the output video.

  -F, --frame-rate-limit FRAME_RATE_LIMIT
                        Maximum frame rate.
  -D, --dimensions-limit DIMENSIONS_LIMIT
                        Maximum dimensions. .5 means 50% as wide and tall; .5,1 means half as wide, full height; 16:9 means the largest possible video with that aspect ratio;
                        1280x720 means exactly that size
  -o, --output-file OUTPUT_FILE
                        Output file. Relative paths use -O if specified, otherwise the current directory.
                        Absolute paths override -O. Existing filenames get a random suffix.
  -O, --output-dir OUTPUT_DIR
                        Output directory, also used as the base for relative -o paths.
                        Without -o, defaults to the configured output directory.
  -d, --debug           Enable debugging messages
  --help                Show this help message and exit.

Video Options:
  Options for videos. Can be specified at the global or per-video level.

  -cl, --crop-location CROP_LOCATION
                        Cropped portion should be in the top/middle/bottom and left/center/right. ".2,.3" means 20% over from the left, and 30% down from the top. 100% means
                        the right side of the crop window will be aligned with the right side of the original video.
  -cs, --crop-size CROP_SIZE
                        Cropped portion size. .5 means 50% as wide and tall; .5,1 means half as wide, full height; 1280x720 means exactly that size
  -p, --speedup SPEEDUP
                        Change the speed. 2 means twice as fast. Audio tempo is adjusted to match.
  -r, --rotate ROTATE   Rotate the video, cropping as needed. Positive values are clockwise.
  -v, --volume VOLUME   Modify volume level. 2 means twice as loud. 0 means omit the audio track.
  -s, --stabilize       Stabilize the video
  -t, --tripod TRIPOD   Enable tripod mode, stabilizing on the time specified in TIME FORMAT.
  -R, --reverse         Reverse the video.
  -T, --transition-duration TRANSITION_DURATION
                        Transition duration when concatenating ranges, in TIME FORMAT.
  -I, --interlace-test  Enable testing the video for interlacing.

Generally speaking, bitrate, frame rate, etc. will be chosen to avoid degrading the quality.
Width and height will be automatically adjusted (with a warning) when it's obvious that they are
wrong. e.g. Width and height will be swapped when all the inputs are portrait instead of landscape.

Known Issues and Limitations

iPhones produce extra metadata streams. Those get lost if the file is re-encoded. ffswak preserves a small whitelist of global descriptive tags only when all non-blank source values agree. (Missing values do not prevent preservation.) It computes creation_time from the earliest selected source clip (each file's recording time plus the start offset of each clip). The whitelist includes GPS/location tags for personal-media use, so remove location metadata before sharing a video if you do not want to disclose where it was recorded. Alternatively, remove location tags from PRESERVED_METADATA_KEYS in the script. Run ffprobe on the input and output to compare metadata.

I add features as I need them. Feel free to suggest enhancements or report problems in the issue tracker.

Author

David Coppit <david@coppit.org>

License

ffswak is licensed under the GNU General Public License, version 3 only. See LICENSE. Its interlace-detection policy is adapted from mpv's TOOLS/idet.sh, which is GPL-2.0-or-later and therefore compatible with GPL-3.0.

Development

See CONTRIBUTING.md for the development setup and checks. The detailed regression-test guide is in tests/README.md. Maintainers can find release instructions in DEVELOPMENT.md.

Metadata

Release files for ffswak 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ffswak 0.1.1
File Size Uploaded
ffswak-0.1.1.tar.gz 65.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ffswak 0.1.1
File Interpreter ABI Platform
ffswak-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 114.4 kB

Release files / ffswak-0.1.1.tar.gz

Download URL ffswak-0.1.1.tar.gz
Size 65.9 kB
Tags Source
SHA-256 checksum
How to use checksums
eebc88ec3608d7d87e869ab018dcbb77ad342a0b733e6117aca96e73448c364f
BLAKE2b-256 checksum
How to use checksums
dd87361d72bf6441ff770cabbd523d58107b9d42ae5e09eccba91edb123454f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ffswak-0.1.1-py3-none-any.whl

Download URL ffswak-0.1.1-py3-none-any.whl
Size 48.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8ce670d47eaf68f5761ffb906c37f3fd4212585c3386c613793031dbbf54dac6
BLAKE2b-256 checksum
How to use checksums
a483c5d596b81acd34e6726dd8db09f44705c7accda1af26e811b502b97f2d1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page