630

I'm converting a video 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?

Rob Bednark
  • 173
  • 1
  • 5
Kamil Hismatullin
  • 6,410
  • 3
  • 13
  • 7
  • 4
    Excellent post from giphy engineers https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/ – spuder Mar 30 '21 at 22:16
  • I had this same macroblocking issue with Clipchamp export to gif feature. I'm mentioning this for the algorithm. – carlin.scott Mar 23 '23 at 23:07

15 Answers15

976

ffmpeg example

GIF output from ffmpeg
183k

ffmpeg can output high quality GIF. Before you start it is always recommended to use a recent version: download or compile.

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
  • This example will skip the first 30 seconds (-ss 30) of the input and create a 3 second output (-t 3).
  • fps filter sets the frame rate. A rate of 10 frames per second is used in the example.
  • scale filter will resize the output to 320 pixels wide and automatically determine the height while preserving the aspect ratio. The lanczos scaling algorithm is used in this example.
  • palettegen and paletteuse filters will generate and use a custom palette generated from your input. These filters have many options, so refer to the links for a list of all available options and values. Also see the Advanced options section below.
  • split filter will allow everything to be done in one command and avoids having to create a temporary PNG file of the palette.
  • Control looping with -loop output option but the values are confusing. A value of 0 is infinite looping, -1 is no looping, and 1 will loop once meaning it will play twice. So a value of 10 will cause the GIF to play 11 times.

Advanced options

The palettegen and paletteuse filters have many additional options. The most important are:

  • stats_mode (palettegen). You can force the filters to focus the palette on the general picture (full which is the default), only the moving parts (diff), or each individual frame (single). For example, to generate a palette for each individual frame use palettegen=stats_mode=single & paletteuse=new=1.

  • dither (paletteuse). Choose the dithering algorithm. There are three main types: deterministic (bayer), error diffusion (all the others including the default sierra2_4a), and none. Your GIF may look better using a particular dithering algorithm, or no dithering at all. If you want to try bayer be sure to test the bayer_scale option too.

See High quality GIF with FFmpeg for explanations, example images, and more detailed info for advanced usage.

Also see the palettegen and paletteuse documentation for all available options and values.


ImageMagick convert example

GIF output from ffmpeg
227k

Another command-line method is to pipe from ffmpeg to convert (or magick) from ImageMagick.

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

ffmpeg options:

  • -vf "fps=10,scale=320:-1:flags=lanczos" a filtergraph using the fps and scale filters. fps sets frame rate to 10, and scale sets the size to 320 pixels wide and height is automatically determined and uses a value that preserves the aspect ratio. The lanczos scaling algorithm is used in this example.

  • -c:v pam Chooses the pam image encoder. The example outputs the PAM (Portable AnyMap) image format which is a simple, lossless RGB format that supports transparency (alpha) and is supported by convert. It is faster to encode than PNG.

  • -f image2pipe chooses the image2pipe muxer because when outputting to a pipe ffmpeg needs to be told which muxer to use.

convert options:

  • -delay See Setting frame rate section below.

  • -loop 0 makes infinite loop.

  • -layers optimize Will enable the general purpose GIF optimizer. See ImageMagick Animation Optimization for more details. It is not guaranteed that it will produce a smaller output, so it is worth trying without -layers optimize and comparing results.

Setting frame rate

Set frame rate with a combination of the fps filter in ffmpeg and -delay in convert. This can get complicated because convert just gets a raw stream of images so no fps is preserved. Secondly, the -delay value in convert is in ticks (there are 100 ticks per second), not in frames per second. For example, with fps=12.5 = 100/12.5 = 8 = -delay 8.

convert rounds the -delay value to a whole number, so 8.4 results in 8 and 8.5 results in 9. This effectively means that only some frame rates are supported when setting a uniform delay over all frames (a specific delay can be set per frame but that is beyond this answer).

-delay appears to be ignored if used as an output option, so it has to be used before - as shown in the example.

Lastly, browsers and image viewers may implement a minimum delay, so your -delay may get ignored anyway.

Video courtesy of U.S. Fish & Wildlife Service National Conservation Training Center.

K3---rnc
  • 280
  • 3
  • 8
