jpegdec: optimise buffer scanning
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Thu, 29 Apr 2010 14:26:49 +0000 (16:26 +0200)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Fri, 30 Apr 2010 15:49:24 +0000 (17:49 +0200)
Specifically, when needing more data, do not rescan from start next time
around, but resume from last position.

See also #583047.

ext/jpeg/gstjpegdec.c
ext/jpeg/gstjpegdec.h

index 606f9a2..d9e1226 100644 (file)
@@ -414,6 +414,7 @@ gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
 {
   guint8 *start, *data, *end;
   guint size;
+  gboolean resync;
 
   size = GST_BUFFER_SIZE (dec->tempbuf);
   start = GST_BUFFER_DATA (dec->tempbuf);
@@ -424,12 +425,14 @@ gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
 
   GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
 
-  /* skip start marker */
-  data += 2;
+  GST_DEBUG ("Parse state: offset=%d, resync=%d, entropy len=%d",
+      dec->parse_offset, dec->parse_resync, dec->parse_entropy_len);
+
+  /* resume from state offset (also skips start marker) */
+  data += (dec->parse_offset ? dec->parse_offset : 2);
 
   while (1) {
     guint frame_len;
-    gboolean resync;
 
     /* do we need to resync? */
     resync = (*data != 0xff);
@@ -441,28 +444,33 @@ gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
         ++data;
       if (G_UNLIKELY (*data != 0xff)) {
         GST_DEBUG ("at end of input and no next marker found, need more data");
-        return 0;
+        goto need_more_data;
       }
     }
+    /* may have marker, but could have been resyncng */
+    resync = resync || dec->parse_resync;
     /* Skip over extra 0xff */
     while (*data == 0xff && data < end)
       ++data;
     /* enough bytes left for marker? (we need 0xNN after the 0xff) */
     if (data >= end) {
       GST_DEBUG ("at end of input and no EOI marker found, need more data");
-      return 0;
+      goto need_more_data1;
     }
 
     if (*data == 0xd9) {
       GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: EOI marker",
           (gint64) (data - start));
+      /* clear parse state */
+      dec->parse_resync = FALSE;
+      dec->parse_offset = 0;
       return (data - start + 1);
     }
 
     if (*data >= 0xd0 && *data <= 0xd7)
       frame_len = 0;
     else if (data >= end - 2)
-      return 0;
+      goto need_more_data1;
     else
       frame_len = GST_READ_UINT16_BE (data + 1);
     GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: tag %02x, frame_len=%u",
@@ -478,22 +486,26 @@ gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
       /* theoretically we could have lost sync and not really need more
        * data, but that's just tough luck and a broken image then */
       GST_DEBUG ("at end of input and no EOI marker found, need more data");
-      return 0;
+      goto need_more_data1;
     }
 
     if (gst_jpeg_dec_parse_tag_has_entropy_segment (*data)) {
       guint8 *d2 = data + 1 + frame_len;
-      guint eseglen = 0;
+      guint eseglen = dec->parse_entropy_len;
 
       GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: finding entropy segment length",
           (gint64) (data - start - 1));
       while (1) {
-        if (d2 + eseglen >= end - 1)
-          return 0;             /* need more data */
+        if (d2 + eseglen >= end - 1) {
+          /* need more data */
+          dec->parse_entropy_len = eseglen;
+          goto need_more_data1;
+        }
         if (d2[eseglen] == 0xff && d2[eseglen + 1] != 0x00)
           break;
         ++eseglen;
       }
+      dec->parse_entropy_len = 0;
       frame_len += eseglen;
       GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
           frame_len);
@@ -511,6 +523,21 @@ gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
 
     data += 1 + frame_len;
   }
+
+  /* EXITS */
+need_more_data:
+  {
+    dec->parse_offset = data - start;
+    dec->parse_resync = resync;
+    return 0;
+  }
+need_more_data1:
+  {
+    /* step back one to point at marker */
+    dec->parse_offset = (data - start) - 1;
+    dec->parse_resync = resync;
+    return 0;
+  }
 }
 
 /* shamelessly ripped from jpegutils.c in mjpegtools */
@@ -1605,6 +1632,9 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
       dec->packetized = FALSE;
       dec->next_ts = 0;
       dec->discont = TRUE;
+      dec->parse_offset = 0;
+      dec->parse_resync = FALSE;
+      dec->parse_entropy_len = FALSE;
       gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
       gst_jpeg_dec_reset_qos (dec);
     default:
index c1e4632..f76089b 100644 (file)
@@ -103,6 +103,11 @@ struct _GstJpegDec {
   gint     stride;
   gint     inc;
 
+  /* parse state */
+  gint     parse_offset;
+  gint     parse_entropy_len;
+  gint     parse_resync;
+
   /* properties */
   gint     idct_method;