docs: update plugin docs
[platform/upstream/gst-plugins-good.git] / ext / jpeg / gstjpegdec.c
index faa3b7e..d88b258 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /**
@@ -28,9 +28,8 @@
  * <refsect2>
  * <title>Example launch line</title>
  * |[
- * gst-launch -v v4l2src ! jpegdec ! ffmpegcolorspace ! xvimagesink
- * ]| The above pipeline reads a motion JPEG stream from a v4l2 camera
- * and renders it to the screen.
+ * gst-launch-1.0 -v filesrc location=mjpeg.avi ! avidemux !  queue ! jpegdec ! videoconvert ! videoscale ! autovideosink
+ * ]| The above pipeline decode the mjpeg stream and renders it to the screen.
  * </refsect2>
  */
 
@@ -76,15 +75,13 @@ GST_STATIC_PAD_TEMPLATE ("src",
 /* *INDENT-ON* */
 
 /* FIXME: sof-marker is for IJG libjpeg 8, should be different for 6.2 */
+/* FIXME: add back "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }"
+ * once we have a parser and/or demuxer set caps properly */
 static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("image/jpeg, "
-        "width = (int) [ " G_STRINGIFY (MIN_WIDTH) ", " G_STRINGIFY (MAX_WIDTH)
-        " ], " "height = (int) [ " G_STRINGIFY (MIN_HEIGHT) ", "
-        G_STRINGIFY (MAX_HEIGHT) " ], framerate = (fraction) [ 0/1, MAX ], "
-        "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }")
+    GST_STATIC_CAPS ("image/jpeg")
     );
 
 GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
@@ -100,13 +97,15 @@ static gboolean gst_jpeg_dec_set_format (GstVideoDecoder * dec,
     GstVideoCodecState * state);
 static gboolean gst_jpeg_dec_start (GstVideoDecoder * bdec);
 static gboolean gst_jpeg_dec_stop (GstVideoDecoder * bdec);
-static gboolean gst_jpeg_dec_reset (GstVideoDecoder * bdec, gboolean hard);
+static gboolean gst_jpeg_dec_flush (GstVideoDecoder * bdec);
 static GstFlowReturn gst_jpeg_dec_parse (GstVideoDecoder * bdec,
     GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
 static GstFlowReturn gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec,
     GstVideoCodecFrame * frame);
 static gboolean gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec,
     GstQuery * query);
+static gboolean gst_jpeg_dec_sink_event (GstVideoDecoder * bdec,
+    GstEvent * event);
 
 #define gst_jpeg_dec_parent_class parent_class
 G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_VIDEO_DECODER);
@@ -117,6 +116,8 @@ gst_jpeg_dec_finalize (GObject * object)
   GstJpegDec *dec = GST_JPEG_DEC (object);
 
   jpeg_destroy_decompress (&dec->cinfo);
+  if (dec->input_state)
+    gst_video_codec_state_unref (dec->input_state);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -145,129 +146,49 @@ gst_jpeg_dec_class_init (GstJpegDecClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   /**
-   * GstJpegDec:max-errors
+   * GstJpegDec:max-errors:
    *
    * Error out after receiving N consecutive decoding errors
    * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
    *
-   * Since: 0.10.27
-   **/
+   * Deprecated: 1.3.1: Property wasn't used internally
+   */
+#ifndef GST_REMOVE_DEPRECATED
   g_object_class_install_property (gobject_class, PROP_MAX_ERRORS,
       g_param_spec_int ("max-errors", "Maximum Consecutive Decoding Errors",
-          "Error out after receiving N consecutive decoding errors "
-          "(-1 = never fail, 0 = automatic, 1 = fail on first error)",
+          "(Deprecated) Error out after receiving N consecutive decoding errors"
+          " (-1 = never fail, 0 = automatic, 1 = fail on first error)",
           -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
+#endif
 
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template));
-  gst_element_class_set_details_simple (element_class, "JPEG image decoder",
-      "Codec/Decoder/Image",
-      "Decode images from JPEG format", "Wim Taymans <wim@fluendo.com>");
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpeg_dec_src_pad_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_jpeg_dec_sink_pad_template);
+  gst_element_class_set_static_metadata (element_class, "JPEG image decoder",
+      "Codec/Decoder/Image", "Decode images from JPEG format",
+      "Wim Taymans <wim@fluendo.com>");
 
   vdec_class->start = gst_jpeg_dec_start;
   vdec_class->stop = gst_jpeg_dec_stop;
