Index: gst/matroska/matroska-mux.c
===================================================================
--- gst/matroska/matroska-mux.c	(revision 476)
+++ gst/matroska/matroska-mux.c	(working copy)
@@ -1,6 +1,7 @@
 /* GStreamer Matroska muxer/demuxer
  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
  * (c) 2005 Michal Benes <michal.benes@xeris.cz>
+ * (c) 2007 Mark Nauwelaerts <mnauw@users.sourceforge.net>
  *
  * matroska-mux.c: matroska file/stream muxer
  *
@@ -121,10 +122,13 @@
     );
 
 static GstStaticPadTemplate subtitlesink_templ =
-GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
+    GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
     GST_PAD_SINK,
     GST_PAD_REQUEST,
-    GST_STATIC_CAPS_ANY);
+    GST_STATIC_CAPS ("text/plain; application/x-ssa; application/x-ass; "
+        "application/x-usf; video/x-dvd-subpicture; "
+        "application/x-subtitle-unknown")
+    );
 
 static GArray *used_uids;
 
@@ -136,9 +140,11 @@
 /* Matroska muxer destructor */
 static void gst_matroska_mux_finalize (GObject * object);
 
-/* Pads collected callback */
-static GstFlowReturn
-gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
+/* MuxPads collected callback */
+static gboolean gst_matroska_mux_handle_sink_event (GstMuxPads * muxpads,
+    GstMuxData * data, GstEvent * event, GstMatroskaMux * mux);
+static GstFlowReturn gst_matroska_mux_handle_buffer (GstMuxPads * muxpads,
+    GstMuxData * data, GstBuffer * buffer, GstMatroskaMux * mux);
 
 /* pad functions */
 static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
@@ -250,9 +256,12 @@
   gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
   gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
 
-  mux->collect = gst_collect_pads_new ();
-  gst_collect_pads_set_function (mux->collect,
-      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
+  mux->collect = (GstCollectPads *) gst_mux_pads_new ();
+  gst_mux_pads_set_event_function ((GstMuxPads *) mux->collect,
+      (GstMuxPadsEventFunction)
+      GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
+  gst_mux_pads_set_function ((GstMuxPads *) mux->collect,
+      (GstMuxPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer),
       mux);
 
   mux->ebml_write = gst_ebml_write_new (mux->srcpad);
@@ -367,13 +376,13 @@
     GstPad *thepad;
 
     collect_pad = (GstMatroskaPad *) walk->data;
-    thepad = collect_pad->collect.pad;
+    thepad = collect_pad->collect.collect_data.pad;
 
     /* free collect pad resources */
     gst_matroska_pad_free (collect_pad);
 
     /* remove from collectpads */
-    gst_collect_pads_remove_pad (mux->collect, thepad);
+    gst_mux_pads_remove_pad ((GstMuxPads *) mux->collect, thepad);
   }
   mux->num_streams = 0;
   mux->num_a_streams = 0;
@@ -424,7 +433,7 @@
  * @pad: Pad which received the event.
  * @event: Received event.
  *
- * handle events - copied from oggmux without understanding 
+ * handle events - copied from oggmux without understanding
  *
  * Returns: #TRUE on success.
  */
@@ -446,33 +455,67 @@
   return gst_pad_event_default (pad, event);
 }
 
-/**
- * gst_matroska_mux_handle_sink_event:
- * @pad: Pad which received the event.
- * @event: Received event.
+ /**
+ * gst_matroska_mux_build_vobsub_private:
+ * @context: #GstMatroskaTrackContext of stream
+ * @clut: a received DVD palette colour table
  *
- * handle events - informational ones like tags
+ * Builds Matroska private data for a VobSub subtitle stream.
  *
- * Returns: #TRUE on success.
  */
+static void
+gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
+    const guint * clut)
+{
+  gchar *clutv[17];
+  gchar *sclut;
+  gint i;
+
+  /* produce comma-separated list in hex format */
+  for (i = 0; i < 16; ++i) {
+    clutv[i] = g_strdup_printf ("%06x", clut[i]);
+  }
+  clutv[i] = NULL;
+  sclut = g_strjoinv (",", clutv);
+
+  /* build codec private; only palette for now */
+  g_free (context->codec_priv);
+  context->codec_priv = g_strdup_printf ("palette: %s", sclut);
+  /* include terminating 0 */
+  context->codec_priv_size = strlen (context->codec_priv) + 1;
+  g_free (sclut);
+  for (i = 0; i < 16; ++i) {
+    g_free (clutv[i]);
+  }
+}
+
+ /**
+ * gst_matroska_mux_handle_buffer:
+ * @muxpads: #GstMuxPads
+ * @data: #GstMuxData whose pad received event
+ * @buffer: event received
+ * @mux: #GstMatroskaMux
+ *
+ * Muxpads callback.
+ *
+ * Returns: #TRUE if event completely dealt with
+ */
 static gboolean
-gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
+gst_matroska_mux_handle_sink_event (GstMuxPads * muxpads, GstMuxData * data,
+    GstEvent * event, GstMatroskaMux * mux)
 {
   GstMatroskaTrackContext *context;
   GstMatroskaPad *collect_pad;
-  GstMatroskaMux *mux;
   GstTagList *list;
-  gboolean ret;
 
-  mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
+  collect_pad = (GstMatroskaPad *) data;
+  g_assert (collect_pad);
+  context = collect_pad->track;
+  g_assert (context);
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_TAG:
       gst_event_parse_tag (event, &list);
-      collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
-      g_assert (collect_pad);
-      context = collect_pad->track;
-      g_assert (context);
       /* FIXME ?
        * strictly speaking, the incoming language code may only be 639-1, so not
        * 639-2 according to matroska specs, but it will have to do for now */
@@ -485,15 +528,42 @@
       }
 
       break;
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    {
+      const GstStructure *structure;
+
+      structure = gst_event_get_structure (event);
+      if (structure != NULL &&
+          gst_structure_has_name (structure, "application/x-gst-dvd") &&
+          !strcmp("dvd-spu-clut-change",
+              gst_structure_get_string (structure, "event"))) {
+        gchar name[16];
+        gint i, value;
+        guint clut[16];
+
+        GST_DEBUG_OBJECT (mux, "New DVD colour table received");
+        /* first transform event data into table form */
+        for (i = 0; i < 16; i++) {
+          g_snprintf (name, sizeof (name), "clut%02d", i);
+          if (!gst_structure_get_int (structure, name, &value)) {
+            GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
+                "contain %s field", name);
+           break;
+          }
+          clut[i] = value;
+        }
+
+        /* transform into private data for stream; text form */
+        gst_matroska_mux_build_vobsub_private (context, clut);
+      }
+      break;
+    }
     default:
       break;
   }
 
-  /* now GstCollectPads can take care of the rest, e.g. EOS */
-  ret = mux->collect_event (pad, event);
-  gst_object_unref (mux);
-
-  return ret;
+  /* we had our peek, let parents take care of usual stuff */
+  return FALSE;
 }
 
 
@@ -1061,6 +1131,11 @@
 }
 
 
+/* we probably don't have the data at start,
+ * so have to reserve (a maximum) space to write this at the end.
+ * bit spacy, but some formats can hold quite some */
+#define SUBTITLE_MAX_CODEC_PRIVATE   2048    /* must be > 128 */
+
 /**
  * gst_matroska_mux_subtitle_pad_setcaps:
  * @pad: Pad which got the caps.
@@ -1073,11 +1148,71 @@
 static gboolean
 gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
 {
-  /* Consider this as boilerplate code for now. There is
-   * no single subtitle creation element in GStreamer,
-   * neither do I know how subtitling works at all. */
+  GstMatroskaTrackContext *context = NULL;
+  GstMatroskaTrackSubtitleContext *subtitlecontext;
+  GstMatroskaMux *mux;
+  GstMatroskaPad *collect_pad;
+  const gchar *mimetype;
+  GstStructure *structure;
+  gconstpointer codec_data;
 
