如何使用ffmpeg以合理的质量将视频转换为GIF?


310

我正在使用ffmpeg 将FLV电影转换为GIF文件。

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif

它的效果很好,但是输出的gif文件的质量很低。

有什么想法可以提高转换后的gif的质量吗?

命令输出:

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif
ffmpeg version 0.8.5-6:0.8.5-0ubuntu0.12.10.1, Copyright (c) 2000-2012 the Libav developers
  built on Jan 24 2013 14:52:53 with gcc 4.7.2
*** THIS PROGRAM IS DEPRECATED ***
This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.flv':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
  Duration: 00:00:18.85, start: 0.000000, bitrate: 3098 kb/s
    Stream #0.0(und): Video: h264 (High), yuv420p, 1280x720, 2905 kb/s, 25 fps, 25 tbr, 50 tbn, 50 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 192 kb/s
    Metadata:
      creation_time   : 2013-02-14 04:00:07
[buffer @ 0x92a8ea0] w:1280 h:720 pixfmt:yuv420p
[scale @ 0x9215100] w:1280 h:720 fmt:yuv420p -> w:320 h:240 fmt:rgb24 flags:0x4
Output #0, gif, to 'output.gif':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
    encoder         : Lavf53.21.1
    Stream #0.0(und): Video: rawvideo, rgb24, 320x240, q=2-31, 200 kb/s, 90k tbn, 10 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Stream mapping:
  Stream #0.0 -> #0.0
Press ctrl-c to stop encoding
frame=  101 fps= 32 q=0.0 Lsize=    8686kB time=10.10 bitrate=7045.0kbits/s dup=0 drop=149    
video:22725kB audio:0kB global headers:0kB muxing overhead -61.778676%

谢谢。


1
有趣的是,当APNG成为现实时,人们仍然如何使用GIF进行调色板工作。
КонстантинВан3

Answers:


447

ffmpeg

ffmpeg的GIF输出
18.3万

ffmpeg可以输出高质量的GIF。始终建议使用最新版本:downloadcompile

ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
  • 本示例将跳过输入的前30秒(-ss 30),并创建一个3秒的输出(-t 3)。
  • fps过滤器设置帧频。
  • 比例滤镜会将输出调整为320像素宽,并在保留长宽比的同时自动确定高度。
  • palettegenpaletteuse过滤器将生成并使用从您的输入生成的自定义调色板。
  • 拆分过滤器将使所有操作都可以在一个命令中完成。
  • -loop输出选项的控制循环。值0是无限循环。

有关更多示例和选项,请参阅使用FFmpeg的高质量GIF


Imagemagick的convert例子

ffmpeg的GIF输出
22.7万

另一种命令行方法是从ImageMagick ffmpeg传递到convert(或magick)。

 ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos" -c:v pam -f image2pipe - | convert -delay 10 - -loop 0 -layers optimize output.gif

设置帧频

使用fpsin ffmpeg-delayin 中的过滤器组合设置帧频convert。这convert会变得很复杂,因为仅获取原始图像流,因此不保留fps。其次,-delay在值convert是在(有每秒100只蜱),而不是在帧每秒。例如,with fps=12.5= 100 / 12.5 = 8 = -delay 8

convert-delay值四舍五入为整数,因此8.4得出8,而8.5得出9。这实际上意味着在所有帧上设置均匀延迟时仅支持某些帧速率(可以为每个帧设置特定的延迟,但是超出了这个答案)。

-delay如果用作输出选项,则似乎会被忽略,因此,-如示例中所示,必须先使用它。

最后,浏览器和图像查看器可能会实现最小延迟,因此-delay无论如何您都可能会被忽略。

视频由美国鱼类和野生动物服务国家保护培训中心提供。


4
添加了一些示例结果(尽管只是静止帧)。在这里,第一个文件是4.1 MB,第二个文件是8 MB。
slhck

2
@LordNeckbeard,您真棒!非常感谢-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin13 '02

6
顺便说一句,convert我最终使用了从PNG帧转换的命令convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif",这大大减少了文件的整体大小
Wilf 2014年

2
好的,我已经知道了scale=0:-1,所以当您将比例设置为时0,它将从视频中获取比例。
Mousa Alfhaily

2
必须将此Q&A永久编码在书本中(或暂时仅固定在书中),因为从现在开始的一百年内,所有通信都将通过模因进行。我认为仅此帖子上的活动就说明了这一点。
乔纳森·诺伊费尔德'18

87

如果您希望避免使用中间图像文件,可以将LordNeckBeard提供的命令ffmpeg与ImageMagick的命令之间通过管道传递,convert这样就不需要中间文件:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - output.gif

