Coverage Report

Created: 2025-11-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/gifdec.c
Line
Count
Source
1
/*
2
 * GIF decoder
3
 * Copyright (c) 2003 Fabrice Bellard
4
 * Copyright (c) 2006 Baptiste Coudurier
5
 * Copyright (c) 2012 Vitaliy E Sugrobov
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
#include "libavutil/mem.h"
25
#include "libavutil/opt.h"
26
#include "avcodec.h"
27
#include "bytestream.h"
28
#include "codec_internal.h"
29
#include "decode.h"
30
#include "lzw.h"
31
#include "gif.h"
32
33
/* This value is intentionally set to "transparent white" color.
34
 * It is much better to have white background instead of black
35
 * when gif image converted to format which not support transparency.
36
 */
37
#define GIF_TRANSPARENT_COLOR    0x00ffffff
38
39
typedef struct GifState {
40
    const AVClass *class;
41
    AVFrame *frame;
42
    int screen_width;
43
    int screen_height;
44
    int has_global_palette;
45
    int bits_per_pixel;
46
    uint32_t bg_color;
47
    int background_color_index;
48
    int transparent_color_index;
49
    int color_resolution;
50
    /* intermediate buffer for storing color indices
51
     * obtained from lzw-encoded data stream */
52
    uint8_t *idx_line;
53
    int idx_line_size;
54
55
    /* after the frame is displayed, the disposal method is used */
56
    int gce_prev_disposal;
57
    int gce_disposal;
58
    /* rectangle describing area that must be disposed */
59
    int gce_l, gce_t, gce_w, gce_h;
60
    /* depending on disposal method we store either part of the image
61
     * drawn on the canvas or background color that
62
     * should be used upon disposal */
63
    uint8_t *stored_img;
64
    int stored_img_size;
65
    int stored_bg_color;
66
67
    GetByteContext gb;
68
    LZWState *lzw;
69
70
    /* aux buffers */
71
    uint32_t global_palette[256];
72
    uint32_t local_palette[256];
73
74
    AVCodecContext *avctx;
75
    int keyframe;
76
    int keyframe_ok;
77
    int trans_color;    /**< color value that is used instead of transparent color */
78
} GifState;
79
80
static void gif_read_palette(GifState *s, uint32_t *pal, int nb)
81
137k
{
82
137k
    int i;
83
84
573k
    for (i = 0; i < nb; i++, pal++)
85
435k
        *pal = (0xffu << 24) | bytestream2_get_be24u(&s->gb);
86
137k
}
87
88
static void gif_fill(AVFrame *picture, uint32_t color)
89
67.2k
{
90
67.2k
    const ptrdiff_t linesize = picture->linesize[0];
91
67.2k
    uint8_t *py = picture->data[0];
92
67.2k
    const int w = picture->width;
93
67.2k
    const int h = picture->height;
94
95
28.1M
    for (int y = 0; y < h; y++) {
96
28.0M
        uint32_t *px = (uint32_t *)py;
97
9.90G
        for (int x = 0; x < w; x++)
98
9.87G
            px[x] = color;
99
28.0M
        py += linesize;
100
28.0M
    }
101
67.2k
}
102
103
static void gif_fill_rect(AVFrame *picture, uint32_t color, int l, int t, int w, int h)
104
551
{
105
551
    const ptrdiff_t linesize = picture->linesize[0];
106
551
    uint8_t *py = picture->data[0] + t * linesize;
107
108
964k
    for (int y = 0; y < h; y++) {
109
963k
        uint32_t *px = ((uint32_t *)py) + l;
110
19.7M
        for (int x = 0; x < w; x++)
111
18.7M
            px[x] = color;
112
963k
        py += linesize;
113
963k
    }
114
551
}
115
116
static void gif_copy_img_rect(const uint8_t *src, uint8_t *dst,
117
                              ptrdiff_t src_linesize,
118
                              ptrdiff_t dst_linesize,
119
                              int l, int t, int w, int h)