-  return FALSE;
+  mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
+
+  /* find context */
+  collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+  g_assert (collect_pad);
+  context = collect_pad->track;
+  g_assert (context);
+  g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE);
+  subtitlecontext = (GstMatroskaTrackSubtitleContext *) context;
+
+  structure = gst_caps_get_structure (caps, 0);
+  mimetype = gst_structure_get_name (structure);
+
+  /* first clear the default set in request_pad */
+  g_free (context->codec_id);
+  context->codec_id = NULL;
+
+  /* get the proper codec_id */
+  if (!strcmp (mimetype, "text/plain")) {
+    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
+  } else if (!strcmp (mimetype, "application/x-ssa")) {
+    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
+  } else if (!strcmp (mimetype, "application/x-ass")) {
+    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
+  } else if (!strcmp (mimetype, "application/x-usf")) {
+    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
+  } else if (!strcmp (mimetype, "video/x-dvd-subpicture")) {
+    context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
+  } else
+    return FALSE;
+
+  /* maybe some private data, e.g. vobsub */
+  codec_data = gst_structure_get_value (structure, "codec_data");
+  if (codec_data != NULL) {
+    guint8 *priv_data = NULL;
+    guint priv_data_size = 0;
+    GstBuffer *codec_data_buf;
+
+    codec_data_buf = g_value_peek_pointer (codec_data);
+    priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
+    if (priv_data_size > SUBTITLE_MAX_CODEC_PRIVATE) {
+      GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
+          " exceeded maximum (%d); discarding", pad,
+          SUBTITLE_MAX_CODEC_PRIVATE);
+      return TRUE;
+    }
+
+    if (context->codec_priv != NULL)
+      g_free (context->codec_priv);
+
+    priv_data = g_malloc0 (priv_data_size);
+    memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
+    context->codec_priv = priv_data;
+    context->codec_priv_size = priv_data_size;
+  }
+
+  return TRUE;
 }
 
 
@@ -1102,6 +1237,7 @@
   gchar *name = NULL;
   GstPadSetCapsFunction setcapsfunc = NULL;
   GstMatroskaTrackContext *context = NULL;
+  gboolean locked = TRUE;
 
   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
     name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
@@ -1124,31 +1260,26 @@
         g_new0 (GstMatroskaTrackSubtitleContext, 1);
     context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
     context->name = g_strdup ("Subtitle");
+    /* setcaps may only provide proper one a lot later */
+    context->codec_id = g_strdup ("S_SUB_UNKNOWN");
+    locked = FALSE;
   } else {
     GST_WARNING_OBJECT (mux, "This is not our template!");
     return NULL;
   }
 
+  mux->num_streams++;
   newpad = gst_pad_new_from_template (templ, name);
   g_free (name);
   collect_pad = (GstMatroskaPad *)
-      gst_collect_pads_add_pad (mux->collect, newpad, sizeof (GstMatroskaPad));
+      gst_mux_pads_add_pad ((GstMuxPads *) mux->collect, newpad,
+          sizeof (GstMatroskaPad));
+  gst_mux_pads_set_locked ((GstMuxPads *) mux->collect,
+      (GstMuxData *) collect_pad, locked);
   context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
   collect_pad->track = context;
   collect_pad->buffer = NULL;
 
-  /* FIXME: hacked way to override/extend the event function of
-   * GstCollectPads; because it sets its own event function giving the
-   * element no access to events.
-   * TODO GstCollectPads should really give its 'users' a clean chance to
-   * properly handle events that are not meant for collectpads itself.
-   * Perhaps a callback or so, though rejected (?) in #340060.
-   * This would allow (clean) transcoding of info from demuxer/streams
-   * to another muxer */
-  mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
-  gst_pad_set_event_function (newpad,
-      GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
-
   gst_pad_set_setcaps_function (newpad, setcapsfunc);
   gst_pad_set_active (newpad, TRUE);
   gst_element_add_pad (element, newpad);
@@ -1178,8 +1309,9 @@
     if (cdata->pad == pad) {
       if (collect_pad->duration > mux->duration)
         mux->duration = collect_pad->duration;
+      mux->num_streams--;
       gst_matroska_pad_free (collect_pad);
-      gst_collect_pads_remove_pad (mux->collect, pad);
+      gst_mux_pads_remove_pad ((GstMuxPads *) mux->collect, pad);
       gst_element_remove_pad (element, pad);
       return;
     }
@@ -1188,7 +1320,6 @@
   g_warning ("%s: unknown pad %s", GST_FUNCTION, GST_PAD_NAME (pad));
 }
 
-
 /**
  * gst_matroska_mux_track_header:
  * @mux: #GstMatroskaMux
@@ -1217,6 +1348,12 @@
     gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKLANGUAGE,
         context->language);
   }
+  /* FIXME: until we have a nice way of getting the codecname
+   * out of the caps, I'm not going to enable this. Too much
+   * (useless, double, boring) work... */
+  /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
+     context->codec_name); */
+  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
 
   /* type-specific stuff */
   switch (context->type) {
@@ -1268,6 +1405,23 @@
       break;
     }
 
