Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/gif_parser.c
Line
Count
Source
1
/*
2
 * GIF parser
3
 * Copyright (c) 2018 Paul B Mahol
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
/**
23
 * @file
24
 * GIF parser
25
 */
26
27
#include "gif.h"
28
#include "parser.h"
29
#include "parser_internal.h"
30
31
typedef enum GIFParseStates {
32
    GIF_HEADER = 1,
33
    GIF_EXTENSION,
34
    GIF_EXTENSION_BLOCK,
35
    GIF_IMAGE,
36
    GIF_IMAGE_BLOCK,
37
} gif_states;
38
39
typedef struct GIFParseContext {
40
    ParseContext pc;
41
    unsigned found_sig;
42
    int found_start;
43
    int found_end;
44
    int index;
45
    int state;
46
    int gct_flag;
47
    int gct_size;
48
    int block_size;
49
    int etype;
50
    int delay;
51
    int keyframe;
52
} GIFParseContext;
53
54
static int gif_find_frame_end(GIFParseContext *g, const uint8_t *buf,
55
                              int buf_size, void *logctx)
56
91.5k
{
57
91.5k
    ParseContext *pc = &g->pc;
58
91.5k
    int index, next = END_NOT_FOUND;
59
60
41.8M
    for (index = 0; index < buf_size; index++) {
61
41.7M
        if (!g->state) {
62
22.4M
            if (!memcmp(buf + index, gif87a_sig, 6) ||
63
22.4M
                !memcmp(buf + index, gif89a_sig, 6)) {
64
19.8k
                g->state = GIF_HEADER;
65
19.8k
                g->found_sig++;
66
19.8k
                g->keyframe = 1;
67
22.4M
            } else if (buf[index] == GIF_EXTENSION_INTRODUCER) {
68
43.5k
                g->state = GIF_EXTENSION;
69
43.5k
                g->found_start = pc->frame_start_found = 1;
70
22.3M
            } else if (buf[index] == GIF_IMAGE_SEPARATOR) {
71
49.3k
                if (g->state != GIF_EXTENSION_BLOCK && g->found_start &&
72
47.2k
                    g->found_end && g->found_sig) {
73
26.8k
                    next = index;
74
26.8k
                    g->found_start = pc->frame_start_found = 1;
75
26.8k
                    g->found_end = 0;
76
26.8k
                    g->index = 0;
77
26.8k
                    g->gct_flag = 0;
78
26.8k
                    g->gct_size = 0;
79
26.8k
                    g->state = GIF_IMAGE;
80
26.8k
                    break;
81
26.8k
                }
82
22.5k
                g->state = GIF_IMAGE;
83
22.3M
            } else if (buf[index] == GIF_TRAILER) {
84
154k
                g->state = 0;
85
154k
                g->found_end = 1;
86
154k
                g->found_sig = 0;
87
22.1M
            } else {
88
22.1M
                g->found_sig = 0;
89
22.1M
            }
90
22.4M
        }
91
92
41.7M
        if (g->state == GIF_HEADER) {
93
311k
            if (g->index == 10) {
94
19.8k
                g->gct_flag = !!(buf[index] & 0x80);
95
19.8k
                g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1));
96
19.8k
            }
97
311k
            if (g->index >= 12 + g->gct_flag * g->gct_size) {
98
19.8k
                g->state = 0;
99
19.8k
                g->index = 0;
100
19.8k
                g->gct_flag = 0;
101
19.8k
                g->gct_size = 0;
102
19.8k
                continue;
103
19.8k
            }
104
291k
            g->index++;
105
41.4M
        } else if (g->state == GIF_EXTENSION) {
106
118k
            if (g->found_start && g->found_end && g->found_sig) {
107
6.22k
                next = index;
108
6.22k
                g->found_start = pc->frame_start_found = 0;
109
6.22k
                g->found_end = 0;
110
6.22k
                g->index = 0;
111
6.22k
                g->gct_flag = 0;
112
6.22k
                g->gct_size = 0;
113
6.22k
                g->state = 0;
114
6.22k
                break;
115
6.22k
            }
116
112k
            if (g->index == 1) {
117
37.3k
                g->etype = buf[index];
118
37.3k
            }
119
112k
            if (g->index >= 2) {
120
37.3k
                g->block_size = buf[index];
121
37.3k
                g->index = 0;
122
37.3k
                g->state = GIF_EXTENSION_BLOCK;
123
37.3k
                continue;
124
37.3k
            }
125
74.6k
            g->index++;
126
41.3M
        } else if (g->state == GIF_IMAGE_BLOCK) {
127
9.85M
            if (!g->index)
128
228k
                g->block_size = buf[index];
129
9.85M
            if (g->index >= g->block_size) {
130
228k
                g->index = 0;
131
228k
                if (!g->block_size) {
132
49.0k
                    g->state = 0;
133
49.0k
                    g->found_end = 1;
134
49.0k
                }
135
228k
                continue;
136
228k
            }
137
9.62M
            g->index++;
138
31.4M
        } else if (g->state == GIF_EXTENSION_BLOCK) {
139
7.79M
            if (g->etype == GIF_GCE_EXT_LABEL) {
140
474k
                if (g->index == 0)
141
32.3k
                    g->delay = 0;
142
474k
                if (g->index >= 1 && g->index <= 2) {
143
42.8k
                    g->delay |= buf[index] << (8 * (g->index - 1));
144
42.8k
                }
145
474k
            }
146
7.79M
            if (g->index >= g->block_size) {
147
207k
                g->block_size = buf[index];
148
207k
                g->index = 0;
149
207k
                if (!g->block_size)
150
37.0k
                    g->state = 0;
151
207k
                continue;
152
207k
            }
153
7.58M
            g->index++;
154
23.6M
        } else if (g->state == GIF_IMAGE) {
155
1.34M
            if (g->index == 9) {
156
49.2k
                g->gct_flag = !!(buf[index] & 0x80);
157
49.2k
                g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1));
