gifdec: resync support
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 21 Jan 2013 17:52:01 +0000 (18:52 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 25 Jan 2013 16:25:16 +0000 (17:25 +0100)
This allows decoding gifs that have junk at the begin
and also allows byte wise seeking

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavformat/gifdec.c

index 4f4ce2c..d43a537 100644 (file)
@@ -70,6 +70,19 @@ static int gif_probe(AVProbeData *p)
     return AVPROBE_SCORE_MAX;
 }
 
+static int resync(AVIOContext *pb)
+{
+    int i;
+    for (i = 0; i < 6; i++) {
+        int b = avio_r8(pb);
+        if (b != gif87a_sig[i] && b != gif89a_sig[i])
+            i = -(b != 'G');
+        if (url_feof(pb))
+            return AVERROR_EOF;
+    }
+    return 0;
+}
+
 static int gif_read_header(AVFormatContext *s)
 {
     GIFDemuxContext *gdc = s->priv_data;
@@ -77,8 +90,7 @@ static int gif_read_header(AVFormatContext *s)
     AVStream        *st;
     int width, height, ret;
 
-    /* skip 6-byte magick */
-    if ((ret = avio_skip(pb, 6)) < 0)
+    if ((ret = resync(pb)) < 0)
         return ret;
 
     gdc->delay  = gdc->default_delay;
@@ -171,6 +183,7 @@ static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     if (keyframe) {
+parse_keyframe:
         /* skip 2 bytes of width and 2 of height */
         if ((ret = avio_skip(pb, 4)) < 0)
             return ret;
@@ -196,7 +209,7 @@ static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
     while (GIF_TRAILER != (block_label = avio_r8(pb)) && !url_feof(pb)) {
         if (block_label == GIF_EXTENSION_INTRODUCER) {
             if ((ret = gif_read_ext (s)) < 0 )
-                return ret;
+                goto resync;
         } else if (block_label == GIF_IMAGE_SEPARATOR) {
             /* skip to last byte of Image Descriptor header */
             if ((ret = avio_skip(pb, 8)) < 0)
@@ -215,11 +228,11 @@ static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
             /* read LZW Minimum Code Size */
             if (avio_r8(pb) < 1) {
                 av_log(s, AV_LOG_ERROR, "lzw minimum code size must be >= 1\n");
-                return AVERROR_INVALIDDATA;
+                goto resync;
             }
 
             if ((ret = gif_skip_subblocks(pb)) < 0)
-                return ret;
+                goto resync;
 
             frame_end = avio_tell(pb);
 
@@ -244,7 +257,14 @@ static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
             break;
         } else {
             av_log(s, AV_LOG_ERROR, "invalid block label\n");
-            return AVERROR_INVALIDDATA;
+resync:
+            if (!keyframe)
+                avio_seek(pb, frame_start, SEEK_SET);
+            if ((ret = resync(pb)) < 0)
+                return ret;
+            frame_start = avio_tell(pb) - 6;
+            keyframe = 1;
+            goto parse_keyframe;
         }
     }