]> git.sesse.net Git - ffmpeg/blob - libavcodec/gif.c
Apply 'cold' attribute to init/uninit functions in libavcodec
[ffmpeg] / libavcodec / gif.c
1 /*
2  * GIF encoder.
3  * Copyright (c) 2000 Fabrice Bellard.
4  * Copyright (c) 2002 Francois Revol.
5  * Copyright (c) 2006 Baptiste Coudurier.
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 /*
25  * First version by Francois Revol revol@free.fr
26  *
27  * Features and limitations:
28  * - currently no compression is performed,
29  *   in fact the size of the data is 9/8 the size of the image in 8bpp
30  * - uses only a global standard palette
31  * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
32  *
33  * Reference documents:
34  * http://www.goice.co.jp/member/mo/formats/gif.html
35  * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
36  * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
37  *
38  * this url claims to have an LZW algorithm not covered by Unisys patent:
39  * http://www.msg.net/utility/whirlgif/gifencod.html
40  * could help reduce the size of the files _a lot_...
41  * some sites mentions an RLE type compression also.
42  */
43
44 #include "avcodec.h"
45 #include "bytestream.h"
46 #include "bitstream.h"
47
48 /* bitstream minipacket size */
49 #define GIF_CHUNKS 100
50
51 /* slows down the decoding (and some browsers don't like it) */
52 /* update on the 'some browsers don't like it issue from above: this was probably due to missing 'Data Sub-block Terminator' (byte 19) in the app_header */
53 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif
54
55 typedef struct {
56     unsigned char r;
57     unsigned char g;
58     unsigned char b;
59 } rgb_triplet;
60
61 /* we use the standard 216 color palette */
62
63 /* this script was used to create the palette:
64  * for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do echo -n "    "; for b in 00 33 66 99 cc ff; do
65  *   echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done
66  */
67
68 static const rgb_triplet gif_clut[216] = {
69     { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
70     { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
71     { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
72     { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
73     { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
74     { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
75     { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
76     { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
77     { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
78     { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
79     { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
80     { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
81     { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
82     { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
83     { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
84     { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
85     { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
86     { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
87     { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
88     { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
89     { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
90     { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
91     { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
92     { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
93     { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
94     { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
95     { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
96     { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
97     { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
98     { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
99     { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
100     { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
101     { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
102     { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
103     { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
104     { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
105 };
106
107 /* The GIF format uses reversed order for bitstreams... */
108 /* at least they don't use PDP_ENDIAN :) */
109 /* so we 'extend' PutBitContext. hmmm, OOP :) */
110 /* seems this thing changed slightly since I wrote it... */
111
112 #ifdef ALT_BITSTREAM_WRITER
113 # error no ALT_BITSTREAM_WRITER support for now
114 #endif
115
116 static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value)
117 {
118     unsigned int bit_buf;
119     int bit_cnt;
120
121     //    printf("put_bits=%d %x\n", n, value);
122     assert(n == 32 || value < (1U << n));
123
124     bit_buf = s->bit_buf;
125     bit_cnt = 32 - s->bit_left; /* XXX:lazyness... was = s->bit_cnt; */
126
127     //    printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf);
128     /* XXX: optimize */
129     if (n < (32-bit_cnt)) {
130         bit_buf |= value << (bit_cnt);
131         bit_cnt+=n;
132     } else {
133         bit_buf |= value << (bit_cnt);
134
135         bytestream_put_le32(&s->buf_ptr, bit_buf);
136
137         //printf("bitbuf = %08x\n", bit_buf);
138         if (s->buf_ptr >= s->buf_end)
139             abort();
140 //            flush_buffer_rev(s);
141         bit_cnt=bit_cnt + n - 32;
142         if (bit_cnt == 0) {
143             bit_buf = 0;
144         } else {
145             bit_buf = value >> (n - bit_cnt);
146         }
147     }
148
149     s->bit_buf = bit_buf;
150     s->bit_left = 32 - bit_cnt;
151 }
152
153 /* pad the end of the output stream with zeros */
154 static void gif_flush_put_bits_rev(PutBitContext *s)
155 {
156     while (s->bit_left < 32) {
157         /* XXX: should test end of buffer */
158         *s->buf_ptr++=s->bit_buf & 0xff;
159         s->bit_buf>>=8;
160         s->bit_left+=8;
161     }
162 //    flush_buffer_rev(s);
163     s->bit_left=32;
164     s->bit_buf=0;
165 }
166
167 /* !RevPutBitContext */
168
169 /* GIF header */
170 static int gif_image_write_header(uint8_t **bytestream,
171                                   int width, int height, int loop_count,
172                                   uint32_t *palette)
173 {
174     int i;
175     unsigned int v;
176
177     bytestream_put_buffer(bytestream, "GIF", 3);
178     bytestream_put_buffer(bytestream, "89a", 3);
179     bytestream_put_le16(bytestream, width);
180     bytestream_put_le16(bytestream, height);
181
182     bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */
183     bytestream_put_byte(bytestream, 0x1f); /* background color index */
184     bytestream_put_byte(bytestream, 0); /* aspect ratio */
185
186     /* the global palette */
187     if (!palette) {
188         bytestream_put_buffer(bytestream, (const unsigned char *)gif_clut, 216*3);
189         for(i=0;i<((256-216)*3);i++)
190             bytestream_put_byte(bytestream, 0);
191     } else {
192         for(i=0;i<256;i++) {
193             v = palette[i];
194             bytestream_put_be24(bytestream, v);
195         }
196     }
197
198         /*        update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif
199                 see http://members.aol.com/royalef/gifabout.htm#net-extension
200
201                 byte   1       : 33 (hex 0x21) GIF Extension code
202                 byte   2       : 255 (hex 0xFF) Application Extension Label
203                 byte   3       : 11 (hex (0x0B) Length of Application Block
204                                          (eleven bytes of data to follow)
205                 bytes  4 to 11 : "NETSCAPE"
206                 bytes 12 to 14 : "2.0"
207                 byte  15       : 3 (hex 0x03) Length of Data Sub-Block
208                                          (three bytes of data to follow)
209                 byte  16       : 1 (hex 0x01)
210                 bytes 17 to 18 : 0 to 65535, an unsigned integer in
211                                          lo-hi byte format. This indicate the
212                                          number of iterations the loop should
213                                          be executed.
214                 bytes 19       : 0 (hex 0x00) a Data Sub-block Terminator
215         */
216
217     /* application extension header */
218 #ifdef GIF_ADD_APP_HEADER
219     if (loop_count >= 0 && loop_count <= 65535) {
220         bytestream_put_byte(bytestream, 0x21);
221         bytestream_put_byte(bytestream, 0xff);
222         bytestream_put_byte(bytestream, 0x0b);
223         bytestream_put_buffer(bytestream, "NETSCAPE2.0", 11);  // bytes 4 to 14
224         bytestream_put_byte(bytestream, 0x03); // byte 15
225         bytestream_put_byte(bytestream, 0x01); // byte 16
226         bytestream_put_le16(bytestream, (uint16_t)loop_count);
227         bytestream_put_byte(bytestream, 0x00); // byte 19
228     }
229 #endif
230     return 0;
231 }
232
233 /* this is maybe slow, but allows for extensions */
234 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
235 {
236     return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
237 }
238
239
240 static int gif_image_write_image(uint8_t **bytestream,
241                                  int x1, int y1, int width, int height,
242                                  const uint8_t *buf, int linesize, int pix_fmt)
243 {
244     PutBitContext p;
245     uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
246     int i, left, w, v;
247     const uint8_t *ptr;
248     /* image block */
249
250     bytestream_put_byte(bytestream, 0x2c);
251     bytestream_put_le16(bytestream, x1);
252     bytestream_put_le16(bytestream, y1);
253     bytestream_put_le16(bytestream, width);
254     bytestream_put_le16(bytestream, height);
255     bytestream_put_byte(bytestream, 0x00); /* flags */
256     /* no local clut */
257
258     bytestream_put_byte(bytestream, 0x08);
259
260     left= width * height;
261
262     init_put_bits(&p, buffer, 130);
263
264 /*
265  * the thing here is the bitstream is written as little packets, with a size byte before
266  * but it's still the same bitstream between packets (no flush !)
267  */
268     ptr = buf;
269     w = width;
270     while(left>0) {
271
272         gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
273
274         for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
275             if (pix_fmt == PIX_FMT_RGB24) {
276                 v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
277                 ptr+=3;
278             } else {
279                 v = *ptr++;
280             }
281             gif_put_bits_rev(&p, 9, v);
282             if (--w == 0) {
283                 w = width;
284                 buf += linesize;
285                 ptr = buf;
286             }
287         }
288
289         if(left<=GIF_CHUNKS) {
290             gif_put_bits_rev(&p, 9, 0x101); /* end of stream */
291             gif_flush_put_bits_rev(&p);
292         }
293         if(pbBufPtr(&p) - p.buf > 0) {
294             bytestream_put_byte(bytestream, pbBufPtr(&p) - p.buf); /* byte count of the packet */
295             bytestream_put_buffer(bytestream, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */
296             p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
297         }
298         left-=GIF_CHUNKS;
299     }
300     bytestream_put_byte(bytestream, 0x00); /* end of image block */
301     bytestream_put_byte(bytestream, 0x3b);
302     return 0;
303 }
304
305 typedef struct {
306     int64_t time, file_time;
307     uint8_t buffer[100]; /* data chunks */
308     AVFrame picture;
309 } GIFContext;
310
311 static av_cold int gif_encode_init(AVCodecContext *avctx)
312 {
313     GIFContext *s = avctx->priv_data;
314
315     avctx->coded_frame = &s->picture;
316     return 0;
317 }
318
319 /* better than nothing gif encoder */
320 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data)
321 {
322     GIFContext *s = avctx->priv_data;
323     AVFrame *pict = data;
324     AVFrame *const p = (AVFrame *)&s->picture;
325     uint8_t *outbuf_ptr = outbuf;
326
327     *p = *pict;
328     p->pict_type = FF_I_TYPE;
329     p->key_frame = 1;
330     gif_image_write_header(&outbuf_ptr, avctx->width, avctx->height, -1, (uint32_t *)pict->data[1]);
331     gif_image_write_image(&outbuf_ptr, 0, 0, avctx->width, avctx->height, pict->data[0], pict->linesize[0], PIX_FMT_PAL8);
332     return outbuf_ptr - outbuf;
333 }
334
335 AVCodec gif_encoder = {
336     "gif",
337     CODEC_TYPE_VIDEO,
338     CODEC_ID_GIF,
339     sizeof(GIFContext),
340     gif_encode_init,
341     gif_encode_frame,
342     NULL, //encode_end,
343     .pix_fmts= (enum PixelFormat[]){PIX_FMT_PAL8, -1},
344 };