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

Kam*_*lin 500 gif ffmpeg

我正在将视频转换为 GIF 文件ffmpeg

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000 output.gif
Run Code Online (Sandbox Code Playgroud)

它工作得很好,但输出 gif 文件的质量非常低。

任何想法如何提高转换后的 gif 的质量?

llo*_*gan 778

ffmpeg 例子

来自 ffmpeg 的 GIF 输出
183k

ffmpeg可以输出高质量的GIF。在开始之前,始终建议使用最新版本:下载编译

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
Run Code Online (Sandbox Code Playgroud)
  • 此示例将跳过输入的前 30 秒 ( -ss 30) 并创建 3 秒输出 ( -t 3)。
  • fps过滤器设置帧速率。示例中使用了每秒 10 帧的速率。
  • 缩放过滤器会将输出调整为 320 像素宽,并在保持纵横比的同时自动确定高度。本例中使用了lanczos缩放算法
  • palettegenpaletteuse过滤器将生成并使用从输入生成的自定义调色板。这些过滤器有许多选项,因此请参阅所有可用选项和值列表的链接。另请参阅下面的高级选项部分。
  • 拆分过滤器将允许在一个命令中完成所有操作,并避免必须创建调色板的临时 PNG 文件。
  • 使用-loop输出选项控制循环,但值令人困惑。值为0无限循环,-1不循环,1将循环一次意味着它将播放两次。因此,值为 10 将导致 GIF 播放 11 次。

高级选项

palettegenpaletteuse过滤器有许多其他选项。最重要的是:

  • stats_mode(调色板)。您可以强制过滤器将调色板聚焦在一般图片(full这是默认设置)、仅移动部分 ( diff) 或每个单独的帧 ( single) 上。例如,要为每个单独的框架生成一个调色板,请使用palettegen=stats_mode=single& paletteuse=new=1

  • dither(调色板)。选择抖动算法。有三种主要类型:确定性 ( bayer)、误差扩散(包括默认值在内的所有其他类型sierra2_4a)和无。使用特定的抖动算法或根本不抖动,您的 GIF 可能看起来更好。如果您想尝试,请bayer务必也测试该bayer_scale选项。

请参阅带有 FFmpeg 的高质量 GIF 以获取说明、示例图像以及有关高级用法的更详细信息。

另请参阅palettegenpaletteuse文档了解所有可用的选项和值。


ImageMagickconvert示例

来自 ffmpeg 的 GIF 输出
227k

另一种命令行方法是从 ImageMagickffmpegconvert(或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
Run Code Online (Sandbox Code Playgroud)

ffmpeg 选项:

  • -vf "fps=10,scale=320:-1:flags=lanczos"使用fpsscale过滤器的filtergraph。fps 将帧速率设置为 10,scale 将大小设置为 320 像素宽,高度是自动确定的,并使用保留纵横比的值。本例中使用了lanczos缩放算法

  • -c:v pam选择 pam 图像编码器。该示例输出 PAM(便携式 AnyMap)图像格式,这是一种简单的无损 RGB 格式,支持透明度 (alpha) 并由convert. 编码速度比 PNG 快。

  • -f image2pipe选择 image2pipe 多路复用器,因为在输出到管道时ffmpeg需要告知使用哪个多路复用器。

convert 选项:

  • -delay请参阅下面的设置帧速率部分。

  • -loop 0 使无限循环。

  • -layers optimize将启用通用 GIF 优化器。有关更多详细信息,请参阅ImageMagick 动画优化。不能保证它会产生较小的输出,因此值得在没有-layers optimize和比较结果的情况下尝试。

设置帧率

使用中和中的fps过滤器组合设置帧速率。这可能会变得复杂,因为只是获取原始图像流,因此不会保留 fps。其次,在值是在(有每秒100只蜱),而不是在帧每秒。例如,与= 100/12.5 = 8 = 。ffmpeg-delayconvertconvert-delayconvertfps=12.5-delay 8

convert将该-delay值四舍五入为整数,因此 8.4 的结果为 8,8.5 的结果为 9。这实际上意味着在对所有帧设置统一延迟时仅支持某些帧速率(可以为每帧设置一个特定的延迟,但超出范围)这个答案)。

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

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

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

  • 顺便说一下,对于从 PNG 帧转换的 `convert` 命令,我最终使用了 `convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif"`,大大减少了整体文件大小 (7认同)
  • 添加了一些示例结果(尽管只是静止帧)。这里,第一个文件是 4.1 MB,第二个大约 8 MB。 (4认同)
  • 好的,我知道了,我使用了 `scale=0:-1`,所以当你将缩放比例设置为 `0` 时,它将从视频中获取缩放比例。 (4认同)
  • @LordNeckbeard,你太棒了!非常感谢`-vf scale=320:-1,format=rgb8,format=rgb24` (3认同)
  • 这个问答必须永久编码在一本书中(或者现在可能只是“固定”),因为从现在起一百年后所有的交流都将通过模因完成。我认为仅此帖子上的活动就说明了这一点。 (2认同)