+/* this is what we write here and must be void'ed later on */
+#define SUBTITLE_DUMMY_SIZE   (1 + 1 + 14 + 1 + 2 + SUBTITLE_MAX_CODEC_PRIVATE)
+
+    case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
+      gpointer buf;
+
+      context->pos = ebml->pos;
+      /* CodecID is mandatory ... */
+      gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, "S_SUB_UNKNOWN");
+      /* reserve space */
+      buf = g_malloc0 (SUBTITLE_MAX_CODEC_PRIVATE);
+      gst_ebml_write_binary (ebml, GST_EBML_ID_VOID, buf,
+          SUBTITLE_MAX_CODEC_PRIVATE);
+      g_free (buf);
+      /* real data has to be written at finish */
+      return;
+    }
     default:
       /* doesn't need type-specific data */
       break;
@@ -1277,12 +1431,6 @@
   if (context->codec_priv)
     gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
         context->codec_priv, context->codec_priv_size);
-  /* FIXME: until we have a nice way of getting the codecname
-   * out of the caps, I'm not going to enable this. Too much
-   * (useless, double, boring) work... */
-  /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
-     context->codec_name); */
-  gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
 }
 
 
@@ -1355,7 +1503,7 @@
     gint64 trackduration;
 
     collect_pad = (GstMatroskaPad *) collected->data;
-    thepad = collect_pad->collect.pad;
+    thepad = collect_pad->collect.collect_data.pad;
 
     /* Query the total length of the track. */
     peerpad = gst_pad_get_peer (thepad);
@@ -1391,7 +1539,7 @@
     GstPad *thepad;
 
     collect_pad = (GstMatroskaPad *) collected->data;
-    thepad = collect_pad->collect.pad;
+    thepad = collect_pad->collect.collect_data.pad;
 
     if (gst_pad_is_linked (thepad) && gst_pad_is_active (thepad) &&
         collect_pad->track->codec_id != 0) {
@@ -1593,19 +1741,58 @@
     gst_ebml_write_seek (ebml, my_pos);
   }
 
-  /* update duration */
-  /* first get the overall duration */
-  /* a released track may have left a duration in here */
+  /* loop tracks:
+   * - first get the overall duration
+   *   (a released track may have left a duration in here)
+   * - write some track header data for subtitles
+   */
   duration = mux->duration;
+  pos = ebml->pos;
   for (collected = mux->collect->data; collected;
       collected = g_slist_next (collected)) {
     GstMatroskaPad *collect_pad;
+    GstMatroskaTrackContext *context;
+    gint voidleft = 0, fill = 0;
+    gpointer codec_id;
 
     collect_pad = (GstMatroskaPad *) collected->data;
+    context = collect_pad->track;
 
     if (collect_pad->duration > duration)
       duration = collect_pad->duration;
+
+    if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE || !context->pos)
+      continue;
+
+  again:
+    /* write subtitle type and possible private data */
+    gst_ebml_write_seek (ebml, context->pos);
+    /* complex way to write ascii to account for extra filling */
+    codec_id = g_malloc0 (strlen (context->codec_id) + 1 + fill);
+    strcpy (codec_id, context->codec_id);
+    gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECID,
+        codec_id, strlen (context->codec_id) + 1 + fill);
+    g_free (codec_id);
+    if (context->codec_priv)
+      gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
+          context->codec_priv, context->codec_priv_size);
+    voidleft = SUBTITLE_DUMMY_SIZE - (ebml->pos - context->pos);
+    /* void'ify; sigh, variable sized length field */
+    if (voidleft == 1) {
+      fill = 1;
+      goto again;
+    } else if (voidleft && voidleft <= 128)
+      gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 2);
+    else if (voidleft >= 130)
+      gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 3);
+    else if (voidleft == 129) { /* 129 */
+      gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 64);
+      gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 63);
+    }
   }
+  gst_ebml_write_seek (ebml, pos);
+
+  /* update duration */
   if (duration != 0) {
     pos = mux->ebml_write->pos;
     gst_ebml_write_seek (ebml, mux->duration_pos);
@@ -1620,58 +1807,13 @@
 
 
 /**
- * gst_matroska_mux_best_pad:
- * @mux: #GstMatroskaMux
- * @popped: True if at least one buffer was popped from #GstCollectPads
- *
- * Find a pad with the oldest data 
- * (data from this pad should be written first).
- *
- * Returns: Selected pad.
- */
-static GstMatroskaPad *
-gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
-{
-  GSList *collected;
-  GstMatroskaPad *best = NULL;
-
-  *popped = FALSE;
-  for (collected = mux->collect->data; collected;
-      collected = g_slist_next (collected)) {
-    GstMatroskaPad *collect_pad;
-
-    collect_pad = (GstMatroskaPad *) collected->data;
-    /* fetch a new buffer if needed */
-    if (collect_pad->buffer == NULL) {
-      collect_pad->buffer = gst_collect_pads_pop (mux->collect,
-          (GstCollectData *) collect_pad);
-
-      if (collect_pad->buffer != NULL)
-        *popped = TRUE;
-    }
-
-    /* if we have a buffer check if it is better then the current best one */
-    if (collect_pad->buffer != NULL) {
-      if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
-          || (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
-              && GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
-              GST_BUFFER_TIMESTAMP (best->buffer))) {
-        best = collect_pad;
-      }
-    }
-  }
-
-  return best;
-}
-
-/**
  * gst_matroska_mux_buffer_header:
  * @track: Track context.
  * @relative_timestamp: relative timestamp of the buffer
  * @flags: Buffer flags.
  *
  * Create a buffer containing buffer header.
- * 
+ *
  * Returns: New buffer.
  */
 GstBuffer *
