X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fgifdec.c;h=c20bde178191067f574144377a07af751a429bac;hb=bc70684e74a185d7b80c8b80bdedda659cb581b8;hp=8993ca615c054b1e1973055b5743f9bde5b2af11;hpb=b14761d1f8372dfe558193b8b754b9f1a858077d;p=ffmpeg diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 8993ca615c0..c20bde17819 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -25,6 +25,7 @@ */ #include "avformat.h" +#include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "internal.h" @@ -68,7 +69,7 @@ typedef struct GIFDemuxContext { */ #define GIF_MIN_DELAY 2 -static int gif_probe(AVProbeData *p) +static int gif_probe(const AVProbeData *p) { /* check magick */ if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6)) @@ -94,12 +95,25 @@ static int resync(AVIOContext *pb) return 0; } +static int gif_skip_subblocks(AVIOContext *pb) +{ + int sb_size, ret = 0; + + while (0x00 != (sb_size = avio_r8(pb))) { + if ((ret = avio_skip(pb, sb_size)) < 0) + return ret; + } + + return ret; +} + static int gif_read_header(AVFormatContext *s) { GIFDemuxContext *gdc = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; - int width, height, ret; + int type, width, height, ret, n, flags; + int64_t nb_frames = 0, duration = 0; if ((ret = resync(pb)) < 0) return ret; @@ -107,6 +121,9 @@ static int gif_read_header(AVFormatContext *s) gdc->delay = gdc->default_delay; width = avio_rl16(pb); height = avio_rl16(pb); + flags = avio_r8(pb); + avio_skip(pb, 1); + n = avio_r8(pb); if (width == 0 || height == 0) return AVERROR_INVALIDDATA; @@ -115,6 +132,57 @@ static int gif_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); + if (flags & 0x80) + avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); + + while ((type = avio_r8(pb)) != GIF_TRAILER) { + if (avio_feof(pb)) + break; + if (type == GIF_EXTENSION_INTRODUCER) { + int subtype = avio_r8(pb); + if (subtype == GIF_COM_EXT_LABEL) { + AVBPrint bp; + int block_size; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + while ((block_size = avio_r8(pb)) != 0) { + avio_read_to_bprint(pb, &bp, block_size); + } + av_dict_set(&s->metadata, "comment", bp.str, 0); + av_bprint_finalize(&bp, NULL); + } else if (subtype == GIF_GCE_EXT_LABEL) { + int block_size = avio_r8(pb); + + if (block_size == 4) { + int delay; + + avio_skip(pb, 1); + delay = avio_rl16(pb); + if (delay < gdc->min_delay) + delay = gdc->default_delay; + delay = FFMIN(delay, gdc->max_delay); + duration += delay; + avio_skip(pb, 1); + } else { + avio_skip(pb, block_size); + } + gif_skip_subblocks(pb); + } else { + gif_skip_subblocks(pb); + } + } else if (type == GIF_IMAGE_SEPARATOR) { + avio_skip(pb, 8); + flags = avio_r8(pb); + if (flags & 0x80) + avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); + avio_skip(pb, 1); + gif_skip_subblocks(pb); + nb_frames++; + } else { + break; + } + } + /* GIF format operates with time in "hundredths of second", * therefore timebase is 1/100 */ avpriv_set_pts_info(st, 64, 1, 100); @@ -122,6 +190,13 @@ static int gif_read_header(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_GIF; st->codecpar->width = width; st->codecpar->height = height; + st->start_time = 0; + st->duration = duration; + st->nb_frames = nb_frames; + if (n) { + st->codecpar->sample_aspect_ratio.num = n + 15; + st->codecpar->sample_aspect_ratio.den = 64; + } /* jump to start because gif decoder needs header data too */ if (avio_seek(pb, 0, SEEK_SET) != 0) @@ -130,18 +205,6 @@ static int gif_read_header(AVFormatContext *s) return 0; } -static int gif_skip_subblocks(AVIOContext *pb) -{ - int sb_size, ret = 0; - - while (0x00 != (sb_size = avio_r8(pb))) { - if ((ret = avio_skip(pb, sb_size)) < 0) - return ret; - } - - return ret; -} - static int gif_read_ext(AVFormatContext *s) { GIFDemuxContext *gdc = s->priv_data; @@ -334,7 +397,7 @@ static const AVClass demuxer_class = { .category = AV_CLASS_CATEGORY_DEMUXER, }; -AVInputFormat ff_gif_demuxer = { +const AVInputFormat ff_gif_demuxer = { .name = "gif", .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"), .priv_data_size = sizeof(GIFDemuxContext),