Browse code

change gif demuxer to gif decoder

Originally committed as revision 6760 to svn://svn.ffmpeg.org/ffmpeg/trunk

Baptiste Coudurier authored on 2006/10/23 00:05:03
Showing 7 changed files
... ...
@@ -64,6 +64,7 @@ version <next>
64 64
 - Tiertex .seq demuxer/video decoder
65 65
 - MTV demuxer
66 66
 - TIFF picture decoder
67
+- GIF picture decoder
67 68
 
68 69
 version 0.4.9-pre1:
69 70
 
... ...
@@ -121,6 +121,7 @@ Codecs:
121 121
   flashsv.c                             Benjamin Larsson
122 122
   flicvideo.c                           Mike Melanson
123 123
   g726.c                                Roman Shaposhnik
124
+  gifdec.c                              Baptiste Coudurier
124 125
   h264*                                 Loren Merritt, Michael Niedermayer
125 126
   h261*                                 Michael Niedermayer
126 127
   h263*                                 Michael Niedermayer
... ...
@@ -84,6 +84,7 @@ OBJS-$(CONFIG_FLASHSV_DECODER)         += flashsv.o
84 84
 OBJS-$(CONFIG_FLIC_DECODER)            += flicvideo.o
85 85
 OBJS-$(CONFIG_FOURXM_DECODER)          += 4xm.o
86 86
 OBJS-$(CONFIG_FRAPS_DECODER)           += fraps.o
87
+OBJS-$(CONFIG_GIF_DECODER)             += gifdec.o
87 88
 OBJS-$(CONFIG_H261_DECODER)            += h261.o
88 89
 OBJS-$(CONFIG_H261_ENCODER)            += h261.o
89 90
 OBJS-$(CONFIG_H264_DECODER)            += h264.o
... ...
@@ -193,6 +193,9 @@ void avcodec_register_all(void)
193 193
 #endif //CONFIG_RAWVIDEO_ENCODER
194 194
 
195 195
     /* decoders */
196
+#ifdef CONFIG_GIF_DECODER
197
+    register_avcodec(&gif_decoder);
198
+#endif
196 199
 #ifdef CONFIG_H263_DECODER
197 200
     register_avcodec(&h263_decoder);
198 201
 #endif //CONFIG_H263_DECODER
