ffmpeg: palettegen и paletteuse без боли
Если конвертировать видео в GIF «в лоб», ffmpeg берёт стандартную палитру на 256 цветов, и результат получается одновременно тяжёлым и грязным. Нормальный способ — два прохода: сначала подобрать палитру под конкретный ролик, потом применить её.
Базовый рецепт
ffmpeg -i in.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,palettegen" palette.png
ffmpeg -i in.mp4 -i palette.png \
-lavfi "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse" out.gif
Фильтры fps и scale должны быть одинаковыми в обоих проходах, иначе палитра будет посчитана по другим кадрам.
Что реально влияет на размер
- fps. 12–15 кадров в секунду почти всегда достаточно. Разница между 15 и 30 — примерно двукратная по весу.
- Ширина. Размер растёт примерно как квадрат ширины. 480 вместо 720 — уже минус половина.
- stats_mode.
palettegen=stats_mode=diffстроит палитру по изменяющимся областям. Хорошо для записей экрана, где фон статичен. - max_colors.
palettegen=max_colors=128для плоской графики почти незаметен глазу.
Дизеринг в paletteuse
По умолчанию используется sierra2_4a. Для сжатия выгоднее dither=bayer:bayer_scale=3: упорядоченный узор хорошо повторяется между кадрами. Подробнее — в заметке про дизеринг.
paletteuse=dither=bayer:bayer_scale=3:diff_mode=rectangle
diff_mode=rectangle перерисовывает только изменившийся прямоугольник кадра — ещё минус 10–30% на статичных сценах.
Итог на одном примере
| Вариант | Размер |
|---|---|
| «В лоб», 30 fps, 720 px | 14,2 МБ |
| Палитра, 15 fps, 480 px | 3,9 МБ |
| + bayer, diff_mode | 2,6 МБ |
| + gifsicle -O3 --lossy=40 | 1,7 МБ |
Про последнюю строку — отдельная запись.