aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul B Mahol2018-12-13 18:37:27 +0100
committerPaul B Mahol2018-12-13 18:58:48 +0100
commit0aa5a7b2e98ee3c6453a9c038b6f612125538d52 (patch)
tree2ffbdef0e161c0cf31498a9ba110301ddf8fbf4a
parentf2664a306fb59961d38eff647317f0e1b5295aaf (diff)
avformat/gifdec: export duration, nb_frames and comment
-rw-r--r--libavcodec/gif.h1
-rw-r--r--libavformat/gifdec.c85
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;