Skip to main content

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 / --duration save 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-accurate for 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vid2gifx-0.1.0.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vid2gifx-0.1.0-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

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

Hashes for vid2gifx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1146c1df134cf9db45082644a619f3f567ae1483426b4d635f9003bd03129223
MD5 9362bfe581ce9b6b57033ebf0d22a590
BLAKE2b-256 c32281104ee6bfc550952a53af38cd831f3264b9105cf4c500d331ab2fd8e74e

See more details on using hashes here.

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

Hashes for vid2gifx-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 347158d18d6412e6a97ee4c930a23f9e565429e5061d651d721e66b0f4a74dc5
MD5 f97b84c6d8df5b7fc663070255ec5444
BLAKE2b-256 c91bfc7f6456c90d2abdfd5dd728b18fde810d28754b69cbba6ca6ec061b57bb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page