llogan
  • 57,139
  • 15
  • 118
  • 145
  • 4
    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
  • 4
    @LordNeckbeard, you are awesome! much thanks for `-vf scale=320:-1,format=rgb8,format=rgb24` – Kamil Hismatullin Feb 22 '13 at 21:53
  • @LordNeckbeard - the `convert` option worked brilliantly - also using an ancient version of ffmpeg directly got a file size of 300Mb with rubbish output, whilst the high quality one from convert was 13Mb... – Wilf Jul 05 '14 at 23:00
  • 7
    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 00:16
  • Is it it possible to crop a few pixels from the resulting GIF? I love these funny GIF from real movies/cartoons scenes, but I've found one, with a bad quality, in which the top... 5cm, more or less, is damaged. If I need to open a new thread I'll gladly – Bruno Augusto May 15 '16 at 21:40
  • Bravo! I used the "ffmpeg example" to convert a CamStudio recording of my screen showing a RAID5 parity recovery of a flash drive RAID5 array. The recovery took about an hour. During that time, I teed the output to a text file. The video was actually the recording of my parsing the text. the AVI was 1.4 GB; the GIF was 2.5 MB. – user38537 May 29 '16 at 04:23
  • In the second approach, you can use ffmpeg instead of imagick. All you need to do, is to use the image2 demuxer's **framrate** option, so you can set the delay between individual frames: `ffmpeg -framerate -i frames/ffout*.png output.gif` – Gergely Lukacsy Jun 02 '16 at 09:35
  • Your ffmpeg example has become a common enough workflow for me that I wrote a bash wrapper script to automate it. Sharing here: https://github.com/jordanh/ffmpeg2gif – Jordan Sep 20 '16 at 16:22
  • How if i don't want to set the scale, i need to make him the the video's scale automatically? – Mousa Alfhaily Sep 16 '17 at 12:07
  • 6
    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
  • 1
    Giphy Engineering has released a nice article recently explaining all the options: https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg – Marcus Mangelsdorf Apr 30 '18 at 09:54
  • @LordNeckbeard How to can I modify your code to take let's say from a particular interval of a movie of let's say between 00:24:45 to 00:25:52? I tried to use the seek command and it did not work!. Can you perhaps help me with this?. I would like to know how to make it work with the palette you say to make and use ffmpeg to build up from that the gif. Btw I used the code as you mention and it works but to take a sample from longer intervals such as I mentioned is not very practical as I have to translate the minutes or hours to seconds. – Chris Steinbeck Bell Jul 16 '18 at 08:25
  • @LordNeckbeard Also the framerate you use how did you obtained?. Does it come from the input movie or is it just a random value that you chosen? – Chris Steinbeck Bell Jul 16 '18 at 08:25
  • @ChrisSteinbeckBell I chose a value low enough to make the GIF smaller in file size, but high enough to look acceptable. You'll just have to experiment depending on your content. – llogan Jul 17 '18 at 19:38
  • @LordNeckbeard Thanks for replying back, but I'd appreciate you could help me with the part of the code regarding time as I'm not too saavy enough to do that modification by myself. As I mentioned I tried to use seek command as ffmpeg documentation suggests the way of -ss 00:24:25 to 00:25:52 – Chris Steinbeck Bell Jul 18 '18 at 02:04
  • @LordNeckbeard just after the input but I can't make ffmpeg to interpret the command the way I need, perhaps can you help me with that?. I'd be really grateful. – Chris Steinbeck Bell Jul 18 '18 at 02:04
  • @ChrisSteinbeckBell Might be worth asking this as a new question and I or someone else can help. Comments may be too limited. – llogan Jul 18 '18 at 17:20
  • 1
    Trying the very first command - to generate the pallette (with ffmpeg-4.0.1): `Option 'flags' not found`. ffmpeg would've been _a lot_ more useful, if the developers knew the concept of backwards compatibility... – Mikhail T. Jul 21 '18 at 19:01
  • @MikhailT. Works for me. Please show your actual command and the complete log. You can use a pastebin site and provide the link here. – llogan Jul 21 '18 at 19:32
  • Err, never mind. I tried removing the `scale=360` part and that didn't work. Don't know, why... – Mikhail T. Jul 21 '18 at 19:41
  • 1
    @MikhailT. The full scale part is `scale=320:-1:flags=lanczos`. The `flags` is an option for scale. I probably should not have included that in the example as it increased complexity of the example. – llogan Jul 21 '18 at 21:17
  • 2
    This Q&A must be permanently encoded in a tome (or maybe just "pinned" for now) because in a hundred years from now all communication will be done via memes. I think the activity on this post alone speaks to that. – Coder Guy Oct 07 '18 at 08:15
  • 1
    What is [x] ?? Why nobody on the whole earh mentioned this [x]? – user1308990 Jan 29 '19 at 13:39
  • 1
    @user1308990 `[x]` is just the label of the output coming from the `fps=10,scale=320:-1:flags=lanczos` filterchain. The label is then referred to by other, separate filterchains or the output file. The label can be almost any arbitrary name, so you could rename it to whatever makes most sense to you. See [FFmpeg Filtering: Introduction](https://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction) for more info. – llogan Jan 30 '19 at 22:25
  • 1
    For the ffmpeg-only solution, I encourage the use of [this brilliant single call with filter graph solution](https://superuser.com/a/1256459/535934) from @alijandro – Leonid Usov Jul 27 '19 at 10:22
  • Please describe all options, what is `-c:v pam`? – Vitaly Zdanevich Dec 16 '19 at 21:02
  • 1
    @VitalyZdanevich Answer updated. – llogan Dec 16 '19 at 21:34
  • I tried creating a GIF of 3 seconds from a 990 KB video of resolution 640 * 360 having a duration of 14 seconds. But the output GIF is having a size of 1.17 MB. I'm using `ffmpeg` command. `ffmpeg -t 3 -i inputfile.mp4 -vf ""fps = 10,scale = 320:-1:flags = lanczos,split[s0][s1];[s0] palettegen[p];[s1] [p] paletteuse"" -loop 0 outputfile.gif`. Is there any way to reduce the size without using `ImageMagick`? – Farshan Apr 15 '20 at 18:36
  • 1
    @Farshan GIF is an antiquated format, so size will always be relatively high. Use a lower fps, smaller scale, and/or shorter `-t`. You can also reduce the number of colors as in `palettegen=max_colors=64`. – llogan Apr 15 '20 at 18:53
  • Wow; thank you. My animated gifs are now incredibly improved. – Edward Falk May 05 '20 at 18:12
  • 1
    [Source for why `lanczos` is a good choice here](https://superuser.com/a/375726/147688). TLDR good for both downsampling and upsampling. – ijoseph Sep 13 '20 at 22:25
  • @llogan My bad, VLC was the culprit. I didn't know it couldn't read gifs. I'll delete the comments – Atralb Oct 19 '20 at 21:17
  • @llogan I found your snippet in a code base recently when trouble shooting why ffmpeg used so much memory, and takes so much time. Turns out that by slicing out the duration beforehand to a temporary file with the same container as input (null audio video copy), and then doing the fps/scale/palette/gif uses a fraction of the memory in a fraction of the time. No idea why, one guess is that palette operates on the whole video otherwise, not sure. – dsvensson Nov 19 '20 at 08:08
  • @dsvensson Never noticed a memory issue (but I'm not making GIFs often and they are using inputs only seconds long). How can the issue be duplicated? What are your commands to resolve it? You can use a pastebin link. Thanks. – llogan Nov 19 '20 at 18:16
  • It is giving No such filter: 'palettegen' Error opening filters! error – Mayank Kumar Chaudhari Dec 24 '20 at 08:30
  • @mayank1513 Your ffmpeg must be really old, or you have configured it to remove support for this filter. – llogan Dec 24 '20 at 18:45
  • I don't know if you have ever faced the problem which i faced but let me explain you, in some devices when you pick `Camera Video` to convert to `Gif` it will gets stretched because if video is portrait, means orientation is `0` but still it will show `90` or `270`, this will only happens to `Camera Videos`, not to other videos and not on every device(currently in `Samsung, OnePlus` works fine but not on `Realme`). – Vivek Thummar Jun 16 '21 at 07:09
  • @VivekThummar Should be asked as a new question. – llogan Jun 16 '21 at 16:34
  • @llogan if you measure ffmpeg memory usage on some long 4k hq video with your command line parameters, and then compared that to if you just slice the first second - and in a second invocation perform the gif conversion you should notice reduced memory usage. /usr/bin/time -v is your mem stats friend. – dsvensson Jul 08 '21 at 08:11
  • You're a legend. – byxor Dec 15 '21 at 22:59
  • 1
    This doesn't work with `ffmpeg` 6.0. I get an error about `lanczos` deprecated or not found. – Geremia Jul 29 '23 at 03:11
104

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 10 -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 10 -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.

notedible
  • 1,259
  • 1
  • 9
  • 4
  • 1
    This set of commands also works with `avconv` – raphael Dec 09 '15 at 02:00
  • You should merge the last two convert commands: `convert -delay 5 -loop 0 -layers Optimize - output.gif` – Clément Jul 05 '16 at 05:50
  • 2
    The gif appears to be running at 2x the speed of the source video? – Titan Oct 10 '16 at 13:28
  • 1
    @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 08 '17 at 04: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 08 '17 at 23:26
  • 1
    Is there a way to maintain the scale? For example, my video file is 904:774. How do I do it without setting `scale=320:-1`? Is there a way to automate it without exploding the size? – Sudhir Singh Khanger Sep 07 '18 at 07:08
  • 1
    @Ajedi32 Thanks. You forgot the `-vf` though, it should be `ffmpeg -ss 30 -t 3 -i input.flv -vf "fps=10,scale=320:-1:flags=lanczos,split[x][z];[z]palettegen[y];[x][y]paletteuse" output.gif` – localhost Oct 03 '20 at 11:48
51

As of ffmpeg 2.6, we can do even better. Based on High quality GIF with FFmpeg:

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
Peregrino69
  • 4,526
  • 2
  • 22
  • 30
pje
  • 611
  • 5
  • 5
30

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
alijandro
  • 401
  • 4
  • 3
  • If I understand that correctly, you are splitting the input into o1 and o2, and copying o2 to o3. So why do you need o3? Why not just use o2 directly? – Chloe Sep 28 '18 at 23:26
  • 1
    @Chloe Did you see the `fifo` filter operation between `o2` and `o3`? To avoid the `Buffer queue overflow` warning. – alijandro Oct 23 '18 at 01:45
29

I made my own version of this 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.

thevangelist
  • 484
  • 1
  • 6
  • 11
  • 3
    Thank you so much for your script. I just tested it and it works great! – orschiro Feb 05 '16 at 09:32
  • 2
    This script is exactly what I wanted - a super easy way to convert OBS screen captures to gifs for bug reporting – jameh May 08 '20 at 21:30
20

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 function is loaded (manually or from . ~/.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.

kenorb
  • 24,736
  • 27
  • 129
  • 199
17

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.

Jet Blue
  • 287
  • 3
  • 8
15

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.

Stephane
  • 161
  • 1
  • 5
11

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.

canoodle
  • 231
  • 1
  • 3
  • 4
8

For Windows users: create a file \Windows\video2gif.bat with this 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 you can use it anywhere like this:

video2gif myvideo.mp4

Then you have myvideo.gif next to your original input file. If myvideo.gif already exists, you will be asked to overwrite it.

I suggest using this versatile batch script.

AmigoJack
  • 105
  • 1
  • 7
Nabi K.A.Z.
  • 420
  • 1
  • 6
  • 11
  • 2
    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](//superuser.com/q/556029/150988#1092909) already gave us a batch file, and that one (like the shell scripts in [pje’s answer](//superuser.com/q/556029/150988#893031) and [thevangelist’s answer](//superuser.com/q/556029/150988#939527)) 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](//superuser.com/q/556029/150988#730389) for an example of an explanation of parts of a command.) – Scott - Слава Україні Apr 21 '17 at 19:09
  • 1
    @Scott You said correct, so I write a new useful script in here: https://github.com/NabiKAZ/video2gif – Nabi K.A.Z. Apr 23 '17 at 06:46
  • 1
    https://github.com/NabiKAZ/video2gif works great even in 2022! – Ray Hulha Mar 17 '22 at 15:49
6

ffmpeg commands:

  1. Run this command so that ffmpeg can figure out a good palette:

    ffmpeg -y -i foo.mp4 -vf fps=30,scale=320:-1:flags=lanczos,palettegen palette.png
    
  2. Run this command to convert the mp4 file into 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
    

You might want to tweak the fps and scale. Smaller for either will result in better file size.

Making a simple alias function

You can also create an alias function like this. I added it to my .bashrc or .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
}

And then just makegif foo

Note: You'll need ffmpeg of course. Get it here https://www.ffmpeg.org/download.html or brew install ffmpeg

Aphex
  • 191
  • 1
  • 3
  • 8
  • Thank you for the alias function. It is very handy – Prabhakar Kasi Jul 29 '20 at 02:14
  • The FFmpeg portion of this answer is nearly identical to that in [llogan's answer](https://superuser.com/a/556031/34985) except this one creates an intermediate palette file and provides no descriptions or documentation links. The alias portion of this answer (which answers a different question, anyways) is identical to [kenorb's answer](https://superuser.com/a/1154859/34985) except this one lacks the path quoting and `fps` and `scale` parameters. -1 for not adding anything new. – Lance U. Matthews Oct 09 '21 at 23:00
  • how do i disable frame dropping and previous image ghosting? my complex filter is this `fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse` – Dean Van Greunen Mar 08 '22 at 16:16
5

How to add a windows 7/10 "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.

chris
  • 191
  • 1
  • 6
4

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
Sun
  • 6,192
  • 10
  • 34
  • 54
1

ImageMagick can do this simply:

convert in.mp4 out.gif
Geremia
  • 546
  • 1
  • 7
  • 28
  • That doesnt answer the question though. With 14 answers there already this needed to be spectacular. – Rohit Gupta Jul 29 '23 at 00:32
  • 1
    @RohitGupta The `ffmpeg` example in [llogan's example](https://superuser.com/a/556031/261550) doesn't work with `ffmpeg` 6.0. I get an error about `lanczos` deprecated or not found. – Geremia Jul 29 '23 at 03:11
-1

You can do:

ffmpeg -i input.mp4 output.gif