convert-formats.sh 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. #!/bin/bash
  2. # Convert MP4 animations to 60fps MP4 (via minterpolate) and optimized GIF.
  3. #
  4. # Usage:
  5. # ./convert-formats.sh input.mp4 [gif_width]
  6. #
  7. # Produces next to the input:
  8. # <name>-60fps.mp4 (1920x1080, 60fps, motion-interpolated)
  9. # <name>.gif (scaled width, 15fps, palette-optimized)
  10. #
  11. # minterpolate flags:
  12. # mi_mode=mci motion compensation interpolation
  13. # mc_mode=aobmc adaptive overlapped block motion comp
  14. # me_mode=bidir bidirectional motion estimation
  15. # vsbmc=1 variable-size block motion comp
  16. # GIF uses two-pass palette:
  17. # pass 1: palettegen with stats_mode=diff (per-video optimal palette)
  18. # pass 2: paletteuse with bayer dither + rectangle diff
  19. # This keeps 30s/1080p animations GIF under ~4MB with good color fidelity.
  20. set -e
  21. INPUT="${1:?Usage: $0 input.mp4 [gif_width]}"
  22. GIF_WIDTH="${2:-960}"
  23. DIR=$(dirname "$INPUT")
  24. BASE=$(basename "$INPUT" .mp4)
  25. OUT60="$DIR/$BASE-60fps.mp4"
  26. OUTGIF="$DIR/$BASE.gif"
  27. PAL="$DIR/.palette-$BASE.png"
  28. echo "▸ 60fps interpolate: $OUT60"
  29. ffmpeg -y -loglevel error -i "$INPUT" \
  30. -vf "minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1" \
  31. -c:v libx264 -pix_fmt yuv420p -crf 18 -preset medium -movflags +faststart \
  32. "$OUT60"
  33. MP4_SIZE=$(du -h "$OUT60" | cut -f1)
  34. echo " ✓ $MP4_SIZE"
  35. echo "▸ GIF (${GIF_WIDTH}w, 15fps, palette-optimized): $OUTGIF"
  36. # Pass 1: generate palette tailored to this video
  37. ffmpeg -y -loglevel error -i "$INPUT" \
  38. -vf "fps=15,scale=${GIF_WIDTH}:-1:flags=lanczos,palettegen=stats_mode=diff" \
  39. "$PAL"
  40. # Pass 2: apply palette with dithering
  41. ffmpeg -y -loglevel error -i "$INPUT" -i "$PAL" \
  42. -lavfi "fps=15,scale=${GIF_WIDTH}:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \
  43. "$OUTGIF"
  44. rm -f "$PAL"
  45. GIF_SIZE=$(du -h "$OUTGIF" | cut -f1)
  46. echo " ✓ $GIF_SIZE"