Index: gst/cdxaparse/Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/cdxaparse/Makefile.am,v
retrieving revision 1.5
diff -u -r1.5 Makefile.am
--- gst/cdxaparse/Makefile.am	11 Sep 2003 19:57:55 -0000	1.5
+++ gst/cdxaparse/Makefile.am	19 Nov 2004 12:52:40 -0000
@@ -1,11 +1,12 @@
+plugin_LTLIBRARIES = libgstcdxaparse.la
 
-plugin_LTLIBRARIES = \
-		libgstcdxaparse.la
-
-libgstcdxaparse_la_SOURCES = gstcdxaparse.c 
+libgstcdxaparse_la_SOURCES = \
+	gstcdxaparse.c \
+	gstcdxastrip.c
 
 noinst_HEADERS = \
-		gstcdxaparse.h
+	gstcdxaparse.h \
+	gstcdxastrip.h
 
 libgstcdxaparse_la_CFLAGS = $(GST_CFLAGS)
 libgstcdxaparse_la_LIBADD =
Index: gst/cdxaparse/gstcdxaparse.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/cdxaparse/gstcdxaparse.c,v
retrieving revision 1.20
diff -u -r1.20 gstcdxaparse.c
--- gst/cdxaparse/gstcdxaparse.c	21 May 2004 14:09:51 -0000	1.20
+++ gst/cdxaparse/gstcdxaparse.c	19 Nov 2004 12:52:40 -0000
@@ -18,13 +18,13 @@
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 #include <string.h>
 
 #include "gstcdxaparse.h"
+#include "gstcdxastrip.h"
 #include "gst/riff/riff-ids.h"
 #include "gst/riff/riff-media.h"
 
@@ -32,9 +32,8 @@
 static void gst_cdxaparse_class_init (GstCDXAParseClass * klass);
 static void gst_cdxaparse_init (GstCDXAParse * cdxaparse);
 
-static GstElementStateReturn gst_cdxaparse_change_state (GstElement * element);
-
 static void gst_cdxaparse_loop (GstElement * element);
+static GstElementStateReturn gst_cdxaparse_change_state (GstElement * element);
 
 static GstStaticPadTemplate sink_template_factory =
 GST_STATIC_PAD_TEMPLATE ("sink",
@@ -50,20 +49,7 @@
     GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) TRUE")
     );
 
-/* CDXAParse signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
-
-enum
-{
-  ARG_0,
-  /* FILL ME */
-};
-
-static GstElementClass *parent_class = NULL;
+static GstRiffReadClass *parent_class = NULL;
 
 GType
 gst_cdxaparse_get_type (void)
@@ -87,6 +73,7 @@
         g_type_register_static (GST_TYPE_RIFF_READ, "GstCDXAParse",
         &cdxaparse_info, 0);
   }
+
   return cdxaparse_type;
 }
 
@@ -113,11 +100,7 @@
 static void
 gst_cdxaparse_class_init (GstCDXAParseClass * klass)
 {
-  GstElementClass *gstelement_class;
-  GObjectClass *object_class;
-
-  gstelement_class = (GstElementClass *) klass;
-  object_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
 
   parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
 
@@ -127,23 +110,23 @@
 static void
 gst_cdxaparse_init (GstCDXAParse * cdxaparse)
 {
-  /* sink */
+  /* FIXME: this element needs to be event aware */
+
   cdxaparse->sinkpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&sink_template_factory), "sink");
-  gst_element_add_pad (GST_ELEMENT (cdxaparse), cdxaparse->sinkpad);
   GST_RIFF_READ (cdxaparse)->sinkpad = cdxaparse->sinkpad;
-
-
-  gst_element_set_loop_function (GST_ELEMENT (cdxaparse), gst_cdxaparse_loop);
-
-  cdxaparse->state = GST_CDXAPARSE_START;
+  gst_element_add_pad (GST_ELEMENT (cdxaparse), cdxaparse->sinkpad);
 
   cdxaparse->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&src_template_factory), "src");
+  /* FIXME: event, query */
   gst_element_add_pad (GST_ELEMENT (cdxaparse), cdxaparse->srcpad);
 
+  gst_element_set_loop_function (GST_ELEMENT (cdxaparse), gst_cdxaparse_loop);
+
+  cdxaparse->state = GST_CDXAPARSE_START;
   cdxaparse->seek_pending = FALSE;
   cdxaparse->seek_offset = 0;
 }
@@ -211,23 +194,6 @@
   return TRUE;
 }
 
