I'm converting .flv movie to .gif file with ffmpeg.

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

It works great, but output gif file has a very low quality.

Any ideas how can I improve quality of converted gif?

Output of command:

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%

Thanks.

migrated from stackoverflow.com Feb 22 '13 at 22:25

This question came from our site for professional and enthusiast programmers.

12 Answers 12

up vote 374 down vote accepted

ffmpeg can now output higher quality GIF. If you are using an older build consider downloading a recent static build or compiling ffmpeg.

ffmpeg example

gif with ffmpeg
203k

This example will skip the first 30 seconds of the input and create a 3 second output. It will scale the output to be 320 pixels wide and automatically determine the height while preserving the aspect ratio. The palettegen and paletteuse filters will generate and use a custom palette generated from your source.

  1. Generate a palette:

    ffmpeg -y -ss 30 -t 3 -i input.flv \
    -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png
    
  2. Output the GIF using the palette:

    ffmpeg -ss 30 -t 3 -i input.flv -i palette.png -filter_complex \
    "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
    

See High quality GIF with FFmpeg for many more examples and options.


convert example

Another command-line method would be to export the movie to frames using ffmpeg then make the GIF with convert from ImageMagick (or GraphicsMagick).

ffmpeg and convert
246k

  1. Export frames:

     mkdir frames
     ffmpeg -i input -vf scale=320:-1:flags=lanczos,fps=10 frames/ffout%03d.png
    
  2. Then use convert (or gm convert if you prefer GraphicsMagick) to make your animated GIF:

     convert -loop 0 frames/ffout*.png output.gif
    

With convert you can control the delay between frames with -delay if desired.

  • 3
    Added some example results (just still frames though). Here, the first file is 4.1 MB, the second around 8 MB. – slhck Feb 22 '13 at 21:44
  • 2
    @LordNeckbeard, you are awesome! much thanks for -vf scale=320:-1,format=rgb8,format=rgb24 – Kamil Hismatullin Feb 22 '13 at 21:53
  • 5
    By the way, for the convert command for converting from the PNG frames I ended up using convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", which reduces the overall file size quite a bit – Wilf Jul 24 '14 at 13:58
  • 1
    I think the convert command should be using -delay 10 (0.1 seconds between frames) to match the -r 10 (10 fps) frame rate you're feeding to ffmpeg. When I use -delay 5, I see the gif play at double speed. – Jack O'Connor Sep 27 '14 at 0:16
  • 2
    Okay, I've got it, i used scale=0:-1, so when you set the scale to 0, it will take the scale from the video. – Mousa Alfhaily Sep 16 '17 at 12:20

If you would prefer to avoid intermediate image files, the commands provided by LordNeckBeard can be piped between ffmpeg and ImageMagick's convert so that no intermediate files are required:

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

The -f image2pipe tells ffmpeg to split the video into images and make it suitable to be piped out, and -vcodec ppm specifies the output format to be ppm (for some reason if the format is png, either convert does not read all the images from the pipe, or ffmpeg does not output them all). The - for both commands specifies that a pipe will be used for output and input respectively.

To optimize the result without saving a file, you can pipe the output from convert to a second convert command:

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

The gif:- tells convert to pipe its output as gif formatted data and -layers Optimize tells the second convert to perform optimize-frame and optimize-transparancy methods (see the ImageMagick Introduction to Animation Optimization). Note that the output from the -layers Optimize may not always provide a smaller file size, so you may want to try converting to a gif without optimization first to be sure.

Remember that during this whole process everything is in memory so you may need sufficient memory if the images are quite large.

  • 1
    This set of commands also works with avconv – raphael Dec 9 '15 at 2:00
  • You should merge the last two convert commands: convert -delay 5 -loop 0 -layers Optimize - output.gif – Clément Jul 5 '16 at 5:50
  • The gif appears to be running at 2x the speed of the source video? – Titan Oct 10 '16 at 13:28
  • @Titan believe it's the -r 10 in the first command and the -delay 5 in the second. I changed the delay to 10 also and it seems to play normally now. – Steven Huang Jan 8 '17 at 4:28
  • 2
    You can also avoid intermediate image files by using the split filter in ffmpeg. No need to pipe anything at all: 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 Jan 8 '17 at 23:26

As of ffmpeg 2.6, we can do even better:

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

HT

I made my own version of the script, which parameterizes the output resolution and frame rate as well.

