[FFmpeg-devel] [PATCH] lavf/gifdec: add loop support.

Clément Bœsch ubitux at gmail.com
Thu Apr 18 22:24:58 CEST 2013


---
Still missing FATE update (need to add -ignore_loop to them), but I'm
waiting for review on the patch to rework the tests.
---
 libavcodec/gif.h     |  2 ++
 libavformat/gifdec.c | 24 +++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/libavcodec/gif.h b/libavcodec/gif.h
index b557534..b4cf665 100644
--- a/libavcodec/gif.h
+++ b/libavcodec/gif.h
@@ -43,5 +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_APP_EXT_LABEL           0xff
+#define NETSCAPE_EXT_STR            "NETSCAPE2.0"
 
 #endif /* AVCODEC_GIFDEFS_H */
diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c
index 1122849..0028734 100644
--- a/libavformat/gifdec.c
+++ b/libavformat/gifdec.c
@@ -44,6 +44,13 @@ typedef struct GIFDemuxContext {
      */
     int min_delay;
     int default_delay;
+
+    /**
+     * loop options
+     */
+    int total_iter;
+    int iter_count;
+    int ignore_loop;
 } GIFDemuxContext;
 
 /**
@@ -156,6 +163,17 @@ static int gif_read_ext(AVFormatContext *s)
         /* skip the rest of the Graphic Control Extension block */
         if ((ret = avio_skip(pb, sb_size - 3)) < 0 )
             return ret;
+    } else if (ext_label == GIF_APP_EXT_LABEL) {
+        uint8_t netscape_ext[sizeof(NETSCAPE_EXT_STR)-1 + 2];
+
+        if ((sb_size = avio_r8(pb)) != strlen(NETSCAPE_EXT_STR))
+            return 0;
+        ret = avio_read(pb, netscape_ext, sizeof(netscape_ext));
+        if (ret < sizeof(netscape_ext))
+            return ret;
+        gdc->total_iter = avio_rl16(pb);
+        if (gdc->total_iter == 0)
+            gdc->total_iter = -1;
     }
 
     if ((ret = gif_skip_subblocks(pb)) < 0)
@@ -268,9 +286,12 @@ resync:
         }
     }
 
-    if (ret >= 0 && !frame_parsed) {
+    if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) {
         /* This might happen when there is no image block
          * between extension blocks and GIF_TRAILER or EOF */
+        if (!gdc->ignore_loop && (block_label == GIF_TRAILER || url_feof(pb))
+            && (gdc->total_iter < 0 || ++gdc->iter_count < gdc->total_iter))
+            return avio_seek(pb, 0, SEEK_SET);
         return AVERROR_EOF;
     } else
         return ret;
@@ -279,6 +300,7 @@ resync:
 static const AVOption options[] = {
     { "min_delay"    , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay)    , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY}    , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
     { "default_delay", "default delay between frames (in hundredths of second)"      , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
+    { "ignore_loop"  , "ignore loop setting (netscape extension)"                    , offsetof(GIFDemuxContext, ignore_loop)  , AV_OPT_TYPE_INT, {.i64 = 0}                , 0,        1, AV_OPT_FLAG_DECODING_PARAM },
     { NULL },
 };
 
-- 
1.8.2.1



More information about the ffmpeg-devel mailing list