Skip to content

MP4 转 GIF 怎么配才不糊?帧率、颜色数、抖动算法的实际取舍 ​

关于我 ​

我是 EZ 在线工具网 的站长,站里的 MP4 转 GIF 工具 就是下面要拆的这个。所以参数怎么来的、哪一档适合干什么,我讲得会比转述清楚一点。

先接受一个前提:GIF 糊是必然的 ​

GIF 最多 256 色,没有音频,没有帧间预测。MP4 一帧能存 1677 万色,还能靠前后帧的差值只存变化的部分;GIF 的每一帧都得独立映射到那张 256 色的表上,再套一层 LZW 无损压缩。

差着两个量级的信息密度,糊是躲不掉的。你能控制的只是糊到什么程度,以及为它付多少体积。

体积大致是怎么涨上去的 ​

不用记公式,记住它是乘法关系就行。总编码量近似正比于 像素数 × 帧数 × 画面复杂度:

  • 分辨率减半,像素数变成原来的四分之一
  • 帧率减半,帧数减半
  • 时长减半,帧数减半

拿个具体点的例子算:1080p、25fps、10 秒,一共 250 帧,每帧约 200 万像素,两阶段滤镜得处理五次亿量级的像素点。把缩放调到 50%,像素数降到四分之一,等于凭空省掉四分之三的计算和体积。

所以标题里说的"不糊",实际是在这四个旋钮之间做交换:时长、分辨率、帧率、颜色数。下面讲怎么定顺序。

两阶段调色板,多跑一遍但值 ​

GIF 的颜色表叫调色板(palette),最多 256 个槽位。问题来了:这张表从哪来?

一步法的做法是拿首帧、或者均匀抽几帧去算,然后全片都用它。这在单一场景的短片段上凑合能用,一旦镜头里从室内切到室外,或者从冷色调切到暖色调,颜色表就对不上了,画面开始全体偏色、色带横飞。

两阶段的做法是先扫一遍:palettegen 把整段视频(或者你框选的那一段)的颜色分布统计出来,生成一张针对这段素材优化的表;paletteuse 再拿这张表去逐帧映射。多跑一遍全片,换来的是一个档次的画质差。我们工具里跑的就这么两条命令:

bash
# 阶段一:扫全片,产出调色板
ffmpeg -i input.mp4 -ss 3 -to 6 \
  -vf "fps=10,scale=iw*0.5:ih*0.5:flags=lanczos,palettegen=max_colors=128" \
  palette.png

# 阶段二:用这张调色板映射每一帧
ffmpeg -i input.mp4 -i palette.png -ss 3 -to 6 \
  -lavfi "[0:v]fps=10,scale=iw*0.5:ih*0.5:flags=lanczos[v];[v][1:v]paletteuse=dither=sierra2" \
  output.gif

注意两条命令用的区间必须一致。调色板取自 3 到 6 秒、成品却拿整段视频去映射,出来的是全片 GIF 配一张只懂 3 秒内容的色表。这种错挺隐蔽的,画面能看,就是颜色说不出的怪。

四个档位,重点在抖动算法 ​

界面上画质只有四档,背后是颜色数和抖动(dither)两个参数在配对:

档位颜色数抖动算法什么时候用
高画质256sierra2_4a渐变多、有肤色、要展示细节
中等画质128sierra2默认,绝大多数场景的平衡点
低画质64bayer:b=6纯色块、文字、图标动画
极小体积32关闭极致压体积,两三个色块的简单动画

抖动是干什么的?它拿有限的 256 个颜色去"骗"眼睛。天空在真实画面里是从深蓝到浅蓝的连续过渡,色表里可能只有五个蓝。直接把每个像素换成最近的蓝,画面上会出现五条硬边。抖动的做法是在过渡区域按特定规则交替使用相邻的两个颜色,隔远看就混成了中间色。

两种抖动思路完全不一样:

sierra2 / sierra2_4a 属于误差扩散。 它逐像素处理,把量化产生的误差摊给右边和下面的邻居像素。优点是过渡自然、噪点分布像胶片颗粒;缺点是慢,而且它撒出来的"噪点"是随机的。

bayer 属于有序抖动。 用一张固定的矩阵去决定每个像素往哪边偏,出来的纹理规律性很强,看着没那么"高级",但计算快、图案稳定。

这里有个反直觉的地方:颜色数低的时候,我们反而把抖动换成 bayer,甚至直接关掉。

原因是 LZW。GIF 用的是无损压缩,压缩率取决于画面里有多少重复模式。误差扩散抖出来的随机噪点,等于往每一帧里撒了几万个"不一样"的像素,LZW 就压不动了,体积能给你涨回去一大截。颜色本来就只剩 32 个,你换来的不是画质,是更大的文件。

所以在低色数档位上关抖动,不是偷懒,是为了让文件真的变小。

按这个顺序砍参数 ​

