X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fgifdec.c;h=7dc67ba87537b6523e8f85a3d794472295df114a;hb=92219ef4ac01b00e630b39cb19e8fbd17fdb63d0;hp=8993ca615c054b1e1973055b5743f9bde5b2af11;hpb=26148e923613e718787c6fc4bf3f64e8909f597c;p=ffmpeg diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 8993ca615c0..7dc67ba8753 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; + 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, -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); @@ -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;