-/*
-
-A sector is 2352 bytes long and is composed of:
-
-!  sync    !  header ! subheader ! data ...   ! edc     !
-! 12 bytes ! 4 bytes ! 8 bytes   ! 2324 bytes ! 4 bytes !
-!-------------------------------------------------------!
-
-We parse the data out of it and send it to the srcpad.
-
-sync : 00 FF FF FF FF FF FF FF FF FF FF 00
-header : hour minute second mode
-sub-header : track channel sub_mode coding repeat (4 bytes)
-edc : checksum
-
-*/
-
 static void
 gst_cdxaparse_loop (GstElement * element)
 {
@@ -235,32 +201,49 @@
   GstRiffRead *riff = GST_RIFF_READ (cdxa);
 
   if (cdxa->state == GST_CDXAPARSE_DATA) {
-
     if (cdxa->dataleft > 0) {
+      gint sync;
       guint32 got_bytes, desired;
       GstBuffer *buf = NULL;
       GstBuffer *outbuf = NULL;
 
-      desired = GST_CDXA_SECTOR_SIZE;
+      /* resync */
+      desired = cdxa->dataleft;
+      if (desired > 1024)
+        desired = 1024;
+      if (gst_bytestream_peek (riff->bs, &buf, desired) != desired) {
+        GST_ELEMENT_ERROR (element, RESOURCE, READ, (NULL), (NULL));
+        return;
+      }
+      sync = gst_cdxastrip_sync (buf);
+      if (sync == -1) {
+        gst_bytestream_flush_fast (riff->bs, desired);
+        cdxa->dataleft -= desired;
+        return;
+      }
+      if (sync > 0) {
+        if (cdxa->dataleft < sync)
+          sync = cdxa->dataleft;
+        gst_bytestream_flush_fast (riff->bs, sync);
+        cdxa->dataleft -= sync;
+        if (cdxa->dataleft == 0)
+          return;
+      }
 
+      /* get data */
+      desired = GST_CDXA_SECTOR_SIZE;
       if (!(buf = gst_riff_read_element_data (riff, desired, &got_bytes)))
         return;
 
       /* Skip CDXA headers, only keep data */
-      outbuf =
-          gst_buffer_create_sub (buf, GST_CDXA_HEADER_SIZE, GST_CDXA_DATA_SIZE);
-
-      gst_buffer_unref (buf);
+      outbuf = gst_cdxastrip_strip (buf);
       gst_pad_push (cdxa->srcpad, GST_DATA (outbuf));
 
-      cdxa->byteoffset += got_bytes;
-      if (got_bytes < cdxa->dataleft) {
+      if (got_bytes < cdxa->dataleft)
         cdxa->dataleft -= got_bytes;
-        return;
-      } else {
+      else
         cdxa->dataleft = 0;
-        cdxa->state = GST_CDXAPARSE_OTHER;
-      }
+      return;
     } else {
       cdxa->state = GST_CDXAPARSE_OTHER;
     }
@@ -268,30 +251,23 @@
 
   switch (cdxa->state) {
     case GST_CDXAPARSE_START:
-      if (!gst_cdxaparse_stream_init (cdxa)) {
+      if (!gst_cdxaparse_stream_init (cdxa))
         return;
-      }
-
       cdxa->state = GST_CDXAPARSE_FMT;
       /* fall-through */
 
     case GST_CDXAPARSE_FMT:
-      if (!gst_cdxaparse_fmt (cdxa)) {
+      if (!gst_cdxaparse_fmt (cdxa))
         return;
-      }
-
       cdxa->state = GST_CDXAPARSE_OTHER;
       /* fall-through */
 
     case GST_CDXAPARSE_OTHER:
-      if (!gst_cdxaparse_other (cdxa)) {
+      if (!gst_cdxaparse_other (cdxa))
         return;
-      }
-
       break;
 
     case GST_CDXAPARSE_DATA:
-
     default:
       g_assert_not_reached ();
   }
@@ -303,27 +279,15 @@
   GstCDXAParse *cdxa = GST_CDXAPARSE (element);
 
   switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-      break;
-
     case GST_STATE_READY_TO_PAUSED:
       cdxa->state = GST_CDXAPARSE_START;
       break;
-
-    case GST_STATE_PAUSED_TO_PLAYING:
-      break;
-
-    case GST_STATE_PLAYING_TO_PAUSED:
-      break;
-
     case GST_STATE_PAUSED_TO_READY:
       cdxa->state = GST_CDXAPARSE_START;
-
       cdxa->seek_pending = FALSE;
       cdxa->seek_offset = 0;
       break;
-
-    case GST_STATE_READY_TO_NULL:
+    default:
       break;
   }
 
@@ -336,12 +300,15 @@
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  if (!gst_library_load ("riff")) {
+  if (!gst_library_load ("riff") ||
+      !gst_library_load ("gstbytestream")) {
     return FALSE;
   }
 
   return gst_element_register (plugin, "cdxaparse", GST_RANK_PRIMARY,
-      GST_TYPE_CDXAPARSE);
+             GST_TYPE_CDXAPARSE) &&
+      gst_element_register (plugin, "cdxastrip",
+          GST_RANK_PRIMARY, GST_TYPE_CDXASTRIP);
 }
 
 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
Index: gst/cdxaparse/gstcdxaparse.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/gst/cdxaparse/gstcdxaparse.h,v
retrieving revision 1.9
diff -u -r1.9 gstcdxaparse.h
--- gst/cdxaparse/gstcdxaparse.h	21 May 2004 14:09:51 -0000	1.9
+++ gst/cdxaparse/gstcdxaparse.h	19 Nov 2004 12:52:40 -0000
@@ -18,7 +18,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __GST_CDXAPARSE_H__
 #define __GST_CDXAPARSE_H__
 
@@ -26,9 +25,7 @@
 #include "gst/riff/riff-ids.h"
 #include "gst/riff/riff-read.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+G_BEGIN_DECLS
 
 #define GST_TYPE_CDXAPARSE \
   (gst_cdxaparse_get_type())
@@ -41,10 +38,6 @@
 #define GST_IS_CDXAPARSE_CLASS(obj) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CDXAPARSE))
 