-  vdec_class->reset = gst_jpeg_dec_reset;
+  vdec_class->flush = gst_jpeg_dec_flush;
   vdec_class->parse = gst_jpeg_dec_parse;
   vdec_class->set_format = gst_jpeg_dec_set_format;
   vdec_class->handle_frame = gst_jpeg_dec_handle_frame;
   vdec_class->decide_allocation = gst_jpeg_dec_decide_allocation;
+  vdec_class->sink_event = gst_jpeg_dec_sink_event;
 
   GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
 }
 
-static void
-gst_jpeg_dec_clear_error (GstJpegDec * dec)
-{
-  g_free (dec->error_msg);
-  dec->error_msg = NULL;
-  dec->error_line = 0;
-  dec->error_func = NULL;
-}
-
-static void
-gst_jpeg_dec_set_error_va (GstJpegDec * dec, const gchar * func, gint line,
-    const gchar * debug_msg_format, va_list args)
-{
-#ifndef GST_DISABLE_GST_DEBUG
-  gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING, __FILE__, func,
-      line, (GObject *) dec, debug_msg_format, args);
-#endif
-
-  g_free (dec->error_msg);
-  if (debug_msg_format)
-    dec->error_msg = g_strdup_vprintf (debug_msg_format, args);
-  else
-    dec->error_msg = NULL;
-
-  dec->error_line = line;
-  dec->error_func = func;
-}
-
-static void
-gst_jpeg_dec_set_error (GstJpegDec * dec, const gchar * func, gint line,
-    const gchar * debug_msg_format, ...)
-{
-  va_list va;
-
-  va_start (va, debug_msg_format);
-  gst_jpeg_dec_set_error_va (dec, func, line, debug_msg_format, va);
-  va_end (va);
-}
-
-static GstFlowReturn
-gst_jpeg_dec_post_error_or_warning (GstJpegDec * dec)
-{
-  GstFlowReturn ret;
-  int max_errors;
-
-  ++dec->error_count;
-  max_errors = g_atomic_int_get (&dec->max_errors);
-
-  if (max_errors < 0) {
-    ret = GST_FLOW_OK;
-  } else if (max_errors == 0) {
-    /* FIXME: do something more clever in "automatic mode" */
-    if (gst_video_decoder_get_packetized (GST_VIDEO_DECODER (dec))) {
-      ret = (dec->error_count < 3) ? GST_FLOW_OK : GST_FLOW_ERROR;
-    } else {
-      ret = GST_FLOW_ERROR;
-    }
-  } else {
-    ret = (dec->error_count < max_errors) ? GST_FLOW_OK : GST_FLOW_ERROR;
-  }
-
-  GST_INFO_OBJECT (dec, "decoding error %d/%d (%s)", dec->error_count,
-      max_errors, (ret == GST_FLOW_OK) ? "ignoring error" : "erroring out");
-
-  gst_element_message_full (GST_ELEMENT (dec),
-      (ret == GST_FLOW_OK) ? GST_MESSAGE_WARNING : GST_MESSAGE_ERROR,
-      GST_STREAM_ERROR, GST_STREAM_ERROR_DECODE,
-      g_strdup (_("Failed to decode JPEG image")), dec->error_msg,
-      __FILE__, dec->error_func, dec->error_line);
-
-  dec->error_msg = NULL;
-  gst_jpeg_dec_clear_error (dec);
-  return ret;
-}
-
 static boolean
 gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
 {
-  GstJpegDec *dec;
-
-  dec = CINFO_GET_JPEGDEC (cinfo);
-  g_return_val_if_fail (dec != NULL, FALSE);
-  g_return_val_if_fail (dec->current_frame != NULL, FALSE);
-  g_return_val_if_fail (dec->current_frame_map.data != NULL, FALSE);
-
-  cinfo->src->next_input_byte = dec->current_frame_map.data;
-  cinfo->src->bytes_in_buffer = dec->current_frame_map.size;
-
-  return TRUE;
+  /* We pass in full frame initially, if this get called, the frame is most likely
+   * corrupted */
+  return FALSE;
 }
 
 static void
@@ -288,25 +209,6 @@ gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
     cinfo->src->next_input_byte += (size_t) num_bytes;
     cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
   }
-#if 0
-  else if (num_bytes > 0) {
-    gint available;
-
-    num_bytes -= cinfo->src->bytes_in_buffer;
-    cinfo->src->next_input_byte += (size_t) cinfo->src->bytes_in_buffer;
-    cinfo->src->bytes_in_buffer = 0;
-
-    available = gst_adapter_available (dec->adapter);
-    if (available < num_bytes || available < dec->rem_img_len) {
-      GST_WARNING_OBJECT (dec, "Less bytes to skip than available in the "
-          "adapter or the remaining image length %ld < %d or %u",
-          num_bytes, available, dec->rem_img_len);
-    }
-    num_bytes = MIN (MIN (num_bytes, available), dec->rem_img_len);
-    gst_adapter_flush (dec->adapter, num_bytes);
-    dec->rem_img_len -= num_bytes;
-  }
-#endif
 }
 
 static boolean