120
1.90k
{
121
1.90k
    const uint8_t *src_py = src;
122
1.90k
    uint8_t *dst_py = dst;
123
124
1.90k
    src_py += t * src_linesize;
125
1.90k
    dst_py += t * dst_linesize;
126
3.37M
    for (int y = 0; y < h; y++) {
127
3.36M
        memcpy(dst_py + l * 4, src_py + l * 4, w * 4);
128
3.36M
        src_py += src_linesize;
129
3.36M
        dst_py += dst_linesize;
130
3.36M
    }
131
1.90k
}
132
133
static int gif_read_image(GifState *s, AVFrame *frame)
134
80.1k
{
135
80.1k
    int left, top, width, height, bits_per_pixel, code_size, flags, pw;
136
80.1k
    int is_interleaved, has_local_palette, y, pass, y1, pal_size, lzwed_len;
137
80.1k
    uint32_t *ptr, *pal, *px, *pr, *ptr1;
138
80.1k
    ptrdiff_t linesize;
139
80.1k
    int ret;
140
80.1k
    uint8_t *idx;
141
142
    /* At least 9 bytes of Image Descriptor. */
143
80.1k
    if (bytestream2_get_bytes_left(&s->gb) < 9)
144
441
        return AVERROR_INVALIDDATA;
145
146
79.7k
    left   = bytestream2_get_le16u(&s->gb);
147
79.7k
    top    = bytestream2_get_le16u(&s->gb);
148
79.7k
    width  = bytestream2_get_le16u(&s->gb);
149
79.7k
    height = bytestream2_get_le16u(&s->gb);
150
79.7k
    flags  = bytestream2_get_byteu(&s->gb);
151
79.7k
    is_interleaved = flags & 0x40;
152
79.7k
    has_local_palette = flags & 0x80;
153
79.7k
    bits_per_pixel = (flags & 0x07) + 1;
154
155
79.7k
    ff_dlog(s->avctx, "image x=%d y=%d w=%d h=%d\n", left, top, width, height);
156
157
79.7k
    if (has_local_palette) {
158
73.6k
        pal_size = 1 << bits_per_pixel;
159
160
73.6k
        if (bytestream2_get_bytes_left(&s->gb) < pal_size * 3)
161
110
            return AVERROR_INVALIDDATA;
162
163
73.5k
        gif_read_palette(s, s->local_palette, pal_size);
164
73.5k
        pal = s->local_palette;
165
73.5k
    } else {
166
6.04k
        if (!s->has_global_palette) {
167
1.48k
            av_log(s->avctx, AV_LOG_ERROR, "picture doesn't have either global or local palette.\n");
168
1.48k
            return AVERROR_INVALIDDATA;
169
1.48k
        }
170
171
4.55k
        pal = s->global_palette;
172
4.55k
    }
173
174
78.1k
    if (s->keyframe) {
175
67.2k
        if (s->transparent_color_index == -1 && s->has_global_palette) {
176
            /* transparency wasn't set before the first frame, fill with background color */
177
63.1k
            gif_fill(frame, s->bg_color);
178
63.1k
        } else {
179
            /* otherwise fill with transparent color.
180
             * this is necessary since by default picture filled with 0x80808080. */
181
4.09k
            gif_fill(frame, s->trans_color);
182
4.09k
        }
183
67.2k
    }
184
185
    /* verify that all the image is inside the screen dimensions */
186
78.1k
    if (!width || width > s->screen_width) {
187
74.1k
        av_log(s->avctx, AV_LOG_WARNING, "Invalid image width: %d, truncating.\n", width);
188
74.1k
        width = s->screen_width;
189
74.1k
    }
190
78.1k
    if (left >= s->screen_width) {
191
685
        av_log(s->avctx, AV_LOG_ERROR, "Invalid left position: %d.\n", left);
192
685
        return AVERROR_INVALIDDATA;
193
685
    }
194
77.4k
    if (!height || height > s->screen_height) {
195
72.6k
        av_log(s->avctx, AV_LOG_WARNING, "Invalid image height: %d, truncating.\n", height);
196
72.6k
        height = s->screen_height;
197
72.6k
    }
198
77.4k
    if (top >= s->screen_height) {
199
1.83k
        av_log(s->avctx, AV_LOG_ERROR, "Invalid top position: %d.\n", top);
200
1.83k
        return AVERROR_INVALIDDATA;
201
1.83k
    }
202
75.6k
    if (left + width > s->screen_width) {
203
        /* width must be kept around to avoid lzw vs line desync */
204
70.0k
        pw = s->screen_width - left;
205
70.0k
        av_log(s->avctx, AV_LOG_WARNING, "Image too wide by %d, truncating.\n",
206
70.0k
               left + width - s->screen_width);
207
70.0k
    } else {
208
5.57k
        pw = width;
209
5.57k
    }
210
75.6k
    if (top + height > s->screen_height) {
211
        /* we don't care about the extra invisible lines */
212
68.4k
        av_log(s->avctx, AV_LOG_WARNING, "Image too high by %d, truncating.\n",
213
68.4k
               top + height - s->screen_height);
214
68.4k
        height = s->screen_height - top;
215
68.4k
    }
216
217
    /* process disposal method */
218
75.6k
    if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) {
219
551
        gif_fill_rect(frame, s->stored_bg_color, s->gce_l, s->gce_t, s->gce_w, s->gce_h);
220
75.0k
    } else if (s->gce_prev_disposal == GCE_DISPOSAL_RESTORE) {
221
719
        gif_copy_img_rect(s->stored_img, frame->data[0],
222
719
            FFABS(frame->linesize[0]), frame->linesize[0], s->gce_l, s->gce_t, s->gce_w, s->gce_h);
223
719
    }
