diff -ur -x Makefile.in -x aclocal.m4 -x configure -x 'config.*' -x ltmain.sh -x '*.spec' /tmp/gst-plugins-bad-0.10.6/REQUIREMENTS gst-plugins-bad-0.10.6/REQUIREMENTS
--- /tmp/gst-plugins-bad-0.10.6/REQUIREMENTS	2007-07-09 07:05:45.000000000 +0100
+++ gst-plugins-bad-0.10.6/REQUIREMENTS	2008-03-27 22:07:47.000000000 +0000
@@ -118,9 +118,11 @@
 libmms		(for MMS protocol support)
 			(http://www.sf.net/projects/libmms)
 libamrnb	(for AMR-NB support)
-			(http://http://www.penguin.cz/~utx/amr)
+			(http://www.penguin.cz/~utx/amr)
 libamrwb	(for AMR-WB support)
-			(http://http://www.penguin.cz/~utx/amr)
+			(http://www.penguin.cz/~utx/amr)
+libkate		(for Kate support)
+			(http://libkate.googlecode.com/)
 
 
 Optional (debian) packages:
diff -ur -x Makefile.in -x aclocal.m4 -x configure -x 'config.*' -x ltmain.sh -x '*.spec' /tmp/gst-plugins-bad-0.10.6/configure.ac gst-plugins-bad-0.10.6/configure.ac
--- /tmp/gst-plugins-bad-0.10.6/configure.ac	2008-02-20 22:13:58.000000000 +0000
+++ gst-plugins-bad-0.10.6/configure.ac	2008-03-27 22:50:27.000000000 +0000
@@ -591,6 +591,17 @@
   AC_SUBST(JACK_LIBS)
 ])
 
+dnl *** kate ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_KATE, true)
+AG_GST_CHECK_FEATURE(KATE, [kate], kate, [
+  PKG_CHECK_MODULES(KATE, kate, HAVE_KATE="yes", [
+    HAVE_KATE="no"
+    AC_MSG_RESULT(no)
+  ])
+  AC_SUBST(KATE_CFLAGS)
+  AC_SUBST(KATE_LIBS)
+])
+
 dnl *** ladspa ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_LADSPA, true)
 AG_GST_CHECK_FEATURE(LADSPA, [ladspa], ladspa, [
@@ -965,6 +976,7 @@
 AM_CONDITIONAL(USE_XVID, false)
 AM_CONDITIONAL(USE_WILDMIDI, false)
 AM_CONDITIONAL(USE_DVB, false)
+AM_CONDITIONAL(USE_KATE, false)
 
 fi dnl of EXT plugins
 
@@ -1085,6 +1097,7 @@
 ext/gsm/Makefile
 ext/ivorbis/Makefile
 ext/jack/Makefile
+ext/kate/Makefile
 ext/ladspa/Makefile
 ext/libmms/Makefile
 ext/Makefile
diff -ur -x Makefile.in -x aclocal.m4 -x configure -x 'config.*' -x ltmain.sh -x '*.spec' /tmp/gst-plugins-bad-0.10.6/ext/Makefile.am gst-plugins-bad-0.10.6/ext/Makefile.am
--- /tmp/gst-plugins-bad-0.10.6/ext/Makefile.am	2008-02-07 23:30:41.000000000 +0000
+++ gst-plugins-bad-0.10.6/ext/Makefile.am	2008-03-27 22:57:53.000000000 +0000
@@ -118,6 +118,12 @@
 JACK_DIR=
 endif
 
+if USE_KATE
+KATE_DIR=kate
+else
+KATE_DIR=
+endif
+
 if USE_LADSPA
 LADSPA_DIR = ladspa
 else
@@ -301,6 +307,7 @@
 	$(HERMES_DIR) \
 	$(IVORBIS_DIR) \
 	$(JACK_DIR) \
+	$(KATE_DIR) \
 	$(LADSPA_DIR) \
 	$(LCS_DIR) \
 	$(LIBFAME_DIR) \
@@ -342,6 +349,7 @@
 	ivorbis \
 	ladspa \
 	jack \
+	kate \
 	libmms \
 	dts \
 	divx \
diff -ur -x Makefile.in -x aclocal.m4 -x configure -x 'config.*' -x ltmain.sh -x '*.spec' /tmp/gst-plugins-bad-0.10.6/gst-plugins-bad.spec.in gst-plugins-bad-0.10.6/gst-plugins-bad.spec.in
--- /tmp/gst-plugins-bad-0.10.6/gst-plugins-bad.spec.in	2008-02-20 20:33:50.000000000 +0000
+++ gst-plugins-bad-0.10.6/gst-plugins-bad.spec.in	2008-03-30 17:15:35.000000000 +0100
@@ -151,6 +151,7 @@
 @USE_DC1394_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstdc1394.so
 @USE_TIMIDITY_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgsttimidity.so
 @USE_SOUP_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstsouphttpsrc.so
+@USE_KATE_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstkate.so
 
 
 %changelog
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkate.c	2008-04-02 19:17:19.000000000 +0100
@@ -0,0 +1,119 @@
+/*
+ * GStreamer
+ * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright 2008 ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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 "gstkate.h"
+#include "gstkatedec.h"
+#include "gstkateparse.h"
+
+GST_DEBUG_CATEGORY (gst_katedec_debug);
+GST_DEBUG_CATEGORY (gst_kateparse_debug);
+
+
+static GstStaticCaps kate_caps = GST_STATIC_CAPS (GST_KATE_MIME_TYPE);
+
+#define KATE_CAPS (gst_static_caps_get(&kate_caps))
+static void
+gst_kate_type_find (GstTypeFind * tf, gpointer private)
+{
+  guint8 *data = gst_type_find_peek (tf, 0, 9);
+
+  if (data) {
+    if (memcmp (data, "\200kate\0\0\0\0", 9) != 0)
+      return;
+
+    gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, KATE_CAPS);
+  }
+}
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and pad templates
+ * register the features
+ */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple (GST_KATE_MIME_TYPE, NULL);
+  if (!gst_type_find_register (plugin, GST_KATE_MIME_TYPE, GST_RANK_PRIMARY,
+          gst_kate_type_find, NULL, caps, NULL, NULL)) {
+    GST_WARNING ("kate: failed to register typefind");
+    gst_caps_unref (caps);
+    return FALSE;
+  }
+  gst_caps_unref (caps);
+
+  GST_DEBUG_CATEGORY_INIT (gst_katedec_debug, "katedec",
+      0, "Kate decoder");
+  GST_DEBUG_CATEGORY_INIT (gst_kateparse_debug, "kateparse",
+      0, "Kate parser");
+
+  if (!gst_element_register (plugin, "katedec",
+      GST_RANK_PRIMARY, GST_TYPE_KATE_DEC))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "kateparse",
+      GST_RANK_NONE, GST_TYPE_KATE_PARSE))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* this is the structure that gstreamer looks for to register plugins
+ */
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "kate",
+    "Kate plugin",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkate.h	2008-04-02 19:46:29.000000000 +0100
@@ -0,0 +1,55 @@
+/*
+ * GStreamer
+ * Copyright 2008 ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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_KATE_H__
+#define __GST_KATE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_KATE_MIME_TYPE "application/x-kate"
+
+G_END_DECLS
+
+#endif /* __GST_KATE_H__ */
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkatedec.c	2008-04-02 19:15:27.000000000 +0100
@@ -0,0 +1,488 @@
+/*
+ * GStreamer
+ * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright 2008 ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:element-katedec
+ * @see_also: oggdemux
+ *
+ * <refsect2>
+ * <para>
+ * This element decodes Kate streams
+ * <ulink url="http://libkate.googlecode.com/">Kate</ulink> is a free codec
+ * for text based data, such as subtitles. Any number of kate streams can be
+ * embedded in an Ogg stream.
+ * </para>
+ * <para>
+ * libkate (see above url) is needed to build this plugin.
+ * </para>
+ * <title>Example pipeline</title>
+ * <para>
+ * This explicitely decodes a Kate stream:
+ * <programlisting>
+ * gst-launch filesrc location=test.ogg ! oggdemux ! katedec ! fakesink silent=TRUE
+ * </programlisting>
+ * </para>
+ * <para>
+ * This will automatically detect and use any Kate streams multiplexed
+ * in an Ogg stream:
+ * <programlisting>
+ * gst-launch playbin uri=file:///tmp/test.ogg
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstkate.h"
+#include "gstkatedec.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_katedec_debug);
+#define GST_CAT_DEFAULT gst_katedec_debug
+
+/* Filter signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_SILENT,
+  ARG_REMOVE_MARKUP
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_KATE_MIME_TYPE)
+    );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("text/plain; text/x-pango-markup")
+    );
+
+GST_BOILERPLATE (GstKateDec, gst_kate_dec, GstElement,
+    GST_TYPE_ELEMENT);
+
+static void gst_kate_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_kate_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstBuffer * buf);
+static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element,
+    GstStateChange transition);
+static const GstQueryType * gst_kate_dec_sink_query_type(GstPad * pad);
+static gboolean gst_kate_dec_sink_query(GstPad * pad, GstQuery * query);
+
+static void
+gst_kate_dec_base_init (gpointer gclass)
+{
+  static GstElementDetails element_details = {
+    "Kate bitstream decoder",
+    "Codec/Decoder/Text",
+    "Decodes Kate text bitstreams",
+    "ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>"
+  };
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_factory));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sink_factory));
+  gst_element_class_set_details (element_class, &element_details);
+}
+
+/* initialize the plugin's class */
+static void
+gst_kate_dec_class_init (GstKateDecClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_kate_dec_set_property;
+  gobject_class->get_property = gst_kate_dec_get_property;
+
+  g_object_class_install_property (gobject_class, ARG_SILENT,
+      g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
+          FALSE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, ARG_REMOVE_MARKUP,
+      g_param_spec_boolean ("remove-markup", "Remove markup", "Remove markup from decoded text ?",
+          FALSE, G_PARAM_READWRITE));
+
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_kate_dec_change_state);
+}
+
+/* initialize the new element
+ * instantiate pads and add them to element
+ * set functions
+ * initialize structure
+ */
+static void
+gst_kate_dec_init (GstKateDec * dec,
+    GstKateDecClass * gclass)
+{
+  GST_DEBUG_OBJECT(dec, "gst_kate_dec_init");
+
+  dec->sinkpad = gst_pad_new_from_static_template ( &sink_factory, "sink");
+  gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR(gst_kate_dec_chain));
+  gst_pad_set_query_function (dec->sinkpad, GST_DEBUG_FUNCPTR (gst_kate_dec_sink_query));
+  gst_pad_use_fixed_caps(dec->sinkpad);
+  gst_pad_set_caps(dec->sinkpad, gst_static_pad_template_get_caps(&sink_factory));
+  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+
+  dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+  dec->silent = FALSE;
+  dec->remove_markup = FALSE;
+  dec->initialized = FALSE;
+}
+
+static void
+gst_kate_dec_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstKateDec *filter = GST_KATE_DEC (object);
+
+  switch (prop_id) {
+    case ARG_SILENT:
+      filter->silent = g_value_get_boolean (value);
+      break;
+    case ARG_REMOVE_MARKUP:
+      filter->remove_markup = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_kate_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstKateDec *filter = GST_KATE_DEC (object);
+
+  switch (prop_id) {
+    case ARG_SILENT:
+      g_value_set_boolean (value, filter->silent);
+      break;
+    case ARG_REMOVE_MARKUP:
+      g_value_set_boolean (value, filter->remove_markup);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstElement vmethod implementations */
+
+/* chain function
+ * this function does the actual processing
+ */
+
+static GstFlowReturn
+gst_kate_dec_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstKateDec *kd = GST_KATE_DEC (gst_pad_get_parent (pad));
+  kate_packet kp;
+  const kate_event *ev = NULL;
+  int ret;
+  GstFlowReturn rflow = GST_FLOW_OK;
+
+  GST_LOG_OBJECT(kd, "got packet, %u bytes, type %02x",
+      GST_BUFFER_SIZE(buf), GST_BUFFER_SIZE(buf)==0 ? -1 : GST_BUFFER_DATA(buf)[0]);
+  kate_packet_wrap(&kp, GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
+  ret = kate_high_decode_packetin(&kd->k, &kp, &ev);
+  if (ret < 0) {
+    GST_WARNING_OBJECT(kd, "kate_high_decode_packetin failed (%d)", ret);
+    gst_object_unref(kd);
+    return GST_FLOW_ERROR;
+  }
+  else if (ret>0) {
+    GST_DEBUG_OBJECT(kd, "kate_high_decode_packetin has received EOS packet");
+    gst_object_unref(kd);
+    return GST_FLOW_OK;
+  }
+
+  /* headers may be interesting to retrieve information from */
+  if (GST_BUFFER_SIZE(buf) > 0) switch (GST_BUFFER_DATA(buf)[0]) {
+    GstCaps *caps;
+    case 0x80: /* ID header */
+      GST_INFO_OBJECT(kd, "Parsed ID header: language %s, category %s", kd->k.ki->language, kd->k.ki->category);
+      caps = gst_caps_new_simple(kd->remove_markup ? "text/plain" : "text/x-pango-markup", NULL);
+      gst_pad_set_caps(kd->srcpad, caps);
+      gst_caps_unref(caps);
+      if (kd->k.ki->language) {
+        GstTagList *tags = gst_tag_list_new();
+        if (tags) {
+          gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE, kd->k.ki->language, NULL);
+          gst_element_found_tags_for_pad(GST_ELEMENT_CAST(kd), kd->srcpad, tags);
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (ev) {
+    gchar *escaped;
+    GstBuffer *buffer;
+    size_t len;
+
+    if (kd->remove_markup) {
+      size_t len0 = ev->len0;
+      escaped = g_strdup(ev->text);
+      kate_text_remove_markup(ev->text_encoding, escaped, &len0);
+    }
+    else {
+      /* no pango markup yet, escape text */
+      /* TODO: actually do the pango thing */
+      escaped = g_markup_printf_escaped("%s", ev->text);
+    }
+
+    len = strlen(escaped);
+    GST_DEBUG_OBJECT(kd, "kate event: %s, escaped %s", ev->text, escaped);
+    buffer = gst_buffer_new_and_alloc(len+1);
+    if (buffer) {
+      /* allocate and copy the NULs, but don't include them in passed size */
+      memcpy(GST_BUFFER_DATA(buffer), escaped, len+1);
+      GST_BUFFER_SIZE(buffer) = len;
+      GST_BUFFER_TIMESTAMP(buffer) = ev->start_time*GST_SECOND;
+      GST_BUFFER_DURATION(buffer) = (ev->end_time-ev->start_time)*GST_SECOND;
+      gst_buffer_set_caps(buffer, GST_PAD_CAPS(kd->srcpad));
+      rflow = gst_pad_push(kd->srcpad, buffer);
+      if (rflow == GST_FLOW_NOT_LINKED) {
+        GST_DEBUG_OBJECT (kd, "source pad not linked, ignored");
+      }
+      else if (rflow != GST_FLOW_OK) {
+        GST_WARNING_OBJECT (kd, "failed to push buffer: %s", gst_flow_get_name(rflow));
+      }
+    }
+    else {
+      GST_WARNING_OBJECT (kd, "failed to create buffer");
+      rflow = GST_FLOW_ERROR;
+    }
+    g_free(escaped);
+  }
+  gst_object_unref(kd);
+  return rflow;
+}
+
+static GstStateChangeReturn
+gst_kate_dec_change_state (GstElement * element, GstStateChange transition)
+{
+  GstKateDec *kd = GST_KATE_DEC (element);
+  GstStateChangeReturn res;
+  int ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      GST_DEBUG_OBJECT (kd, "READY -> PAUSED, initializing kate state");
+      ret = kate_high_decode_init (&kd->k);
+      if (ret < 0) {
+        GST_WARNING_OBJECT (kd, "failed to initialize kate state: %d", ret);
+      }
+      kd->initialized = TRUE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  res = parent_class->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_DEBUG_OBJECT (kd, "PAUSED -> READY, clearing kate state");
+      if (kd->initialized) {
+        kate_high_decode_clear (&kd->k);
+        kd->initialized = FALSE;
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return res;
+}
+
+static GstClockTime
+gst_kate_dec_granule_time(kate_state *k, gint64 granulepos)
+{
+  float t;
+
+  if (granulepos == -1)
+    return -1;
+
+  t = kate_granule_time(k->ki, granulepos);
+  return t*GST_SECOND;
+}
+
+/*
+conversions on the sink:
+  - default is granules at num/den rate
+  - time <-> default is possible
+  - bytes do not mean anything, packets can be any number of bytes, and we
+    have no way to know the number of bytes emitted without decoding
+conversions on the source:
+  - nothing
+*/
+
+static gboolean
+gst_kate_dec_convert(GstPad *pad, GstFormat src_fmt, gint64 src_val, GstFormat *dest_fmt, gint64 *dest_val)
+{
+  GstKateDec *kd;
+  gboolean res = FALSE;
+
+  if (src_fmt == *dest_fmt) {
+    *dest_val = src_val;
+    return TRUE;
+  }
+
+  kd = GST_KATE_DEC (gst_pad_get_parent (pad));
+
+  if (!kd->initialized) {
+    GST_WARNING_OBJECT(kd, "not initialized yet");
+    gst_object_unref(kd);
+    return FALSE;
+  }
+
+  if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
+    GST_WARNING_OBJECT(kd, "unsupported format");
+    gst_object_unref(kd);
+    return FALSE;
+  }
+
+  switch (src_fmt) {
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_fmt) {
+        case GST_FORMAT_TIME:
+          *dest_val = gst_kate_dec_granule_time(&kd->k, src_val);
+          res = TRUE;
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_fmt) {
+        case GST_FORMAT_DEFAULT:
+          // TODO
+          GST_DEBUG_OBJECT(kd, "can't convert time to granpos - backlink needed");
+          res = FALSE;
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+
+  gst_object_unref(kd);
+  return res;
+}
+
+#if 0
+static const GstQueryType *
+gst_kate_dec_query_type (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_CONVERT,
+    0
+  };
+
+  return types;
+}
+#endif
+
+static gboolean gst_kate_dec_sink_query(GstPad * pad, GstQuery * query)
+{
+  switch (GST_QUERY_TYPE(query)) {
+    case GST_QUERY_CONVERT:
+      {
+        GstFormat src_fmt, dest_fmt;
+        gint64 src_val, dest_val;
+
+        gst_query_parse_convert(query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+        if (!gst_kate_dec_convert(pad, src_fmt, src_val, &dest_fmt, &dest_val)) {
+          return gst_pad_query_default(pad, query);
+        }
+        gst_query_set_convert(query, src_fmt, src_val, dest_fmt, dest_val);
+        return TRUE;
+      }
+    default:
+      return gst_pad_query_default(pad, query);
+  }
+}
+
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkatedec.h	2008-03-30 18:21:39.000000000 +0100
@@ -0,0 +1,91 @@
+/*
+ * GStreamer
+ * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright 2008 ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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_KATE_DEC_H__
+#define __GST_KATE_DEC_H__
+
+#include <gst/gst.h>
+#include <kate/kate.h>
+
+G_BEGIN_DECLS
+
+/* #defines don't like whitespacey bits */
+#define GST_TYPE_KATE_DEC \
+  (gst_kate_dec_get_type())
+#define GST_KATE_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_KATE_DEC,GstKateDec))
+#define GST_KATE_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_KATE,GstKateDecClass))
+#define GST_IS_KATE_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_KATE_DEC))
+#define GST_IS_KATE_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_KATE_DEC))
+
+typedef struct _GstKateDec      GstKateDec;
+typedef struct _GstKateDecClass GstKateDecClass;
+
+struct _GstKateDec
+{
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  kate_state k;
+
+  gboolean silent;
+  gboolean remove_markup;
+  gboolean initialized;
+};
+
+struct _GstKateDecClass 
+{
+  GstElementClass parent_class;
+};
+
+GType gst_kate_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_KATE_DEC_H__ */
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkateparse.c	2008-04-02 23:40:39.000000000 +0100
@@ -0,0 +1,590 @@
+/* GStreamer
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) 2006 Andy Wingo <wingo@pobox.com>
+ * Copyright (C) 2008 ogg.k.ogg.k <ogg.k.ogg.k@googlemail.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:element-kateparse
+ * @short_description: parses kate streams 
+ * @see_also: katedec, vorbisparse, oggdemux, theoraparse
+ *
+ * <refsect2>
+ * <para>
+ * The kateparse element will parse the header packets of the Kate
+ * stream and put them as the streamheader in the caps. This is used in the
+ * multifdsink case where you want to stream live kate streams to multiple
+ * clients, each client has to receive the streamheaders first before they can
+ * consume the kate packets.
+ * </para>
+ * <para>
+ * This element also makes sure that the buffers that it pushes out are properly
+ * timestamped and that their offset and offset_end are set. The buffers that
+ * kateparse outputs have all of the metadata that oggmux expects to receive,
+ * which allows you to (for example) remux an ogg/kate file.
+ * </para>
+ * <title>Example pipelines</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v filesrc location=kate.ogg ! oggdemux ! kateparse ! fakesink
+ * </programlisting>
+ * This pipeline shows that the streamheader is set in the caps, and that each
+ * buffer has the timestamp, duration, offset, and offset_end set.
+ * </para>
+ * <para>
+ * <programlisting>
+ * gst-launch filesrc location=kate.ogg ! oggdemux ! kateparse \
+ *            ! oggmux ! filesink location=kate-remuxed.ogg
+ * </programlisting>
+ * This pipeline shows remuxing. kate-remuxed.ogg might not be exactly the same
+ * as kate.ogg, but they should produce exactly the same decoded data.
+ * </para>
+ * </refsect2>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstkate.h"
+#include "gstkateparse.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_kateparse_debug);
+#define GST_CAT_DEFAULT gst_kateparse_debug
+
+static const GstElementDetails gst_kate_parse_details = {
+  "KateParse",
+  "Codec/Parser/Text",
+  "parse raw kate streams",
+  "ogg.k.ogg.k <ogg.k.ogg.k at googlemail dot com>"
+};
+
+static GstStaticPadTemplate gst_kate_parse_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_KATE_MIME_TYPE)
+    );
+
+static GstStaticPadTemplate gst_kate_parse_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_KATE_MIME_TYPE)
+    );
+
+GST_BOILERPLATE (GstKateParse, gst_kate_parse, GstElement,
+    GST_TYPE_ELEMENT);
+
+static GstFlowReturn gst_kate_parse_chain (GstPad * pad, GstBuffer * buffer);
+static GstStateChangeReturn gst_kate_parse_change_state (GstElement * element,
+    GstStateChange transition);
+static gboolean gst_kate_parse_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_kate_parse_src_query (GstPad * pad, GstQuery * query);
+static gboolean gst_kate_parse_convert (GstPad * pad,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value);
+static GstFlowReturn gst_kate_parse_parse_packet (GstKateParse * parse,
+    GstBuffer * buf);
+
+static void
+gst_kate_parse_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_kate_parse_src_factory));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_kate_parse_sink_factory));
+  gst_element_class_set_details (element_class, &gst_kate_parse_details);
+}
+
+static void
+gst_kate_parse_class_init (GstKateParseClass * klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gstelement_class->change_state = gst_kate_parse_change_state;
+
+  klass->parse_packet = GST_DEBUG_FUNCPTR (gst_kate_parse_parse_packet);
+}
+
+static void
+gst_kate_parse_init (GstKateParse * parse, GstKateParseClass * g_class)
+{
+  parse->sinkpad =
+      gst_pad_new_from_static_template (&gst_kate_parse_sink_factory, "sink");
+  gst_pad_set_chain_function (parse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_kate_parse_chain));
+  gst_pad_set_event_function (parse->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_kate_parse_sink_event));
+  gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
+
+  parse->srcpad =
+      gst_pad_new_from_static_template (&gst_kate_parse_src_factory, "src");
+  gst_pad_set_query_function (parse->srcpad,
+      GST_DEBUG_FUNCPTR (gst_kate_parse_src_query));
+  gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
+}
+
+static void
+gst_kate_parse_set_header_on_caps (GstKateParse * parse, GstCaps * caps)
+{
+  GstBuffer *buf;
+  GstStructure *structure;
+  GList *headers;
+  GValue array = { 0 };
+  GValue value = { 0 };
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  g_assert (parse);
+  g_assert (parse->streamheader);
+  headers = parse->streamheader;
+  g_value_init (&array, GST_TYPE_ARRAY);
+  while (headers) {
+    g_assert(headers->data);
+    buf = headers->data;
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+    g_value_init (&value, GST_TYPE_BUFFER);
+    gst_value_set_buffer (&value, buf);
+    gst_value_array_append_value (&array, &value);
+    if (!headers->next) {
+      gst_structure_set_value (structure, "streamheader", &array);
+    }
+    g_value_unset (&value);
+    headers = headers->next;
+  }
+  g_value_unset (&array);
+}
+
+static void
+gst_kate_parse_drain_event_queue (GstKateParse * parse)
+{
+  while (parse->event_queue->length) {
+    GstEvent *event;
+
+    event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
+    gst_pad_event_default (parse->sinkpad, event);
+  }
+}
+
+static void
+gst_kate_parse_push_headers (GstKateParse * parse)
+{
+  /* mark and put on caps */
+  GstCaps *caps;
+  GstBuffer *outbuf;
+  kate_packet packet;
+  GList *headers, *outbuf_list = NULL;
+  int ret;
+
+  /* get the headers into the caps, passing them to kate as we go */
+  caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
+  gst_kate_parse_set_header_on_caps (parse, caps);
+  GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
+  gst_pad_set_caps (parse->srcpad, caps);
+  gst_caps_unref (caps);
+
+  headers = parse->streamheader;
+  while (headers) {
+    outbuf = GST_BUFFER_CAST (headers->data);
+    kate_packet_wrap(&packet, GST_BUFFER_SIZE (outbuf), GST_BUFFER_DATA (outbuf));
+    ret = kate_decode_headerin (&parse->ki, &parse->kc, &packet);
+    if (ret<0) {
+      GST_WARNING_OBJECT(parse, "kate_decode_headerin returned %d", ret);
+    }
+    outbuf_list = g_list_append (outbuf_list, outbuf);
+    headers = headers->next;
+  }
+
+  /* first process queued events */
+  gst_kate_parse_drain_event_queue (parse);
+
+  /* push out buffers, ignoring return value... */
+  headers = outbuf_list;
+  while (headers) {
+    outbuf = GST_BUFFER_CAST (headers->data);
+    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (parse->srcpad));
+    gst_pad_push (parse->srcpad, outbuf);
+    headers = headers->next;
+  }
+
+  g_list_free(outbuf_list);
+  g_list_free (parse->streamheader);
+  parse->streamheader = NULL;
+
+  parse->streamheader_sent = TRUE;
+}
+
+static void
+gst_kate_parse_clear_queue (GstKateParse * parse)
+{
+  while (parse->buffer_queue->length) {
+    GstBuffer *buf;
+
+    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
+    gst_buffer_unref (buf);
+  }
+  while (parse->event_queue->length) {
+    GstEvent *event;
+
+    event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
+    gst_event_unref (event);
+  }
+}
+
+static GstFlowReturn
+gst_kate_parse_push_buffer (GstKateParse * parse, GstBuffer * buf,
+    gint64 granulepos)
+{
+  /* oggmux uses the offset end as a granpos, and offset/timestamp as
+     the actual time - humor it */
+  GST_LOG_OBJECT(parse, "granulepos %16llx", granulepos);
+  GST_WARNING_OBJECT(parse, "gst_kate_parse_push_buffer");
+  GST_BUFFER_OFFSET (buf) = kate_granule_time(&parse->ki, granulepos)*GST_SECOND;
+  GST_BUFFER_OFFSET_END (buf) = granulepos;
+  GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_OFFSET (buf);
+  GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DISCONT);
+
+  gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
+
+  return gst_pad_push (parse->srcpad, buf);
+}
+
+static GstFlowReturn
+gst_kate_parse_drain_queue_prematurely (GstKateParse * parse)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* got an EOS event, make sure to push out any buffers that were in the queue
+   * -- won't normally be the case, but this catches the
+   * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
+   * stream. */
+
+  /* if we got EOS before any buffers came, go ahead and push the other events
+   * first */
+  gst_kate_parse_drain_event_queue (parse);
+
+  if (!g_queue_is_empty (parse->buffer_queue)) {
+    GstBuffer *buf;
+    gint64 granpos;
+
+    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
+
+    granpos = GST_BUFFER_OFFSET_END(buf);
+    ret = gst_kate_parse_push_buffer (parse, buf, granpos);
+
+    if (ret != GST_FLOW_OK)
+      goto done;
+  }
+
+  g_assert(g_queue_is_empty(parse->buffer_queue));
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_kate_parse_drain_queue (GstKateParse * parse, gint64 granulepos)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (!g_queue_is_empty (parse->buffer_queue)) {
+    GstBuffer *buf;
+    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
+    ret = gst_kate_parse_push_buffer (parse, buf, granulepos);
+
+    if (ret != GST_FLOW_OK)
+      goto done;
+  }
+  g_assert (g_queue_is_empty (parse->buffer_queue));
+
+done:
+  return ret;
+}
+
+static GstFlowReturn
+gst_kate_parse_queue_buffer (GstKateParse * parse, GstBuffer * buf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint64 granpos;
+
+  buf = gst_buffer_make_metadata_writable (buf);
+
+  /* oggdemux stores the granule pos in the offset end, assuming all streams are
+     end pos timed as vorbis and theora are, and I can't fix it because there is
+     no way to determine whether a codec times by start or end time unless you
+     know which codec - and kate is in bad so oggdemux can't know about it */
+  granpos = GST_BUFFER_OFFSET_END(buf);
+  GST_LOG_OBJECT(parse, "granpos %16llx", granpos);
+  g_queue_push_tail (parse->buffer_queue, buf);
+
+  g_assert (granpos >= 0);
+  ret = gst_kate_parse_drain_queue (parse, granpos);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_kate_parse_parse_packet (GstKateParse * parse, GstBuffer * buf)
+{
+  GstFlowReturn ret;
+
+  parse->packetno++;
+
+  if (GST_BUFFER_SIZE(buf)>0 && GST_BUFFER_DATA(buf)[0] & 0x80) {
+    GST_DEBUG_OBJECT(parse, "Found header %02x", GST_BUFFER_DATA(buf)[0]);
+    /* if 0x80 is set, it's streamheader,
+     * so put it on the streamheader list and return */
+    parse->streamheader = g_list_append (parse->streamheader, buf);
+    ret = GST_FLOW_OK;
+  } else {
+    if (!parse->streamheader_sent) {
+      GST_DEBUG_OBJECT(parse, "Found non header, pushing headers seen so far");
+      gst_kate_parse_push_headers (parse);
+    }
+
+    ret = gst_kate_parse_queue_buffer (parse, buf);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_kate_parse_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstKateParseClass *klass;
+  GstKateParse *parse;
+
+  parse = GST_KATE_PARSE (GST_PAD_PARENT (pad));
+  klass = GST_KATE_PARSE_CLASS (G_OBJECT_GET_CLASS (parse));
+
+  g_assert (klass->parse_packet != NULL);
+
+  return klass->parse_packet (parse, buffer);
+}
+
+static gboolean
+gst_kate_parse_queue_event (GstKateParse * parse, GstEvent * event)
+{
+  GstFlowReturn ret = TRUE;
+
+  g_queue_push_tail (parse->event_queue, event);
+
+  return ret;
+}
+
+static gboolean
+gst_kate_parse_sink_event (GstPad * pad, GstEvent * event)
+{
+  gboolean ret;
+  GstKateParse *parse;
+
+  parse = GST_KATE_PARSE (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      gst_kate_parse_clear_queue (parse);
+      ret = gst_pad_event_default (pad, event);
+      break;
+    case GST_EVENT_EOS:
+      gst_kate_parse_drain_queue_prematurely (parse);
+      ret = gst_pad_event_default (pad, event);
+      break;
+    default:
+      if (!parse->streamheader_sent && GST_EVENT_IS_SERIALIZED (event))
+        ret = gst_kate_parse_queue_event (parse, event);
+      else
+        ret = gst_pad_event_default (pad, event);
+      break;
+  }
+
+  gst_object_unref (parse);
+
+  return ret;
+}
+
+static gboolean
+gst_kate_parse_convert (GstPad * pad,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value)
+{
+  gboolean res = TRUE;
+  GstKateParse *parse;
+
+  parse = GST_KATE_PARSE (GST_PAD_PARENT (pad));
+
+  /* fixme: assumes atomic access to lots of instance variables modified from
+   * the streaming thread, including 64-bit variables */
+
+  if (!parse->streamheader_sent)
+    return FALSE;
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  if (parse->sinkpad == pad &&
+      (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
+    return FALSE;
+
+  switch (src_format) {
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          *dest_value = kate_granule_time(&parse->ki, src_value) * GST_SECOND;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+  }
+
+  return res;
+}
+
+static gboolean
+gst_kate_parse_src_query (GstPad * pad, GstQuery * query)
+{
+#if 1
+  // TODO
+  GST_WARNING("gst_kate_parse_src_query");
+  return FALSE;
+#else
+  gint64 granulepos;
+  GstKateParse *parse;
+  gboolean res = FALSE;
+
+  parse = GST_KATE_PARSE (GST_PAD_PARENT (pad));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+    {
+      GstFormat format;
+      gint64 value;
+
+      granulepos = parse->prev_granulepos;
+
+      gst_query_parse_position (query, &format, NULL);
+
+      /* and convert to the final format */
+      if (!(res =
+              gst_kate_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos,
+                  &format, &value)))
+        goto error;
+
+      /* fixme: support segments
+         value = (value - parse->segment_start) + parse->segment_time;
+       */
+
+      gst_query_set_position (query, format, value);
+
+      GST_LOG_OBJECT (parse, "query %p: peer returned granulepos: %"
+          G_GUINT64_FORMAT " - we return %" G_GUINT64_FORMAT " (format %u)",
+          query, granulepos, value, format);
+
+      break;
+    }
+    case GST_QUERY_DURATION:
+    {
+      /* fixme: not threadsafe */
+      /* query peer for total length */
+      if (!gst_pad_is_linked (parse->sinkpad)) {
+        GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked",
+            parse->sinkpad);
+        goto error;
+      }
+      if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query)))
+        goto error;
+      break;
+    }
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      if (!(res =
+              gst_kate_parse_convert (pad, src_fmt, src_val, &dest_fmt,
+                  &dest_val)))
+        goto error;
+      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, query);
+      break;
+  }
+  return res;
+
+error:
+  {
+    GST_WARNING_OBJECT (parse, "error handling query");
+    return res;
+  }
+#endif
+}
+
+static GstStateChangeReturn
+gst_kate_parse_change_state (GstElement * element, GstStateChange transition)
+{
+  GstKateParse *parse = GST_KATE_PARSE (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      kate_info_init (&parse->ki);
+      kate_comment_init (&parse->kc);
+      parse->packetno = 0;
+      parse->streamheader_sent = FALSE;
+      parse->buffer_queue = g_queue_new ();
+      parse->event_queue = g_queue_new ();
+      break;
+    default:
+      break;
+  }
+
+  ret = parent_class->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      kate_info_clear (&parse->ki);
+      kate_comment_clear (&parse->kc);
+      gst_kate_parse_clear_queue (parse);
+      g_queue_free (parse->buffer_queue);
+      parse->buffer_queue = NULL;
+      g_queue_free (parse->event_queue);
+      parse->event_queue = NULL;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/gstkateparse.h	2008-04-02 23:40:47.000000000 +0100
@@ -0,0 +1,79 @@
+/* -*- c-basic-offset: 2 -*-
+ * GStreamer
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) <2008> ogg.k.ogg.k <ogg.k.ogg.k at googlemail dot com>
+ *
+ * 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_KATE_PARSE_H__
+#define __GST_KATE_PARSE_H__
+
+
+#include <gst/gst.h>
+#include <kate/kate.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_KATE_PARSE \
+  (gst_kate_parse_get_type())
+#define GST_KATE_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_KATE_PARSE,GstKateParse))
+#define GST_KATE_PARSE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_KATE_PARSE,GstKateParseClass))
+#define GST_IS_KATE_PARSE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_KATE_PARSE))
+#define GST_IS_KATKATEE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_KATE_PARSE))
+
+typedef struct _GstKateParse GstKateParse;
+typedef struct _GstKateParseClass GstKateParseClass;
+
+/**
+ * GstKateParse:
+ *
+ * Opaque data structure.
+ */
+struct _GstKateParse {
+  GstElement            element;
+
+  GstPad *              sinkpad;
+  GstPad *              srcpad;
+
+  guint                 packetno;
+  gboolean              streamheader_sent;
+  GList *               streamheader;
+
+  GQueue *		event_queue;
+  GQueue *		buffer_queue;
+
+  kate_info		ki;
+  kate_comment	        kc;
+};
+
+struct _GstKateParseClass {
+  GstElementClass parent_class;
+
+  /* virtual functions */
+  GstFlowReturn  (*parse_packet) (GstKateParse * parse, GstBuffer * buf);
+};
+
+GType gst_kate_parse_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_KATE_PARSE_H__ */
--- /dev/null	2008-03-26 19:55:28.536647000 +0000
+++ gst-plugins-bad-0.10.6/ext/kate/Makefile.am	2008-04-02 19:45:25.000000000 +0100
@@ -0,0 +1,15 @@
+# plugindir is set in configure
+
+plugin_LTLIBRARIES = libgstkate.la
+
+# sources used to compile this plug-in
+libgstkate_la_SOURCES = gstkate.c gstkatedec.c gstkateparse.c
+
+# flags used to compile this plugin
+# add other _CFLAGS and _LIBS as needed
+libgstkate_la_CFLAGS = $(GST_CFLAGS)
+libgstkate_la_LIBADD = $(GST_LIBS) $(KATE_LIBS)
+libgstkate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+# headers we need but don't want installed
+noinst_HEADERS = gstkatedec.h gstkateparse.h