@@ -350,21 +252,6 @@ gst_jpeg_dec_init (GstJpegDec * dec)
 {
   GST_DEBUG ("initializing");
 
-#if 0
-  /* create the sink and src pads */
-  dec->sinkpad =
-      gst_pad_new_from_static_template (&gst_jpeg_dec_sink_pad_template,
-      "sink");
-  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-  gst_pad_set_setcaps_function (dec->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_jpeg_dec_setcaps));
-
-  dec->srcpad =
-      gst_pad_new_from_static_template (&gst_jpeg_dec_src_pad_template, "src");
-  gst_pad_use_fixed_caps (dec->srcpad);
-  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-#endif
-
   /* setup jpeglib */
   memset (&dec->cinfo, 0, sizeof (dec->cinfo));
   memset (&dec->jerr, 0, sizeof (dec->jerr));
@@ -386,36 +273,11 @@ gst_jpeg_dec_init (GstJpegDec * dec)
   /* init properties */
   dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
   dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
-}
 
-#if 0
-static gboolean
-gst_jpeg_dec_ensure_header (GstJpegDec * dec)
-{
-  gint av;
-  gint offset;
-
-  av = gst_adapter_available (dec->adapter);
-  /* we expect at least 4 bytes, first of which start marker */
-  offset = gst_adapter_masked_scan_uint32 (dec->adapter, 0xffffff00, 0xffd8ff00,
-      0, av);
-  if (G_UNLIKELY (offset < 0)) {
-    GST_DEBUG_OBJECT (dec, "No JPEG header in current buffer");
-    /* not found */
-    if (av > 4)
-      gst_adapter_flush (dec->adapter, av - 4);
-    return FALSE;
-  }
-
-  if (offset > 0) {
-    GST_LOG_OBJECT (dec, "Skipping %u bytes.", offset);
-    gst_adapter_flush (dec->adapter, offset);
-  }
-  GST_DEBUG_OBJECT (dec, "Found JPEG header");
-
-  return TRUE;
+  gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
+      (dec), TRUE);
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (dec));
 }
-#endif
 
 static inline gboolean
 gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
@@ -435,6 +297,8 @@ gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
   gint offset = 0, noffset;
   GstJpegDec *dec = (GstJpegDec *) bdec;
 
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+
   /* FIXME : The overhead of using scan_uint32 is massive */
 
   size = gst_adapter_available (adapter);
@@ -512,11 +376,12 @@ gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
       goto have_full_frame;
     }
     if (value == 0xd8) {
-      /* Skip this frame if we found another SOI marker */
-      GST_DEBUG ("0x%08x: SOI marker before EOI, skipping", offset + 2);
+      GST_DEBUG ("0x%08x: SOI marker before EOI marker", offset + 2);
+
+      /* clear parse state */
+      dec->saw_header = FALSE;
       dec->parse_resync = FALSE;
-      /* FIXME : Need to skip data */
-      toadd -= offset + 2;
+      toadd = offset;
       goto have_full_frame;
     }
 
@@ -596,10 +461,12 @@ need_more_data:
 have_full_frame:
   if (toadd)
     gst_video_decoder_add_to_frame (bdec, toadd);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
   return gst_video_decoder_have_frame (bdec);
 
 drop_frame:
-  return GST_VIDEO_DECODER_FLOW_DROPPED;
+  gst_adapter_flush (adapter, size);
+  return GST_FLOW_OK;
 }
 
 
@@ -729,15 +596,6 @@ static gboolean
 gst_jpeg_dec_set_format (GstVideoDecoder * dec, GstVideoCodecState * state)
 {
   GstJpegDec *jpeg = GST_JPEG_DEC (dec);
-  GstVideoInfo *info = &state->info;
-
-  /* FIXME : previously jpegdec would handled input as packetized
-   * if the framerate was present. Here we consider it packetized if
-   * the fps is != 1/1 */
-  if (GST_VIDEO_INFO_FPS_N (info) != 1 && GST_VIDEO_INFO_FPS_D (info) != 1)
-    gst_video_decoder_set_packetized (dec, TRUE);
-  else
-    gst_video_decoder_set_packetized (dec, FALSE);
 
   if (jpeg->input_state)
     gst_video_codec_state_unref (jpeg->input_state);
@@ -805,7 +663,8 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
 }
 
 static void
-gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame)
+gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
 {
   guchar *rows[16];
   guchar **scanarray[1] = { rows };
@@ -818,14 +677,18 @@ gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame)
   GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
 
   width = GST_VIDEO_FRAME_WIDTH (frame);
-  height = GST_VIDEO_FRAME_HEIGHT (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
 
   if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
     return;
 
   base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  if (field == 2) {
+    base[0] += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  }
+
   pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
-  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
 
   memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
 
@@ -850,7 +713,8 @@ gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame)
 }
 
 static void
-gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame)
+gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
 {
   guchar *r_rows[16], *g_rows[16], *b_rows[16];
   guchar **scanarray[3] = { r_rows, g_rows, b_rows };
@@ -863,16 +727,19 @@ gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame)
   GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
 
   width = GST_VIDEO_FRAME_WIDTH (frame);
-  height = GST_VIDEO_FRAME_HEIGHT (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
 
   if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
     return;
 
-  for (i = 0; i < 3; i++)
+  for (i = 0; i < 3; i++) {
     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
+    if (field == 2)
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+  }
 
   pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
-  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+  rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
 
   memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
   memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
@@ -904,14 +771,14 @@ gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame)
 
 static void
 gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
-    gint r_h, gint comp)
+    gint r_h, gint comp, guint field, guint num_fields)
 {
   guchar *y_rows[16], *u_rows[16], *v_rows[16];
   guchar **scanarray[3] = { y_rows, u_rows, v_rows };
   gint i, j, k;
   gint lines;
   guchar *base[3], *last[3];
-  gint stride[3];
+  gint rowsize[3], stride[3];
   gint width, height;
 
   GST_DEBUG_OBJECT (dec,
@@ -925,11 +792,16 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
 
   for (i = 0; i < 3; i++) {
     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
-    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
+    rowsize[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
     /* make sure we don't make jpeglib write beyond our buffer,
      * which might happen if (height % (r_v*DCTSIZE)) != 0 */
     last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
         (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
+
+    if (field == 2) {
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    }
   }
 
   memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
@@ -950,22 +822,22 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
     if (G_LIKELY (lines > 0)) {
       for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
         if (G_LIKELY (base[0] <= last[0])) {
-          memcpy (base[0], y_rows[j], stride[0]);
+          memcpy (base[0], y_rows[j], rowsize[0]);
           base[0] += stride[0];
         }
         if (r_v == 2) {
           if (G_LIKELY (base[0] <= last[0])) {
-            memcpy (base[0], y_rows[j + 1], stride[0]);
+            memcpy (base[0], y_rows[j + 1], rowsize[0]);
             base[0] += stride[0];
           }
         }
         if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
           if (r_h == 2) {
-            memcpy (base[1], u_rows[k], stride[1]);
-            memcpy (base[2], v_rows[k], stride[2]);
+            memcpy (base[1], u_rows[k], rowsize[1]);
+            memcpy (base[2], v_rows[k], rowsize[2]);
           } else if (r_h == 1) {
-            hresamplecpy1 (base[1], u_rows[k], stride[1]);
-            hresamplecpy1 (base[2], v_rows[k], stride[2]);
+            hresamplecpy1 (base[1], u_rows[k], rowsize[1]);
+            hresamplecpy1 (base[2], v_rows[k], rowsize[2]);
           } else {
             /* FIXME: implement (at least we avoid crashing by doing nothing) */
           }
@@ -983,7 +855,8 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
 }
 
 static GstFlowReturn
-gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame)
+gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
+    guint field, guint num_fields)
 {
   guchar **line[3];             /* the jpeg line buffer         */
   guchar *y[4 * DCTSIZE] = { NULL, };   /* alloc enough for the lines   */
@@ -1010,11 +883,15 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame)
 
   for (i = 0; i < 3; i++) {
     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
-    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
     /* make sure we don't make jpeglib write beyond our buffer,
      * which might happen if (height % (r_v*DCTSIZE)) != 0 */
     last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
         (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
+
+    if (field == 2) {
+      base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
+    }
   }
 
   /* let jpeglib decode directly into our final buffer */
@@ -1053,15 +930,20 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame)
 
 format_not_supported:
   {
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "Unsupported subsampling schema: v_samp factors: %u %u %u",
-        v_samp[0], v_samp[1], v_samp[2]);
-    return GST_FLOW_ERROR;
+    gboolean ret = GST_FLOW_OK;
+
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Unsupported subsampling schema: v_samp factors: %u %u %u", v_samp[0],
+            v_samp[1], v_samp[2]), ret);
+
+    return ret;
   }
 }
 
 static void
-gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
+gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc,
+    gboolean interlaced)
 {
   GstVideoCodecState *outstate;
   GstVideoInfo *info;
@@ -1097,62 +979,37 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
       gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
       width, height, dec->input_state);
 
+  switch (clrspc) {
+    case JCS_RGB:
+    case JCS_GRAYSCALE:
+      break;
+    default:
+      outstate->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
+      outstate->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
+      outstate->info.colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
+      outstate->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
+      break;
+  }
+
+  if (interlaced) {
+    outstate->info.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+    GST_VIDEO_INFO_FIELD_ORDER (&outstate->info) =
+        GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
+  }
+
   gst_video_codec_state_unref (outstate);
 
+  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
+
   GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
   GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
 }
 
 static GstFlowReturn
-gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
+gst_jpeg_dec_prepare_decode (GstJpegDec * dec)
 {
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstJpegDec *dec = (GstJpegDec *) bdec;
-  GstVideoFrame vframe;
-  gint width, height;
-  gint r_h, r_v;
-  guint code, hdr_ok;
-  gboolean need_unmap = TRUE;
-  GstVideoCodecState *state = NULL;
-
-#if 0
-again:
-  if (!gst_jpeg_dec_ensure_header (dec))
-    goto need_more_data;
-
-  /* If we know that each input buffer contains data
-   * for a whole jpeg image (e.g. MJPEG streams), just 
-   * do some sanity checking instead of parsing all of 
-   * the jpeg data */
-  if (dec->packetized) {
-    img_len = gst_adapter_available (dec->adapter);
-  } else {
-    /* Parse jpeg image to handle jpeg input that
-     * is not aligned to buffer boundaries */
-    img_len = gst_jpeg_dec_parse_image_data (dec);
-
-    if (img_len == 0) {
-      goto need_more_data;
-    } else if (img_len < 0) {
-      gst_adapter_flush (dec->adapter, -img_len);
-      goto again;
-    }
-  }
-#endif
-
-  dec->current_frame = frame;
-  gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
-  gst_jpeg_dec_fill_input_buffer (&dec->cinfo);
-
-  if (setjmp (dec->jerr.setjmp_buffer)) {
-    code = dec->jerr.pub.msg_code;
-
-    if (code == JERR_INPUT_EOF) {
-      GST_DEBUG ("jpeg input EOF error, we probably need more data");
-      goto need_more_data;
-    }
-    goto decode_error;
-  }
+  G_GNUC_UNUSED GstFlowReturn ret;
+  guint r_h, r_v, hdr_ok;
 
   /* read header */
   hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
@@ -1230,32 +1087,66 @@ again:
       break;
   }
 
-  width = dec->cinfo.output_width;
-  height = dec->cinfo.output_height;
-
-  if (G_UNLIKELY (width < MIN_WIDTH || width > MAX_WIDTH ||
-          height < MIN_HEIGHT || height > MAX_HEIGHT))
+  if (G_UNLIKELY (dec->cinfo.output_width < MIN_WIDTH ||
+          dec->cinfo.output_width > MAX_WIDTH ||
+          dec->cinfo.output_height < MIN_HEIGHT ||
+          dec->cinfo.output_height > MAX_HEIGHT))
     goto wrong_size;
 
-  gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space);
-
-  state = gst_video_decoder_get_output_state (bdec);
-  ret = gst_video_decoder_alloc_output_frame (bdec, frame);
-  if (G_UNLIKELY (ret != GST_FLOW_OK))
-    goto alloc_failed;
+  return GST_FLOW_OK;
 
-  if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
-          GST_MAP_READWRITE))
-    goto alloc_failed;
+/* ERRORS */
+wrong_size:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture is too small or too big (%ux%u)", dec->cinfo.output_width,
+            dec->cinfo.output_height), ret);
+    return GST_FLOW_ERROR;
+  }
+components_not_supported:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("number of components not supported: %d (max 3)",
+            dec->cinfo.num_components), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+unsupported_colorspace:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture has unknown or unsupported colourspace"), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+invalid_yuvrgbgrayscale:
+  {
+    ret = GST_FLOW_ERROR;
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")),
+        ("Picture is corrupt or unhandled YUV/RGB/grayscale layout"), ret);
+    jpeg_abort_decompress (&dec->cinfo);
+    return GST_FLOW_ERROR;
+  }
+}
 
-  GST_LOG_OBJECT (dec, "width %d, height %d", width, height);
+static GstFlowReturn
+gst_jpeg_dec_decode (GstJpegDec * dec, GstVideoFrame * vframe, guint width,
+    guint height, guint field, guint num_fields)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
 
   if (dec->cinfo.jpeg_color_space == JCS_RGB) {
-    gst_jpeg_dec_decode_rgb (dec, &vframe);
+    gst_jpeg_dec_decode_rgb (dec, vframe, field, num_fields);
   } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