-f image2pipe告诉FFmpeg视频分割成图像,并使其适合于管道输送出去,并-vcodec ppm指定输出格式是PPM(由于某种原因,如果格式是png,或者convert不从管读取所有的图像,或者FFMPEG确实不能全部输出)。在-这两个命令指定的管道将被分别用于输出和输入。

要在不保存文件的情况下优化结果,可以将输出通过管道convert传递给第二个convert命令:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - gif:- | convert -layers Optimize - output.gif

gif:-Tell convert管道将其输出作为gif格式的数据进行传递,并-layers Optimize告诉第二个convertPerform optimize-frameoptimize-transparancy方法(请参见ImageMagick 动画优化简介)。请注意,的输出-layers Optimize可能并不总是提供较小的文件大小,因此您可能需要尝试先转换为gif而不进行优化,以确保安全。

请记住,在整个过程中,所有内容都在内存中,因此,如果图像很大,则可能需要足够的内存。


1
这组命令还适用于avconv
raphael 2015年

你应该合并的最后两个转换命令:convert -delay 5 -loop 0 -layers Optimize - output.gif
克莱门特

gif的运行速度似乎是源视频的2倍?
泰坦

@Titan相信它是第一个命令中的-r 10,第二个命令中的-delay 5。我也将延迟更改为10,现在看来正常播放了。
Steven Huang

2
您还可以通过使用splitffmpeg中的过滤器来避免中间图像文件。根本不需要传送任何内容:ffmpeg -ss 30 -t 3 -i "input.flv fps=10,scale=320:-1:flags=lanczos,split[x][z];[z]palettegen[y];[x][y]paletteuse" output.gif
Ajedi32 '17

37

从ffmpeg 2.6开始,我们可以做得更好:

palette="/tmp/palette.png"
filters="fps=15,scale=320:-1:flags=lanczos"

ffmpeg -i input.flv -vf "$filters,palettegen" -y $palette
ffmpeg -i input.flv -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y output.gif

H T


18

我制作了自己的脚本版本,该脚本还参数化了输出分辨率和帧速率。

运行./gifenc.sh input.mov output.gif 720 10将从您给它提供的电影中输出720p宽10fps GIF。您可能需要对chmod +x gifenc.sh文件进行处理。

#!/bin/sh

palette="/tmp/palette.png"

filters="fps=$4,scale=$3:-1:flags=lanczos"

ffmpeg -v warning -i "$1" -vf "$filters,palettegen" -y "$palette"
ffmpeg -v warning -i "$1" -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y "$2"

您可以在我的Github上阅读详细信息

假设:已安装ffmpeg,并且脚本与其他文件位于同一文件夹中。


3
非常感谢您的脚本。我刚刚测试了它,效果很好!
orschiro'2

15

@Stephane的答案非常好。但是它会像Buffer queue overflow, dropping.某些视频一样收到警告,并且生成的gif帧丢失了。

这是带有fifo过滤器的更好版本,可避免Buffer queue overflow在使用paletteuse过滤器时使用。通过使用split过滤器可以避免创建中间调色板PNG文件。

ffmpeg -i input.mp4 -filter_complex 'fps=10,scale=320:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' out.gif

如果我正确理解,则将输入分为o1和o2,然后将o2复制到o3。那么,为什么需要o3?为什么不直接使用o2?
Chloe

1
@Chloe您是否看到和fifo之间的过滤器操作?为了避免警告。o2o3Buffer queue overflow
alijandro

+1对我来说确实很好(并解决了所提到的问题)。
伊恩·柯林斯

我绝对喜欢这种解决方案。荣誉!
Leonid Usov

10

制作了脚本,进行了测试并可以工作。

用法:

./avi2gif.sh ./vokoscreen-2015-05-28_12-41-56.avi

有电话:)

vim avi2gif.sh

#!/bin/sh

INPUT=$1

# default settings, modify if you want.

START_AT_SECOND=0; # in seconds, if you want to skip the first 30 seconds put 30 here

LENGTH_OF_GIF_VIDEO=9999999; # in seconds, how long the gif animation should be

echo "Generate a palette:"
ffmpeg -y -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png

echo "Output the GIF using the palette:"
ffmpeg -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" $INPUT.gif

顺便说一句:vokoscreen是一个出色的Linux 抓屏工具:)

非常感谢Michael Kohaupt :)岩石稳定。

一些文件大小统计信息:

5.3M = vokoscreen-2015-04-28_15-43-17.avi-> vokoscreen-2015-05-28_12-41-56.avi.gif = 1013K

这里查看结果。


10

ffmpeg调色板方法可以在单一的命令运行,而无需中介.png文件。

ffmpeg -y -ss 30 -t 3 -i input.flv -filter_complex \
"fps=10,scale=320:-1:flags=lanczos[x];[x]split[x1][x2]; \
[x1]palettegen[p];[x2][p]paletteuse" output.gif

这可以归功于split过滤器。


10

Linux / Unix / macOS

