avformat/gifdec: export duration, nb_frames and comment
authorPaul B Mahol <onemda@gmail.com>
Thu, 13 Dec 2018 17:37:27 +0000 (18:37 +0100)
committerPaul B Mahol <onemda@gmail.com>
Thu, 13 Dec 2018 17:58:48 +0000 (18:58 +0100)
libavcodec/gif.h
libavformat/gifdec.c

index 9f35778..7fb6149 100644 (file)
@@ -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"
 
index 1f3ac8d..7dc67ba 100644 (file)
@@ -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;