3 * Copyright (c) 2012 Vitaliy E Sugrobov
5 * This file is part of FFmpeg.
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.
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.
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
29 #include "libavutil/bprint.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/opt.h"
32 #include "avio_internal.h"
34 #include "libavcodec/gif.h"
36 #define GIF_PACKET_SIZE 1024
38 typedef struct GIFDemuxContext
{
41 * Time span in hundredths of second before
42 * the next frame should be drawn on screen.
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.
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.
67 #define GIF_DEFAULT_DELAY 10
69 * By default delay values less than this threshold considered to be invalid.
71 #define GIF_MIN_DELAY 2
73 static int gif_probe(const AVProbeData
*p
)
76 if (memcmp(p
->buf
, gif87a_sig
, 6) && memcmp(p
->buf
, gif89a_sig
, 6))
79 /* width or height contains zero? */
80 if (!AV_RL16(&p
->buf
[6]) || !AV_RL16(&p
->buf
[8]))
83 return AVPROBE_SCORE_MAX
;
86 static int resync(AVIOContext
*pb
)
88 int ret
= ffio_ensure_seekback(pb
, 13);
92 for (int i
= 0; i
< 6; i
++) {
94 if (b
!= gif87a_sig
[i
] && b
!= gif89a_sig
[i
])
102 static int gif_skip_subblocks(AVIOContext
*pb
)
104 int sb_size
, ret
= 0;
106 while (0x00 != (sb_size
= avio_r8(pb
))) {
107 if ((ret
= avio_skip(pb
, sb_size
)) < 0)
114 static int gif_read_header(AVFormatContext
*s
)
116 GIFDemuxContext
*gdc
= s
->priv_data
;
117 AVIOContext
*pb
= s
->pb
;
119 int type
, width
, height
, ret
, n
, flags
;
120 int64_t nb_frames
= 0, duration
= 0, pos
;
123 if ((ret
= resync(pb
)) < 0)
127 gdc
->delay
= gdc
->default_delay
;
128 width
= avio_rl16(pb
);
129 height
= avio_rl16(pb
);
134 if (width
== 0 || height
== 0)
135 return AVERROR_INVALIDDATA
;
137 st
= avformat_new_stream(s
, NULL
);
139 return AVERROR(ENOMEM
);
141 if (!(pb
->seekable
& AVIO_SEEKABLE_NORMAL
))
145 avio_skip(pb
, 3 * (1 << ((flags
& 0x07) + 1)));
147 while ((type
= avio_r8(pb
)) != GIF_TRAILER
) {
150 if (type
== GIF_EXTENSION_INTRODUCER
) {
151 int subtype
= avio_r8(pb
);
152 if (subtype
== GIF_COM_EXT_LABEL
) {
156 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_UNLIMITED
);
157 while ((block_size
= avio_r8(pb
)) != 0) {
158 avio_read_to_bprint(pb
, &bp
, block_size
);
160 av_dict_set(&s
->metadata
, "comment", bp
.str
, 0);
161 av_bprint_finalize(&bp
, NULL
);
162 } else if (subtype
== GIF_GCE_EXT_LABEL
) {
163 int block_size
= avio_r8(pb
);
165 if (block_size
== 4) {
169 delay
= avio_rl16(pb
);
170 delay
= delay
? delay
: gdc
->default_delay
;
174 avio_skip(pb
, block_size
);
176 gif_skip_subblocks(pb
);
177 } else if (subtype
== GIF_APP_EXT_LABEL
) {
181 sb_size
= avio_r8(pb
);
182 ret
= avio_read(pb
, data
, sb_size
);
183 if (ret
< 0 || !sb_size
)
186 if (sb_size
== strlen(NETSCAPE_EXT_STR
)) {
187 sb_size
= avio_r8(pb
);
188 ret
= avio_read(pb
, data
, sb_size
);
189 if (ret
< 0 || !sb_size
)
192 if (sb_size
== 3 && data
[0] == 1) {
193 gdc
->total_iter
= AV_RL16(data
+1);
194 av_log(s
, AV_LOG_DEBUG
, "Loop count is %d\n", gdc
->total_iter
);
196 if (gdc
->total_iter
== 0)
197 gdc
->total_iter
= -1;
200 gif_skip_subblocks(pb
);
202 gif_skip_subblocks(pb
);
204 } else if (type
== GIF_IMAGE_SEPARATOR
) {
208 avio_skip(pb
, 3 * (1 << ((flags
& 0x07) + 1)));
210 gif_skip_subblocks(pb
);
218 /* jump to start because gif decoder needs header data too */
219 ret64
= avio_seek(pb
, pos
- 6, SEEK_SET
);
223 /* GIF format operates with time in "hundredths of second",
224 * therefore timebase is 1/100 */
225 avpriv_set_pts_info(st
, 64, 1, 100);
226 ffstream(st
)->need_parsing
= AVSTREAM_PARSE_FULL_RAW
;
227 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
228 st
->codecpar
->codec_id
= AV_CODEC_ID_GIF
;
229 st
->codecpar
->width
= width
;
230 st
->codecpar
->height
= height
;
232 av_reduce(&st
->avg_frame_rate
.num
, &st
->avg_frame_rate
.den
,
233 100, duration
/ nb_frames
, INT_MAX
);
234 } else if (duration
) {
235 st
->avg_frame_rate
= (AVRational
) { 100, duration
};
238 st
->duration
= duration
;
239 st
->nb_frames
= nb_frames
;
241 st
->codecpar
->sample_aspect_ratio
= av_make_q(n
+ 15, 64);
246 static int gif_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
248 GIFDemuxContext
*gdc
= s
->priv_data
;
249 AVIOContext
*pb
= s
->pb
;
252 if ((pb
->seekable
& AVIO_SEEKABLE_NORMAL
) &&
253 !gdc
->ignore_loop
&& avio_feof(pb
) &&
254 (gdc
->total_iter
< 0 || (++gdc
->iter_count
< gdc
->total_iter
))) {
255 avio_seek(pb
, 0, SEEK_SET
);
257 if ((ret
= av_new_packet(pkt
, GIF_PACKET_SIZE
)) < 0)
260 pkt
->pos
= avio_tell(pb
);
261 pkt
->stream_index
= 0;
262 ret
= avio_read_partial(pb
, pkt
->data
, GIF_PACKET_SIZE
);
264 av_packet_unref(pkt
);
267 av_shrink_packet(pkt
, ret
);
271 static const AVOption options
[] = {
272 { "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
},
273 { "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
},
274 { "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
},
275 { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext
, ignore_loop
) , AV_OPT_TYPE_BOOL
,{.i64
= 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM
},
279 static const AVClass demuxer_class
= {
280 .class_name
= "GIF demuxer",
281 .item_name
= av_default_item_name
,
283 .version
= LIBAVUTIL_VERSION_INT
,
284 .category
= AV_CLASS_CATEGORY_DEMUXER
,
287 const FFInputFormat ff_gif_demuxer
= {
289 .p
.long_name
= NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"),
290 .p
.flags
= AVFMT_GENERIC_INDEX
,
291 .p
.extensions
= "gif",
292 .p
.priv_class
= &demuxer_class
,
293 .priv_data_size
= sizeof(GIFDemuxContext
),
294 .read_probe
= gif_probe
,
295 .read_header
= gif_read_header
,
296 .read_packet
= gif_read_packet
,