FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/gifdec.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 106 126 84.1%
Functions: 5 5 100.0%
Branches: 57 94 60.6%

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 7186 static int gif_probe(const AVProbeData *p)
74 {
75 /* check magick */
76
3/4
✓ Branch 0 taken 7186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7171 times.
✓ Branch 3 taken 15 times.
7186 if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6))
77 7171 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 int ret = ffio_ensure_seekback(pb, 13);
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (ret < 0)
90 return ret;
91
92
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 15 times.
105 for (int i = 0; i < 6; i++) {
93 90 int b = avio_r8(pb);
94
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])
95 i = -(b != 'G');
96
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
90 if (avio_feof(pb))
97 return AVERROR_EOF;
98 }
99 15 return 0;
100 }
101
102 2719 static int gif_skip_subblocks(AVIOContext *pb)
103 {
104 2719 int sb_size, ret = 0;
105
106
2/2
✓ Branch 1 taken 21683 times.
✓ Branch 2 taken 2719 times.
24402 while (0x00 != (sb_size = avio_r8(pb))) {
107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21683 times.
21683 if ((ret = avio_skip(pb, sb_size)) < 0)
108 return ret;
109 }
110
111 2719 return ret;
112 }
113
114 15 static int gif_read_header(AVFormatContext *s)
115 {
116 15 GIFDemuxContext *gdc = s->priv_data;
117 15 AVIOContext *pb = s->pb;
118 AVStream *st;
119 int type, width, height, ret, n, flags;
120 15 int64_t nb_frames = 0, duration = 0, pos;
121
122
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = resync(pb)) < 0)
123 return ret;
124
125 15 pos = avio_tell(pb);
126 15 gdc->delay = gdc->default_delay;
127 15 width = avio_rl16(pb);
128 15 height = avio_rl16(pb);
129 15 flags = avio_r8(pb);
130 15 avio_skip(pb, 1);
131 15 n = avio_r8(pb);
132
133
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)
134 return AVERROR_INVALIDDATA;
135
136 15 st = avformat_new_stream(s, NULL);
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!st)
138 return AVERROR(ENOMEM);
139
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
141 goto skip;
142
143
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
15 if (flags & 0x80)
144 8 avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1)));
145
146
2/2
✓ Branch 1 taken 2721 times.
✓ Branch 2 taken 15 times.
2736 while ((type = avio_r8(pb)) != GIF_TRAILER) {
147
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2721 times.
2721 if (avio_feof(pb))
148 break;
149
2/2
✓ Branch 0 taken 1366 times.
✓ Branch 1 taken 1355 times.
2721 if (type == GIF_EXTENSION_INTRODUCER) {
150 1366 int subtype = avio_r8(pb);
151
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1364 times.
1366 if (subtype == GIF_COM_EXT_LABEL) {
152 AVBPrint bp;
153 int block_size;
154
155 2 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
156
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 while ((block_size = avio_r8(pb)) != 0) {
157 2 avio_read_to_bprint(pb, &bp, block_size);
158 }
159 2 av_dict_set(&s->metadata, "comment", bp.str, 0);
160 2 av_bprint_finalize(&bp, NULL);
161
2/2
✓ Branch 0 taken 1355 times.
✓ Branch 1 taken 9 times.
1364 } else if (subtype == GIF_GCE_EXT_LABEL) {
162 1355 int block_size = avio_r8(pb);
163
164
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 if (block_size == 4) {
165 int delay;
166
167 1355 avio_skip(pb, 1);
168 1355 delay = avio_rl16(pb);
169
2/2
✓ Branch 0 taken 1211 times.
✓ Branch 1 taken 144 times.
1355 delay = delay ? delay : gdc->default_delay;
170 1355 duration += delay;
171 1355 avio_skip(pb, 1);
172 } else {
173 avio_skip(pb, block_size);
174 }
175 1355 gif_skip_subblocks(pb);
176
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 } else if (subtype == GIF_APP_EXT_LABEL) {
177 uint8_t data[256];
178 int sb_size;
179
180 9 sb_size = avio_r8(pb);
181 9 ret = avio_read(pb, data, sb_size);
182
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)
183 break;
184
185
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (sb_size == strlen(NETSCAPE_EXT_STR)) {
186 9 sb_size = avio_r8(pb);
187 9 ret = avio_read(pb, data, sb_size);
188
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)
189 break;
190
191
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) {
192 8 gdc->total_iter = AV_RL16(data+1);
193 8 av_log(s, AV_LOG_DEBUG, "Loop count is %d\n", gdc->total_iter);
194
195
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (gdc->total_iter == 0)
196 8 gdc->total_iter = -1;
197 }
198 }
199 9 gif_skip_subblocks(pb);
200 } else {
201 gif_skip_subblocks(pb);
202 }
203
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 } else if (type == GIF_IMAGE_SEPARATOR) {
204 1355 avio_skip(pb, 8);
205 1355 flags = avio_r8(pb);
206
2/2
✓ Branch 0 taken 1213 times.
✓ Branch 1 taken 142 times.
1355 if (flags & 0x80)
207 1213 avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1)));
208 1355 avio_skip(pb, 1);
209 1355 gif_skip_subblocks(pb);
210 1355 nb_frames++;
211 } else {
212 break;
213 }
214 }
215
216 15 skip:
217 /* jump to start because gif decoder needs header data too */
218
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if (avio_seek(pb, pos - 6, SEEK_SET) != pos - 6)
219 return AVERROR(EIO);
220
221 /* GIF format operates with time in "hundredths of second",
222 * therefore timebase is 1/100 */
223 15 avpriv_set_pts_info(st, 64, 1, 100);
224 15 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
225 15 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
226 15 st->codecpar->codec_id = AV_CODEC_ID_GIF;
227 15 st->codecpar->width = width;
228 15 st->codecpar->height = height;
229
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (nb_frames > 1) {
230 15 av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
231 100, duration / nb_frames, INT_MAX);
232 } else if (duration) {
233 st->avg_frame_rate = (AVRational) { 100, duration };
234 }
235 15 st->start_time = 0;
236 15 st->duration = duration;
237 15 st->nb_frames = nb_frames;
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (n)
239 st->codecpar->sample_aspect_ratio = av_make_q(n + 15, 64);
240
241 15 return 0;
242 }
243
244 42872 static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
245 {
246 42872 GIFDemuxContext *gdc = s->priv_data;
247 42872 AVIOContext *pb = s->pb;
248 int ret;
249
250
1/2
✓ Branch 0 taken 42872 times.
✗ Branch 1 not taken.
42872 if ((pb->seekable & AVIO_SEEKABLE_NORMAL) &&
251
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) &&
252 (gdc->total_iter < 0 || (++gdc->iter_count < gdc->total_iter))) {
253 avio_seek(pb, 0, SEEK_SET);
254 }
255
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42872 times.
42872 if ((ret = av_new_packet(pkt, GIF_PACKET_SIZE)) < 0)
256 return ret;
257
258 42872 pkt->pos = avio_tell(pb);
259 42872 pkt->stream_index = 0;
260 42872 ret = avio_read_partial(pb, pkt->data, GIF_PACKET_SIZE);
261
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 42799 times.
42872 if (ret < 0) {
262 73 av_packet_unref(pkt);
263 73 return ret;
264 }
265 42799 av_shrink_packet(pkt, ret);
266 42799 return ret;
267 }
268
269 static const AVOption options[] = {
270 { "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 },
271 { "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 },
272 { "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 },
273 { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_BOOL,{.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM },
274 { NULL },
275 };
276
277 static const AVClass demuxer_class = {
278 .class_name = "GIF demuxer",
279 .item_name = av_default_item_name,
280 .option = options,
281 .version = LIBAVUTIL_VERSION_INT,
282 .category = AV_CLASS_CATEGORY_DEMUXER,
283 };
284
285 const FFInputFormat ff_gif_demuxer = {
286 .p.name = "gif",
287 .p.long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"),
288 .p.flags = AVFMT_GENERIC_INDEX,
289 .p.extensions = "gif",
290 .p.priv_class = &demuxer_class,
291 .priv_data_size = sizeof(GIFDemuxContext),
292 .read_probe = gif_probe,
293 .read_header = gif_read_header,
294 .read_packet = gif_read_packet,
295 };
296