224
225
75.6k
    s->gce_prev_disposal = s->gce_disposal;
226
227
75.6k
    if (s->gce_disposal != GCE_DISPOSAL_NONE) {
228
2.33k
        s->gce_l = left;  s->gce_t = top;
229
2.33k
        s->gce_w = pw;    s->gce_h = height;
230
231
2.33k
        if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) {
232
794
            if (s->transparent_color_index >= 0)
233
556
                s->stored_bg_color = s->trans_color;
234
238
            else
235
238
                s->stored_bg_color = s->bg_color;
236
1.53k
        } else if (s->gce_disposal == GCE_DISPOSAL_RESTORE) {
237
1.19k
            av_fast_malloc(&s->stored_img, &s->stored_img_size, FFABS(frame->linesize[0]) * frame->height);
238
1.19k
            if (!s->stored_img)
239
0
                return AVERROR(ENOMEM);
240
241
1.19k
            gif_copy_img_rect(frame->data[0], s->stored_img,
242
1.19k
                frame->linesize[0], FFABS(frame->linesize[0]), left, top, pw, height);
243
1.19k
        }
244
2.33k
    }
245
246
    /* Expect at least 2 bytes: 1 for lzw code size and 1 for block size. */
247
75.6k
    if (bytestream2_get_bytes_left(&s->gb) < 2)
248
311
        return AVERROR_INVALIDDATA;
249
250
    /* now get the image data */
251
75.2k
    code_size = bytestream2_get_byteu(&s->gb);
252
75.2k
    if ((ret = ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer,
253
75.2k
                                  bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF)) < 0) {
254
4.26k
        av_log(s->avctx, AV_LOG_ERROR, "LZW init failed\n");
255
4.26k
        return ret;
256
4.26k
    }
257
258
    /* read all the image */
259
71.0k
    linesize = frame->linesize[0];
260
71.0k
    ptr1 = (uint32_t *)(frame->data[0] + top * linesize) + left;
261
71.0k
    ptr = ptr1;
262
71.0k
    pass = 0;
263
71.0k
    y1 = 0;
264
117k
    for (y = 0; y < height; y++) {
265
116k
        int count = ff_lzw_decode(s->lzw, s->idx_line, width);
266
116k
        if (count != width) {
267
70.4k
            if (count)
268
68.6k
                av_log(s->avctx, AV_LOG_ERROR, "LZW decode failed\n");
269
70.4k
            goto decode_tail;
270
70.4k
        }
271
272
46.1k
        pr = ptr + pw;
273
274
2.42M
        for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) {
275
2.38M
            if (*idx != s->transparent_color_index)
276
2.37M
                *px = pal[*idx];
277
2.38M
        }
