FFmpeg-only video to GIF converter with palettegen/paletteuse and size targeting.
Project description
video2gif — FFmpeg-only video → GIF converter
A clean, configurable Python CLI that converts and optimizes videos to GIFs using FFmpeg’s palettegen → paletteuse workflow. Includes optional size targeting (stay under a byte budget), frame-accurate seek, and VFR preservation.
Quick start
# Install ffmpeg first (macOS: brew install ffmpeg, Ubuntu: apt-get install ffmpeg, Windows: winget install ffmpeg)
python video2gif.py input.mp4 output.gif
How this script can be used (common recipes)
Each example includes a short description of what it does.
1) Default high-quality conversion
python video2gif.py in.mp4 out.gif
Converts using a good default FPS and palette workflow. No resizing, full clip.
2) Social-ready (smaller, crisp)
python video2gif.py in.mp4 out.gif --preset social
Sensible default for previews (fps=12, width=480), good balance of size and quality.
3) Tiny footprint (docs, chats)
python video2gif.py in.mp4 out.gif --preset tiny
Aggressively smaller (fps=8, width=360, colors=64) for inline docs/PRs.
4) High-quality demo
python video2gif.py in.mp4 out.gif --preset hq
Higher FPS and width for smoother playback; bigger files.
5) Cap width (keep aspect)
python video2gif.py in.mp4 out.gif --width 480
Resizes by width (height auto-computed) with high-quality Lanczos scaling.
6) Fixed size (both dimensions)
python video2gif.py in.mp4 out.gif --width 640 --height 360
Forces exact dimensions (may change aspect).
7) Lower the FPS
python video2gif.py in.mp4 out.gif --fps 10
Reduces temporal density → much smaller files.
8) Limit color palette
python video2gif.py in.mp4 out.gif --colors 96
Fewer colors = smaller GIF; quality still decent with dithering.
9) Change dithering style
python video2gif.py in.mp4 out.gif --dither floyd_steinberg
Controls how colors are approximated; default sierra2_4a is usually best.
10) Trim a segment
python video2gif.py in.mp4 out.gif --start 3.2 --duration 6.5
Encodes only a portion of the video.
11) Frame-accurate trimming
python video2gif.py in.mp4 out.gif --start 3.2 --duration 6.5 --seek-accurate
Places -ss/-t after -i to avoid keyframe-aligned “early start” artifacts (slower).
12) Preserve original timing (VFR)
python video2gif.py in.mp4 out.gif --keep-vfr
Skips the fps filter; uses per-frame delays to keep source pacing.
13) Crop before scaling
python video2gif.py in.mp4 out.gif --crop 480:480:100:60 --width 480
Cuts to a region (width:height:x:y), then scales. Great for removing borders/UIs.
14) Deinterlace first
python video2gif.py in.mp4 out.gif --deinterlace
Applies yadif for interlaced sources.
15) Control loop count
python video2gif.py in.mp4 out.gif --loop 0 # infinite (default)
python video2gif.py in.mp4 out.gif --loop 1 # play once
Sets the repeat behavior for the GIF.
16) Enforce a max file size (size targeting)
python video2gif.py in.mp4 out.gif --max-bytes 4_000_000
Iteratively shrinks colors → fps → width until the GIF fits under 4 MB (uses floors to protect quality; see next examples).
17) Size targeting with quality floors
python video2gif.py in.mp4 out.gif --max-bytes 3_000_000 --min-colors 48 --min-fps 8 --min-width 320
Keeps at least 48 colors, 8 FPS, and 320px width while trying to meet 3 MB.
18) Combine preset + size cap
python video2gif.py in.mp4 out.gif --preset social --max-bytes 4_000_000
Starts from a reasonable baseline, then shrinks only if needed.
19) Crisp UI/text with fewer colors
python video2gif.py in.mp4 out.gif --width 480 --fps 12 --colors 64
Keeps resolution and motion; reduces palette for significant size savings.
20) Motion-first preference
python video2gif.py in.mp4 out.gif --max-bytes 4_000_000 --min-fps 12
Tells the search to avoid dropping FPS much; it will reduce colors/width instead.
Full CLI
positional arguments:
input Input video file
output Output GIF path (e.g., out.gif)
core quality/size:
--fps INT Frames per second (default 12 unless --keep-vfr)
--width INT Scale to this width (keeps aspect unless height also set)
--height INT Scale to this height (keeps aspect unless width also set)
--colors INT Palette colors (2–256). Fewer = smaller
advanced tuning:
--dither {none,bayer,floyd_steinberg,sierra2,sierra2_4a}
Dither algorithm (default: sierra2_4a)
--stats-mode {full,diff}
palettegen statistics mode (default: full)
trim/crop/deinterlace:
--start FLOAT Start time in seconds
--duration FLOAT Duration in seconds
--crop W:H:X:Y Crop before scaling (e.g., 480:480:100:60)
--deinterlace Apply yadif deinterlace
timing/mux:
--keep-vfr Preserve source timing (omit fps filter; per-frame delays)
--seek-accurate Place -ss/-t after -i for frame-accurate trimming
--loop INT GIF loop count (0=infinite, 1=once, ...)
presets:
--preset {social,tiny,hq}
Convenience starting points you can still override
size targeting:
--max-bytes INT Try to keep final GIF ≤ this many bytes
--min-fps INT Floor when shrinking FPS (default: 6)
--min-width INT Floor when shrinking width (default: 240)
--min-colors INT Floor when shrinking colors (default: 32)
How size targeting works (in one paragraph)
When --max-bytes is set, the script does first-fit trials that progressively reduce colors → fps → width along gentle “ladder” values (e.g., colors 256→128→96→64, fps 12→11→10→…, width 720→648→… until --min-* floors). After each trial it measures the actual GIF and stops at the first that’s ≤ budget. If none fit, it writes a best-effort file using the floors and prints a warning.
Quality tips
- For tiny but readable:
--fps 10 --width 360 --colors 64 - Keep text/UI sharp: prefer reducing colors before reducing width
- Preserve pacing:
--keep-vfr(if viewers show odd timing, go back to fixed--fps) - Trim aggressively:
--start/--durationsave more size than any other knob
Troubleshooting
- “ffmpeg not found” → Install FFmpeg and ensure it’s in your PATH.
- Starts a bit early → Use
--seek-accuratefor frame-accurate trims. - Choppy playback → Increase
--fps, or avoid size targeting floors that force low FPS. - Big file even after targeting → Raise the budget or allow lower floors (
--min-*). - Banding with low colors → Try a different
--dither(e.g.,floyd_steinberg).
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vid2gifx-0.1.0.tar.gz.
File metadata
- Download URL: vid2gifx-0.1.0.tar.gz
- Upload date:
- Size: 11.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1146c1df134cf9db45082644a619f3f567ae1483426b4d635f9003bd03129223
|
|
| MD5 |
9362bfe581ce9b6b57033ebf0d22a590
|
|
| BLAKE2b-256 |
c32281104ee6bfc550952a53af38cd831f3264b9105cf4c500d331ab2fd8e74e
|
File details
Details for the file vid2gifx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: vid2gifx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
347158d18d6412e6a97ee4c930a23f9e565429e5061d651d721e66b0f4a74dc5
|
|
| MD5 |
f97b84c6d8df5b7fc663070255ec5444
|
|
| BLAKE2b-256 |
c91bfc7f6456c90d2abdfd5dd728b18fde810d28754b69cbba6ca6ec061b57bb
|