comparison gifdec.c @ 46:890e9121a54d libavformat

added animated GIF decoder (pts and various disposal handling are missing)
author bellard
date Sun, 02 Feb 2003 19:16:51 +0000
parents
children 658be43f6a0d
comparison
equal deleted inserted replaced
45:2036f790ece3 46:890e9121a54d
1 /*
2 * GIF decoder
3 * Copyright (c) 2003 Fabrice Bellard.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "avformat.h"
20
21 //#define DEBUG
22
23 #define MAXBITS 12
24 #define SIZTABLE (1<<MAXBITS)
25
26 #define GCE_DISPOSAL_NONE 0
27 #define GCE_DISPOSAL_INPLACE 1
28 #define GCE_DISPOSAL_BACKGROUND 2
29 #define GCE_DISPOSAL_RESTORE 3
30
31 typedef struct GifState {
32 int screen_width;
33 int screen_height;
34 int bits_per_pixel;
35 int background_color_index;
36 int transparent_color_index;
37 int color_resolution;
38 int image_count;
39 uint8_t *image_buf;
40 /* after the frame is displayed, the disposal method is used */
41 int gce_disposal;
42 /* delay during which the frame is shown */
43 int gce_delay;
44
45 /* LZW compatible decoder */
46 ByteIOContext *f;
47 int eob_reached;
48 uint8_t *pbuf, *ebuf;
49 int bbits;
50 unsigned int bbuf;
51
52 int cursize; /* The current code size */
53 int curmask;
54 int codesize;
55 int clear_code;
56 int end_code;
57 int newcodes; /* First available code */
58 int top_slot; /* Highest code for current size */
59 int slot; /* Last read code */
60 int fc, oc;
61 uint8_t *sp;
62 uint8_t stack[SIZTABLE];
63 uint8_t suffix[SIZTABLE];
64 uint16_t prefix[SIZTABLE];
65
66 /* aux buffers */
67 uint8_t global_palette[256 * 3];
68 uint8_t local_palette[256 * 3];
69 uint8_t buf[256];
70 } GifState;
71
72
73 static const uint8_t gif87a_sig[6] = "GIF87a";
74 static const uint8_t gif89a_sig[6] = "GIF89a";
75
76 static const uint16_t mask[17] =
77 {
78 0x0000, 0x0001, 0x0003, 0x0007,
79 0x000F, 0x001F, 0x003F, 0x007F,
80 0x00FF, 0x01FF, 0x03FF, 0x07FF,
81 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
82 };
83
84 static int gif_probe(AVProbeData * pd)
85 {
86 if (pd->buf_size >= 24 &&
87 (memcmp(pd->buf, gif87a_sig, 6) == 0 ||
88 memcmp(pd->buf, gif89a_sig, 6) == 0))
89 return AVPROBE_SCORE_MAX;
90 else
91 return 0;
92 }
93
94 static void GLZWDecodeInit(GifState * s, int csize)
95 {
96 /* read buffer */
97 s->eob_reached = 0;
98 s->pbuf = s->buf;
99 s->ebuf = s->buf;
100 s->bbuf = 0;
101 s->bbits = 0;
102
103 /* decoder */
104 s->codesize = csize;
105 s->cursize = s->codesize + 1;
106 s->curmask = mask[s->cursize];
107 s->top_slot = 1 << s->cursize;
108 s->clear_code = 1 << s->codesize;
109 s->end_code = s->clear_code + 1;
110 s->slot = s->newcodes = s->clear_code + 2;
111 s->oc = s->fc = 0;
112 s->sp = s->stack;
113 }
114
115 /* XXX: optimize */
116 static inline int GetCode(GifState * s)
117 {
118 int c, sizbuf;
119 uint8_t *ptr;
120
121 while (s->bbits < s->cursize) {
122 ptr = s->pbuf;
123 if (ptr >= s->ebuf) {
124 if (!s->eob_reached) {
125 sizbuf = get_byte(s->f);
126 s->ebuf = s->buf + sizbuf;
127 s->pbuf = s->buf;
128 if (sizbuf > 0) {
129 get_buffer(s->f, s->buf, sizbuf);
130 } else {
131 s->eob_reached = 1;
132 }
133 }
134 ptr = s->pbuf;
135 }
136 s->bbuf |= ptr[0] << s->bbits;
137 ptr++;
138 s->pbuf = ptr;
139 s->bbits += 8;
140 }
141 c = s->bbuf & s->curmask;
142 s->bbuf >>= s->cursize;
143 s->bbits -= s->cursize;
144 return c;
145 }
146
147 /* NOTE: the algorithm here is inspired from the LZW GIF decoder
148 written by Steven A. Bennett in 1987. */
149 /* return the number of byte decoded */
150 static int GLZWDecode(GifState * s, uint8_t * buf, int len)
151 {
152 int l, c, code, oc, fc;
153 uint8_t *sp;
154
155 if (s->end_code < 0)
156 return 0;
157
158 l = len;
159 sp = s->sp;
160 oc = s->oc;
161 fc = s->fc;
162
163 while (sp > s->stack) {
164 *buf++ = *(--sp);
165 if ((--l) == 0)
166 goto the_end;
167 }
168
169 for (;;) {
170 c = GetCode(s);
171 if (c == s->end_code) {
172 s->end_code = -1;
173 break;
174 } else if (c == s->clear_code) {
175 s->cursize = s->codesize + 1;
176 s->curmask = mask[s->cursize];
177 s->slot = s->newcodes;
178 s->top_slot = 1 << s->cursize;
179 while ((c = GetCode(s)) == s->clear_code);
180 if (c == s->end_code) {
181 s->end_code = -1;
182 break;
183 }
184 /* test error */
185 if (c >= s->slot)
186 c = 0;
187 fc = oc = c;
188 *buf++ = c;
189 if ((--l) == 0)
190 break;
191 } else {
192 code = c;
193 if (code >= s->slot) {
194 *sp++ = fc;
195 code = oc;
196 }
197 while (code >= s->newcodes) {
198 *sp++ = s->suffix[code];
199 code = s->prefix[code];
200 }
201 *sp++ = code;
202 if (s->slot < s->top_slot) {
203 s->suffix[s->slot] = fc = code;
204 s->prefix[s->slot++] = oc;
205 oc = c;
206 }
207 if (s->slot >= s->top_slot) {
208 if (s->cursize < MAXBITS) {
209 s->top_slot <<= 1;
210 s->curmask = mask[++s->cursize];
211 }
212 }
213 while (sp > s->stack) {
214 *buf++ = *(--sp);
215 if ((--l) == 0)
216 goto the_end;
217 }
218 }
219 }
220 the_end:
221 s->sp = sp;
222 s->oc = oc;
223 s->fc = fc;
224 return len - l;
225 }
226
227 static int gif_read_image(AVFormatContext * s1, AVPacket * pkt)
228 {
229 GifState *s = s1->priv_data;
230 int left, top, width, height, bits_per_pixel, code_size, flags;
231 int is_interleaved, has_local_palette, y, x, linesize;
232 ByteIOContext *f = &s1->pb;
233 uint8_t *ptr, *line, *d, *spal, *palette, *sptr;
234
235 left = get_le16(f);
236 top = get_le16(f);
237 width = get_le16(f);
238 height = get_le16(f);
239 flags = get_byte(f);
240 is_interleaved = flags & 0x40;
241 has_local_palette = flags & 0x80;
242 bits_per_pixel = (flags & 0x07) + 1;
243 #ifdef DEBUG
244 printf("gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height);
245 #endif
246
247 if (has_local_palette) {
248 get_buffer(f, s->local_palette, 3 * (1 << bits_per_pixel));
249 palette = s->local_palette;
250 } else {
251 palette = s->global_palette;
252 }
253
254 /* allocate local image (XXX: horrible, needs API change) */
255 if (s->image_count == 0) {
256 /* modify screen width/height if invalid */
257 if (left + width > s->screen_width)
258 s->screen_width = left + width;
259 if (top + height > s->screen_height)
260 s->screen_width = top + height;
261 s->image_buf = av_malloc(s->screen_width * s->screen_height * 3);
262 if (!s->image_buf)
263 return -ENOMEM;
264 } else {
265 /* verify that all the image is inside the screen dimensions */
266 if (left + width > s->screen_width ||
267 top + height > s->screen_height)
268 return -EINVAL;
269 }
270 s->image_count++;
271
272 line = av_malloc(width);
273 if (!line)
274 return -ENOMEM;
275
276 /* now get the image data */
277 s->f = f;
278 code_size = get_byte(f);
279 GLZWDecodeInit(s, code_size);
280
281 /* read all the image and transcode it to RGB24 (horrible) */
282 linesize = s->screen_width * 3;
283 ptr = s->image_buf + top * linesize + (left * 3);
284 for (y = 0; y < height; y++) {
285 GLZWDecode(s, line, width);
286 d = ptr;
287 sptr = line;
288 for(x = 0; x < width; x++) {
289 spal = palette + sptr[0] * 3;
290 d[0] = spal[0];
291 d[1] = spal[1];
292 d[2] = spal[2];
293 d += 3;
294 sptr++;
295 }
296 ptr += linesize;
297 }
298 av_free(line);
299
300 /* read the garbage data until end marker is found */
301 while (!s->eob_reached)
302 GetCode(s);
303
304 /* output image */
305 /* XXX: avoid copying */
306 if (av_new_packet(pkt, s->screen_width * s->screen_height * 3)) {
307 av_free(line);
308 return -EIO;
309 }
310 pkt->stream_index = 0;
311 memcpy(pkt->data, s->image_buf, s->screen_width * s->screen_height * 3);
312 return 0;
313 }
314
315 static int gif_read_extension(AVFormatContext * s1)
316 {
317 GifState *s = s1->priv_data;
318 ByteIOContext *f = &s1->pb;
319 int ext_code, ext_len, i, gce_flags, gce_transparent_index;
320
321 /* extension */
322 ext_code = get_byte(f);
323 ext_len = get_byte(f);
324 #ifdef DEBUG
325 printf("gif: ext_code=0x%x len=%d\n", ext_code, ext_len);
326 #endif
327 switch(ext_code) {
328 case 0xf9:
329 if (ext_len != 4)
330 goto discard_ext;
331 s->transparent_color_index = -1;
332 gce_flags = get_byte(f);
333 s->gce_delay = get_le16(f);
334 gce_transparent_index = get_byte(f);
335 if (gce_flags & 0x01)
336 s->transparent_color_index = gce_transparent_index;
337 else
338 s->transparent_color_index = -1;
339 s->gce_disposal = (gce_flags >> 2) & 0x7;
340 #ifdef DEBUG
341 printf("gif: gce_flags=%x delay=%d tcolor=%d disposal=%d\n",
342 gce_flags, s->gce_delay,
343 s->transparent_color_index, s->gce_disposal);
344 #endif
345 ext_len = get_byte(f);
346 break;
347 }
348
349 /* NOTE: many extension blocks can come after */
350 discard_ext:
351 while (ext_len != 0) {
352 for (i = 0; i < ext_len; i++)
353 get_byte(f);
354 ext_len = get_byte(f);
355 #ifdef DEBUG
356 printf("gif: ext_len1=%d\n", ext_len);
357 #endif
358 }
359 return 0;
360 }
361
362 static int gif_read_header(AVFormatContext * s1,
363 AVFormatParameters * ap)
364 {
365 GifState *s = s1->priv_data;
366 ByteIOContext *f = &s1->pb;
367 AVStream *st;
368 uint8_t sig[6];
369 int ret, v, n;
370 int has_global_palette;
371
372 /* read gif signature */
373 ret = get_buffer(f, sig, 6);
374 if (ret != 6)
375 return -1;
376 if (memcmp(sig, gif87a_sig, 6) != 0 &&
377 memcmp(sig, gif89a_sig, 6) != 0)
378 return -1;
379
380 /* read screen header */
381 s->transparent_color_index = -1;
382 s->screen_width = get_le16(f);
383 s->screen_height = get_le16(f);
384 v = get_byte(f);
385 s->color_resolution = ((v & 0x70) >> 4) + 1;
386 has_global_palette = (v & 0x80);
387 s->bits_per_pixel = (v & 0x07) + 1;
388 s->background_color_index = get_byte(f);
389 get_byte(f); /* ignored */
390 #ifdef DEBUG
391 printf("gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
392 s->screen_width, s->screen_height, s->bits_per_pixel,
393 has_global_palette);
394 #endif
395 if (has_global_palette) {
396 n = 1 << s->bits_per_pixel;
397 get_buffer(f, s->global_palette, n * 3);
398 }
399 /* now we are ready: build format streams */
400 st = av_new_stream(s1, 0);
401 if (!st)
402 return -1;
403
404 st->codec.codec_type = CODEC_TYPE_VIDEO;
405 st->codec.codec_id = CODEC_ID_RAWVIDEO;
406 st->codec.frame_rate = 5 * FRAME_RATE_BASE;
407 /* XXX: check if screen size is always valid */
408 st->codec.width = s->screen_width;
409 st->codec.height = s->screen_height;
410 st->codec.pix_fmt = PIX_FMT_RGB24;
411 return 0;
412 }
413
414 static int gif_read_packet(AVFormatContext * s1,
415 AVPacket * pkt)
416 {
417 ByteIOContext *f = &s1->pb;
418 int ret, code;
419
420 for (;;) {
421 code = url_fgetc(f);
422 #ifdef DEBUG
423 printf("gif: code=%02x '%c'\n", code, code);
424 #endif
425 switch (code) {
426 case ',':
427 if (gif_read_image(s1, pkt) < 0)
428 return -EIO;
429 ret = 0;
430 goto the_end;
431 case ';':
432 /* end of image */
433 ret = -EIO;
434 goto the_end;
435 case '!':
436 if (gif_read_extension(s1) < 0)
437 return -EIO;
438 break;
439 case EOF:
440 default:
441 /* error or errneous EOF */
442 ret = -EIO;
443 goto the_end;
444 }
445 }
446 the_end:
447 return ret;
448 }
449
450 static int gif_read_close(AVFormatContext *s1)
451 {
452 GifState *s = s1->priv_data;
453 av_free(s->image_buf);
454 return 0;
455 }
456
457 AVInputFormat gif_iformat =
458 {
459 "gif",
460 "gif format",
461 sizeof(GifState),
462 gif_probe,
463 gif_read_header,
464 gif_read_packet,
465 gif_read_close,
466 };