Running ./gifenc.sh input.mov output.gif 720 10 will output 720p wide 10fps GIF from the movie you gave it. You might need to do chmod +x gifenc.sh for the file.

#!/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"

You can read the details on my Github

Assumptions: ffmpeg is installed, and the script is in the same folder as the other files.

  • 2
    Thank you so much for your script. I just tested it and it works great! – orschiro Feb 5 '16 at 9:32

made a script, tested and works.

usage:

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

HAVE 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

btw: vokoscreen is an EXCELLENT ScreenCapturing tool for Linux :)

THANKS A LOT Michael Kohaupt :) Rock steady.

some file size stats:

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

see the results here.

The answer from @Stephane is very good. But it will get a warning like Buffer queue overflow, dropping. for some video, and the generated gif has some frame dropped.

Here is a better version with fifo filter to avoid Buffer queue overflow when using paletteuse filter. By using split filter to avoid the creation of intermediate palette PNG file.

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

Linux/Unix/macOS

Following @LordNeckbeard approach with ffmpeg command, please find the following useful Bash function which can be added into your ~/bash_profile file:

# 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"
}

Once the file is loaded (. ~/.bash_profile), you should have new video2gif command.

Example usage:

video2gif input.flv

or:

video2gif input.flv 320 10

Scale to 320 width with 10 frames per second.

You can also specify a different video format (such as mp4).


macOS

You can try GIF Brewery app which can create GIFs from video files.


Alternatively there are several websites which are doing conversion online free of charge.

  • Tangential/offtopic: For anyone wondering why Community edited this, it was to HTTPSify the link in the first line of the answer. (Stack Overflow's HTTPS transition is well underway!) – i336_ Apr 23 '17 at 4:49

The ffmpeg with palette method can be run in a single command, without intermediary .png file.

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

This can be done thanks to the split filter.

Below is the batch file for Windows users:

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

Source: High quality GIF with FFmpeg: Extracting just a sample

If you just want to use one input variable and have the output name have just the GIF (pronounced JIF) extension, then use this instead:

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

For windows users:
create video2gif.bat file in windows directory with these content:

@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

And then anywhere you can use it be like this example:

video2gif myvideo.mp4

Then you have myvideo.gif in current directory.
If myvideo.gif there is existed, question from you for overwrite it.

EDIT:

I suggest use this batch script: https://github.com/NabiKAZ/video2gif

  • 1
    I see that you have done two things here: (1) written the commands as a Windows (.BAT) command script, and  (2) provided a different combination of filters (none of the other answers uses both fps=10 and scale=-1:-1).  Sun’s answer already gave us a batch file, and that one (like the shell scripts in pje’s answer and thevangelist’s answer) has the advantage that it assigns the list of filters to a variable (once),  … (Cont’d) – Scott Apr 21 '17 at 19:09
  • 1
    (Cont’d) …  so it doesn’t need to spell out the list twice (as your batch file does).   (I presume that this creates a risk that, if the user edits the script to change one of the lists but not the other, the inconsistency will cause a problem.)   Can you at least explain your choice of filters (fps=10,scale=-1:-1)?   (See notedible’s answer for an example of an explanation of parts of a command.) – Scott Apr 21 '17 at 19:09
  • @Scott You said correct, so I write a new useful script in here: github.com/NabiKAZ/video2gif – Nabi K.A.Z. Apr 23 '17 at 6:46

The selected answer assumes you wish to scale the source video and change its fps in the gif produced. If you do not need to do this, the following works:

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

This came in handy when I wanted a gif that faithfully recreated the source video I was using.

How to add a windows "right-click" context menu entry to convert your video file to gif

Some of the other answers mentioned the video2gif script, which I used. But, you could use any script.

To create the context-menu option, you need to edit your registry. Open a powershell command prompt, running w/ admin privs. Execute these commands:

$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

Now when you right click a file you'll have a "Run Video2Gif" option!

btw I installed ffmpeg to C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\ and put the video2gif.bat script in the bin dir right next to ffmpeg.exe. I also added C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin to my windows PATH, but I don't think you need to.

If you want the option of being able to supply some extra command line flags / args to the script, then make a new file named video2gif-prompt.bat, and have the registry referce it instead of 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%

You can still just hit enter to quickly get the defaults.

protected by Community Nov 26 '17 at 22:51

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.