[FFMpeg开发]视频转高质量GIF优化方案(接近ps生成效果),从原理剖析

摘要

虽然此前有人发过了,但是这个博主没有分析原理并且没有提炼出来。不适合开发者学习。
所以我只是进行二次优化,原文高质量视频转gif

此前,做产品的时候,产品用到了ffmpeg框架,手上几个ffmpeg衍生的产品做出来的gif画质都贼差,我不禁怀疑ffmpeg是不是没法整视频转gif,目前我只知道免费软件里,视频转gif比较厉害的就格式工厂了,不过转出来噪点很严重,就是下面的效果(我手上有几款商业方式跟格式工厂基本差不多就不提了,效果一样)
在这里插入图片描述
也许现在你还能接受,但是实际上我们不会要那么大分辨率的gif,把格式工厂的分辨率缩小,换一张色彩变动明显的
在这里插入图片描述
如果图片色彩越多,则小点点会越多。

不得以,只能通过源码分析,跟分析其他软件的做法,针对GIF方面整理出了三套优化策略。
由于产品源码实现难度比较高,目前就不从api对接的源码设计上介绍自己的优化过程了,我将会结合ffmpeg源码使用命令行讲解如何优化出高质量的gif图。

效果

在这里插入图片描述
这就是优化出来的结果,堪比ps生成的效果,命令行有几点会比较坑,最需要注重二次画质损失的问题,因为ffmpeg里面的swscale用的算法问题,pal8是没法进行缩放的,如果滤镜输出与需要输出不一致,会转换变成rgb8再进行缩放(pal是8位色板方案,缩放时色彩抖动可能会缺色导致画板无法映射?)

优化灵感

说起来也很搞笑,我开始一直没有做出那个博主的效果,到最后我才发现,我代码里像素格式的获取跟ffmpeg初始化不同,我是先初始化gif编码器的像素格式,宽高,再初始化滤镜ffmpeg是先初始化滤镜再初始化编码器像素格式,因为ffmpeg的avfilter滤镜是链式的,通常来说我们in out尺寸像素方案、分辨率方案不一致的时候ffmpeg会使用sws帮你缩放。但是sws像素处理方案里面没有pal8所以会变成rgb8。导出来就成这样
在这里插入图片描述
在使用ffmpeg开发的时候一定要注意,尽量不要使用swscale做缩放了,尽量使用ffmpeg里的avfilter的滤镜。

灵感前奏

我先从ffmpeg里的gif编码器结构体定义分析
在这里插入图片描述
因为我一般使用默认方式,而这个编码器会使用RGB8方案。RGB8方案是使用RGB32平摊出来的,也就是按332方式分配Rgb色(听说是人眼对蓝色敏感比较低)
ffmpeg的swscale里是没有pal8的处理的,这里可以看utils.c里的定义
在这里插入图片描述
而rgb8是粗暴的临近抖色方案
在这里插入图片描述

临近抖色,意思是如果色表没有命中,会往临近颜色靠,简单的说就是整除方案,假设现在要把128区间映射到12区间,128/10即可进行平摊分布。但是这样就会造成颜色抖动特别明细,造成噪点。也就是格式工厂的方案。

既然使用sws解决不了,那似乎就没法子了,但是我想起了一个使用ffmpeg的工具,screentogif,这东西使用ffmpeg转出来的效果还不错(跟我最后那个一样)。想办法干他命令行指令
在这里插入图片描述
拿出我珍藏的命令行截取版本的ffmpeg
在这里插入图片描述
替换
在这里插入图片描述
在这里插入图片描述
concat是合并图片的方案直接无视,palettegen=statsmode=diff[pal],[0:v][pal]palettuse=new=1:diff_mode=rectangle 这个滤镜几乎就是秘籍了。然后我根据这个滤镜找到那个博主的文章,跟那个博主的区别比较明显,他是先生成全局色表再进抖动。这样的结果是,大小相对较小,但是容易陷入贪心陷阱。损失一部分颜色。而这个滤镜方案会当色板出现变化才更换,否则使用上一次的色板。这个方案相对较好,但是对压缩帮助不大,因为gif使用的编码方案是前后像素变化。如果调色板变动,这基本没法使用了。 2021/4/7分析源码时发现,diff是另外一种全局加权算法而已,最终只有一张色表

