About two years ago, I tried to improve FFmpeg support for GIF encoding, at least very decent. In particular, to join a transparent mechanism GIF encoder. However, you can write the code so that it is not always optimal, this is very common. But this is still only prevents encoder embarrassing attempt.
But recently Stupeflix, we need a method to produce high-quality Legend app GIF, so I decided to spend some effort in it.
All this blog FFmpeg
2.6 Characteristics listed are available, and to use these features in the next version of the Legend app (probably around March 26).
Do not read the article too long: the Usage section focuses on how to use.
Initial lift (2013)
Let's look at 2013 to introduce a transparent GIF encoder mechanism of action:
% Ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale = 300: -1 -gifflags -transdiff -y bbb-notrans.gif
% Ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale = 300: -1 -gifflags + transdiff -y bbb-trans.gif
% Ls -l bbb -. * Gif
-rw-r - r-- 1 ux ux 1.1M Mar 15 22:50 bbb-notrans.gif
-rw-r - r-- 1 ux ux 369K Mar 15 22:50 bbb-trans.gif
The default option is to take effect when your picture is highly intense movement or color changes, you should turn it off.
Another compression scheme is implemented Shear redraw GIF is only a sub-rectangle but the figure does not change the basic means elsewhere. Of course, in the movie, we do not use, we talk later.
In addition to the above mechanisms, before I did not made any progress. Other measures may also be less obvious, in short, there are still many defects in image quality.
Limitation of 256 colors
As you probably know, GIF is limited to the 256-color palette. And by default, FFmpeg uses only a generic version of toner to try to cover all areas of color, in order to support the file contains a lot of content:
Ordered dither and error diffusion
Jitter to avoid falling into this problem (limitation of 256 colors), in the above Bonnie Bear rabbit GIF, ordered Bayer dithering is applied. Through its 8 x 8 mesh pattern can be easily identified. Although it is not the best way, but it also has many advantages, such as vivid, fast, in fact, possible to prevent the strip similar visual effect and small problems.
You will find that most other dithering methods are based on the error, the principle is: a monochrome error (difference selected color from the palette and color you want between) will spread to the entire screen. Cause of a "cluster effect" between frames, or even identical to the source region between the frames, but this often provide a better quality, because it is completely wiped out GIF compression:
% Ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale = 300: -1: sws_dither = ed -y bbb-error-diffusal.gif
% Ls -l bbb-error-diffusal.gif
-rw-r - r-- 1 ux ux 1.3M Mar 15 23:10 bbb-error-diffusal.gif
GIF improve the picture quality of a better first step is to define the palette. Stored in GIF format with a global palette, but you can on a picture (or sprite; after covering a one on the front, but it can be overridden in a particular offset positions in order to obtain a more small size) to redefine a palette. Color palette for each frame can be substituted with a global palette to only one function. Once you stop to define a palette, it will fall to the global palette. This means that you can not define a palette of a series of frames, and this is precisely what you want. (Typical approach is to define a new palette in each scene change time).
So, in other words, you need to follow this pattern: a global palette, or a color palette for each frame.
A color palette for each frame (not implemented)
I first started to calculate a color palette in each frame, but I found that the presence of such defects as follows:
Cost: a 256-color palette size 768B, and are not included in the LZW algorithm mechanism, so it is not compressed. While its must be stored in each frame, which means that there is a sequence for 25FPS 150 kilobits per second overhead (768 * 8 * 25b = 150 * 1024b). Though in many cases it can be ignored.
In my initial tests were due to changes in the color palette to produce a brightness flicker effect, which is not a little better.
This is the reason I do not use this method to calculate a global palette, choosing instead to replace two reasons. Now I retrospect, it might retry this methodology, because in a way, and now the color quantization is better than I had time to test some of the state.
For a series of frames of each frame using the same palette (typically done during scene changes, as mentioned earlier) it is also possible. Or, better approach is: use only when the sub-rectangle changes.
All of these are left as an exercise for the reader. Welcome to add, if you are interested in this, then you can feel free to contact me.
A global palette (already implemented)
Having a global color palette mean a 2-pass (second check code) compression method (unless you are willing to put all the video frames are stored in memory).
The first pass is to calculate the whole picture a palette, which is the new filter involved palettegen place. This filter for all colors of each frame to produce a histogram, and generates a color palette based on these.
There are still some chores at the technical level: This filter realizes this Color Paul Heckbert of Image Quantization for Frame Buffer
Display (1982) paper a variant of the algorithm. Here are a few differences I remember (or be specific about the papers undefined behavior):
It uses a full resolution color histogram. Instead of paper as the next key sampling RGB 5 Recommended: 5: 5 histograms, this filter is 1600 million possible RGB 8: 8: 8 colors using a hash table.
Other cell division is at the midpoint of any course of conduct, to be split on the checkered squares chosen according to the color variance (the square with a large color variance will be priority truncated) .
The other frame colors depending on the importance of color averaging, for me, this is not defined in the paper.
When along one dimension (red, green or blue) divided grid, if equal, green is a priority in the red, then blue.
So anyway, this filter is doing color quantization, and generates a color palette (usually stored in a PNG file).
It usually looks something like this (upscaled):
Color mapping jitter
Second pass (check code) is accomplished by paletteuse filter, just like its name, it will use this palette to generate the final color flow quantification, its task is to find the generated palette the most appropriate color to represent the color of the input. This is where you can choose which dither method places.
Here, too, there are some small problems on the technical side:
Filters for five dithering method, however, only the original paper a method is proposed.
Like palettegen same color resolution (24-bit input color will be mapped to a palette entry) completed no damage input. It is through a K-d Tree (when k = 3 when it is clear that each dimension is RGB component) iterative implementation and a cache system to achieve this goal.
Using these two filters will allow you to be so GIF encoder (single global palette, jitter-free):
Using the same parameters manually run twice (check code) is a bit annoying, but also to adjust the parameters for each pass. So I recommend to write a simple script, as follows:
#! / Bin / sh
palette = "/ tmp / palette.png"
filters = "fps = 15, scale = 320: -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
... Can be used like this:
% ./gifenc.sh Video.mkv anim.gif
filters variables include:
An adjustment frame rate (reduced to 15 makes the screen does not look smooth, but you can make the final GIF smaller)
Replace a default (currently bilinear) lanczos scaler scaler scaling. The reason it is recommended that you use to zoom in and out lanczos or bicubic than bilinear more superior. If you do so, your input will be more blurred.
Extraction: for example purposes only
You will not necessarily a complete video encoding, so you may have to use -ss and -t option to select a fragment of interest. If you do so, then it must ensure that it is used as an input option added (before -i option), for example:
#! / Bin / sh
start_time = 12: 23
duration = 35
palette = "/ tmp / palette.png"
filters = "fps = 15, scale = 320: -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
If not, then at least in the first pass and it will not lead to a plurality of frames output (palette), so it will not do what you want.
An alternative is to copy the stream you want to extract pre-encoded fragments look like this:
% Ffmpeg -ss 12:23 -t 35 -i full.mkv -c: v copy -map 0: v -y video.mkv
If the stream is not precise enough to copy, you can add a trim filter. E.g:
filters = "trim = start_frame = 12: end_frame = 431, fps = 15, scale = 320: -1: flags = lanczos"
Get the best color palette output Getting the best out of the palette generation
Now we can begin to see the fun part in palettegen filter, primary and make you interested to try the option is probably stats_mode.
The main role of this option is to allow you to specify the video you need the whole thing, or just moving objects. If you use stats_mode = full (default), all pixels will be part of the color of statistics. If you use stats_mode = diff, only the former a different pixel will be counted.
Note: The option to add a filter, the need to do this: filter = opt1 = value1: opt2 = value2
The first GIF image using stats_mode = full (default). Throughout the process, the background shows no change, the result is the color of the sky because wise to get more attention. On the other hand, as a result, the text has been destroyed fade
On the other hand, the second is the use of GIF image stats_mode = diff, which is helpful for moving objects. In fact, text fade better performance at the expense of the sky had a little problem jitter
Get the best output color map
paletteuse filter has a little more options to operate. The most obvious is the jitter (dither option). The only effective predictable jitter is the Bayer dithering, all other jitter are based on error diffusion.
If you really want to use Bayer (because you have a speed limit or size), you can use bayer_scale option to reduce or increase its checkered pattern.
Of course, you can also use dither = none to disable jitter.
About error diffusion dithering, you will want to use floyd_steinberg, sierra2 and sierra2_4a. For more information about these, I will redirect you here DHALF.TXT.
For lazy people, floyd_steinberg is the most popular, while sierra2_4a is sierra2 (this is the default) is a fast / miniaturized version of the principle of diffusion is to use three instead of seven pixels pixels. heckbert is a record I mentioned earlier in the paper, but only as a reference introduced (you probably did not expect).
Finally, after the use of dithering, you might be interested in this option diff_mode. In reference to this passage:
Only changes in the rectangular area will be pre-treated. This is wrong and GIF cut / offset compression mechanism is relatively similar. If only part of the image is changing, this option helps accelerate encoding, and this option also by some way limit the scope of error diffusion dithering in the rectangular area, the boundary of the rectangular region that is moving scene (if the scene was little changed, this is more conducive to the determined output while reducing moving noise and better output GIF compression).
In other words: If you want to use in the image of the background error diffusion dithering, although the background is static, but can limit the error diffusion in the whole image with this option.