第一步,砍时长。 收益线性,损失最小。一段 30 秒的录屏做成动图没人看得完,圈出最有信息量的 3 到 5 秒。这一步能砍掉量级的体积,还不影响清晰度。

第二步,砍分辨率。 收益是平方级的。砍之前先想清楚这张 GIF 最终在哪儿显示:微信表情包的实际显示宽度就几百像素,你做 1920 宽再压到 50%,纯属浪费。反过来,要放进 PPT 或者文档放大看,就别砍到 25%。

第三步,定帧率。 8 到 12 帧是动图的甜点区。低于 8 帧有明显顿挫感;高于 15 帧对表情包、操作演示这类内容基本是浪费——GIF 每多一帧就是完整一帧的像素量。真正的视频转成 10 帧,观感上完全够用。

最后才动颜色数和抖动。 只有前面三步砍完体积还不满意,再去调色数。因为色数一降,色带和色块是肉眼可见的,属于"伤画质"的操作,能不做就不做。

三套现成配方 ​

聊天用的表情包:缩放 25% 到 37.5%、10fps、64 色(bayer)、时长压在 3 秒内。重点是体积小、发送快,画面糙一点没人介意。

README / 文档演示图:缩放 50%、12 到 15fps、128 色。宽度控制在 800 像素左右,放在文档里不横向溢出,体积也还算克制。

产品动效展示:缩放 75%、15fps、256 色。这种场景就是要好看,接受体积大一点;如果对方能打开视频,直接发 MP4 更划算。

操作步骤 ​

  1. 上传 MP4 或 MOV,单个文件不超过 1GB
  2. 在「分辨率缩放」里选比例,选项是原始、75%、50%(推荐)、37.5%、25%
  3. 在「帧率」里选 5、10(推荐)、15、20、25 帧
  4. 在「画质质量」里选高画质(256 色)、中等画质(128 色,推荐)、低画质(64 色)、极小体积(32 色)
  5. 只想转某一段,勾上「启用时间裁剪」,填起始和结束时间(单位秒)
  6. 点「开始转换」,等两个阶段跑完。结果区会给出原文件大小、输出大小、转换耗时和处理速度,拿这几个数一对比就知道参数该怎么微调

第一次点转换要等久一点,因为浏览器得先把 22MB 左右的转码内核拉下来,之后走缓存。进度停在 10% 或者 40% 不动是正常的,那两个位置分别在跑调色板和 GIF 合成。

有些场合你根本不该用 GIF ​

这条比参数更值得看。

GIF 是 1987 年的格式,它当年解决的是"在没法放视频的地方放动图"。现在网页、GitHub README、绝大多数博客都支持 <video> 标签,你完全可以让一段无声循环的视频干同样的活:

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

同样的画面,MP4 或 WebM 通常比 GIF 小一个数量级,还没有 256 色的限制,没有色带。很多人做网站动图还在用 GIF,纯粹是习惯没改过来。

GIF 真正该用的地方是:聊天软件、邮件、以及任何塞不进 video 标签的文档。这些场景里它是唯一选择,那就老老实实按上面的顺序砍参数。

排错 ​

  • 卡在 10% 或 40% 很久:第一阶段在扫全片统计颜色分布,源视频越长越慢。先用时间裁剪圈出需要的片段,比什么都管用。
  • 页面白掉或者报内存错误:文件太大或时长太长。GIF 是在你本地浏览器的内存里拼的,数据量比源视频膨胀得厉害。先剪再转。
  • 发到微信里不动了:多半是体积超过平台限制。往下压分辨率,缩短时长。
  • 渐变区域出现明显色阶:色数太低,换 128 或 256 色,抖动保持 sierra。反过来,如果画面本来就是纯色块和文字,用 64 色加 bayer 就够了。

我们做不到的部分 ​

  • 输入只认 MP4 和 MOV。内部的 H.264、H.265、VP9 都能正确解码,但容器得是这两个。
  • 没有声音。GIF 格式本身不支持音频轨道,这不是工具的限制。
  • 单文件上限 1GB。而且是纯浏览器本地跑,内存吃紧,手机端别扔大文件进去。
  • 文件不上传。转码在你的浏览器里完成,我们碰不到你的素材,这点在 隐私政策 里也写了。代价是速度取决于你的设备,跟服务器性能没关系。

就这样 ​

参数先按这套顺序动:时长 → 分辨率 → 帧率 → 颜色数,八成问题都能解决。

真需要一帧帧调参数的话,直接去 MP4 转 GIF 工具 试,本地方案的好处就是随便试,一次不满意换个参数再来,不用担心流量和次数。

如果你要的是"把视频变小然后发出去",而不是非得做成动图,那 视频压缩工具 是对的路子——同画质下 MP4 能压到 GIF 的零头。静图压缩就交给 图片压缩工具。


📌 相关文章 ​

🚀 推荐阅读 ​

Last updated: