首页 / FFmpeg 入门教程 / 视频转 GIF 与 GIF 转视频

FFmpeg 入门教程

视频转 GIF 与 GIF 转视频

本教程共 32 篇 · 第 15 篇 · 更新于 2026-08-09 · 约 7 分钟阅读

FFmpegGIFpalettegenpaletteuse视频转GIFGIF转MP4动图

本节目标:把视频片段转成画质好、体积小的 GIF;反过来把 GIF 压成 MP4 节省空间。

GIF 又老又低效,但在社交网络、文档、聊天里依然无处不在。直接用 FFmpeg 转 GIF 很容易,但默认输出色彩很差、体积也大。这一章讲怎么做出「又清晰又小」的 GIF。

视频转 GIF:最简写法

先截取一段,再输出 GIF:

ffmpeg -ss 00:00:05 -t 3 -i input.mp4 output.gif

从第 5 秒开始取 3 秒,直接生成 GIF。能跑,但效果通常很差——颜色发灰、有颗粒感。原因是 GIF 只支持 256 色调色板,而 FFmpeg 默认用的通用调色板对每一段画面都不是最优的。

高质量 GIF:两步调色板法

正确做法分两步:先为这段视频生成专属调色板,再用这个调色板输出 GIF。

第一步:生成调色板

ffmpeg -ss 00:00:05 -t 3 -i input.mp4 \
  -vf "fps=15,scale=480:-1:flags=lanczos,palettegen" \
  palette.png
  • fps=15:GIF 不需要太高帧率,15fps 足够顺滑,再高体积暴涨。
  • scale=480:-1:flags=lanczos:缩到宽 480,用 lanczos 算法保锐利。
  • palettegen:滤镜,统计这段画面所有像素,生成一张最优的 256 色调色板。

输出一张 palette.png(通常很小,几百字节到 1KB)。

第二步:用调色板输出 GIF

ffmpeg -ss 00:00:05 -t 3 -i input.mp4 -i palette.png \
  -filter_complex "[0:v]fps=15,scale=480:-1:flags=lanczos[v];[v][1:v]paletteuse" \
  output.gif
  • 有两个输入:原视频和调色板图片。
  • [0:v]fps=15,scale=...[v]:先对视频做帧率和缩放处理。
  • [v][1:v]paletteuse:把处理后的视频和第二个输入的调色板一起喂给 paletteuse 滤镜,按这个调色板量化颜色。

效果比直接转好非常多,体积往往还更小。

一条命令搞定(用滤镜链)

不想生成中间文件,可以把 palettegen 和 paletteuse 串在一条命令里:

ffmpeg -ss 00:00:05 -t 3 -i input.mp4 \
  -filter_complex "[0:v]fps=15,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" \
  output.gif

split[a][b] 把处理后的视频流复制成两份,一份给 palettegen 生成调色板,另一份和调色板一起给 paletteuse。效果和两步法完全一致。

Tip

上面这条命令里 split 之后的两条分支会自动排队执行:palettegen 必须先看完整个视频才能产出调色板,FFmpeg 会处理好这个顺序。

进一步优化

控制抖动(dithering)

GIF 颜色少,渐变区域容易出现色带。paletteuse 默认会用抖动算法来模拟更多颜色,但抖动也会让颗粒感变重、体积变大。

# 默认的 Bayer 抖动,颗粒较规则
ffmpeg ... -filter_complex "...paletteuse=dither=bayer:bayer_scale=3" output.gif

# 不用抖动,色块最干净,但渐变可能有断层
ffmpeg ... -filter_complex "...paletteuse=dither=none" output.gif

# Floyd–Steinberg 误差扩散,画质好但体积稍大
ffmpeg ... -filter_complex "...paletteuse=dither=floyd_steinberg" output.gif

每帧独立调色板

GIF 默认整个动画共用一张调色板。如果画面场景变化剧烈(比如从室内切到户外),共用调色板两边都照顾不好。可以让每帧用自己的调色板:

ffmpeg ... -filter_complex "...palettegen=stats_mode=single[pal];[v][pal]paletteuse=new=1" output.gif

代价是文件会大不少。大多数情况下,默认的全局调色板就够了。

降帧率和尺寸

影响 GIF 体积最明显的两个因素:

  1. 帧率:15fps 就很流畅了,10fps 也能用。每降一半帧率,体积大约少 30-40%。
  2. 宽度:480 宽适合聊天和文档,320 宽适合表情。
# 10fps、宽 320、无抖动,体积最小
ffmpeg -i input.mp4 \
  -filter_complex "fps=10,scale=320:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse=dither=none" \
  output.gif

从透明背景视频生成

如果源是带 alpha 通道的 WebM 或 MOV,GIF 也支持透明:

ffmpeg -i input.mov \
  -filter_complex "fps=15,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen=reserve_transparent=on[p];[b][p]paletteuse=alpha_threshold=128" \
  output.gif

GIF 转视频(MP4)

GIF 体积大、不支持音频、浏览器解码效率低。把它转成 MP4 通常能小 50%-90%。

基本命令

ffmpeg -i input.gif \
  -movflags faststart \
  -pix_fmt yuv420p \
  -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" \
  output.mp4

每个参数的作用:

  • -movflags faststart:把元信息挪到文件头,让浏览器可以边下边播。
  • -pix_fmt yuv420p:保证所有浏览器和播放器都能播。
  • scale=trunc(iw/2)*2:trunc(ih/2)*2:GIF 的尺寸可能是奇数,H.264 要求偶数,这里把宽高都取最近的偶数。

控制体积和质量

# 高质量 CRF 18
ffmpeg -i input.gif -movflags faststart -pix_fmt yuv420p -crf 18 output.mp4

# 限制码率
ffmpeg -i input.gif -movflags faststart -pix_fmt yuv420p -b:v 1M output.mp4

限制最大宽度

很多 GIF 很小,没必要放大:

ffmpeg -i input.gif \
  -movflags faststart -pix_fmt yuv420p \
  -vf "scale='min(720,iw)':-2" \
  output.mp4

min(720,iw) 表示宽度最多 720,小的就保持原尺寸。

让 MP4 循环播放

GIF 默认无限循环,MP4 本身不循环,要靠 HTML 的 loop 属性或播放器设置。如果输出文件需要自带循环信息,可以加 -loop 0(但这是给 GIF 用的输出选项,对 MP4 无效)。网页里这样写:

<video src="output.mp4" autoplay loop muted playsinline></video>

常见问题

GIF 颜色很糟糕。 没生成调色板,直接输出了。用两步调色板法重转。

GIF 太大。 降帧率到 10-15、缩窄宽度到 320-480、试 dither=none

MP4 播不了。 检查是不是加了 -pix_fmt yuv420p,宽高是不是偶数。某些老设备不支持 HEVC,用 H.264 最稳妥。

GIF 转 MP4 后速度不对。 GIF 的帧延迟不统一,FFmpeg 会处理。如果仍然异常,用 -fflags +genpts 重新生成时间戳:

ffmpeg -fflags +genpts -i input.gif -movflags faststart -pix_fmt yuv420p output.mp4

小结

  • 视频转 GIF 别直接输出,用 palettegen + paletteuse 两步法质量明显更好。
  • 帧率 10-15、宽度 320-480 是体积和质量的甜点区。
  • GIF 转 MP4 加 -pix_fmt yuv420p-movflags faststart,并用 trunc(iw/2)*2 保证偶数尺寸。
  • MP4 体积通常只有 GIF 的 1/2 到 1/10,网页和 App 里应该优先用 MP4。

下一章讲图片序列和视频的互相转换。