-    gst_jpeg_dec_decode_grayscale (dec, &vframe);
+    gst_jpeg_dec_decode_grayscale (dec, vframe, field, num_fields);
   } else {
-    GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
+    GST_LOG_OBJECT (dec, "decompressing (required scanline buffer height = %u)",
         dec->cinfo.rec_outbuf_height);
 
     /* For some widths jpeglib requires more horizontal padding than I420 
@@ -1269,40 +1160,216 @@ again:
             || dec->cinfo.comp_info[2].h_samp_factor != 1)) {
       GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
           "indirect decoding using extra buffer copy");
-      gst_jpeg_dec_decode_indirect (dec, &vframe, r_v, r_h,
-          dec->cinfo.num_components);
+      gst_jpeg_dec_decode_indirect (dec, vframe,
+          dec->cinfo.comp_info[0].v_samp_factor,
+          dec->cinfo.comp_info[0].h_samp_factor, dec->cinfo.num_components,
+          field, num_fields);
     } else {
-      ret = gst_jpeg_dec_decode_direct (dec, &vframe);
+      ret = gst_jpeg_dec_decode_direct (dec, vframe, field, num_fields);
+    }
+  }
+
+  GST_LOG_OBJECT (dec, "decompressing finished: %s", gst_flow_get_name (ret));
+
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    jpeg_abort_decompress (&dec->cinfo);
+  } else {
+    jpeg_finish_decompress (&dec->cinfo);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+  GstVideoFrame vframe;
+  gint num_fields;              /* number of fields (1 or 2) */
+  gint output_height;           /* height of output image (one or two fields) */
+  gint height;                  /* height of current frame (whole image or a field) */
+  gint width;
+  guint code;
+  gboolean need_unmap = TRUE;
+  GstVideoCodecState *state = NULL;
+  gboolean release_frame = TRUE;
+  gboolean has_eoi;
+  guint8 *data;
+  gsize nbytes;
+
+  gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
+
+  data = dec->current_frame_map.data;
+  nbytes = dec->current_frame_map.size;
+  has_eoi = ((data[nbytes - 2] != 0xff) || (data[nbytes - 1] != 0xd9));
+
+  /* some cameras fail to send an end-of-image marker (EOI),
+   * add it if that is the case. */
+  if (!has_eoi) {
+    GstMapInfo map;
+    GstBuffer *eoibuf = gst_buffer_new_and_alloc (2);
+
+    /* unmap, will add EOI and remap at the end */
+    gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
+
+    gst_buffer_map (eoibuf, &map, GST_MAP_WRITE);
+    map.data[0] = 0xff;
+    map.data[1] = 0xd9;
+    gst_buffer_unmap (eoibuf, &map);
+
+    /* append to input buffer, and remap */
+    frame->input_buffer = gst_buffer_append (frame->input_buffer, eoibuf);
+
+    gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
+    GST_DEBUG ("fixup EOI marker added");
+  }
+
+  dec->current_frame = frame;
+  dec->cinfo.src->next_input_byte = dec->current_frame_map.data;
+  dec->cinfo.src->bytes_in_buffer = dec->current_frame_map.size;
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
 
-      if (G_UNLIKELY (ret != GST_FLOW_OK))
-        goto decode_direct_failed;
+    if (code == JERR_INPUT_EOF) {
+      GST_DEBUG ("jpeg input EOF error, we probably need more data");
+      goto need_more_data;
     }
+    goto decode_error;
   }
 
-  gst_video_frame_unmap (&vframe);
+  /* read header and check values */
+  ret = gst_jpeg_dec_prepare_decode (dec);
+  if (G_UNLIKELY (ret == GST_FLOW_ERROR))
+    goto done;
+
+  width = dec->cinfo.output_width;
+  height = dec->cinfo.output_height;
+
+  /* is it interlaced MJPEG? (we really don't want to scan the jpeg data
+   * to see if there are two SOF markers in the packet to detect this) */
+  if (gst_video_decoder_get_packetized (bdec) &&
+      dec->input_state->info.height > height &&
+      dec->input_state->info.height <= (height * 2)
+      && dec->input_state->info.width == width) {
+    GST_LOG_OBJECT (dec,
+        "looks like an interlaced image: "
+        "input width/height of %dx%d with JPEG frame width/height of %dx%d",
+        dec->input_state->info.width, dec->input_state->info.height, width,
+        height);
+    output_height = dec->input_state->info.height;
+    height = dec->input_state->info.height / 2;
+    num_fields = 2;
+    GST_LOG_OBJECT (dec, "field height=%d", height);
+  } else {
+    output_height = height;
+    num_fields = 1;
+  }
+
+  gst_jpeg_dec_negotiate (dec, width, output_height,
+      dec->cinfo.jpeg_color_space, num_fields == 2);
+
+  state = gst_video_decoder_get_output_state (bdec);
+  ret = gst_video_decoder_allocate_output_frame (bdec, frame);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    goto alloc_failed;
+
+  if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
+          GST_MAP_READWRITE))
+    goto alloc_failed;
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
+    gst_video_frame_unmap (&vframe);
+    goto decode_error;
+  }
 