278
279
46.1k
        if (is_interleaved) {
280
12.0k
            switch(pass) {
281
0
            default:
282
4.09k
            case 0:
283
5.70k
            case 1:
284
5.70k
                y1 += 8;
285
5.70k
                ptr += linesize * 2;
286
5.70k
                break;
287
2.77k
            case 2:
288
2.77k
                y1 += 4;
289
2.77k
                ptr += linesize * 1;
290
2.77k
                break;
291
3.61k
            case 3:
292
3.61k
                y1 += 2;
293
3.61k
                ptr += linesize / 2;
294
3.61k
                break;
295
12.0k
            }
296
14.1k
            while (y1 >= height) {
297
2.07k
                y1  = 4 >> pass;
298
2.07k
                ptr = ptr1 + linesize / 4 * y1;
299
2.07k
                pass++;
300
2.07k
            }
301
34.0k
        } else {
302
34.0k
            ptr += linesize / 4;
303
34.0k
        }
304
46.1k
    }
305
306
71.0k
 decode_tail:
307
    /* read the garbage data until end marker is found */
308
71.0k
    lzwed_len = ff_lzw_decode_tail(s->lzw);
309
71.0k
    bytestream2_skipu(&s->gb, lzwed_len);
310
311
    /* Graphic Control Extension's scope is single frame.
312
     * Remove its influence. */
313
71.0k
    s->transparent_color_index = -1;
314
71.0k
    s->gce_disposal = GCE_DISPOSAL_NONE;
315
316
71.0k
    return 0;
