shrivel
A small cross-platform command-line tool that transcodes videos to
H.265/HEVC or AV1 by orchestrating FFmpeg. HEVC is the
default; select AV1 with --codec av1. Point it at a folder
of videos and it shrinks them, picking a quality target per file based on the
source bitrate.
Requirements
ffmpegandffprobeavailable in yourPATH.- Rust (2024 edition) to build from source.
Installation
Or build without installing:
# binary: target/release/shrivel
Usage
# Recursively convert every .mp4 in ./input into ./output
# Custom folders and quality
# Convert one file into the output directory
# Resample to 30 fps, denoise, and skip files already using the selected codec
# Scale to 1280 pixels width, resample, and denoise
# Process several container types, forcing the CPU encoder
# Encode to AV1 (auto-select hardware when usable, otherwise SVT-AV1 on CPU)
# Preview the FFmpeg commands without running them
When the input is a directory, it is searched recursively. Converted files
keep their paths relative to the input folder, and the corresponding
subdirectories are created inside the output folder. For example,
input/trips/day1.mp4 is written to output/trips/day1.mp4. When the input is
a single video file, it is written directly inside the output directory with
the same filename.
Options
| Option | Default | Description |
|---|---|---|
--codec <CODEC> |
hevc |
Output codec: hevc or av1. |
-i, --input <FILE_OR_DIR> |
input |
Video file or directory containing source videos. |
-o, --output <DIR> |
output |
Directory for converted videos (created if missing). Must differ from the input directory. |
--cq <N> |
26 |
Base constant-quality value, 0-51. Lower means better quality and larger files. |
--fps <FPS> |
source | Target frame rate. The source frame rate is kept when omitted. |
--skip-same-codec |
off | Skip files already using the selected output codec. |
--denoise |
off | Apply a light hqdn3d=3:3:8:8 denoise filter. |
--scale <WIDTH> |
source | Target width for scaling. Height is calculated proportionally. Uses bicubic interpolation. |
-e, --encoder <NAME> |
auto |
One of auto, nvenc, qsv, amf, videotoolbox, software; available choices depend on the codec. |
--ext <EXT,...> |
mp4 |
Comma-separated input extensions, matched case-insensitively. |
--skip-existing |
off | Skip files whose output already exists instead of overwriting them. |
--dry-run |
off | Print the FFmpeg commands without running them. |
The process exits with a non-zero status if at least one file failed to convert.
How it works
For each input file shrivel:
-
Runs
ffprobeto read the video codec, bitrate and frame rate. If the video stream has no bitrate (common in Matroska files), the container bitrate is used instead. -
Optionally skips the file when it already uses the selected codec (
--skip-same-codec). -
Adapts the quality value to the source bitrate. Heavily compressed sources gain little from a strict target, so the value is relaxed to avoid inflating the output:
Source bitrate Effective CQ unknown base below 3000 kbit/s base + 4 3000 to 5999 kbit/s base + 2 6000 kbit/s or more base The result is capped at 51.
-
Builds the video filter chain (denoise, then frame-rate change). A frame-rate change is applied only when the source differs from the target by more than 0.5 fps, and it forces constant-frame-rate output to avoid leftover variable-frame-rate drift.
-
Runs FFmpeg, mapping the first video stream and all audio streams. Audio is copied without re-encoding. Other streams (subtitles, data) are dropped.
-
Reports the input and output sizes. If FFmpeg fails, the partial output file is removed and the first lines of FFmpeg's error output are shown.
HEVC files in .mp4, .m4v and .mov outputs are tagged hvc1 so they play
on Apple devices. AV1 outputs do not receive this HEVC-specific tag.
Encoders
With --encoder auto (the default), shrivel tries each hardware encoder
supported by the selected codec in turn by encoding one tiny synthetic frame,
and uses the first one that works. If none works it uses software x265 for
HEVC or SVT-AV1 for AV1. An encoder being listed by
ffmpeg -encoders is not enough, because hardware encoders are often compiled
in but unusable on the current machine.
| Encoder | FFmpeg codec | Notes |
|---|---|---|
nvenc |
hevc_nvenc, av1_nvenc |
NVIDIA GPUs; AV1 requires supported GPU/driver. |
videotoolbox |
hevc_videotoolbox |
macOS; HEVC only. CQ maps approximately to VideoToolbox's -q:v scale. |
qsv |
hevc_qsv, av1_qsv |
Intel Quick Sync; AV1 requires supported hardware/runtime. |
amf |
hevc_amf, av1_amf |
AMD GPUs; AV1 requires supported GPU/driver. |
software |
libx265, libsvtav1 |
CPU encoding. FFmpeg must be built with the selected encoder. |
Quality values are not directly comparable between codecs or encoders. --cq
is a shared starting point (0-51); check a short clip when switching backend
or codec. SVT-AV1 uses preset 6 by default. Hardware AV1 encoding is available
only when both FFmpeg and the system hardware/runtime support that encoder.