@@ -1719,7 +1861,8 @@
 
   /* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
   if (collect_pad->track->xiph_headers_to_skip > 0) {
-    GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
+    GST_LOG_OBJECT (collect_pad->collect.collect_data.pad,
+        "dropping streamheader buffer");
     gst_buffer_unref (buf);
     --collect_pad->track->xiph_headers_to_skip;
     return GST_FLOW_OK;
@@ -1728,7 +1871,7 @@
   /* hm, invalid timestamp (due to --to be fixed--- element upstream);
    * this would wreak havoc with time stored in matroska file */
   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
-    GST_WARNING_OBJECT (collect_pad->collect.pad,
+    GST_WARNING_OBJECT (collect_pad->collect.collect_data.pad,
         "Invalid buffer timestamp; dropping buffer");
     gst_buffer_unref (buf);
     return GST_FLOW_OK;
@@ -1876,18 +2019,20 @@
 
 
 /**
- * gst_matroska_mux_collected:
- * @pads: #GstCollectPads
- * @uuser_data: #GstMatroskaMux
+ * gst_matroska_mux_handle_buffer:
+ * @muxpads: #GstMuxPads
+ * @data: #GstMuxData
+ * @buffer: next buffer to handle
+ * @mux: #GstMatroskaMux
  *
- * Collectpads callback.
+ * Muxpads callback.
  *
  * Returns: #GstFlowReturn
  */
 static GstFlowReturn
-gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
+gst_matroska_mux_handle_buffer (GstMuxPads * muxpads, GstMuxData * data,
+    GstBuffer * buffer, GstMatroskaMux * mux)
 {
-  GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
   GstMatroskaPad *best;
   gboolean popped;
   GstFlowReturn ret;
@@ -1907,8 +2052,8 @@
   }
 
   do {
-    /* which stream to write from? */
-    best = gst_matroska_mux_best_pad (mux, &popped);
+    /* parent has given stream to write from */
+    best = (GstMatroskaPad *) data;
 
     /* if there is no best pad, we have reached EOS */
     if (best == NULL) {
@@ -1918,8 +2063,11 @@
       ret = GST_FLOW_UNEXPECTED;
       break;
     }
-    GST_DEBUG_OBJECT (best->collect.pad, "best pad");
 
+    best->buffer = buffer;
+    popped = TRUE;
+    GST_DEBUG_OBJECT (best->collect.collect_data.pad, "best pad");
+
     /* write one buffer */
     ret = gst_matroska_mux_write_data (mux, best);
   } while (ret == GST_FLOW_OK && !popped);
@@ -1947,12 +2095,12 @@
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_collect_pads_start (mux->collect);
+      gst_mux_pads_start ((GstMuxPads *) mux->collect);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      gst_collect_pads_stop (mux->collect);
+      gst_mux_pads_stop ((GstMuxPads *) mux->collect);
       break;
     default:
       break;
Index: gst/matroska/matroska-mux.h
===================================================================
--- gst/matroska/matroska-mux.h	(revision 476)
+++ gst/matroska/matroska-mux.h	(working copy)
@@ -25,6 +25,7 @@
 
 #include <gst/gst.h>
 #include <gst/base/gstcollectpads.h>
+#include <gst/base/gstmuxpads.h>
 
 #include "ebml-write.h"
 #include "matroska-ids.h"
@@ -70,7 +71,7 @@
 /* all information needed for one matroska stream */
 typedef struct
 {
-  GstCollectData collect;       /* we extend the CollectData */
+  GstMuxData collect;       /* we extend the MuxData */
   GstMatroskaTrackContext *track;
 
   GstBuffer *buffer;            /* the queued buffer for this pad */