158
49.2k
            }
159
1.34M
            if (g->index >= 10 + g->gct_flag * g->gct_size) {
160
49.2k
                g->state = GIF_IMAGE_BLOCK;
161
49.2k
                g->index = 0;
162
49.2k
                g->gct_flag = 0;
163
49.2k
                g->gct_size = 0;
164
49.2k
                continue;
165
49.2k
            }
166
1.29M
            g->index++;
167
1.29M
        }
168
41.7M
    }
169
170
91.5k
    return next;
171
91.5k
}
172
173
static int gif_parse(AVCodecParserContext *s, AVCodecContext *avctx,
174
                     const uint8_t **poutbuf, int *poutbuf_size,
175
                     const uint8_t *buf, int buf_size)
176
91.5k
{
177
91.5k
    GIFParseContext *g = s->priv_data;
178
91.5k
    int next;
179
180
91.5k
    *poutbuf_size = 0;
181
91.5k
    *poutbuf = NULL;
182
183
91.5k
    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
184
0
        next = buf_size;
185
91.5k
    } else {
186
91.5k
        next = gif_find_frame_end(g, buf, buf_size, avctx);
187
91.5k
        if (ff_combine_frame(&g->pc, next, &buf, &buf_size) < 0) {
188
57.6k
            *poutbuf      = NULL;
189
57.6k
            *poutbuf_size = 0;
190
57.6k
            return buf_size;
191
57.6k
        }
192
91.5k
    }
193
194
33.8k
    s->duration  = g->delay ? g->delay : 10;
195
33.8k
    s->key_frame = g->keyframe;
196
33.8k
    s->pict_type = g->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
197
33.8k
    g->keyframe  = 0;
198
199
33.8k
    *poutbuf      = buf;
200
33.8k
    *poutbuf_size = buf_size;
201
33.8k
    return next;
202
91.5k
}
203
204
const FFCodecParser ff_gif_parser = {
205
    PARSER_CODEC_LIST(AV_CODEC_ID_GIF),
206
    .priv_data_size = sizeof(GIFParseContext),
207
    .parse          = gif_parse,
208
    .close          = ff_parse_close,
209
};