@LordNeckbeard方法ffmpeg命令,请找到可以添加到您的以下有用的bash函数~/.bash_profile文件:

# Convert video to gif file.
# Usage: video2gif video_file (scale) (fps)
video2gif() {
  ffmpeg -y -i "${1}" -vf fps=${3:-10},scale=${2:-320}:-1:flags=lanczos,palettegen "${1}.png"
  ffmpeg -i "${1}" -i "${1}.png" -filter_complex "fps=${3:-10},scale=${2:-320}:-1:flags=lanczos[x];[x][1:v]paletteuse" "${1}".gif
  rm "${1}.png"
}

一旦函数被加载(手动或从. ~/.bash_profile),您应该有新的video2gif命令。

用法示例:

video2gif input.flv

要么:

video2gif input.flv 320 10

以每秒10帧的比例缩放到320宽度。

您还可以指定其他视频格式(例如mp4)。


苹果系统

您可以尝试GIF Brewery应用程序,该应用程序可以从视频文件创建GIF。


另外,有一些网站免费在线进行转换。


您的脚本为我引发了一个错误,原因是没有png文件,也没有gif输出,但是.mp4输入文件保持不变
lacostenycoder

7

选择的答案假设您希望缩放源视频并在生成的gif中更改其fps。如果您不需要这样做,则可以进行以下操作:

src="input.flv"
dest="output.gif"
palette="/tmp/palette.png"

ffmpeg -i $src -vf palettegen -y $palette
ffmpeg -i $src -i $palette -lavfi paletteuse -y $dest

当我想要一个可以忠实地重新创建我正在使用的源视频的gif时,这很方便。


6

对于Windows用户:在Windows目录中使用以下内容
创建video2gif.bat文件:

@echo off
set arg1=%1
set arg2=%arg1:~0,-4%
ffmpeg -y -i %arg1% -vf fps=10,scale=-1:-1:flags=lanczos,palettegen %TEMP%\palette.png
ffmpeg -i %arg1% -i %TEMP%\palette.png -filter_complex "fps=10,scale=-1:-1:flags=lanczos[x];[x][1:v]paletteuse" %arg2%.gif
del /f %TEMP%\palette.png

然后可以在任何可以使用它的地方使用此示例:

video2gif myvideo.mp4

然后,您myvideo.gif在当前目录中。
如果myvideo.gif存在,请询问您是否将其覆盖。

编辑:

我建议使用此批处理脚本:https : //github.com/NabiKAZ/video2gif


2
我看到您在这里做了两件事:(1)将命令编写为Windows(.BAT)命令脚本,并且(2)提供了不同的过滤器组合(其他答案 没有同时使用fps=10scale=-1:-1)。  Sun的答案已经给了我们一个批处理文件,并且该文件(如pje的答案thevangelist的答案中的shell脚本一样)具有将过滤器列表分配给变量的优点(一次),……(续)
Scott

1
(续)…因此它不需要两次拼出列表(就像您的批处理文件一样)。(我假设这会带来风险,如果用户编辑脚本以更改列表之一而不更改列表,则不一致会引起问题。)您能否至少说明选择过滤器(fps=10,scale=-1:-1)?(有关命令部分解释的示例,请参见注意的答案。)
斯科特(Scott

1
@Scott您说的没错,所以我在这里写了一个新的有用的脚本:github.com/NabiKAZ/video2gif
Nabi KAZ

4

以下是Windows用户的批处理文件:

gifenc.bat:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %2

来源:带有FFmpeg的高质量GIF:仅提取样本

如果您只想使用一个输入变量,并且输出名称仅具有GIF(发音为JIF)扩展名,请改用以下命令:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
set var1=%1
set var2=%var1:~0,-4%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %var2%.gif

3

如何添加Windows 7/10“右键单击”上下文菜单项以将视频文件转换为gif

其他一些答案提到了我使用的video2gif脚本。但是,您可以使用任何脚本。

要创建上下文菜单选项,您需要编辑注册表。打开一个Powershell命令提示符,运行带有admin privs的命令。执行以下命令:

$key = "Registry::HKEY_CLASSES_ROOT\`*\shell\Run Video2Gif"
New-Item -Path $key"\Command" -Value "C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat `"%1`"" -Force

现在,当您右键单击文件时,将具有“运行Video2Gif”选项!

顺便说一句,我安装了ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\并将video2gif.bat脚本放在旁边的bin目录中ffmpeg.exe。我还添加C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin了我的窗户PATH,但我认为您不需要。

如果您希望能够为脚本提供一些额外的命令行标志/ args,请制作一个名为的新文件video2gif-prompt.bat,并让注册表引用它,而不是video2gif.bat

@echo off
set /p inp=Enter extrta args, if desired:
C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat %* %inp%

您仍然可以按Enter快速获取默认值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.