317
71.0k
}
318
319
static int gif_read_extension(GifState *s)
320
15.8k
{
321
15.8k
    int ext_code, ext_len, gce_flags, gce_transparent_index;
322
323
    /* There must be at least 2 bytes:
324
     * 1 for extension label and 1 for extension length. */
325
15.8k
    if (bytestream2_get_bytes_left(&s->gb) < 2)
326
208
        return AVERROR_INVALIDDATA;
327
328
15.6k
    ext_code = bytestream2_get_byteu(&s->gb);
329
15.6k
    ext_len  = bytestream2_get_byteu(&s->gb);
330
331
15.6k
    ff_dlog(s->avctx, "ext_code=0x%x len=%d\n", ext_code, ext_len);
332
333
15.6k
    switch(ext_code) {
334
2.29k
    case GIF_GCE_EXT_LABEL:
335
2.29k
        if (ext_len != 4)
336
276
            goto discard_ext;
337
338
        /* We need at least 5 bytes more: 4 is for extension body
339
         * and 1 for next block size. */
340
2.02k
        if (bytestream2_get_bytes_left(&s->gb) < 5)
341
458
            return AVERROR_INVALIDDATA;
342
343
1.56k
        gce_flags    = bytestream2_get_byteu(&s->gb);
344
1.56k
        bytestream2_skipu(&s->gb, 2);    // delay during which the frame is shown
345
1.56k
        gce_transparent_index = bytestream2_get_byteu(&s->gb);
346
1.56k
        if (gce_flags & 0x01)
347
1.14k
            s->transparent_color_index = gce_transparent_index;
348
414
        else
349
414
            s->transparent_color_index = -1;
350
1.56k
        s->gce_disposal = (gce_flags >> 2) & 0x7;
351
352
1.56k
        ff_dlog(s->avctx, "gce_flags=%x tcolor=%d disposal=%d\n",
353
1.56k
               gce_flags,
354
1.56k
               s->transparent_color_index, s->gce_disposal);
355
356
1.56k
        if (s->gce_disposal > 3) {
357
376
            s->gce_disposal = GCE_DISPOSAL_NONE;
358
376
            ff_dlog(s->avctx, "invalid value in gce_disposal (%d). Using default value of 0.\n", ext_len);
359
376
        }
360
361
1.56k
        ext_len = bytestream2_get_byteu(&s->gb);
362
1.56k
        break;
363
15.6k
    }
364
365
    /* NOTE: many extension blocks can come after */
366
15.1k
 discard_ext:
367
23.9k
    while (ext_len) {
368
        /* There must be at least ext_len bytes and 1 for next block size byte. */
369
10.1k
        if (bytestream2_get_bytes_left(&s->gb) < ext_len + 1)
370
1.33k
            return AVERROR_INVALIDDATA;
371
372
8.80k
        bytestream2_skipu(&s->gb, ext_len);
373
8.80k
        ext_len = bytestream2_get_byteu(&s->gb);
374
375
8.80k
        ff_dlog(s->avctx, "ext_len1=%d\n", ext_len);
376
8.80k
    }
377
13.8k
    return 0;
378
15.1k
}
379
380
static int gif_read_header1(GifState *s)
381
74.1k
{
382
74.1k
    uint8_t sig[6];
383
74.1k
    int v, n;
384
74.1k
    int background_color_index;
385
386
74.1k
    if (bytestream2_get_bytes_left(&s->gb) < 13)
387
381
        return AVERROR_INVALIDDATA;
388
389
    /* read gif signature */
390
73.7k
    bytestream2_get_bufferu(&s->gb, sig, 6);
391
73.7k
    if (memcmp(sig, gif87a_sig, 6) &&
392
66.8k
        memcmp(sig, gif89a_sig, 6))
393
0
        return AVERROR_INVALIDDATA;
394
395
    /* read screen header */
396
73.7k
    s->transparent_color_index = -1;
397
73.7k
    s->screen_width  = bytestream2_get_le16u(&s->gb);
398
73.7k
    s->screen_height = bytestream2_get_le16u(&s->gb);
399
400
73.7k
    v = bytestream2_get_byteu(&s->gb);
401
73.7k
    s->color_resolution = ((v & 0x70) >> 4) + 1;
402
73.7k
    s->has_global_palette = (v & 0x80);
403
73.7k
    s->bits_per_pixel = (v & 0x07) + 1;
404
73.7k
    background_color_index = bytestream2_get_byteu(&s->gb);
405
73.7k
    n = bytestream2_get_byteu(&s->gb);
406
73.7k
    if (n) {
407
67.5k
        s->avctx->sample_aspect_ratio.num = n + 15;
408
67.5k
        s->avctx->sample_aspect_ratio.den = 64;
409
67.5k
    }
410
411
73.7k
    ff_dlog(s->avctx, "screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
412
73.7k
           s->screen_width, s->screen_height, s->bits_per_pixel,
413
73.7k
           s->has_global_palette);
414
415
73.7k
    if (s->has_global_palette) {
416
64.5k
        s->background_color_index = background_color_index;
417
64.5k
        n = 1 << s->bits_per_pixel;
418
64.5k
        if (bytestream2_get_bytes_left(&s->gb) < n * 3)
419
341
            return AVERROR_INVALIDDATA;
420
421
64.1k
        gif_read_palette(s, s->global_palette, n);
422
64.1k
        s->bg_color = s->global_palette[s->background_color_index];
423
64.1k
    } else
424
9.24k
        s->background_color_index = -1;
425
426
73.4k
    return 0;
427
73.7k
}
428
429
static int gif_parse_next_image(GifState *s, AVFrame *frame)
430
110k
{
431
124k
    while (bytestream2_get_bytes_left(&s->gb) > 0) {
432
123k
        int code = bytestream2_get_byte(&s->gb);
433
123k
        int ret;
434
435
123k
        av_log(s->avctx, AV_LOG_DEBUG, "code=%02x '%c'\n", code, code);
436
437
123k
        switch (code) {
438
80.1k
        case GIF_IMAGE_SEPARATOR:
439
80.1k
            return gif_read_image(s, frame);
440
15.8k
        case GIF_EXTENSION_INTRODUCER:
441
15.8k
            if ((ret = gif_read_extension(s)) < 0)
442
2.00k
                return ret;
443
13.8k
            break;
444
13.8k
        case GIF_TRAILER:
445
            /* end of image */
446
1.56k
            return AVERROR_EOF;
447
26.3k
        default:
448
            /* erroneous block label */
449
26.3k
            return AVERROR_INVALIDDATA;
450
123k
        }
451
123k
    }
452
779
    return AVERROR_EOF;
453
110k
}
454
455
static av_cold int gif_decode_init(AVCodecContext *avctx)
456
2.19k
{
457
2.19k
    GifState *s = avctx->priv_data;
458
459
2.19k
    s->avctx = avctx;
460
461
2.19k
    avctx->pix_fmt = AV_PIX_FMT_RGB32;
462
2.19k
    s->frame = av_frame_alloc();
463
2.19k
    if (!s->frame)
464
0
        return AVERROR(ENOMEM);
465
2.19k
    ff_lzw_decode_open(&s->lzw);
466
2.19k
    if (!s->lzw)
467
0
        return AVERROR(ENOMEM);
468
2.19k
    return 0;
469
2.19k
}
470
471
static int gif_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
472
                            int *got_frame, AVPacket *avpkt)
