FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/gifdec.c
Date: 2023-12-04 05:51:44
Exec Total Coverage
Lines: 105 124 84.7%
Functions: 5 5 100.0%
Branches: 56 92 60.9%

Line Branch Exec Source
1 /*
2 * GIF demuxer
3 * Copyright (c) 2012 Vitaliy E Sugrobov
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 demuxer.
25 */
26
27 #include "avformat.h"
28 #include "libavutil/bprint.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/opt.h"
31 #include "avio_internal.h"
32 #include "internal.h"
33 #include "libavcodec/gif.h"
34
35 #define GIF_PACKET_SIZE 1024
36
37 typedef struct GIFDemuxContext {
38 const AVClass *class;
39 /**
40 * Time span in hundredths of second before
41 * the next frame should be drawn on screen.
42 */
43 int delay;
44 /**
45 * Minimum allowed delay between frames in hundredths of
46 * second. Values below this threshold considered to be
47 * invalid and set to value of default_delay.
48 */
49 int min_delay;
50 int max_delay;
51 int default_delay;
52
53 /**
54 * loop options
55 */
56 int total_iter;
57 int iter_count;
58 int ignore_loop;
59 } GIFDemuxContext;
60
61 /**
62 * Major web browsers display gifs at ~10-15fps when rate
63 * is not explicitly set or have too low values. We assume default rate to be 10.
64 * Default delay = 100hundredths of second / 10fps = 10hos per frame.
65 */
66 #define GIF_DEFAULT_DELAY 10
67 /**
68 * By default delay values less than this threshold considered to be invalid.
69 */
70 #define GIF_MIN_DELAY 2
71
72 6924 static int gif_probe(const AVProbeData *p)
73 {
74 /* check magick */
75
3/4
✓ Branch 0 taken 6924 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6909 times.
✓ Branch 3 taken 15 times.
6924 if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6))
76 6909 return 0;
77
78 /* width or height contains zero? */
79
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (!AV_RL16(&p->buf[6]) || !AV_RL16(&p->buf[8]))
80 return 0;
81
82 15 return AVPROBE_SCORE_MAX;
83 }
84
85 15 static int resync(AVIOContext *pb)
86 {
87 15 ffio_ensure_seekback(pb, 13);
88
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 15 times.
105 for (int i = 0; i < 6; i++) {
89 90 int b = avio_r8(pb);
90
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
90 if (b != gif87a_sig[i] && b != gif89a_sig[i])
91 i = -(b != 'G');
92
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
90 if (avio_feof(pb))
93 return AVERROR_EOF;
94 }
95 15 return 0;
96 }
97
98 2719 static int gif_skip_subblocks(AVIOContext *pb)
99 {
100 2719 int sb_size, ret = 0;
101
102
2/2
✓ Branch 1 taken 21683 times.
✓ Branch 2 taken 2719 times.
24402 while (0x00 != (sb_size = avio_r8(pb))) {
103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21683 times.
21683 if ((ret = avio_skip(pb, sb_size)) < 0)
104 return ret;
105 }
106
107 2719 return ret;
108 }
109
110 15 static int gif_read_header(AVFormatContext *s)
111 {
112 15 GIFDemuxContext *gdc = s->priv_data;
113 15 AVIOContext *pb = s->pb;
114 AVStream *st;
115 int type, width, height, ret, n, flags;
116 15 int64_t nb_frames = 0, duration = 0, pos;
117
118
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = resync(pb)) < 0)
119 return ret;
120
121 15 pos = avio_tell(pb);
122 15 gdc->delay = gdc->default_delay;
123 15 width = avio_rl16(pb);
124 15 height = avio_rl16(pb);
125 15 flags = avio_r8(pb);
126 15 avio_skip(pb, 1);
127 15 n = avio_r8(pb);
128
129
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (width == 0 || height == 0)
130 return AVERROR_INVALIDDATA;
131
132 15 st = avformat_new_stream(s, NULL);
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!st)
134 return AVERROR(ENOMEM);
135
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
137 goto skip;
138
139
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
15 if (flags & 0x80)
140 8 avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1)));
141
142
2/2
✓ Branch 1 taken 2721 times.
✓ Branch 2 taken 15 times.
2736 while ((type = avio_r8(pb)) != GIF_TRAILER) {
143
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2721 times.
2721 if (avio_feof(pb))
144 break;
145
2/2
✓ Branch 0 taken 1366 times.
✓ Branch 1 taken 1355 times.
2721 if (type == GIF_EXTENSION_INTRODUCER) {
146 1366 int subtype = avio_r8(pb);
147
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1364 times.
1366 if (subtype == GIF_COM_EXT_LABEL) {
148 AVBPrint bp;
149 int block_size;
150
151 2 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
152
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 while ((block_size = avio_r8(pb)) != 0) {
153 2 avio_read_to_bprint(pb, &bp, block_size);
154 }
155 2 av_dict_set(&s->metadata, "comment", bp.str, 0);
156 2 av_bprint_finalize(&bp, NULL);
157
2/2
✓ Branch 0 taken 1355 times.
✓ Branch 1 taken 9 times.
1364 } else if (subtype == GIF_GCE_EXT_LABEL) {
158 1355 int block_size = avio_r8(pb);
159
160
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 if (block_size == 4) {
161 int delay;
162
163 1355 avio_skip(pb, 1);
164 1355 delay = avio_rl16(pb);
165
2/2
✓ Branch 0 taken 1211 times.
✓ Branch 1 taken 144 times.
1355 delay = delay ? delay : gdc->default_delay;
166 1355 duration += delay;
167 1355 avio_skip(pb, 1);
168 } else {
169 avio_skip(pb, block_size);
170 }
171 1355 gif_skip_subblocks(pb);
172
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 } else if (subtype == GIF_APP_EXT_LABEL) {
173 uint8_t data[256];
174 int sb_size;
175
176 9 sb_size = avio_r8(pb);
177 9 ret = avio_read(pb, data, sb_size);
178
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 if (ret < 0 || !sb_size)
179 break;
180
181
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (sb_size == strlen(NETSCAPE_EXT_STR)) {
182 9 sb_size = avio_r8(pb);
183 9 ret = avio_read(pb, data, sb_size);
184
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 if (ret < 0 || !sb_size)
185 break;
186
187
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
9 if (sb_size == 3 && data[0] == 1) {
188 8 gdc->total_iter = AV_RL16(data+1);
189 8 av_log(s, AV_LOG_DEBUG, "Loop count is %d\n", gdc->total_iter);
190
191
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (gdc->total_iter == 0)
192 8 gdc->total_iter = -1;
193 }
194 }
195 9 gif_skip_subblocks(pb);
196 } else {
197 gif_skip_subblocks(pb);
198 }
199
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 } else if (type == GIF_IMAGE_SEPARATOR) {
200 1355 avio_skip(pb, 8);
201 1355 flags = avio_r8(pb);
202
2/2
✓ Branch 0 taken 1213 times.
✓ Branch 1 taken 142 times.
1355 if (flags & 0x80)
203 1213 avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1)));
204 1355 avio_skip(pb, 1);
205 1355 gif_skip_subblocks(pb);
206 1355 nb_frames++;
207 } else {
208 break;
209 }
210 }
211
212 15 skip:
213 /* jump to start because gif decoder needs header data too */
214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if (avio_seek(pb, pos - 6, SEEK_SET) != pos - 6)
215 return AVERROR(EIO);
216
217 /* GIF format operates with time in "hundredths of second",
218 * therefore timebase is 1/100 */
219 15 avpriv_set_pts_info(st, 64, 1, 100);
220 15 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
221 15 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
222 15 st->codecpar->codec_id = AV_CODEC_ID_GIF;
223 15 st->codecpar->width = width;
224 15 st->codecpar->height = height;
225
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (nb_frames > 1) {
226 15 av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
227 100, duration / nb_frames, INT_MAX);
228 } else if (duration) {
229 st->avg_frame_rate = (AVRational) { 100, duration };
230 }
231 15 st->start_time = 0;
232 15 st->duration = duration;
233 15 st->nb_frames = nb_frames;
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (n)
235 st->codecpar->sample_aspect_ratio = av_make_q(n + 15, 64);
236
237 15 return 0;
238 }
239
240 42872 static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
241 {
242 42872 GIFDemuxContext *gdc = s->priv_data;
243 42872 AVIOContext *pb = s->pb;
244 int ret;
245
246
1/2
✓ Branch 0 taken 42872 times.
✗ Branch 1 not taken.
42872 if ((pb->seekable & AVIO_SEEKABLE_NORMAL) &&
247
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42872 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
42872 !gdc->ignore_loop && avio_feof(pb) &&
248 (gdc->total_iter < 0 || (++gdc->iter_count < gdc->total_iter))) {
249 avio_seek(pb, 0, SEEK_SET);
250 }
251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42872 times.
42872 if ((ret = av_new_packet(pkt, GIF_PACKET_SIZE)) < 0)
252 return ret;
253
254 42872 pkt->pos = avio_tell(pb);
255 42872 pkt->stream_index = 0;
256 42872 ret = avio_read_partial(pb, pkt->data, GIF_PACKET_SIZE);
257
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 42799 times.
42872 if (ret < 0) {
258 73 av_packet_unref(pkt);
259 73 return ret;
260 }
261 42799 av_shrink_packet(pkt, ret);
262 42799 return ret;
263 }
264
265 static const AVOption options[] = {
266 { "min_delay" , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay) , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY} , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
267 { "max_gif_delay", "maximum valid delay between frames (in hundredths of seconds)", offsetof(GIFDemuxContext, max_delay) , AV_OPT_TYPE_INT, {.i64 = 65535} , 0, 65535 , AV_OPT_FLAG_DECODING_PARAM },
268 { "default_delay", "default delay between frames (in hundredths of second)" , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
269 { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_BOOL,{.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM },
270 { NULL },
271 };
272
273 static const AVClass demuxer_class = {
274 .class_name = "GIF demuxer",
275 .item_name = av_default_item_name,
276 .option = options,
277 .version = LIBAVUTIL_VERSION_INT,
278 .category = AV_CLASS_CATEGORY_DEMUXER,
279 };
280
281 const AVInputFormat ff_gif_demuxer = {
282 .name = "gif",
283 .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"),
284 .priv_data_size = sizeof(GIFDemuxContext),
285 .read_probe = gif_probe,
286 .read_header = gif_read_header,
287 .read_packet = gif_read_packet,
288 .flags = AVFMT_GENERIC_INDEX,
289 .extensions = "gif",
290 .priv_class = &demuxer_class,
291 };
292