优化滤镜分析

首先是palettegen滤镜,这个滤镜用于彩色统计,支持的子项有如下
在这里插入图片描述

max_color用于限制色板大小,越小对压缩越有帮助,最大256
reserver_transparent保留透明度,考虑到可能会有透明通道,尽量不改,transparency_color设置透明通道的背景色
stats_mode默认为full,可能会导致内存爆炸,所以一般使用diff跟single,diff的话会在gif编码的时候进行画板比对,所以其实用不用都会被过滤,我代码里使用的是single。
在这里插入图片描述
接着就是运用滤镜
palettuse
在这里插入图片描述
这个滤镜有点复杂,但是是抖动的关键
dither,使用的抖动方案,每个方案的效果在这里有效果展示
抖动效果参考
bayer_scale,参考里也有,按我的理解是搭配bayer用的,用于抖动搜索,搜索为1为暴力抖色,搜索越高时间越久,效果越好。
diff_mode,抖动方式,使用矩阵效果跟不使用其实看起来差距不大 2021/4/7分析源码发现如果色板是每张图一张会出bug
new,这个比较重要,标志是不是每张图片抖动是不是只使用一个色板,默认不使用新色板,这表示你生成的其他色板将不会再被使用
debug_kdtree mean_err debug_accuracy一般没人用,我们不是ffmpeg开发者
color_search,色彩搜索算法,这个看不出效果

整理资料

经过上面的分析,视频转gif,
考虑大小使用单一色板,这样对图片压缩好,但是相对使用色板难度较高,如果使用原图生成的色板,可能会失去部分色彩。并且要跑两次程序,一次生成色板,一次抖色。
考虑失真情况,每张图生成一个色板,这个是screentogif使用的方案。效果好,色彩优异。
综合考虑,使用rgb8的色板,进行抖色。这个方案会有噪点,但是体积控制较好,色彩比格式工厂优异

命令行指令

考虑大小版本
ffmpeg -i “H:\样本.mp4” -s 320x180 -vf “[in]scale=320x180,split[split1][split2];[split1]palettegen[pal];[split2][pal]paletteuse” H:\FFOutput\test.gif
注意-s的尺寸务必与scale一致,否则会造成二次损失,另外如果帧数超过300建议先生成色板再抖色编码,速度很慢

考虑色彩版本
ffmpeg -i “H:\样本.mp4” -s 320x180 -vf “[in]scale=320x180,split[split1][split2];[split1]palettegen=stats_mode=diff[pal];[split2][pal]paletteuse=new=1:diff_mode=rectangle” H:\FFOutput\test.gif

2021/4/7分析源码后调整因为矩阵扫描会用上一次调色板,调试板是不能变化的,修复bug问题
ffmpeg -i “H:\样本.mp4” -s 320x180 -vf “[in]scale=320x180,split[split1][split2];[split1]palettegen=stats_mode=single[pal];[split2][pal]paletteuse=new=1” H:\FFOutput\test.gif
注意事项 -s要与scale一致,可以超过300帧速度相对慢

综合考虑的方案
需要自己生成调色板,有心人自己实现吧

另外上门两个对同个视频生成的效果如下
大小考虑:
在这里插入图片描述

色彩考虑:
考虑色彩版本
在这里插入图片描述
1.86/1.57 大了差不多1/5,分辨率越大,动作越复杂区别会越大,不过应该不会有人需要超过几千帧的表情包吧…(一个300帧1920p视频,比默认rgb8方案大了差不多3倍还是蛮恐怖的,提一嘴,这上面的gif是20帧的)

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值