FFmpeg coverage


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