-#define GST_CDXA_SECTOR_SIZE  	2352
-#define GST_CDXA_DATA_SIZE  	2324
-#define GST_CDXA_HEADER_SIZE	24
-
 typedef enum {
   GST_CDXAPARSE_START,
   GST_CDXAPARSE_FMT,
@@ -65,7 +58,6 @@
   GstCDXAParseState state;
 
   guint64 dataleft, datasize, datastart;
-  int byteoffset;
   
   gboolean seek_pending;
   guint64 seek_offset;
@@ -77,10 +69,6 @@
 
 GType 		gst_cdxaparse_get_type		(void);
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
+G_END_DECLS
 
 #endif /* __GST_CDXAPARSE_H__ */
-
Index: sys/vcd/vcdsrc.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/sys/vcd/vcdsrc.c,v
retrieving revision 1.17
diff -u -r1.17 vcdsrc.c
--- sys/vcd/vcdsrc.c	21 May 2004 23:53:08 -0000	1.17
+++ sys/vcd/vcdsrc.c	19 Nov 2004 12:55:05 -0000
@@ -36,13 +36,6 @@
 
 #include <vcdsrc.h>
 
-
-static GstElementDetails vcdsrc_details = GST_ELEMENT_DETAILS ("VCD Source",
-    "Source/File",
-    "Asynchronous read from VCD disk",
-    "Erik Walthinsen <omega@cse.ogi.edu>");
-
-
 /* VCDSrc signals and args */
 enum
 {
@@ -60,95 +53,148 @@
   ARG_MAX_ERRORS
 };
 
-static void vcdsrc_base_init (gpointer g_class);
-static void vcdsrc_class_init (VCDSrcClass * klass);
-static void vcdsrc_init (VCDSrc * vcdsrc);
-static void vcdsrc_set_property (GObject * object, guint prop_id,
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_vcdsrc_debug);
+#define GST_CAT_DEFAULT gst_vcdsrc_debug
+
+static void gst_vcdsrc_base_init (gpointer g_class);
+static void gst_vcdsrc_class_init (GstVCDSrcClass * klass);
+static void gst_vcdsrc_init (GstVCDSrc * vcdsrc);
+static void gst_vcdsrc_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
-static void vcdsrc_get_property (GObject * object, guint prop_id,
+static void gst_vcdsrc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstData *vcdsrc_get (GstPad * pad);
-
-/*static GstBuffer *		vcdsrc_get_region	(GstPad *pad,gulong offset,gulong size); */
-static GstElementStateReturn vcdsrc_change_state (GstElement * element);
-
-static void vcdsrc_recalculate (VCDSrc * vcdsrc);
+static const GstEventMask *gst_vcdsrc_get_event_mask (GstPad * pad);
+static const GstQueryType *gst_vcdsrc_get_query_types (GstPad * pad);
+static const GstFormat *gst_vcdsrc_get_formats (GstPad * pad);
+static gboolean gst_vcdsrc_srcpad_event (GstPad * pad, GstEvent * event);
+static gboolean gst_vcdsrc_srcpad_query (GstPad * pad, GstQueryType type,
+    GstFormat * format, gint64 * value);
+
+static GstData *gst_vcdsrc_get (GstPad * pad);
+static GstElementStateReturn gst_vcdsrc_change_state (GstElement * element);
+static inline guint64 gst_vcdsrc_msf (GstVCDSrc * vcdsrc, gint track);
+static void gst_vcdsrc_recalculate (GstVCDSrc * vcdsrc);
 
+static void gst_vcdsrc_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
 
 static GstElementClass *parent_class = NULL;
 
 /*static guint vcdsrc_signals[LAST_SIGNAL] = { 0 }; */
 
 GType
-vcdsrc_get_type (void)
+gst_vcdsrc_get_type (void)
 {
-  static GType vcdsrc_type = 0;
+  static GType gst_vcdsrc_type = 0;
 
-  if (!vcdsrc_type) {
-    static const GTypeInfo vcdsrc_info = {
-      sizeof (VCDSrcClass),
-      vcdsrc_base_init,
+  if (!gst_vcdsrc_type) {
+    static const GTypeInfo gst_vcdsrc_info = {
+      sizeof (GstVCDSrcClass),
+      gst_vcdsrc_base_init,
       NULL,
-      (GClassInitFunc) vcdsrc_class_init,
+      (GClassInitFunc) gst_vcdsrc_class_init,
       NULL,
       NULL,
-      sizeof (VCDSrc),
+      sizeof (GstVCDSrc),
       0,
-      (GInstanceInitFunc) vcdsrc_init,
+      (GInstanceInitFunc) gst_vcdsrc_init,
+    };
+    static const GInterfaceInfo urihandler_info = {
+      gst_vcdsrc_uri_handler_init,
+      NULL,
+      NULL
     };
 
-    vcdsrc_type =
-        g_type_register_static (GST_TYPE_ELEMENT, "VCDSrc", &vcdsrc_info, 0);
+    gst_vcdsrc_type =
+        g_type_register_static (GST_TYPE_ELEMENT,
+            "GstVCDSrc", &gst_vcdsrc_info, 0);
+    g_type_add_interface_static (gst_vcdsrc_type,
+        GST_TYPE_URI_HANDLER, &urihandler_info);
   }
-  return vcdsrc_type;
+
+  return gst_vcdsrc_type;
 }
 
 static void
-vcdsrc_base_init (gpointer g_class)
+gst_vcdsrc_base_init (gpointer g_class)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  static GstElementDetails gst_vcdsrc_details = GST_ELEMENT_DETAILS ("VCD Source",
+    "Source/File",
+    "Asynchronous read from VCD disk",
+    "Erik Walthinsen <omega@cse.ogi.edu>");
 
-  gst_element_class_set_details (element_class, &vcdsrc_details);
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&srctemplate));
+  gst_element_class_set_details (element_class, &gst_vcdsrc_details);
 }
+
 static void
-vcdsrc_class_init (VCDSrcClass * klass)
+gst_vcdsrc_class_init (GstVCDSrcClass * klass)
 {
-  GObjectClass *gobject_class;
-  GstElementClass *gstelement_class;
-
-  gobject_class = (GObjectClass *) klass;
-  gstelement_class = (GstElementClass *) klass;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
 
   parent_class = g_type_class_peek_parent (klass);
 
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION, g_param_spec_string ("location", "location", "location", NULL, G_PARAM_READWRITE));    /* CHECKME */
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK, g_param_spec_int ("track", "track", "track", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));  /* CHECKME */
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTESPERREAD, g_param_spec_int ("bytesperread", "bytesperread", "bytesperread", G_MININT, G_MAXINT, 0, G_PARAM_READABLE));       /* CHECKME */
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OFFSET, g_param_spec_int ("offset", "offset", "offset", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));      /* CHECKME */
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_ERRORS,
-      g_param_spec_int ("max-errors", "", "", 0, G_MAXINT, 16,
-          G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_LOCATION,
+      g_param_spec_string ("location", "Location",
+            "CD device location", NULL, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_TRACK,
+      g_param_spec_int ("track", "Track",
+          "Track number to play",
+          G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_BYTESPERREAD,
+      g_param_spec_int ("bytesperread","Bytes per read",
+          "Bytes to read per iteration (VCD sector size)",
+          G_MININT, G_MAXINT, 0, G_PARAM_READABLE));
+  g_object_class_install_property (gobject_class, ARG_OFFSET,
+      g_param_spec_int ("offset", "Offset", "Offset",
+          G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_MAX_ERRORS,
+      g_param_spec_int ("max-errors", "Max. errors",
+          "Maximum number of errors before bailing out",
+          0, G_MAXINT, 16, G_PARAM_READWRITE));
 
-  gobject_class->set_property = vcdsrc_set_property;
-  gobject_class->get_property = vcdsrc_get_property;
+  gobject_class->set_property = gst_vcdsrc_set_property;
+  gobject_class->get_property = gst_vcdsrc_get_property;
 
-  gstelement_class->change_state = vcdsrc_change_state;
+  gstelement_class->change_state = gst_vcdsrc_change_state;
+
+  GST_DEBUG_CATEGORY_INIT (gst_vcdsrc_debug, "vcdsrc", 0,
+      "VideoCD Source element");
 }
 
 static void
-vcdsrc_init (VCDSrc * vcdsrc)
+gst_vcdsrc_init (GstVCDSrc * vcdsrc)
 {
-  vcdsrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
-  gst_pad_set_get_function (vcdsrc->srcpad, vcdsrc_get);
-/*  gst_pad_set_get_region_function (vcdsrc->srcpad, vcdsrc_getregion); */
+  vcdsrc->srcpad =
+      gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
+      "src");
+  gst_pad_set_get_function (vcdsrc->srcpad, gst_vcdsrc_get);
+#if 0
+  gst_pad_set_get_region_function (vcdsrc->srcpad, vcdsrc_getregion);
+#endif
+  gst_pad_set_event_function (vcdsrc->srcpad, gst_vcdsrc_srcpad_event);
+  gst_pad_set_event_mask_function (vcdsrc->srcpad, gst_vcdsrc_get_event_mask);
+  gst_pad_set_query_function (vcdsrc->srcpad, gst_vcdsrc_srcpad_query);
+  gst_pad_set_query_type_function (vcdsrc->srcpad, gst_vcdsrc_get_query_types);
+  gst_pad_set_formats_function (vcdsrc->srcpad, gst_vcdsrc_get_formats);
   gst_element_add_pad (GST_ELEMENT (vcdsrc), vcdsrc->srcpad);
 
   vcdsrc->device = g_strdup ("/dev/cdrom");
-  vcdsrc->track = 2;
+  vcdsrc->track = 1;
   vcdsrc->fd = 0;
   vcdsrc->trackoffset = 0;
   vcdsrc->curoffset = 0;
+  vcdsrc->tempoffset = 0;
+  vcdsrc->discont = vcdsrc->flush = FALSE;
   vcdsrc->bytes_per_read = VCD_BYTES_PER_SECTOR;
   vcdsrc->seq = 0;
   vcdsrc->max_errors = 16;
@@ -156,14 +202,14 @@
 
 
 static void
-vcdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
+gst_vcdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
     GParamSpec * pspec)
 {
-  VCDSrc *src;
+  GstVCDSrc *src;
 
   /* it's not null if we got it, but it might not be ours */
   g_return_if_fail (GST_IS_VCDSRC (object));
-  src = VCDSRC (object);
+  src = GST_VCDSRC (object);
 
   switch (prop_id) {
     case ARG_LOCATION:
@@ -180,14 +226,11 @@
         src->device = g_strdup (g_value_get_string (value));
       break;
     case ARG_TRACK:
-      src->track = g_value_get_int (value);
-      vcdsrc_recalculate (src);
-      break;
-/*    case ARG_BYTESPERREAD:
-      src->bytes_per_read = g_value_get_int (value);
-      break;*/
-    case ARG_OFFSET:
-      src->curoffset = g_value_get_int (value) / VCD_BYTES_PER_SECTOR;
+      if (g_value_get_int (value) >= 1 &&
+          g_value_get_int (value) < src->numtracks) {
+        src->track = g_value_get_int (value);
+        gst_vcdsrc_recalculate (src);
+      }
       break;
     case ARG_MAX_ERRORS:
       src->max_errors = g_value_get_int (value);
@@ -199,14 +242,14 @@
 }
 
 static void
-vcdsrc_get_property (GObject * object, guint prop_id, GValue * value,
+gst_vcdsrc_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
 {
-  VCDSrc *src;
+  GstVCDSrc *src;
 
   /* it's not null if we got it, but it might not be ours */
   g_return_if_fail (GST_IS_VCDSRC (object));
-  src = VCDSRC (object);
+  src = GST_VCDSRC (object);
 
   switch (prop_id) {
     case ARG_LOCATION:
@@ -230,71 +273,210 @@
   }
 }
 
+/*
+ * Querying and seeking.
+ */
+
+static const GstEventMask *
+gst_vcdsrc_get_event_mask (GstPad * pad)
+{
+  static const GstEventMask masks[] = {
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR |
+          GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
+    {0, 0}
+  };
+
+  return masks;
+}
+
+static const GstQueryType *
+gst_vcdsrc_get_query_types (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_TOTAL,
+    GST_QUERY_POSITION,
+    0
+  };
+
+  return types;
+}
+
+static const GstFormat *
+gst_vcdsrc_get_formats (GstPad * pad)
+{
+  static const GstFormat formats[] = {
+    GST_FORMAT_BYTES,
+    0,
+  };
+
+  return formats;
+}
+
+static gboolean
+gst_vcdsrc_srcpad_event (GstPad * pad, GstEvent * event)
+{
+  GstVCDSrc *vcdsrc = GST_VCDSRC (gst_pad_get_parent (pad));
+  gboolean res = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK: {
+      gint64 new_off;
+
+      if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES)
+        return FALSE;
+
+      new_off = GST_EVENT_SEEK_OFFSET (event);
+      switch (GST_EVENT_SEEK_METHOD (event)) {
+        case GST_SEEK_METHOD_SET:
+          /* no-op */
+          break;
+        case GST_SEEK_METHOD_CUR:
+          new_off += vcdsrc->curoffset * vcdsrc->bytes_per_read;
+          break;
+        case GST_SEEK_METHOD_END:
+          new_off = (gst_vcdsrc_msf (vcdsrc, vcdsrc->track + 1) -
+              vcdsrc->trackoffset) * vcdsrc->bytes_per_read - new_off;
+          break;
+        default:
+          return FALSE;
+      }
+
+      if (new_off < 0 ||
+          new_off > (gst_vcdsrc_msf (vcdsrc, vcdsrc->track + 1) -
+              vcdsrc->trackoffset) * vcdsrc->bytes_per_read)
+        return FALSE;
+
+      vcdsrc->curoffset = new_off / vcdsrc->bytes_per_read;
+      vcdsrc->tempoffset = new_off % vcdsrc->bytes_per_read;
+      vcdsrc->discont = TRUE;
+      if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH)
+        vcdsrc->flush = TRUE;
+      break;
+    }
+    default:
+      res = FALSE;
+      break;
+  }
+
+  gst_event_unref (event);
+
+  return res;
+}
+
+static gboolean
+gst_vcdsrc_srcpad_query (GstPad * pad, GstQueryType type,
+    GstFormat * format, gint64 * value)
+{
+  GstVCDSrc *vcdsrc = GST_VCDSRC (gst_pad_get_parent (pad));
+  gboolean res = TRUE;
+
+  if (*format != GST_FORMAT_BYTES)
+    return FALSE;
+
+  switch (type) {
+    case GST_QUERY_TOTAL:
+      *value = (gst_vcdsrc_msf (vcdsrc, vcdsrc->track + 1) -
+          vcdsrc->trackoffset) * vcdsrc->bytes_per_read;
+      break;
+    case GST_QUERY_POSITION:
+      *value = vcdsrc->curoffset * vcdsrc->bytes_per_read;
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+
+  return res;
+}
+
+/*
+ * Data.
+ */
+
 static GstData *
-vcdsrc_get (GstPad * pad)
+gst_vcdsrc_get (GstPad * pad)
 {
-  VCDSrc *vcdsrc;
+  GstVCDSrc *vcdsrc;
+  GstFormat fmt = GST_FORMAT_BYTES;
   GstBuffer *buf;
   gulong offset;
   struct cdrom_msf *msf;
   gint error_count = 0;
 
-  /* fprintf(stderr,"in vcdsrc_push\n"); */
-
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  vcdsrc = VCDSRC (GST_OBJECT_PARENT (pad));
+  vcdsrc = GST_VCDSRC (GST_OBJECT_PARENT (pad));
   g_return_val_if_fail (GST_FLAG_IS_SET (vcdsrc, VCDSRC_OPEN), NULL);
 
-  /* create the buffer */
-  /* FIXME: should eventually use a bufferpool for this */
-  buf = gst_buffer_new ();
-  g_return_val_if_fail (buf != NULL, NULL);
+  offset = vcdsrc->trackoffset + vcdsrc->curoffset;
+  if (offset >= gst_vcdsrc_msf (vcdsrc, vcdsrc->track + 1)) {
+    gst_element_set_eos (GST_ELEMENT (vcdsrc));
+    return GST_DATA (gst_event_new (GST_EVENT_EOS));
+  }
 
-  /* allocate the space for the buffer data */
-  GST_BUFFER_DATA (buf) = g_malloc (vcdsrc->bytes_per_read);
-  memset (GST_BUFFER_DATA (buf), 0, vcdsrc->bytes_per_read);
-  g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
+  if (vcdsrc->discont) {
+    if (vcdsrc->flush) {
+      vcdsrc->flush = FALSE;
+      return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
+    }
+    vcdsrc->discont = FALSE;
+    return GST_DATA (gst_event_new_discontinuous (FALSE,
+        GST_FORMAT_BYTES, vcdsrc->curoffset * vcdsrc->bytes_per_read,
+        GST_FORMAT_UNDEFINED));
+  }
 
+  /* create the buffer */
+  /* FIXME: should eventually use a bufferpool for this */
+  buf = gst_buffer_new_and_alloc (vcdsrc->bytes_per_read);
   msf = (struct cdrom_msf *) GST_BUFFER_DATA (buf);
 
-read_sector:
-
+read:
   /* read it in from the device */
-  offset = vcdsrc->trackoffset + vcdsrc->curoffset;
   msf->cdmsf_frame0 = offset % 75;
   msf->cdmsf_sec0 = (offset / 75) % 60;
   msf->cdmsf_min0 = (offset / (75 * 60));
 
-  /*GST_INFO("msf is %d:%d:%d\n",msf->cdmsf_min0,msf->cdmsf_sec0, */
-  /* msf->cdmsf_frame0); */
+  GST_LOG ("msf is %d:%d:%d", msf->cdmsf_min0,msf->cdmsf_sec0,
+      msf->cdmsf_frame0);
 
-  if (ioctl (vcdsrc->fd, CDROMREADRAW, msf)) {
-    if (++error_count > vcdsrc->max_errors) {
-      gst_element_set_eos (GST_ELEMENT (vcdsrc));
-      return GST_DATA (gst_event_new (GST_EVENT_EOS));
+  if (ioctl (vcdsrc->fd, CDROMREADRAW, msf) < 0) {
+    if (++error_count <= vcdsrc->max_errors) {
+      vcdsrc->curoffset++;
+      offset++;
+      goto read;
     }
 
-    fprintf (stderr, "%s while reading raw data from cdrom at %d:%d:%d\n",
-        strerror (errno), msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
-    vcdsrc->curoffset += 1;
+    GST_ELEMENT_ERROR (vcdsrc, RESOURCE, READ, (NULL),
+        ("Read from cdrom at %d:%d:%d failed: %s",
+        msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0,
+        strerror (errno)));
 
-    /* Or we can return a zero-filled buffer.  Which is better? */
-    goto read_sector;
+    return GST_DATA (gst_event_new (GST_EVENT_INTERRUPT));
   }
 
 
-  GST_BUFFER_OFFSET (buf) = vcdsrc->curoffset;
+  gst_pad_query (pad, GST_QUERY_POSITION, &fmt,
+      (gint64 *) &GST_BUFFER_OFFSET (buf));
   GST_BUFFER_SIZE (buf) = vcdsrc->bytes_per_read;
   vcdsrc->curoffset += 1;
 
+  if (vcdsrc->tempoffset != 0) {
+    GstBuffer *sub;
+
+    sub = gst_buffer_create_sub (buf, vcdsrc->tempoffset,
+        vcdsrc->bytes_per_read - vcdsrc->tempoffset);
+    vcdsrc->tempoffset = 0;
+    gst_buffer_unref (buf);
+    buf = sub;
+  }
+
   return GST_DATA (buf);
 }
 
 /* open the file, necessary to go to RUNNING state */
 static gboolean
-vcdsrc_open_file (VCDSrc * src)
+gst_vcdsrc_open_file (GstVCDSrc * src)
 {
   int i;
 
@@ -309,43 +491,40 @@
 
   /* read the table of contents */
   if (ioctl (src->fd, CDROMREADTOCHDR, &src->tochdr)) {
-    perror ("reading toc of VCD\n");
-/* FIXME 	*/
-/*    exit(1);	*/
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+    close (src->fd);
+    return FALSE;
   }
 
   /* allocate enough track structs for disk */
   src->numtracks = (src->tochdr.cdth_trk1 - src->tochdr.cdth_trk0) + 1;
-  src->tracks = g_new (struct cdrom_tocentry, src->numtracks);
+  src->tracks = g_new (struct cdrom_tocentry, src->numtracks + 1);
 
   /* read each track entry */
-  for (i = 0; i < src->numtracks; i++) {
-    src->tracks[i].cdte_track = i + 1;
+  for (i = 0; i <= src->numtracks; i++) {
+    src->tracks[i].cdte_track = i == src->numtracks ? CDROM_LEADOUT : i + 1;
     src->tracks[i].cdte_format = CDROM_MSF;
     if (ioctl (src->fd, CDROMREADTOCENTRY, &src->tracks[i])) {
-      perror ("reading tocentry");
-/* FIXME 	*/
-/*      exit(1);*/
+      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+      g_free (src->tracks);
+      close (src->fd);
+      return FALSE;
     }
-    fprintf (stderr, "VCDSrc: track begins at %d:%d:%d\n",
+    GST_DEBUG ("track %d begins at %d:%02d.%02d", i,
         src->tracks[i].cdte_addr.msf.minute,
         src->tracks[i].cdte_addr.msf.second,
         src->tracks[i].cdte_addr.msf.frame);
   }
 
-  src->trackoffset =
-      (((src->tracks[src->track - 1].cdte_addr.msf.minute * 60) +
-          src->tracks[src->track - 1].cdte_addr.msf.second) * 75) +
-      src->tracks[src->track - 1].cdte_addr.msf.frame;
-  fprintf (stderr, "VCDSrc: track offset is %ld\n", src->trackoffset);
-
   GST_FLAG_SET (src, VCDSRC_OPEN);
+  gst_vcdsrc_recalculate (src);
+
   return TRUE;
 }
 
 /* close the file */
 static void
-vcdsrc_close_file (VCDSrc * src)
+gst_vcdsrc_close_file (GstVCDSrc * src)
 {
   g_return_if_fail (GST_FLAG_IS_SET (src, VCDSRC_OPEN));
 
@@ -355,46 +534,107 @@
   /* zero out a lot of our state */
   src->fd = 0;
   src->curoffset = 0;
-  src->seq = 0;
+  src->seq = 0; 
+
+  g_free (src->tracks);
 
   GST_FLAG_UNSET (src, VCDSRC_OPEN);
 }
 
 static GstElementStateReturn
-vcdsrc_change_state (GstElement * element)
+gst_vcdsrc_change_state (GstElement * element)
 {
-  g_return_val_if_fail (GST_IS_VCDSRC (element), GST_STATE_FAILURE);
+  GstVCDSrc *vcdsrc = GST_VCDSRC (element);
 
-  /* if going down into NULL state, close the file if it's open */
-  if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
-    if (GST_FLAG_IS_SET (element, VCDSRC_OPEN))
-      vcdsrc_close_file (VCDSRC (element));
-    /* otherwise (READY or higher) we need to open the sound card */
-  } else {
-    if (!GST_FLAG_IS_SET (element, VCDSRC_OPEN)) {
-      if (!vcdsrc_open_file (VCDSRC (element)))
-        return GST_STATE_FAILURE;
-    }
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_READY_TO_NULL:
+      if (GST_FLAG_IS_SET (element, VCDSRC_OPEN))
+        gst_vcdsrc_close_file (vcdsrc);
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      vcdsrc->curoffset = 0;
+      vcdsrc->discont = vcdsrc->flush = FALSE;
+      break;
+    case GST_STATE_NULL_TO_READY:
+      if (!GST_FLAG_IS_SET (element, VCDSRC_OPEN))
+        if (!gst_vcdsrc_open_file (vcdsrc))
+          return GST_STATE_FAILURE;
+      break;
+    default:
+      break;
   }
 
   if (GST_ELEMENT_CLASS (parent_class)->change_state)
     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
   return GST_STATE_SUCCESS;
 }
 
+static inline guint64
+gst_vcdsrc_msf (GstVCDSrc * vcdsrc, gint track)
+{
+  return (vcdsrc->tracks[track].cdte_addr.msf.minute * 60 +
+      vcdsrc->tracks[track].cdte_addr.msf.second) * 75 +
+      vcdsrc->tracks[track].cdte_addr.msf.frame;
+}
+
 static void
-vcdsrc_recalculate (VCDSrc * vcdsrc)
+gst_vcdsrc_recalculate (GstVCDSrc * vcdsrc)
 {
   if (GST_FLAG_IS_SET (vcdsrc, VCDSRC_OPEN)) {
     /* calculate track offset (beginning of track) */
-    vcdsrc->trackoffset =
-        (((vcdsrc->tracks[vcdsrc->track - 1].cdte_addr.msf.minute * 60) +
-            vcdsrc->tracks[vcdsrc->track - 1].cdte_addr.msf.second) * 75) +
-        vcdsrc->tracks[vcdsrc->track - 1].cdte_addr.msf.frame;
-    fprintf (stderr, "VCDSrc: track offset is %ld\n", vcdsrc->trackoffset);
+    vcdsrc->trackoffset = gst_vcdsrc_msf (vcdsrc, vcdsrc->track);
+    GST_DEBUG ("track offset is %ld", vcdsrc->trackoffset);
   }
 }
 
+/*
+ * URI interface.
+ */
+
+static guint
+gst_vcdsrc_uri_get_type (void)
+{
+  return GST_URI_SRC;
+}
+
+static gchar **
+gst_vcdsrc_uri_get_protocols (void)
+{
+  static gchar *protocols[] = { "vcd", NULL };
+
+  return protocols;
+}
+
+static const gchar *
+gst_vcdsrc_uri_get_uri (GstURIHandler * handler)
+{
+  return "vcd://";
+}
+
+static gboolean
+gst_vcdsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+  gboolean ret;
+  gchar *protocol = gst_uri_get_protocol (uri);
+
+  ret = (protocol && !strcmp (protocol, "vcd")) ? TRUE : FALSE;
+  g_free (protocol);
+
+  return ret;
+}
+
+static void
+gst_vcdsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_vcdsrc_uri_get_type;
+  iface->get_protocols = gst_vcdsrc_uri_get_protocols;
+  iface->get_uri = gst_vcdsrc_uri_get_uri;
+  iface->set_uri = gst_vcdsrc_uri_set_uri;
+}
+
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
Index: sys/vcd/vcdsrc.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins/sys/vcd/vcdsrc.h,v
retrieving revision 1.6
diff -u -r1.6 vcdsrc.h
--- sys/vcd/vcdsrc.h	15 Mar 2004 16:32:54 -0000	1.6
+++ sys/vcd/vcdsrc.h	19 Nov 2004 12:55:05 -0000
@@ -21,25 +21,19 @@
 #ifndef __VCDSRC_H__
 #define __VCDSRC_H__
 
-
 #include <gst/gst.h>
-
 #include <linux/cdrom.h>
 
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
+G_BEGIN_DECLS
 
 #define VCD_BYTES_PER_SECTOR 2352
 
 #define GST_TYPE_VCDSRC \
-  (vcdsrc_get_type())
-#define VCDSRC(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VCDSRC,VCDSrc))
-#define VCDSRC_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VCDSRC,VCDSrcClass))
+  (gst_vcdsrc_get_type())
+#define GST_VCDSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VCDSRC,GstVCDSrc))
+#define GST_VCDSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VCDSRC,GstVCDSrcClass))
 #define GST_IS_VCDSRC(obj) \
   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VCDSRC))
 #define GST_IS_VCDSRC_CLASS(obj) \
@@ -50,12 +44,12 @@
   VCDSRC_OPEN		= GST_ELEMENT_FLAG_LAST,
 
   VCDSRC_FLAG_LAST	= GST_ELEMENT_FLAG_LAST+2,
-} VCDSrcFlags;
+} GstVCDSrcFlags;
 