-  GST_LOG_OBJECT (dec, "decompressing finished");
-  jpeg_finish_decompress (&dec->cinfo);
+  GST_LOG_OBJECT (dec, "width %d, height %d, fields %d", width, output_height,
+      num_fields);
 
-  /* reset error count on successful decode */
-  dec->error_count = 0;
+  ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 1, num_fields);
+  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+    gst_video_frame_unmap (&vframe);
+    goto decode_failed;
+  }
+
+  if (setjmp (dec->jerr.setjmp_buffer)) {
+    code = dec->jerr.pub.msg_code;
+    gst_video_frame_unmap (&vframe);
+    goto decode_error;
+  }
+
+  /* decode second field if there is one */
+  if (num_fields == 2) {
+    GstVideoFormat field2_format;
+
+    /* skip any chunk or padding bytes before the next SOI marker; both fields
+     * are in one single buffer here, so direct access should be fine here */
+    while (dec->jsrc.pub.bytes_in_buffer > 2 &&
+        GST_READ_UINT16_BE (dec->jsrc.pub.next_input_byte) != 0xffd8) {
+      --dec->jsrc.pub.bytes_in_buffer;
+      ++dec->jsrc.pub.next_input_byte;
+    }
+
+    if (gst_jpeg_dec_prepare_decode (dec) != GST_FLOW_OK) {
+      GST_WARNING_OBJECT (dec, "problem reading jpeg header of 2nd field");
+      /* FIXME: post a warning message here? */
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+
+    /* check if format has changed for the second field */
+    switch (dec->cinfo.jpeg_color_space) {
+      case JCS_RGB:
+        field2_format = GST_VIDEO_FORMAT_RGB;
+        break;
+      case JCS_GRAYSCALE:
+        field2_format = GST_VIDEO_FORMAT_GRAY8;
+        break;
+      default:
+        field2_format = GST_VIDEO_FORMAT_I420;
+        break;
+    }
+
+    GST_LOG_OBJECT (dec,
+        "got for second field of interlaced image: "
+        "input width/height of %dx%d with JPEG frame width/height of %dx%d",
+        dec->input_state->info.width, dec->input_state->info.height,
+        dec->cinfo.output_width, dec->cinfo.output_height);
+
+    if (dec->cinfo.output_width != GST_VIDEO_INFO_WIDTH (&state->info) ||
+        GST_VIDEO_INFO_HEIGHT (&state->info) <= dec->cinfo.output_height ||
+        GST_VIDEO_INFO_HEIGHT (&state->info) > (dec->cinfo.output_height * 2) ||
+        field2_format != GST_VIDEO_INFO_FORMAT (&state->info)) {
+      GST_WARNING_OBJECT (dec, "second field has different format than first");
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+
+    ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 2, 2);
+    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+      gst_video_frame_unmap (&vframe);
+      goto decode_failed;
+    }
+  }
+  gst_video_frame_unmap (&vframe);
 
   gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
   ret = gst_video_decoder_finish_frame (bdec, frame);
+  release_frame = FALSE;
   need_unmap = FALSE;
 
 done:
 
 exit:
 
-  if (G_UNLIKELY (ret == GST_FLOW_ERROR)) {
-    jpeg_abort_decompress (&dec->cinfo);
-    ret = gst_jpeg_dec_post_error_or_warning (dec);
-  }
-
   if (need_unmap)
     gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
 
+  if (release_frame)
+    gst_video_decoder_release_frame (bdec, frame);
+
   if (state)
     gst_video_codec_state_unref (state);
 
@@ -1316,33 +1383,27 @@ need_more_data:
     goto exit;
   }
   /* ERRORS */
-wrong_size:
-  {
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "Picture is too small or too big (%ux%u)", width, height);
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
 decode_error:
   {
     gchar err_msg[JMSG_LENGTH_MAX];
 
     dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
 
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "Decode error #%u: %s", code, err_msg);
+    GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+        (_("Failed to decode JPEG image")), ("Decode error #%u: %s", code,
+            err_msg), ret);
 
     gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
     gst_video_decoder_drop_frame (bdec, frame);
