ffmpeg相关命令 转换gif
前言
使用FFmpeg能够很方便的给视频片段或GIF加水印,同时还能对选取的片段生成GIF图,但是在使用默认FFmpeg设置情况下,生成的GIF画质很差,有很明显的栅格化现象。如何生成高质量的GIF是一个需要探索的问题。
问题复现
对以下这个GIF(input.gif)
添加如下水印(logo.jpg):
使用FFmpeg命令如下:
ffmpeg -i input.gif -vf "movie=logo.jpg,scale= 30: 30[watermark];[in][watermark] overlay=x=10:y=10[out] " -y out1.gif
生成下面这个GIF(out1.gif),可以看到画质很差,有很明显的栅格化现象。
这个现象不仅在加水印的过程中出现,只要是通过FFmpeg初级命令(如ffmpeg -i in.mp4 out.gif
)对视频或者GIF生成GIF图时,均会出现这种栅格化现象。
问题思考
通过搜索看到两篇比较有启示的文章(见参考资料[4]和[6]),参考资料[4]主要描述的是GIF的存储和压缩原理,文章中关于调色盘的解释和gifsicle命令工具查看GIF元信息的部分对自己的启发比较多。
使用gifsicle工具对原GIF和生成的GIF进行分析:
原GIF:
* input.gif 26 images
logical screen 400x400
global color table [256]
background 254
loop forever
+ image #0 400x400
disposal asis delay 0.08s
+ image #1 400x400 transparent 255
local color table [256]
disposal asis delay 0.08s
+ image #2 400x400 transparent 253
local color table [256]
disposal asis delay 0.08s
+ image #3 400x400 transparent 255
local color table [256]
disposal asis delay 0.08s
+ image #4 400x400 transparent 253
local color table [256]
disposal asis delay 0.08s
+ image #5 400x400 transparent 255
local color table [256]
disposal asis delay 0.08s
+ image #6 400x400 transparent 252
local color table [256]
disposal asis delay 0.08s
+ image #7 400x400 transparent 254
生成的GIF:
* out1.gif 26 images
logical screen 400x400
global color table [256]
background 31
loop forever
+ image #0 400x400
disposal asis delay 0.08s
+ image #1 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #2 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #3 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #4 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #5 391x395 at 4,1 transparent 4
disposal asis delay 0.08s
+ image #6 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #7 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #8 391x395 at 4,1 transparent 4
disposal asis delay 0.08s
+ image #9 391x394 at 4,2 transparent 4
disposal asis delay 0.08s
+ image #10 391x394 at 4,2 transparent 4
发现最大的区别就是local color table [256]
,也就是局部调色盘。
※ 注解
GIF是支持全局调色板和局部调色板同时存在的,如果GIF的某帧有自己的局部调色板,那么则使用该局部调色板进行颜色量化。如果没有局部调色板,则使用全局调色板进行颜色量化。
结合参考资料[6]中描述的相近现象及参考文章,大致了解了调色板对GIF的重要性。
进一步找到参考资料[5],里面对GIF生成的画质做了很详尽的讨论,也很详细地阐述了调色板的作用。
文中指出FFmpeg默认的调色板是以下256颜色的:
也就是说,在使用基础FFmpeg命令生成GIF时是调用上述的默认调色板(全局调色板,global color table [256]
)进行编码,但是上述调色板的颜色对于任意帧色彩的量化有很大的局限。
弄清楚造成栅格化现象的原因,思考出两种解决方案:
(1)全局调色板角度,根据每一个GIF的所有帧单独计算一个全局调色板。
(2)局部调色板角度,对于GIF的每一帧单独计算一个局部调色板。
在参考资料[3]中,有一个回复解决了开头的问题:
(1)使用新的全局调色板:
ffmpeg -i input.gif -vf "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" out.gif
(2)使用局部调色板:
ffmpeg -i input.gif -vf "split[s0][s1];[s0]palettegen=stats_mode=single[p];[s1][p]paletteuse=new=1" out.gif
下面是用上述命令新生成的GIF:
很好地解决了栅格化现象。
以下是对input.gif加水印的同时生成新的高质量GIF命令:
ffmpeg -i input.gif -vf "movie=logo.jpg,scale= 30: 30[watermark];[in][watermark] overlay=x=10:y=10,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse[out] " -y out2.gif
不仅是对GIF,也可以延伸至视频加水印生成GIF的应用,大家自己多搜索多琢磨即可。
总结
GIF支持全局调色板和局部调色板同时存在的,如果GIF的某帧有自己的局部调色板,那么则使用该局部调色板进行颜色量化。如果没有局部调色板,则使用全局调色板进行颜色量化。
使用如下命令可以很好的使用FFmpeg生成高清gif图。
ffmpeg -i input.gif -vf "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" out.gif
FFmpeg是一个非常强大的音视频处理工具,如果遇到问题可以多看官方文档(参考资料[1])。使用搜索引擎辅助自己理解和解决问题。深入思考产生现象的原因,往往深入地理解对解决问题非常有益。
参考资料
[1] FFmpeg 官方文档: ffmpeg Documentation
[2] FFmpeg常用命令小结
[3] superuser问答社区:How do I convert a video to GIF using ffmpeg, with reasonable quality?
[4] medium文章:High Quality Gifs with FFMPEG
[5] blog.pkh.me博客 – High quality GIF with FFmpeg
[6] 浓缩的才是精华:浅析GIF格式图片的存储和压缩
[7] Gifsicle
tinygif
set p0=%1
#ffmpeg -i %p0% -b:v 2048k -gifflags +transdiff -vf "split[s0][s1];[s0]palettegen=stats_mode=single[p];[s1][p]paletteuse=new=1" -y %p0%.gif -threads 8
ffmpeg -i %p0% -b:v 2048k -gifflags +transdiff -vf "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -y %p0%.gif -threads 8
echo "转换完成"
tinymp4
set p0=%1
ffmpeg -i %p0% -b 1024k -y %p0%.mp4 -threads 8
echo "转换完成"
tinymp3
set p0=%1
ffmpeg -i %p0% -vn -y %p0%.mp3 -threads 8
echo "转换完成"
tinypng
set p0=%1
ffmpeg -i %p0% -y %p0%.png
echo "转换完成"
转换png pix8格式
set p0=%1
ffmpeg -hide_banner -i %p0% -pix_fmt pal8 -y %p0%.png
echo "转换完成"
将直播流转换为mp4
ffmpeg -i http://60.199.188.151/HLS/WG_ETTV-N/index.m3u8 -c:v copy -c:a copy -bsf:a aac_adtstoasc d:\cap.mp4