473
174k
{
474
174k
    GifState *s = avctx->priv_data;
475
174k
    int ret;
476
477
174k
    bytestream2_init(&s->gb, avpkt->data, avpkt->size);
478
479
174k
    if (avpkt->size >= 6) {
480
109k
        s->keyframe = memcmp(avpkt->data, gif87a_sig, 6) == 0 ||
481
102k
                      memcmp(avpkt->data, gif89a_sig, 6) == 0;
482
109k
    } else {
483
65.3k
        s->keyframe = 0;
484
65.3k
    }
485
486
174k
    if (s->keyframe) {
487
74.1k
        s->keyframe_ok = 0;
488
74.1k
        s->gce_prev_disposal = GCE_DISPOSAL_NONE;
489
74.1k
        if ((ret = gif_read_header1(s)) < 0)
490
722
            return ret;
491
492
73.4k
        if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0)
493
1.47k
            return ret;
494
495
71.9k
        av_frame_unref(s->frame);
496
71.9k
        av_fast_malloc(&s->idx_line, &s->idx_line_size, s->screen_width);
497
71.9k
        if (!s->idx_line)
498
0
            return AVERROR(ENOMEM);
499
100k
    } else if (!s->keyframe_ok) {
500
61.2k
        av_log(avctx, AV_LOG_ERROR, "cannot decode frame without keyframe\n");
501
61.2k
        return AVERROR_INVALIDDATA;
502
61.2k
    }
503
504
111k
    ret = ff_reget_buffer(avctx, s->frame, 0);
505
111k
    if (ret < 0)
506
291
        return ret;
507
508
110k
    ret = gif_parse_next_image(s, s->frame);
509
110k
    if (ret < 0)
510
39.8k
        return ret;
511
512
71.0k
    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
513
0
        return ret;
514
515
71.0k
    rframe->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
516
71.0k
    rframe->flags     = AV_FRAME_FLAG_KEY * s->keyframe;
517
71.0k
    s->keyframe_ok   |= !!s->keyframe;
518
519
71.0k
    *got_frame = 1;
520
521
71.0k
    return bytestream2_tell(&s->gb);
522
71.0k
}
523
524
static av_cold int gif_decode_close(AVCodecContext *avctx)
525
2.19k
{
526
2.19k
    GifState *s = avctx->priv_data;
527
528
2.19k
    ff_lzw_decode_close(&s->lzw);
529
2.19k
    av_frame_free(&s->frame);
530
2.19k
    av_freep(&s->idx_line);
531
2.19k
    av_freep(&s->stored_img);
532
533
2.19k
    return 0;
534
2.19k
}
535
536
static const AVOption options[] = {
537
    { "trans_color", "color value (ARGB) that is used instead of transparent color",
538
      offsetof(GifState, trans_color), AV_OPT_TYPE_INT,
539
      {.i64 = GIF_TRANSPARENT_COLOR}, 0, 0xffffffff,
540
      AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_VIDEO_PARAM },
541
    { NULL },
542
};
543
544
static const AVClass decoder_class = {
545
    .class_name = "gif decoder",
546
    .item_name  = av_default_item_name,
547
    .option     = options,
548
    .version    = LIBAVUTIL_VERSION_INT,
549
    .category   = AV_CLASS_CATEGORY_DECODER,
550
};
551
552
const FFCodec ff_gif_decoder = {
553
    .p.name         = "gif",
554
    CODEC_LONG_NAME("GIF (Graphics Interchange Format)"),
555
    .p.type         = AVMEDIA_TYPE_VIDEO,
556
    .p.id           = AV_CODEC_ID_GIF,
557
    .priv_data_size = sizeof(GifState),
558
    .init           = gif_decode_init,
559
    .close          = gif_decode_close,
560
    FF_CODEC_DECODE_CB(gif_decode_frame),
561
    .p.capabilities = AV_CODEC_CAP_DR1,
562
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
563
    .p.priv_class   = &decoder_class,
564
};