+    release_frame = FALSE;
     need_unmap = FALSE;
+    jpeg_abort_decompress (&dec->cinfo);
 
-    ret = GST_FLOW_ERROR;
     goto done;
   }
-decode_direct_failed:
+decode_failed:
   {
     /* already posted an error message */
-    jpeg_abort_decompress (&dec->cinfo);
     goto done;
   }
 alloc_failed:
@@ -1356,50 +1417,32 @@ alloc_failed:
     jpeg_abort_decompress (&dec->cinfo);
     if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING &&
         ret != GST_FLOW_NOT_LINKED) {
-      gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-          "Buffer allocation failed, reason: %s", reason);
+      GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
+          (_("Failed to decode JPEG image")),
+          ("Buffer allocation failed, reason: %s", reason), ret);
+      jpeg_abort_decompress (&dec->cinfo);
     }
     goto exit;
   }
-components_not_supported:
-  {
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "number of components not supported: %d (max 3)",
-        dec->cinfo.num_components);
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
-unsupported_colorspace:
-  {
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "Picture has unknown or unsupported colourspace");
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
-invalid_yuvrgbgrayscale:
-  {
-    gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
-        "Picture is corrupt or unhandled YUV/RGB/grayscale layout");
-    ret = GST_FLOW_ERROR;
-    goto done;
-  }
 }
 
 static gboolean
 gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
 {
-  GstBufferPool *pool;
+  GstBufferPool *pool = NULL;
   GstStructure *config;
 
   if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
     return FALSE;
 
-  g_assert (gst_query_get_n_allocation_pools (query) > 0);
-  gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
-  g_assert (pool != NULL);
+  if (gst_query_get_n_allocation_pools (query) > 0)
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
+
+  if (pool == NULL)
+    return FALSE;
 
   config = gst_buffer_pool_get_config (pool);
-  if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) {
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
     gst_buffer_pool_config_add_option (config,
         GST_BUFFER_POOL_OPTION_VIDEO_META);
   }
@@ -1410,12 +1453,44 @@ gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
 }
 
 static gboolean
-gst_jpeg_dec_reset (GstVideoDecoder * bdec, gboolean hard)
+gst_jpeg_dec_sink_event (GstVideoDecoder * bdec, GstEvent * event)
+{
+  const GstSegment *segment;
+
+  if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
+    goto done;
+
+  gst_event_parse_segment (event, &segment);
+
+  if (segment->format == GST_FORMAT_TIME)
+    gst_video_decoder_set_packetized (bdec, TRUE);
+  else
+    gst_video_decoder_set_packetized (bdec, FALSE);
+
+done:
+  return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (bdec, event);
+}
+
+static gboolean
+gst_jpeg_dec_start (GstVideoDecoder * bdec)
+{
+  GstJpegDec *dec = (GstJpegDec *) bdec;
+
+  dec->saw_header = FALSE;
+  dec->parse_entropy_len = 0;
+  dec->parse_resync = FALSE;
+
+  gst_video_decoder_set_packetized (bdec, FALSE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_jpeg_dec_flush (GstVideoDecoder * bdec)
 {
   GstJpegDec *dec = (GstJpegDec *) bdec;
 
   jpeg_abort_decompress (&dec->cinfo);
-  dec->parse_offset = 0;
   dec->parse_entropy_len = 0;
   dec->parse_resync = FALSE;
   dec->saw_header = FALSE;
@@ -1435,10 +1510,11 @@ gst_jpeg_dec_set_property (GObject * object, guint prop_id,
     case PROP_IDCT_METHOD:
       dec->idct_method = g_value_get_enum (value);
       break;
+#ifndef GST_REMOVE_DEPRECATED
     case PROP_MAX_ERRORS:
       g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
       break;
-
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1457,10 +1533,11 @@ gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_IDCT_METHOD:
       g_value_set_enum (value, dec->idct_method);
       break;
+#ifndef GST_REMOVE_DEPRECATED
     case PROP_MAX_ERRORS:
       g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
       break;
-
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1468,18 +1545,6 @@ gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
 }
 
 static gboolean
-gst_jpeg_dec_start (GstVideoDecoder * bdec)
-{
-  GstJpegDec *dec = (GstJpegDec *) bdec;
-
-  dec->error_count = 0;
-  dec->parse_entropy_len = 0;
-  dec->parse_resync = FALSE;
-
-  return TRUE;
-}
-
-static gboolean
 gst_jpeg_dec_stop (GstVideoDecoder * bdec)
 {
   GstJpegDec *dec = (GstJpegDec *) bdec;