]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/gif.c
715f0aa371752b5d19861fe7d199c0c8c5855801
[frescor/ffmpeg.git] / 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
47 /* The GIF format uses reversed order for bitstreams... */
48 /* at least they don't use PDP_ENDIAN :) */
49 #define BITSTREAM_WRITER_LE
50
51 #include "bitstream.h"
52
53 /* bitstream minipacket size */
54 #define GIF_CHUNKS 100
55
56 /* slows down the decoding (and some browsers don't like it) */
57 /* 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 */
58 #define GIF_ADD_APP_HEADER // required to enable looping of animated gif
59
60 typedef struct {
61     unsigned char r;
62     unsigned char g;
63     unsigned char b;
64 } rgb_triplet;
65
66 /* we use the standard 216 color palette */
67
68 /* this script was used to create the palette:
69  * 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
70  *   echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done
71  */
72
73 static const rgb_triplet gif_clut[216] = {
74     { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
75     { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
76     { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
77     { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
78     { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
79     { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
80     { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
81     { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
82     { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
83     { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
84     { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
85     { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
86     { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
87     { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
88     { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
89     { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
90     { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
91     { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
92     { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
93     { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
94     { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
95     { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
96     { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
97     { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
98     { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
99     { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
100     { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
101     { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
102     { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
103     { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
104     { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
105     { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
106     { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
107     { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
108     { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
109     { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
110 };
111
112 /* GIF header */
113 static int gif_image_write_header(uint8_t **bytestream,
114                                   int width, int height, int loop_count,
115                                   uint32_t *palette)
116 {
117     int i;
118     unsigned int v;
119
120     bytestream_put_buffer(bytestream, "GIF", 3);
121     bytestream_put_buffer(bytestream, "89a", 3);
122     bytestream_put_le16(bytestream, width);
123     bytestream_put_le16(bytestream, height);
124
125     bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */
126     bytestream_put_byte(bytestream, 0x1f); /* background color index */
127     bytestream_put_byte(bytestream, 0); /* aspect ratio */
128
129     /* the global palette */
130     if (!palette) {
131         bytestream_put_buffer(bytestream, (const unsigned char *)gif_clut, 216*3);
132         for(i=0;i<((256-216)*3);i++)
133             bytestream_put_byte(bytestream, 0);
134     } else {
135         for(i=0;i<256;i++) {
136             v = palette[i];
137             bytestream_put_be24(bytestream, v);
138         }
139     }
140
141         /*        update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif
142                 see http://members.aol.com/royalef/gifabout.htm#net-extension
143
144                 byte   1       : 33 (hex 0x21) GIF Extension code
145                 byte   2       : 255 (hex 0xFF) Application Extension Label
146                 byte   3       : 11 (hex (0x0B) Length of Application Block
147                                          (eleven bytes of data to follow)
148                 bytes  4 to 11 : "NETSCAPE"
149                 bytes 12 to 14 : "2.0"
150                 byte  15       : 3 (hex 0x03) Length of Data Sub-Block
151                                          (three bytes of data to follow)
152                 byte  16       : 1 (hex 0x01)
153                 bytes 17 to 18 : 0 to 65535, an unsigned integer in
154                                          lo-hi byte format. This indicate the
155                                          number of iterations the loop should
156                                          be executed.
157                 bytes 19       : 0 (hex 0x00) a Data Sub-block Terminator
158         */
159
160     /* application extension header */
161 #ifdef GIF_ADD_APP_HEADER
162     if (loop_count >= 0 && loop_count <= 65535) {
163         bytestream_put_byte(bytestream, 0x21);
164         bytestream_put_byte(bytestream, 0xff);
165         bytestream_put_byte(bytestream, 0x0b);
166         bytestream_put_buffer(bytestream, "NETSCAPE2.0", 11);  // bytes 4 to 14
167         bytestream_put_byte(bytestream, 0x03); // byte 15
168         bytestream_put_byte(bytestream, 0x01); // byte 16
169         bytestream_put_le16(bytestream, (uint16_t)loop_count);
170         bytestream_put_byte(bytestream, 0x00); // byte 19
171     }
172 #endif
173     return 0;
174 }
175
176 /* this is maybe slow, but allows for extensions */
177 static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
178 {
179     return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
180 }
181
182
183 static int gif_image_write_image(uint8_t **bytestream,
184                                  int x1, int y1, int width, int height,
185                                  const uint8_t *buf, int linesize, int pix_fmt)
186 {
187     PutBitContext p;
188     uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
189     int i, left, w, v;
190     const uint8_t *ptr;
191     /* image block */
192
193     bytestream_put_byte(bytestream, 0x2c);
194     bytestream_put_le16(bytestream, x1);
195     bytestream_put_le16(bytestream, y1);
196     bytestream_put_le16(bytestream, width);
197     bytestream_put_le16(bytestream, height);
198     bytestream_put_byte(bytestream, 0x00); /* flags */
199     /* no local clut */
200
201     bytestream_put_byte(bytestream, 0x08);
202
203     left= width * height;
204
205     init_put_bits(&p, buffer, 130);
206
207 /*
208  * the thing here is the bitstream is written as little packets, with a size byte before
209  * but it's still the same bitstream between packets (no flush !)
210  */
211     ptr = buf;
212     w = width;
213     while(left>0) {
214
215         put_bits(&p, 9, 0x0100); /* clear code */
216
217         for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
218             if (pix_fmt == PIX_FMT_RGB24) {
219                 v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
220                 ptr+=3;
221             } else {
222                 v = *ptr++;
223             }
224             put_bits(&p, 9, v);
225             if (--w == 0) {
226                 w = width;
227                 buf += linesize;
228                 ptr = buf;
229             }
230         }
231
232         if(left<=GIF_CHUNKS) {
233             put_bits(&p, 9, 0x101); /* end of stream */
234             flush_put_bits(&p);
235         }
236         if(pbBufPtr(&p) - p.buf > 0) {
237             bytestream_put_byte(bytestream, pbBufPtr(&p) - p.buf); /* byte count of the packet */
238             bytestream_put_buffer(bytestream, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */
239             p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
240         }
241         left-=GIF_CHUNKS;
242     }
243     bytestream_put_byte(bytestream, 0x00); /* end of image block */
244     bytestream_put_byte(bytestream, 0x3b);
245     return 0;
246 }
247
248 typedef struct {
249     int64_t time, file_time;
250     uint8_t buffer[100]; /* data chunks */
251     AVFrame picture;
252 } GIFContext;
253
254 static av_cold int gif_encode_init(AVCodecContext *avctx)
255 {
256     GIFContext *s = avctx->priv_data;
257
258     avctx->coded_frame = &s->picture;
259     return 0;
260 }
261
262 /* better than nothing gif encoder */
263 static int gif_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data)
264 {
265     GIFContext *s = avctx->priv_data;
266     AVFrame *pict = data;
267     AVFrame *const p = (AVFrame *)&s->picture;
268     uint8_t *outbuf_ptr = outbuf;
269
270     *p = *pict;
271     p->pict_type = FF_I_TYPE;
272     p->key_frame = 1;
273     gif_image_write_header(&outbuf_ptr, avctx->width, avctx->height, -1, (uint32_t *)pict->data[1]);
274     gif_image_write_image(&outbuf_ptr, 0, 0, avctx->width, avctx->height, pict->data[0], pict->linesize[0], PIX_FMT_PAL8);
275     return outbuf_ptr - outbuf;
276 }
277
278 AVCodec gif_encoder = {
279     "gif",
280     CODEC_TYPE_VIDEO,
281     CODEC_ID_GIF,
282     sizeof(GIFContext),
283     gif_encode_init,
284     gif_encode_frame,
285     NULL, //encode_end,
286     .pix_fmts= (enum PixelFormat[]){PIX_FMT_PAL8, PIX_FMT_NONE},
287     .long_name= NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
288 };