-typedef struct _VCDSrc VCDSrc;
-typedef struct _VCDSrcClass VCDSrcClass;
+typedef struct _GstVCDSrc GstVCDSrc;
+typedef struct _GstVCDSrcClass GstVCDSrcClass;
 
-struct _VCDSrc {
+struct _GstVCDSrc {
   GstElement element;
   /* pads */
   GstPad *srcpad;
@@ -75,6 +69,10 @@
   gulong trackoffset;
   gulong frameoffset;
 
+  /* bytes offset in next buf */
+  gulong tempoffset;
+  gboolean discont, flush;
+
   gulong curoffset;			/* current offset in file */
   gulong bytes_per_read;		/* bytes per read */
 
@@ -82,15 +80,12 @@
   int max_errors;
 };
 
-struct _VCDSrcClass {
+struct _GstVCDSrcClass {
   GstElementClass parent_class;
 };
 
-GType vcdsrc_get_type(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+GType gst_vcdsrc_get_type(void);
 
+G_END_DECLS
 
 #endif /* __VCDSRC_H__ */
--- /dev/null	2004-02-23 22:02:56.000000000 +0100
+++ gst/cdxaparse/gstcdxastrip.c	2004-11-16 00:18:53.000000000 +0100
@@ -0,0 +1,408 @@
+/* GStreamer CDXA sync strippper
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+#include "gstcdxastrip.h"
+
+static void gst_cdxastrip_base_init (GstCDXAStripClass * klass);
+static void gst_cdxastrip_class_init (GstCDXAStripClass * klass);
+static void gst_cdxastrip_init (GstCDXAStrip * cdxastrip);
+
+static const GstEventMask *gst_cdxastrip_get_event_mask (GstPad * pad);
+static gboolean gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event);
+static const GstFormat *gst_cdxastrip_get_src_formats (GstPad * pad);
+static const GstQueryType *gst_cdxastrip_get_src_query_types (GstPad * pad);
+static gboolean gst_cdxastrip_handle_src_query (GstPad * pad,
+    GstQueryType type, GstFormat * format, gint64 * value);
+
+static void gst_cdxastrip_chain (GstPad * pad, GstData * data);
+static GstElementStateReturn gst_cdxastrip_change_state (GstElement * element);
+
+static GstStaticPadTemplate sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-vcd")
+    );
+
+static GstStaticPadTemplate src_template_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) TRUE")
+    );
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_cdxastrip_get_type (void)
+{
+  static GType cdxastrip_type = 0;
+
+  if (!cdxastrip_type) {
+    static const GTypeInfo cdxastrip_info = {
+      sizeof (GstCDXAStripClass),
+      (GBaseInitFunc) gst_cdxastrip_base_init,
+      NULL,
+      (GClassInitFunc) gst_cdxastrip_class_init,
+      NULL,
+      NULL,
+      sizeof (GstCDXAStrip),
+      0,
+      (GInstanceInitFunc) gst_cdxastrip_init,
+    };
+
+    cdxastrip_type =
+        g_type_register_static (GST_TYPE_ELEMENT, "GstCDXAStrip",
+        &cdxastrip_info, 0);
+  }
+
+  return cdxastrip_type;
+}
+
+static void
+gst_cdxastrip_base_init (GstCDXAStripClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  static GstElementDetails gst_cdxastrip_details =
+      GST_ELEMENT_DETAILS ("vcd parser",
+      "Codec/Parser",
+      "Strip (S)VCD stream from its syncheaders",
+      "Ronald Bultje <rbultje@ronald.bitfreak.net>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sink_template_factory));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_template_factory));
+
+  gst_element_class_set_details (element_class, &gst_cdxastrip_details);
+}
+
+static void
+gst_cdxastrip_class_init (GstCDXAStripClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  element_class->change_state = gst_cdxastrip_change_state;
+}
+
+static void
+gst_cdxastrip_init (GstCDXAStrip * cdxastrip)
+{
+  GST_FLAG_SET (cdxastrip, GST_ELEMENT_EVENT_AWARE);
+
+  cdxastrip->sinkpad = gst_pad_new_from_template (
+      gst_static_pad_template_get (&sink_template_factory), "sink");
+  gst_pad_set_chain_function (cdxastrip->sinkpad, gst_cdxastrip_chain);
+  gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->sinkpad);
+
+  cdxastrip->srcpad =
+      gst_pad_new_from_template (gst_static_pad_template_get
+      (&src_template_factory), "src");
+  gst_pad_set_formats_function (cdxastrip->srcpad, gst_cdxastrip_get_src_formats);
+  gst_pad_set_event_mask_function (cdxastrip->srcpad, gst_cdxastrip_get_event_mask);
+  gst_pad_set_event_function (cdxastrip->srcpad, gst_cdxastrip_handle_src_event);
+  gst_pad_set_query_type_function (cdxastrip->srcpad, gst_cdxastrip_get_src_query_types);
+  gst_pad_set_query_function (cdxastrip->srcpad, gst_cdxastrip_handle_src_query);
+  gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->srcpad);
+}
+
+/*
+ * Stuff.
+ */
+
+static const GstFormat *
+gst_cdxastrip_get_src_formats (GstPad * pad)
+{
+  static const GstFormat formats[] = {
+    GST_FORMAT_BYTES,
+    0
+  };
+
+  return formats;
+}
+
+static const GstQueryType *
+gst_cdxastrip_get_src_query_types (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_TOTAL,
+    GST_QUERY_POSITION,
+    0
+  };
+
+  return types;
+}
+
+static gboolean
+gst_cdxastrip_handle_src_query (GstPad * pad,
+    GstQueryType type, GstFormat * format, gint64 * value)
+{
+  GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad));
+
+  if (!gst_pad_query (GST_PAD_PEER (cdxa->sinkpad), type, format, value))
+    return FALSE;
+
+  if (*format != GST_FORMAT_BYTES)
+    return TRUE;
+
+  switch (type) {
+    case GST_QUERY_TOTAL:
+    case GST_QUERY_POSITION: {
+      gint num, rest;
+
+      num = *value / GST_CDXA_SECTOR_SIZE;
+      rest = *value % GST_CDXA_SECTOR_SIZE;
+
+      *value = num * GST_CDXA_DATA_SIZE;
+      if (rest > GST_CDXA_HEADER_SIZE) {
+        if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE)
+          *value += GST_CDXA_DATA_SIZE;
+        else
+          *value += rest - GST_CDXA_HEADER_SIZE;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+static const GstEventMask *
+gst_cdxastrip_get_event_mask (GstPad * pad)
+{
+  static const GstEventMask masks[] = {
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
+    {0,}
+  };
+
+  return masks;
+}
+
+static gboolean
+gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event)
+{
+  GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+      switch (GST_EVENT_SEEK_FORMAT (event)) {
+        case GST_FORMAT_BYTES: {
+          GstEvent *new;
+          gint64 off;
+          gint num, rest;
+
+          off = GST_EVENT_SEEK_OFFSET (event);
+          num = off / GST_CDXA_DATA_SIZE;
+          rest = off % GST_CDXA_DATA_SIZE;
+          off = num * GST_CDXA_SECTOR_SIZE;
+          if (rest > 0)
+            off += rest + GST_CDXA_HEADER_SIZE;
+          new = gst_event_new_seek (GST_EVENT_SEEK_TYPE (event), off);
+          gst_event_unref (event);
+          event = new;
+        }
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return gst_pad_send_event (GST_PAD_PEER (cdxa->sinkpad), event);
+}
+
+/*
+ * A sector is 2352 bytes long and is composed of:
+ * 
+ * !  sync    !  header ! subheader ! data ...   ! edc     !
+ * ! 12 bytes ! 4 bytes ! 8 bytes   ! 2324 bytes ! 4 bytes !
+ * !-------------------------------------------------------!
+ * 
+ * We strip the data out of it and send it to the srcpad.
+ * 
+ * sync : 00 FF FF FF FF FF FF FF FF FF FF 00
+ * header : hour minute second mode
+ * sub-header : track channel sub_mode coding repeat (4 bytes)
+ * edc : checksum
+ */
+
+GstBuffer *
+gst_cdxastrip_strip (GstBuffer * buf)
+{
+  GstBuffer *sub;
+
+  g_assert (GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE);
+
+  /* Skip CDXA headers, only keep data.
+   * FIXME: check sync, resync, ... */
+  sub = gst_buffer_create_sub (buf,
+      GST_CDXA_HEADER_SIZE, GST_CDXA_DATA_SIZE);
+  gst_buffer_unref (buf);
+
+  return sub;
+}
+
+/*
+ * -1 = no sync (discard buffer),
+ * otherwise offset indicates syncpoint in buffer.
+ */
+
+gint
+gst_cdxastrip_sync (GstBuffer * buf)
+{
+  guint size, off = 0;
+  guint8 *data;
+
+  for (size = GST_BUFFER_SIZE (buf), data = GST_BUFFER_DATA (buf);
+       size >= 12; size--, data++, off++) {
+    /* we could do a checksum check as well, but who cares... */
+    if (!memcmp (data,
+             "\000\377\377\377\377\377\377\377\377\377\377\000", 12))
+      return off;
+  }
+
+  return -1;
+}
+
+/*
+ * Do stuff.
+ */
+
+static void
+gst_cdxastrip_handle_event (GstCDXAStrip *cdxa, GstEvent * event)
+{
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_DISCONTINUOUS: {
+      gint64 new_off, off;
+
+      if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &new_off)) {
+        GstEvent *new;
+        gint chunknum, rest;
+
+        chunknum = new_off / GST_CDXA_SECTOR_SIZE;
+        rest = new_off % GST_CDXA_SECTOR_SIZE;
+        off = chunknum * GST_CDXA_DATA_SIZE;
+        if (rest > GST_CDXA_HEADER_SIZE) {
+          if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE)
+            off += GST_CDXA_DATA_SIZE;
+          else
+            off += rest - GST_CDXA_HEADER_SIZE;
+        }
+        new = gst_event_new_discontinuous (
+            GST_EVENT_DISCONT_NEW_MEDIA (event),
+            GST_FORMAT_BYTES, new_off, GST_FORMAT_UNDEFINED);
+        gst_event_unref (event);
+        event = new;
+      }
+      gst_pad_event_default (cdxa->sinkpad, event);
+      break;
+    }
+    case GST_EVENT_FLUSH:
+      if (cdxa->cache) {
+        gst_buffer_unref (cdxa->cache);
+        cdxa->cache = NULL;
+      }
+      /* fall-through */
+    default:
+      gst_pad_event_default (cdxa->sinkpad, event);
+      break;
+  }
+}
+
+static void
+gst_cdxastrip_chain (GstPad * pad, GstData * data)
+{
+  GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad));
+  GstBuffer *buf, *sub;
+  gint sync;
+
+  if (GST_IS_EVENT (data)) {
+    gst_cdxastrip_handle_event (cdxa, GST_EVENT (data));
+    return;
+  }
+
+  buf = GST_BUFFER (data);
+  if (cdxa->cache) {
+    buf = gst_buffer_join (cdxa->cache, buf);
+  }
+  cdxa->cache = NULL;
+
+  while (buf && GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE) {
+    /* sync */
+    sync = gst_cdxastrip_sync (buf);
+    if (sync < 0) {
+      gst_buffer_unref (buf);
+      return;
+    }
+    sub = gst_buffer_create_sub (buf, sync, GST_BUFFER_SIZE (buf) - sync);
+    gst_buffer_unref (buf);
+    buf = sub;
+    if (GST_BUFFER_SIZE (buf) < GST_CDXA_SECTOR_SIZE)
+      break;
+
+    /* one chunk */
+    sub = gst_cdxastrip_strip (gst_buffer_ref (buf));
+    gst_pad_push (cdxa->srcpad, GST_DATA (sub));
+
+    /* cache */
+    if (GST_BUFFER_SIZE (buf) != GST_CDXA_SECTOR_SIZE) {
+      sub = gst_buffer_create_sub (buf, GST_CDXA_SECTOR_SIZE,
+          GST_BUFFER_SIZE (buf) - GST_CDXA_SECTOR_SIZE);
+    } else {
+      sub = NULL;
+    }
+    gst_buffer_unref (buf);
+    buf = sub;
+  }
+
+  cdxa->cache = buf;
+}
+
+static GstElementStateReturn
+gst_cdxastrip_change_state (GstElement * element)
+{
+  GstCDXAStrip *cdxa = GST_CDXASTRIP (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_PAUSED_TO_READY:
+      if (cdxa->cache) {
+        gst_buffer_unref (cdxa->cache);
+        cdxa->cache = NULL;
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (parent_class->change_state)
+    return parent_class->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
--- /dev/null	2004-02-23 22:02:56.000000000 +0100
+++ gst/cdxaparse/gstcdxastrip.h	2004-11-16 00:35:22.000000000 +0100
@@ -0,0 +1,67 @@
+/* GStreamer CDXA sync strippper
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef __GST_CDXASTRIP_H__
+#define __GST_CDXASTRIP_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CDXASTRIP \
+  (gst_cdxastrip_get_type())
+#define GST_CDXASTRIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CDXASTRIP,GstCDXAStrip))
+#define GST_CDXASTRIP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CDXASTRIP,GstCDXAStrip))
+#define GST_IS_CDXASTRIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CDXASTRIP))
+#define GST_IS_CDXASTRIP_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CDXASTRIP))
+
+#define GST_CDXA_SECTOR_SIZE  	2352
+#define GST_CDXA_DATA_SIZE  	2324
+#define GST_CDXA_HEADER_SIZE	24
+
+typedef struct _GstCDXAStrip GstCDXAStrip;
+typedef struct _GstCDXAStripClass GstCDXAStripClass;
+
+struct _GstCDXAStrip {
+  GstElement parent;
+
+  /* pads */
+  GstPad *sinkpad, *srcpad;
+  GstBuffer *cache;
+};
+
+struct _GstCDXAStripClass {
+  GstElementClass parent_class;
+};
+
+GType	 	gst_cdxastrip_get_type	(void);
+
+/*
+ * Also useful for CDXAparse.
+ */
+GstBuffer *	gst_cdxastrip_strip	(GstBuffer * buf);
+gint		gst_cdxastrip_sync	(GstBuffer * buf);
+
+G_END_DECLS
+
+#endif /* __GST_CDXASTRIP_H__ */
--- gst/typefind/gsttypefindfunctions.c.old	2004-11-19 13:56:24.781203322 +0100
+++ gst/typefind/gsttypefindfunctions.c	2004-11-15 22:36:42.000000000 +0100
@@ -1433,6 +1454,9 @@
       avi_exts, "AVI ");
   TYPE_FIND_REGISTER_RIFF (plugin, "video/x-cdxa", GST_RANK_PRIMARY,
       cdxa_exts, "CDXA");
+  TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-vcd", GST_RANK_PRIMARY,
+      cdxa_exts, "\000\377\377\377\377\377\377\377\377\377\377\000", 12,
+      GST_TYPE_FIND_MAXIMUM);
   TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-flac", GST_RANK_PRIMARY,
       flac_exts, "fLaC", 4, GST_TYPE_FIND_MAXIMUM);
   TYPE_FIND_REGISTER (plugin, "video/x-fli", GST_RANK_MARGINAL, flx_type_find,
--- gst/playback/gstdecodebin.c.old	2004-11-19 17:20:07.101707671 +0100
+++ gst/playback/gstdecodebin.c	2004-11-15 23:02:07.000000000 +0100
@@ -227,7 +242,9 @@
 
   klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
   /* only demuxers and decoders can play */
-  if (strstr (klass, "Demux") == NULL && strstr (klass, "Decoder") == NULL) {
+  if (strstr (klass, "Demux") == NULL &&
+      strstr (klass, "Decoder") == NULL &&
+      strstr (klass, "Parse") == NULL) {
     return FALSE;
   }
 
