diff options
author | Paul B Mahol <onemda@gmail.com> | 2018-12-13 18:37:27 +0100 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2018-12-13 18:58:48 +0100 |
commit | 0aa5a7b2e98ee3c6453a9c038b6f612125538d52 (patch) | |
tree | 2ffbdef0e161c0cf31498a9ba110301ddf8fbf4a | |
parent | f2664a306fb59961d38eff647317f0e1b5295aaf (diff) | |
download | ffmpeg-0aa5a7b2e98ee3c6453a9c038b6f612125538d52.tar.gz |
avformat/gifdec: export duration, nb_frames and comment
-rw-r--r-- | libavcodec/gif.h | 1 | ||||
-rw-r--r-- | libavformat/gifdec.c | 85 |
2 files changed, 72 insertions, 14 deletions
diff --git a/libavcodec/gif.h b/libavcodec/gif.h index 9f35778857..7fb61495bc 100644 --- a/libavcodec/gif.h +++ b/libavcodec/gif.h @@ -43,6 +43,7 @@ static const uint8_t gif89a_sig[6] = "GIF89a"; #define GIF_EXTENSION_INTRODUCER 0x21 #define GIF_IMAGE_SEPARATOR 0x2c #define GIF_GCE_EXT_LABEL 0xf9 +#define GIF_COM_EXT_LABEL 0xfe #define GIF_APP_EXT_LABEL 0xff #define NETSCAPE_EXT_STR "NETSCAPE2.0" diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 1f3ac8d8d9..7dc67ba875 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" @@ -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, n; + int type, width, height, ret, n, flags; + int64_t nb_frames = 0, duration = 0; if ((ret = resync(pb)) < 0) return ret; @@ -107,7 +121,8 @@ static int gif_read_header(AVFormatContext *s) gdc->delay = gdc->default_delay; width = avio_rl16(pb); height = avio_rl16(pb); - avio_skip(pb, 2); + flags = avio_r8(pb); + avio_skip(pb, 1); n = avio_r8(pb); if (width == 0 || height == 0) @@ -117,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, -1); + 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); @@ -124,6 +190,9 @@ 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; @@ -136,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; |