... ...
@@ -37,8 +37,8 @@ extern "C" {
37 37
 #define AV_STRINGIFY(s)         AV_TOSTRING(s)
38 38
 #define AV_TOSTRING(s) #s
39 39
 
40
-#define LIBAVCODEC_VERSION_INT  ((51<<16)+(20<<8)+0)
41
-#define LIBAVCODEC_VERSION      51.20.0
40
+#define LIBAVCODEC_VERSION_INT  ((51<<16)+(21<<8)+0)
41
+#define LIBAVCODEC_VERSION      51.21.0
42 42
 #define LIBAVCODEC_BUILD        LIBAVCODEC_VERSION_INT
43 43
 
44 44
 #define LIBAVCODEC_IDENT        "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
... ...
@@ -148,6 +148,7 @@ enum CodecID {
148 148
     CODEC_ID_DSICINVIDEO,
149 149
     CODEC_ID_TIERTEXSEQVIDEO,
150 150
     CODEC_ID_TIFF,
151
+    CODEC_ID_GIF,
151 152
 
152 153
     /* various pcm "codecs" */
153 154
     CODEC_ID_PCM_S16LE= 0x10000,
... ...
@@ -2177,6 +2178,7 @@ extern AVCodec sonic_ls_encoder;
2177 2177
 extern AVCodec svq1_encoder;
2178 2178
 extern AVCodec x264_encoder;
2179 2179
 
2180
+extern AVCodec gif_decoder;
2180 2181
 extern AVCodec h263_decoder;
2181 2182
 extern AVCodec h261_decoder;
2182 2183
 extern AVCodec mpeg4_decoder;
2183 2184
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+/*
1
+ * Bytestream functions
2
+ * copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr>
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#ifndef FFMPEG_BYTESTREAM_H
22
+#define FFMPEG_BYTESTREAM_H
23
+
24
+static always_inline unsigned int bytestream_get_le32(uint8_t **b)
25
+{
26
+    (*b) += 4;
27
+    return LE_32(*b - 4);
28
+}
29
+
30
+static always_inline unsigned int bytestream_get_le16(uint8_t **b)
31
+{
32
+    (*b) += 2;
33
+    return LE_16(*b - 2);
34
+}
35
+
36
+static always_inline unsigned int bytestream_get_byte(uint8_t **b)
37
+{
38
+    (*b)++;
39
+    return (*b)[-1];
40
+}
41
+
42
+static always_inline unsigned int bytestream_get_buffer(uint8_t **b, uint8_t *dst, unsigned int size)
43
+{
44
+    memcpy(dst, *b, size);
45
+    (*b) += size;
46
+    return size;
47
+}
48
+
49
+#endif /* FFMPEG_BYTESTREAM_H */
0 50
new file mode 100644
... ...
@@ -0,0 +1,495 @@
0
+/*
1
+ * GIF decoder
2
+ * Copyright (c) 2003 Fabrice Bellard.
3
+ * Copyright (c) 2006 Baptiste Coudurier.
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+//#define DEBUG
23
+
24
+#include "avcodec.h"
25
+#include "bytestream.h"
26
+
27
+#define MAXBITS                 12
28
+#define         SIZTABLE        (1<<MAXBITS)
29
+
30
+#define GCE_DISPOSAL_NONE       0
31
+#define GCE_DISPOSAL_INPLACE    1
32
+#define GCE_DISPOSAL_BACKGROUND 2
33
+#define GCE_DISPOSAL_RESTORE    3
34
+
35
+typedef struct GifState {
36
+    int screen_width;
37
+    int screen_height;
38
+    int bits_per_pixel;
39
+    int background_color_index;
40
+    int transparent_color_index;
41
+    int color_resolution;
42
+    uint8_t *image_buf;
43
+    int image_linesize;
44
+    uint32_t image_palette[256];
45
+    int pix_fmt;
46
+
47
+    /* after the frame is displayed, the disposal method is used */
48
+    int gce_disposal;
49
+    /* delay during which the frame is shown */
50
+    int gce_delay;
51
+
52
+    /* LZW compatible decoder */
53
+    uint8_t *bytestream;
54
+    int eob_reached;
55
+    uint8_t *pbuf, *ebuf;
56
+    int bbits;
57
+    unsigned int bbuf;
58
+
59
+    int cursize;                /* The current code size */
60
+    int curmask;
61
+    int codesize;
62
+    int clear_code;
63
+    int end_code;
64
+    int newcodes;               /* First available code */
65
+    int top_slot;               /* Highest code for current size */
66
+    int slot;                   /* Last read code */
67
+    int fc, oc;
68
+    uint8_t *sp;
69
+    uint8_t stack[SIZTABLE];
70
+    uint8_t suffix[SIZTABLE];
71
+    uint16_t prefix[SIZTABLE];
72
+
73
+    /* aux buffers */
74
+    uint8_t global_palette[256 * 3];
75
+    uint8_t local_palette[256 * 3];
76
+    uint8_t buf[256];
77
+} GifState;
78
+
79
+static const uint8_t gif87a_sig[6] = "GIF87a";
80
+static const uint8_t gif89a_sig[6] = "GIF89a";
81
+
82
+static const uint16_t mask[17] =
83
+{
84
+    0x0000, 0x0001, 0x0003, 0x0007,
85
+    0x000F, 0x001F, 0x003F, 0x007F,
86
+    0x00FF, 0x01FF, 0x03FF, 0x07FF,
87
+    0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
88
+};
89
+
90
+static void GLZWDecodeInit(GifState * s, int csize)
91
+{
92
+    /* read buffer */
93
+    s->eob_reached = 0;
94
+    s->pbuf = s->buf;
95
+    s->ebuf = s->buf;
96
+    s->bbuf = 0;
97
+    s->bbits = 0;
98
+
99
+    /* decoder */
100
+    s->codesize = csize;
101
+    s->cursize = s->codesize + 1;
102
+    s->curmask = mask[s->cursize];
103
+    s->top_slot = 1 << s->cursize;
104
+    s->clear_code = 1 << s->codesize;
105
+    s->end_code = s->clear_code + 1;
106
+    s->slot = s->newcodes = s->clear_code + 2;
107
+    s->oc = s->fc = 0;
108
+    s->sp = s->stack;
109
+}
110
+
111
+/* XXX: optimize */
112
+static inline int GetCode(GifState * s)
113
+{
114
+    int c, sizbuf;
115
+    uint8_t *ptr;
116
+
117
+    while (s->bbits < s->cursize) {
118
+        ptr = s->pbuf;
119
+        if (ptr >= s->ebuf) {
120
+            if (!s->eob_reached) {
121
+                sizbuf = bytestream_get_byte(&s->bytestream);
122
+                s->ebuf = s->buf + sizbuf;
123
+                s->pbuf = s->buf;
124
+                if (sizbuf > 0) {
125
+                    bytestream_get_buffer(&s->bytestream, s->buf, sizbuf);
126
+                } else {
127
+                    s->eob_reached = 1;
128
+                }
129
+            }
130
+            ptr = s->pbuf;
131
+        }
132
+        s->bbuf |= ptr[0] << s->bbits;
133
+        ptr++;
134
+        s->pbuf = ptr;
135
+        s->bbits += 8;
136
+    }
137
+    c = s->bbuf & s->curmask;
138
+    s->bbuf >>= s->cursize;
139
+    s->bbits -= s->cursize;
140
+    return c;
141
+}
142
+
143
+/* NOTE: the algorithm here is inspired from the LZW GIF decoder
144
+   written by Steven A. Bennett in 1987. */
145
+/* return the number of byte decoded */
146
+static int GLZWDecode(GifState * s, uint8_t * buf, int len)
147
+{
148
+    int l, c, code, oc, fc;
149
+    uint8_t *sp;
150
+
151
+    if (s->end_code < 0)
152
+        return 0;
153
+
154
+    l = len;
155
+    sp = s->sp;
156
+    oc = s->oc;
157
+    fc = s->fc;
158
+
159
+    while (sp > s->stack) {
160
+        *buf++ = *(--sp);
161
+        if ((--l) == 0)
162
+            goto the_end;
163
+    }
164
+
165
+    for (;;) {
166
+        c = GetCode(s);
167
+        if (c == s->end_code) {
168
+            s->end_code = -1;
169
+            break;
170
+        } else if (c == s->clear_code) {
171
+            s->cursize = s->codesize + 1;
172
+            s->curmask = mask[s->cursize];
173
+            s->slot = s->newcodes;
174
+            s->top_slot = 1 << s->cursize;
175
+            while ((c = GetCode(s)) == s->clear_code);
176
+            if (c == s->end_code) {
177
+                s->end_code = -1;
178
+                break;
179
+            }
180
+            /* test error */
181
+            if (c >= s->slot)
182
+                c = 0;
183
+            fc = oc = c;
184
+            *buf++ = c;
185
+            if ((--l) == 0)
186
+                break;
187
+        } else {
188
+            code = c;
189
+            if (code >= s->slot) {
190
+                *sp++ = fc;
191
+                code = oc;
192
+            }
193
+            while (code >= s->newcodes) {
194
+                *sp++ = s->suffix[code];
195
+                code = s->prefix[code];
196
+            }
197
+            *sp++ = code;
198
+            if (s->slot < s->top_slot) {
199
+                s->suffix[s->slot] = fc = code;
200
+                s->prefix[s->slot++] = oc;
201
+                oc = c;
202
+            }
203
+            if (s->slot >= s->top_slot) {
204
+                if (s->cursize < MAXBITS) {
205
+                    s->top_slot <<= 1;
206
+                    s->curmask = mask[++s->cursize];
207
+                }
208
+            }
209
+            while (sp > s->stack) {
210
+                *buf++ = *(--sp);
211
+                if ((--l) == 0)
212
+                    goto the_end;
213
+            }
214
+        }
215
+    }
216
+  the_end:
217
+    s->sp = sp;
218
+    s->oc = oc;
219
+    s->fc = fc;
220
+    return len - l;
221
+}
222
+
223
+static int gif_read_image(GifState *s)
224
+{
225
+    int left, top, width, height, bits_per_pixel, code_size, flags;
226
+    int is_interleaved, has_local_palette, y, x, pass, y1, linesize, n, i;
227
+    uint8_t *ptr, *line, *d, *spal, *palette, *sptr, *ptr1;
228
+
229
+    left = bytestream_get_le16(&s->bytestream);
230
+    top = bytestream_get_le16(&s->bytestream);
231
+    width = bytestream_get_le16(&s->bytestream);
232
+    height = bytestream_get_le16(&s->bytestream);
233
+    flags = bytestream_get_byte(&s->bytestream);
234
+    is_interleaved = flags & 0x40;
235
+    has_local_palette = flags & 0x80;
236
+    bits_per_pixel = (flags & 0x07) + 1;
237
+#ifdef DEBUG
238
+    printf("gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height);
239
+#endif
240
+
241
+    if (has_local_palette) {
242
+        bytestream_get_buffer(&s->bytestream, s->local_palette, 3 * (1 << bits_per_pixel));
243
+        palette = s->local_palette;
244
+    } else {
245
+        palette = s->global_palette;
246
+        bits_per_pixel = s->bits_per_pixel;
247
+    }
248
+
249
+    /* verify that all the image is inside the screen dimensions */
250
+    if (left + width > s->screen_width ||
251
+        top + height > s->screen_height)
252
+        return -EINVAL;
253
+
254
+    /* build the palette */
255
+        n = (1 << bits_per_pixel);
256
+        spal = palette;
257
+        for(i = 0; i < n; i++) {
258
+            s->image_palette[i] = (0xff << 24) |
259
+                (spal[0] << 16) | (spal[1] << 8) | (spal[2]);
260
+            spal += 3;
261
+        }
262
+        for(; i < 256; i++)
263
+            s->image_palette[i] = (0xff << 24);
264
+        /* handle transparency */
265
+        if (s->transparent_color_index >= 0)
266
+            s->image_palette[s->transparent_color_index] = 0;
267
+        line = NULL;
268
+
269
+    /* now get the image data */
270
+    code_size = bytestream_get_byte(&s->bytestream);
271
+    GLZWDecodeInit(s, code_size);
272
+
273
+    /* read all the image */
274
+    linesize = s->image_linesize;
275
+    ptr1 = s->image_buf + top * linesize + (left * 3);
276
+    ptr = ptr1;
277
+    pass = 0;
278
+    y1 = 0;
279
+    for (y = 0; y < height; y++) {
280
+            GLZWDecode(s, ptr, width);
281
+        if (is_interleaved) {
282
+            switch(pass) {
283
+            default:
284
+            case 0:
285
+            case 1:
286
+                y1 += 8;
287
+                ptr += linesize * 8;
288
+                if (y1 >= height) {
289
+                    y1 = 4;
290
+                    if (pass == 0)
291
+                        ptr = ptr1 + linesize * 4;
292
+                    else
293
+                        ptr = ptr1 + linesize * 2;
294
+                    pass++;
295
+                }
296
+                break;
297
+            case 2:
298
+                y1 += 4;
299
+                ptr += linesize * 4;
300
+                if (y1 >= height) {
301
+                    y1 = 1;
302
+                    ptr = ptr1 + linesize;
303
+                    pass++;
304
+                }
305
+                break;
306
+            case 3:
307
+                y1 += 2;
308
+                ptr += linesize * 2;
309
+                break;
310
+            }
311
+        } else {
312
+            ptr += linesize;
313
+        }
314
+    }
315
+    av_free(line);
316
+
317
+    /* read the garbage data until end marker is found */
318
+    while (!s->eob_reached)
319
+        GetCode(s);
320
+    return 0;
321
+}
322
+
323
+static int gif_read_extension(GifState *s)
324
+{
325
+    int ext_code, ext_len, i, gce_flags, gce_transparent_index;
326
+
327
+    /* extension */
328
+    ext_code = bytestream_get_byte(&s->bytestream);
329
+    ext_len = bytestream_get_byte(&s->bytestream);
330
+#ifdef DEBUG
331
+    printf("gif: ext_code=0x%x len=%d\n", ext_code, ext_len);
332
+#endif
333
+    switch(ext_code) {
334
+    case 0xf9:
335
+        if (ext_len != 4)
336
+            goto discard_ext;
337
+        s->transparent_color_index = -1;
338
+        gce_flags = bytestream_get_byte(&s->bytestream);
339
+        s->gce_delay = bytestream_get_le16(&s->bytestream);
340
+        gce_transparent_index = bytestream_get_byte(&s->bytestream);
341
+        if (gce_flags & 0x01)
342
+            s->transparent_color_index = gce_transparent_index;
343
+        else
344
+            s->transparent_color_index = -1;
345
+        s->gce_disposal = (gce_flags >> 2) & 0x7;
346
+#ifdef DEBUG
347
+        printf("gif: gce_flags=%x delay=%d tcolor=%d disposal=%d\n",
348
+               gce_flags, s->gce_delay,
349
+               s->transparent_color_index, s->gce_disposal);
350
+#endif
351
+        ext_len = bytestream_get_byte(&s->bytestream);
352
+        break;
353
+    }
354
+
355
+    /* NOTE: many extension blocks can come after */
356
+ discard_ext:
357
+    while (ext_len != 0) {
358
+        for (i = 0; i < ext_len; i++)
359
+            bytestream_get_byte(&s->bytestream);
360
+        ext_len = bytestream_get_byte(&s->bytestream);
361
+#ifdef DEBUG
362
+        printf("gif: ext_len1=%d\n", ext_len);
363
+#endif
364
+    }
365
+    return 0;
366
+}
367
+
368
+static int gif_read_header1(GifState *s)
369
+{
370
+    uint8_t sig[6];
371
+    int ret, v, n;
372
+    int has_global_palette;
373
+
374
+    /* read gif signature */
375
+    bytestream_get_buffer(&s->bytestream, sig, 6);
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 = bytestream_get_le16(&s->bytestream);
383
+    s->screen_height = bytestream_get_le16(&s->bytestream);
384
+    if(   (unsigned)s->screen_width  > 32767
385
+       || (unsigned)s->screen_height > 32767){
386
+        av_log(NULL, AV_LOG_ERROR, "picture size too large\n");
387
+        return -1;
388
+    }
389
+
390
+    v = bytestream_get_byte(&s->bytestream);
391
+    s->color_resolution = ((v & 0x70) >> 4) + 1;
392
+    has_global_palette = (v & 0x80);
393
+    s->bits_per_pixel = (v & 0x07) + 1;
394
+    s->background_color_index = bytestream_get_byte(&s->bytestream);
395
+    bytestream_get_byte(&s->bytestream);                /* ignored */
396
+#ifdef DEBUG
397
+    printf("gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
398
+           s->screen_width, s->screen_height, s->bits_per_pixel,
399
+           has_global_palette);
400
+#endif
401
+    if (has_global_palette) {
402
+        n = 1 << s->bits_per_pixel;
403
+        bytestream_get_buffer(&s->bytestream, s->global_palette, n * 3);
404
+    }
405
+    return 0;
406
+}
407
+
408
+static int gif_parse_next_image(GifState *s)
409
+{
410
+    int ret, code;
411
+
412
+    for (;;) {
413
+        code = bytestream_get_byte(&s->bytestream);
414
+#ifdef DEBUG
415
+        printf("gif: code=%02x '%c'\n", code, code);
416
+#endif
417
+        switch (code) {
418
+        case ',':
419
+            if (gif_read_image(s) < 0)
420
+                return -1;
421
+            ret = 0;
422
+            goto the_end;
423
+        case ';':
424
+            /* end of image */
425
+            ret = -1;
426
+            goto the_end;
427
+        case '!':
428
+            if (gif_read_extension(s) < 0)
429
+                return -1;
430
+            break;
431
+        case EOF:
432
+        default:
433
+            /* error or errneous EOF */
434
+            ret = -1;
435
+            goto the_end;
436
+        }
437
+    }
438
+  the_end:
439
+    return ret;
440
+}
441
+
442
+static int gif_decode_init(AVCodecContext *avctx)
443
+{
444
+    GifState *s = avctx->priv_data;
445
+
446
+    return 0;
447
+}
448
+
449
+static int gif_decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size)
450
+{
451
+    GifState *s = avctx->priv_data;
452
+    AVFrame *picture = data;
453
+    int ret;
454
+
455
+    s->bytestream = buf;
456
+    if (gif_read_header1(s) < 0)
457
+        return -1;
458
+
459
+    /* allocate image buffer */
460
+    s->image_linesize = s->screen_width * 3;
461
+    s->image_buf = av_malloc(s->screen_height * s->image_linesize);
462
+    if (!s->image_buf)
463
+        return -ENOMEM;
464
+    s->pix_fmt = PIX_FMT_PAL8;
465
+    /* now we are ready: build format streams */
466
+
467
+    /* XXX: check if screen size is always valid */
468
+    avctx->width = s->screen_width;
469
+    avctx->height = s->screen_height;
470
+    avctx->pix_fmt = PIX_FMT_PAL8;
471
+
472
+    ret = gif_parse_next_image(s);
473
+    if (ret < 0)
474
+        return ret;
475
+
476
+    picture->data[0] = s->image_buf;
477
+    picture->linesize[0] = s->image_linesize;
478
+    picture->data[1] = s->image_palette;
479
+    picture->linesize[1] = 4;
480
+
481
+    *data_size = sizeof(AVPicture);
482
+    return 0;
483
+}
484
+
485
+AVCodec gif_decoder = {
486
+    "gif",
487
+    CODEC_TYPE_VIDEO,
488
+    CODEC_ID_GIF,
489
+    sizeof(GifState),
490
+    gif_decode_init,
491
+    NULL,
492
+    NULL,
493
+    gif_decode_frame,
494
+};