小智 95

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

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 10 -loop 0 - output.gif
Run Code Online (Sandbox Code Playgroud)

-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 10 -loop 0 - gif:- | convert -layers Optimize - output.gif
Run Code Online (Sandbox Code Playgroud)

gif:-讲述convert到管其输出为gif格式化数据和-layers Optimize告诉第二convert执行optimize-frameoptimize-transparancy方法(参见ImageMagick的介绍动画优化)。请注意,来自 的输出-layers Optimize可能并不总是提供较小的文件大小,因此您可能需要先尝试在没有优化的情况下转换为 gif 以确保。

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

  • gif 似乎以源视频速度的 2 倍运行? (2认同)
  • 您还可以通过在 ffmpeg 中使用 `split` 过滤器来避免中间图像文件。根本不需要管道:`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` (2认同)

pje*_*pje 43

从 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
Run Code Online (Sandbox Code Playgroud)

H T

  • 这是做什么的? (9认同)

the*_*ist 25

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

运行./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"
Run Code Online (Sandbox Code Playgroud)

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

假设:安装了ffmpeg,并且脚本与其他文件在同一个文件夹中。

  • 非常感谢您的脚本。我刚刚测试了它,效果很好! (3认同)
  • 这个脚本正是我想要的 - 一种将 OBS 屏幕截图转换为用于错误报告的 gif 的超级简单方法 (2认同)

小智 24

@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
Run Code Online (Sandbox Code Playgroud)


ken*_*orb 14

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"
}
Run Code Online (Sandbox Code Playgroud)

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

用法示例:

video2gif input.flv
Run Code Online (Sandbox Code Playgroud)

或者:

video2gif input.flv 320 10
Run Code Online (Sandbox Code Playgroud)

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

您还可以指定不同的视频格式(例如 mp4)。


苹果系统

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


或者,有几个网站免费在线进行转换。


小智 13

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
Run Code Online (Sandbox Code Playgroud)

这可以通过split过滤器完成。


Jet*_*lue 13

所选答案假定您希望缩放源视频并在生成的 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
Run Code Online (Sandbox Code Playgroud)

当我想要一个忠实地重现我正在使用的源视频的 gif 时,这会派上用场。


can*_*dle 11

制作了一个脚本,经过测试并有效。

用法:

./avi2gif.sh ./vokoscreen-2015-05-28_12-41-56.avi
Run Code Online (Sandbox Code Playgroud)

有 PHUN :)

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
Run Code Online (Sandbox Code Playgroud)

顺便说一句:vokoscreen是适用于 Linux 的优秀截屏工具 :)

非常感谢 Michael Kohaupt :) 稳定。

一些文件大小统计信息:

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

此处查看结果。


Aph*_*hex 7

ffmpeg 命令:

  1. 运行此命令以便 ffmpeg 可以找出一个好的调色板:

    ffmpeg -y -i foo.mp4 -vf fps=30,scale=320:-1:flags=lanczos,palettegen palette.png
    
    Run Code Online (Sandbox Code Playgroud)
  2. 运行以下命令将 mp4 文件转换为 gif:

    ffmpeg -y -i foo.mp4 -i palette.png -filter_complex "fps=30,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" foo.gif
    
    Run Code Online (Sandbox Code Playgroud)

您可能想要调整 fps 和比例。任何一个较小都会导致更好的文件大小。

制作一个简单的别名函数

您还可以创建这样的别名函数。我将其添加到我的.bashrcor中.bash_profile

function makegif {
  ffmpeg -y -i $1 -vf fps=30,scale=320:-1:flags=lanczos,palettegen palette.png
  ffmpeg -y -i $1 -i palette.png -filter_complex "fps=30,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" $1.gif
}
Run Code Online (Sandbox Code Playgroud)

然后就只是makegif foo

注意:您当然需要 ffmpeg。在这里获取它https://www.ffmpeg.org/download.htmlbrew install ffmpeg


Nab*_*.Z. 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
Run Code Online (Sandbox Code Playgroud)

然后你可以在任何地方使用它,就像这个例子:

video2gif myvideo.mp4
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

  • 我看到您在这里做了两件事:(1) 将命令编写为 Windows (.BAT) 命令脚本,以及 (2) 提供了不同的过滤器组合(其他答案都没有使用 *both* `fps=10 ` 和 `scale=-1:-1`)。[Sun 的回答](//superuser.com/q/556029/150988#1092909) 已经给了我们一个批处理文件,那个(就像[pje 的回答](//superuser.com/q/556029/ 150988#893031) 和 [thevangelist's answer](//superuser.com/q/556029/150988#939527)) 的优点是它将过滤器列表分配给一个变量 (*once*),……(续) (2认同)

小智 5

如何添加 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
Run Code Online (Sandbox Code Playgroud)

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

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

如果您希望能够为脚本提供一些额外的命令行标志/参数,请创建一个名为 的新文件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%
Run Code Online (Sandbox Code Playgroud)

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