Index: docs/libs/gstreamer-libs-sections.txt
===================================================================
--- docs/libs/gstreamer-libs-sections.txt	(.../tags/0.10.13/gstreamer/docs)	(revision 456)
+++ docs/libs/gstreamer-libs-sections.txt	(.../branches/0.10.13/gstreamer/docs)	(working copy)
@@ -289,6 +293,41 @@
 
 
 <SECTION>
+<FILE>gstmuxpads</FILE>
+<TITLE>GstMuxPads</TITLE>
+<INCLUDE>gst/base/gstmuxpads.h</INCLUDE>
+GstMuxData
+GstMuxPads
+GstMuxPadsFunction
+GstMuxPadsCollectFunction
+GstMuxPadsEventFunction
+GstMuxPadsCompareFunction
+GstMuxDataDestroyNotify
+gst_mux_pads_new
+gst_mux_pads_set_function
+gst_mux_pads_set_collect_function
+gst_mux_pads_set_event_function
+gst_mux_pads_set_compare_function
+gst_mux_pads_add_pad
+gst_mux_pads_add_pad_full
+gst_mux_pads_remove_pad
+gst_mux_pads_set_locked
+gst_mux_pads_start
+gst_mux_pads_stop
+<SUBSECTION Standard>
+GstMuxPadsClass
+GST_MUX_PADS
+GST_IS_MUX_PADS
+GST_TYPE_MUX_PADS
+GST_MUX_PADS_CLASS
+GST_IS_MUX_PADS_CLASS
+GST_MUX_PADS_GET_CLASS
+<SUBSECTION Private>
+gst_mux_pads_get_type
+</SECTION>
+
+
+<SECTION>
 <FILE>gstpushsrc</FILE>
 <TITLE>GstPushSrc</TITLE>
 <INCLUDE>gst/base/gstpushsrc.h</INCLUDE>
Index: docs/libs/gstreamer-libs.types
===================================================================
--- docs/libs/gstreamer-libs.types	(.../tags/0.10.13/gstreamer/docs)	(revision 456)
+++ docs/libs/gstreamer-libs.types	(.../branches/0.10.13/gstreamer/docs)	(working copy)
@@ -13,6 +13,8 @@
 gst_base_transform_get_type
 #include <gst/base/gstcollectpads.h>
 gst_collect_pads_get_type
+#include <gst/base/gstmuxpads.h>
+gst_mux_pads_get_type
 #include <gst/base/gstpushsrc.h>
 gst_push_src_get_type
 
Index: docs/libs/gstreamer-libs-docs.sgml
===================================================================
--- docs/libs/gstreamer-libs-docs.sgml	(.../tags/0.10.13/gstreamer/docs)	(revision 456)
+++ docs/libs/gstreamer-libs-docs.sgml	(.../branches/0.10.13/gstreamer/docs)	(working copy)
@@ -9,6 +9,7 @@
 <!ENTITY GstBaseSink SYSTEM "xml/gstbasesink.xml">
 <!ENTITY GstBaseTransform SYSTEM "xml/gstbasetransform.xml">
 <!ENTITY GstCollectPads SYSTEM "xml/gstcollectpads.xml">
+<!ENTITY GstMuxPads SYSTEM "xml/gstmuxpads.xml">
 <!ENTITY GstPushSrc SYSTEM "xml/gstpushsrc.xml">
 <!ENTITY GstTypeFindHelper SYSTEM "xml/gsttypefindhelper.xml">
 <!ENTITY GstDataQueue SYSTEM "xml/gstdataqueue.xml">
@@ -59,6 +60,7 @@
   
       &GstAdapter;
       &GstCollectPads;
+      &GstMuxPads;
       &GstTypeFindHelper;
       &GstDataQueue;
     </chapter>
Index: libs/gst/base/gstmuxpads.c
===================================================================
--- libs/gst/base/gstmuxpads.c	(.../tags/0.10.13/gstreamer/libs/gst/base)	(revision 0)
+++ libs/gst/base/gstmuxpads.c	(.../branches/0.10.13/gstreamer/libs/gst/base)	(revision 480)
@@ -0,0 +1,785 @@
+/* GStreamer
+ * Copyright (C) 2007 Michal Benes <michal.benes@itonis.tv>
+ * Copyright (C) 2007 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * gstmuxpads.c:
+ *
+ * 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:gstmuxpads
+ * @short_description: manages a set of pads that operate in muxer mode
+ * @see_also: #GstCollectPads
+ *
+ * Manages a set of pads that operate in muxer mode. This means that buffers
+ * collected on all pads are sorted according to their timestamp and given to
+ * the manager of this object.
+ * Being derived from #GstCollectPads, similar usage comments apply.
+ * Additionally:
+ * <itemizedlist>
+ *   <listitem><para>
+ *     MuxPads is created with gst_mux_pads_new().
+ *   </para></listitem>
+ *   <listitem><para>
+ *     If a callback is set by gst_mux_pads_set_collect_function(),
+ *     it is up to the managing element to choose from which pad(s)
+ *     to dequeue data.  However, if one is typically interested in
+ *     the oldest buffer, it suffices setting a callback with
+ *     gst_collect_pads_set_function(), which will then be called
+ *     with the oldest buffer.
+ *   </para></listitem>
+ *   <listitem><para>
+ *     The oldest buffer is found according to a compare function which can be
+ *     overriden by gst_mux_pads_set_compare_function ().
+ *     The default compare function compares timestamps assuming
+ *     GST_CLOCK_TIME_NONE as the oldest timestamp.
+ *   </para></listitem>
+ *   <listitem><para>
+ *     #GstMuxPads is also aware that some streams may use NEWSEGMENT events
+ *     to indicate gaps, i.e. a period of time during which no data
+ *     is streamed, as is typically the case with subtitle streams.
+ *     This is handled by temporarily not waiting for data to arrive on pad 
+ *     in question in such situation.  If some (video/audio) streams are known
+ *     not to exhibit such gaps, gst_mux_pads_set_locked() (during setup) 
+ *     can be used to ensure that the corresponding pads are always waited for.
+ *   </para></listitem>
+ * </itemizedlist>
+ *
+ */
+
+#include "gstmuxpads.h"
+
+GST_DEBUG_CATEGORY_STATIC (mux_pads_debug);
+#define GST_CAT_DEFAULT mux_pads_debug
+
+GST_BOILERPLATE (GstMuxPads, gst_mux_pads, GstCollectPads,
+    GST_TYPE_COLLECT_PADS);
+
+static void gst_mux_pads_init (GstMuxPads * muxpads,
+    GstMuxPadsClass * g_class);
+static void gst_mux_pads_finalize (GObject * object);
+static gboolean gst_mux_pads_event (GstCollectPads * pads,
+    GstCollectData * cdata, GstEvent * event, gpointer user_data);
+static GstFlowReturn gst_mux_pads_collected (GstCollectPads * pads,
+    gpointer user_data);
+static gint gst_mux_pads_default_compare_func (GstMuxPads * muxpads,
+    GstMuxData * data1, GstClockTime timestamp1, GstMuxData * data2,
+    GstClockTime timestamp2, gpointer user_data);
+static void gst_mux_data_destroy_notify (GstCollectData * data);
+
+static void
+gst_mux_pads_base_init (gpointer g_class)
+{
+  GST_DEBUG_CATEGORY_INIT (mux_pads_debug, "muxpads", 0, "GstMuxPads");
+}
+
+static void
+gst_mux_pads_class_init (GstMuxPadsClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mux_pads_finalize);
+}
+
+static void
+gst_mux_pads_init (GstMuxPads * muxpads, GstMuxPadsClass * g_class)
+{
+  /* Init callbacks */
+  muxpads->func = NULL;
+  muxpads->user_data = NULL;
+  muxpads->collect_func = NULL;
+  muxpads->collect_user_data = NULL;
+  muxpads->event_func = NULL;
+  muxpads->event_user_data = NULL;
+  muxpads->compare_func = gst_mux_pads_default_compare_func;
+  muxpads->compare_user_data = NULL;
+  muxpads->mux_data = NULL;
+  muxpads->mux_time = GST_CLOCK_TIME_NONE;
+
+  /* Init parents callbacks */
+  gst_collect_pads_set_function (GST_COLLECT_PADS (muxpads),
+      GST_DEBUG_FUNCPTR (gst_mux_pads_collected), NULL);
+  gst_collect_pads_set_event_function (GST_COLLECT_PADS (muxpads),
+      GST_DEBUG_FUNCPTR (gst_mux_pads_event), NULL);
+
+  muxpads->lock = g_mutex_new ();
+  muxpads->cond = g_cond_new ();
+  muxpads->pad_list = NULL;
+}
+
+static void
+gst_mux_pads_finalize (GObject * object)
+{
+  GstMuxPads *muxpads = GST_MUX_PADS (object);
+
+  g_mutex_free (muxpads->lock);
+  g_cond_free (muxpads->cond);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * gst_mux_pads_new:
+ *
+ * Create a new instance of #GstMuxPads.
+ *
+ * Returns: a new #GstMuxPads, or NULL in case of an error.
+ *
+ * MT safe.
+ */
+GstMuxPads *
+gst_mux_pads_new (void)
+{
+  GstMuxPads *newmuxpads;
+
+  newmuxpads = g_object_new (GST_TYPE_MUX_PADS, NULL);
+
+  return newmuxpads;
+}
+
+/**
+ * gst_mux_pads_set_function:
+ * @muxpads: the muxpads to use
+ * @func: the function to set
+ * @user_data: user data passed to the function
+ *
+ * Set the callback function and user data that will be called with
+ * the oldest buffer when all pads have been collected.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_set_function (GstMuxPads * muxpads,
+    GstMuxPadsFunction func, gpointer user_data)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  GST_OBJECT_LOCK (muxpads);
+  muxpads->func = func;
+  muxpads->user_data = user_data;
+  GST_OBJECT_UNLOCK (muxpads);
+}
+
+/**
+ * gst_mux_pads_set_collect_function:
+ * @muxpads: the muxpads to use
+ * @func: the function to set
+ * @user_data: user data passed to the function
+ *
+ * Set the callback function and user data that will be called when
+ * (at least) all the pads added to the collection in waiting state have
+ * buffers queued.
+ * Evidently, this callback is not compatible with gst_mux_pads_set_function()
+ * callback.  If this callback is set, the other one will be ignored.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_set_collect_function (GstMuxPads * muxpads,
+    GstMuxPadsCollectFunction func, gpointer user_data)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  GST_OBJECT_LOCK (muxpads);
+  muxpads->collect_func = func;
+  muxpads->collect_user_data = user_data;
+  GST_OBJECT_UNLOCK (muxpads);
+}
+
+/**
+ * gst_mux_pads_set_event_function:
+ * @muxpads: the muxpads to use
+ * @func: the function to set
+ * @user_data: user data passed to the function
+ *
+ * Set the event callback function and user data that will be called after
+ * muxpads has processed and event originating from one of the handled pads.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_set_event_function (GstMuxPads * muxpads,
+    GstMuxPadsEventFunction func, gpointer user_data)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  GST_OBJECT_LOCK (muxpads);
+  muxpads->event_func = func;
+  muxpads->event_user_data = user_data;
+  GST_OBJECT_UNLOCK (muxpads);
+}
+
+/**
+ * gst_mux_pads_set_compare_function:
+ * @muxpads: the muxpads to use
+ * @func: the function to set
+ * @user_data: user data passed to the function
+ *
+ * Set the timestamp comparison function.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_set_compare_function (GstMuxPads * muxpads,
+    GstMuxPadsCompareFunction func, gpointer user_data)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  GST_OBJECT_LOCK (muxpads);
+  muxpads->compare_func = func;
+  muxpads->compare_user_data = user_data;
+  GST_OBJECT_UNLOCK (muxpads);
+}
+
+/**
+ * gst_mux_pads_add_pad:
+ * @muxpads: the muxpads to use
+ * @pad: the pad to add
+ * @size: the size of the returned #GstMuxData structure
+ *
+ * Similar to gst_collect_pads_add_pad(), but now with
+ * a @size for a #GstMuxDataAdd a pad to the muxpads.
+ *
+ * Returns: a new #GstMuxData to identify the new pad. Or NULL
+ *   if wrong parameters are supplied.
+ *
+ * MT safe.
+ */
+GstMuxData *
+gst_mux_pads_add_pad (GstMuxPads * muxpads, GstPad * pad, guint size)
+{
+  return gst_mux_pads_add_pad_full (muxpads, pad, size, NULL);
+}
+
+/**
+ * gst_mux_pads_add_pad_full:
+ * @muxpads: the collectsmuxpads to use
+ * @pad: the pad to add
+ * @size: the size of the returned #GstMuxData structure
+ * @destroy_notify: function to be called before the returned #GstMuxData
+ * structure is freed
+ *
+ * Similar to gst_collect_pads_add_pad_full(), but now with
+ * a @size for a #GstMuxDataAdd a pad to the muxpads.
+ *
+ * Returns: a new #GstMuxData to identify the new pad. Or NULL
+ *   if wrong parameters are supplied.
+ *
+ * MT safe.
+ */
+GstMuxData *
+gst_mux_pads_add_pad_full (GstMuxPads * muxpads, GstPad * pad, guint size,
+    GstMuxDataDestroyNotify destroy_notify)
+{
+  GstMuxData *data;
+
+  g_return_val_if_fail (muxpads != NULL, NULL);
+  g_return_val_if_fail (GST_IS_MUX_PADS (muxpads), NULL);
+  g_return_val_if_fail (pad != NULL, NULL);
+  g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL);
+  g_return_val_if_fail (size >= sizeof (GstMuxData), NULL);
+
+  /* let destroy know we are working on this pad */
+  g_mutex_lock (muxpads->lock);
+  muxpads->pad_list = g_slist_append (muxpads->pad_list, pad);
+  g_mutex_unlock (muxpads->lock);
+
+  /* Init GstMuxData */
+  data =
+      (GstMuxData *) gst_collect_pads_add_pad_full (GST_COLLECT_PADS (muxpads),
+          pad, size, gst_mux_data_destroy_notify);
+
+  GST_OBJECT_LOCK (pad);
+  g_mutex_lock (muxpads->lock);
+  if (data) {
+    data->destroy_notify = destroy_notify;
+    data->waiting = TRUE;
+    data->locked = FALSE;
+  }
+  muxpads->pad_list = g_slist_remove (muxpads->pad_list, pad);
+  /* we are basically finished, let destroy know */
+  g_cond_broadcast (muxpads->cond);
+  g_mutex_unlock (muxpads->lock);
+  GST_OBJECT_UNLOCK (pad);
+
+  return data;
+}
+
+/**
+ * gst_mux_pads_remove_pad:
+ * @muxpads: the collectsmuxpads to use
+ * @pad: the pad to remove
+ *
+ * Remove a pad from the muxpads (see also gst_collect_pads_remove_pad).
+ * This function will also free the #GstMuxData and all the resources
+ * that were allocated with gst_mux_pads_add_pad() or gst_mux_add_pad_full().
+ *
+ * The pad will be deactivated automatically when @muxpads is stopped.
+ *
+ * Returns: %TRUE if the pad could be removed.
+ *
+ * MT safe.
+ */
+gboolean
+gst_mux_pads_remove_pad (GstMuxPads * muxpads, GstPad * pad)
+{
+  g_return_val_if_fail (muxpads != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_MUX_PADS (muxpads), FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  return gst_collect_pads_remove_pad (GST_COLLECT_PADS (muxpads), pad);
+}
+
+/**
+ * gst_mux_pads_start:
+ * @muxpads: the muxpads to use
+ *
+ * Starts the processing of data in the muxpads.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_start (GstMuxPads * muxpads)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  muxpads->mux_data = NULL;
+  muxpads->mux_time = GST_CLOCK_TIME_NONE;
+  gst_collect_pads_start (GST_COLLECT_PADS (muxpads));
+}
+
+/**
+ * gst_mux_pads_stop:
+ * @muxpads: the muxpads to use
+ *
+ * Stops the processing of data in the muxpads. This function
+ * will also unblock any blocking operations.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_stop (GstMuxPads * muxpads)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  gst_collect_pads_stop (GST_COLLECT_PADS (muxpads));
+}
+
+/**
+ * gst_mux_pads_set_locked:
+ * @muxpads: the muxpads to use
+ * @data: the data to use
+ * @locked: to lock or unlock
+ *
+ * Locks the waiting state of data to the current one, or unlocks it,
+ * where the former will make @muxpads never change waiting state.
+ * This is of typical use to a muxer element where non-subtitles streams
+ * should always be in waiting state, e.g. to assure that caps information is
+ * available on all these streams when headers have to be written.
+ *
+ * MT safe.
+ */
+void
+gst_mux_pads_set_locked (GstMuxPads * muxpads, GstMuxData * data,
+    gboolean locked)
+{
+  g_return_if_fail (muxpads != NULL);
+  g_return_if_fail (GST_IS_MUX_PADS (muxpads));
+
+  GST_OBJECT_LOCK (muxpads);
+  data->locked = locked;
+  GST_OBJECT_UNLOCK (muxpads);
+}
+
+/* General overview:
+ * - only pad with a buffer can determine mux_data (and mux_time)
+ * - what's with the locks:
+ *   PAD_LOCK is taken (!after! LOCK) because the whole pad collection has to
+ *     be examined as in gst_collect_pads_check_collected, so protect against
+ *     intermediate changes
+ *   LOCK is either already taken (by CollectPads) or has to be taken prior to
+ *     calling some CollectPads functions
+ *   btw; unlike GstQueue which has a dedicated lock protecting its data,
+ *     CollectPads uses the object LOCK for this and hangs on to it
+ *     into collected_function.
+ *     As such, LOCK can end up being held for a long time (and into a WAIT);
+ *     makes it dangerous/tricky to use for "standard object access" protection
+ *     (according to design docs).
+ */
+
+/*
+ * Function to recalculate the waiting state of all pads.
+ *
+ * Must be called with parent LOCK and PAD_LOCK.
+ *
+ * Returns TRUE if a pad was set to waiting
+ * (from non-waiting state).
+ */
+static gboolean
+gst_mux_pads_recalculate_waiting (GstMuxPads * muxpads)
+{
+  GSList *collected;
+  gboolean result = FALSE;
+
+  /* If muxing time is not known, there is nothing to do. */
+  if (muxpads->mux_data == NULL)
+    return FALSE;
+
+  for (collected = GST_COLLECT_PADS (muxpads)->data; collected;
+      collected = g_slist_next (collected)) {
+    GstMuxData *mux_data = (GstMuxData *) collected->data;
+    GstCollectData *collect_data = (GstCollectData *) collected->data;
+    int cmp_res;
+
+    /* Check if pad has a segment */
+    if (collect_data->segment.format == GST_FORMAT_UNDEFINED)
+      continue;
+
+    /* Check segment format */
+    if (collect_data->segment.format != GST_FORMAT_TIME) {
+      GST_ERROR_OBJECT (muxpads, "GstMuxPads can handle only time segments.");
+      continue;
+    }
+
+    /* Check if the waiting state should be changed */
+    cmp_res = muxpads->compare_func (muxpads, mux_data,
+        collect_data->segment.start, muxpads->mux_data, muxpads->mux_time,
+        muxpads->compare_user_data);
+    if (mux_data->waiting) {
+      if (!mux_data->locked && cmp_res > 0) {
+        /* Stop waiting */
+        gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads), collect_data,
+            FALSE);
+        mux_data->waiting = FALSE;
+      }
+    } else {
+      if (!mux_data->locked && cmp_res <= 0) {
+        /* Start waiting */
+        gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads), collect_data,
+            TRUE);
+        mux_data->waiting = TRUE;
+        result = TRUE;
+      }
+    }
+  }
+
+  return result;
+}
+
+/*
+ * Function that finds the oldest/best pad;
+ * any current one is completely ignored/reset and a new one is determined.
+ *
+ * Returns TRUE if there is another pad without a buffer that has
+ * an older (segment) time than the best pad.
+ *
+ * Must be called with parent LOCK and PAD_LOCK.
+ */
+static void
+gst_mux_pads_find_best_pad (GstMuxPads * muxpads)
+{
+  GSList *collected;
+  GstCollectPads *pads = GST_COLLECT_PADS (muxpads);
+  GstMuxData *best = NULL;
+  GstClockTime best_time = GST_CLOCK_TIME_NONE;
+
+  for (collected = pads->data; collected;
+      collected = g_slist_next (collected)) {
+    GstBuffer *buffer;
+    GstMuxData *mux_data = (GstMuxData *) collected->data;
+    GstCollectData *collect_data = (GstCollectData *) collected->data;
+    GstClockTime timestamp;
+
+    buffer = gst_collect_pads_peek (pads,
+        (GstCollectData *) mux_data);
+    /* if we have a buffer check if it is better then the current best one */
+    if (buffer != NULL) {
+      timestamp = GST_BUFFER_TIMESTAMP (buffer);
+      gst_buffer_unref (buffer);
+      if (best == NULL || muxpads->compare_func (muxpads, mux_data, timestamp,
+                            best, best_time, muxpads->compare_user_data) < 0) {
+        best = mux_data;
+        best_time = timestamp;
+      }
+    } else if (!mux_data->waiting &&
+               collect_data->segment.format == GST_FORMAT_TIME) {
+      /* only look at non-waiting pads, e.g. EOS pads don't count anymore */
+      timestamp = collect_data->segment.start;
+      if (muxpads->compare_func (muxpads, mux_data, timestamp,
+              best, best_time, muxpads->compare_user_data) < 0) {
+      }
+    }
+  }
+
+  /* Set muxing time */
+  muxpads->mux_data = best;
+  muxpads->mux_time = best_time;
+
+  GST_DEBUG_OBJECT (muxpads, "best pad %s, best time %" GST_TIME_FORMAT,
+      best ? GST_PAD_NAME (((GstCollectData *) best)->pad) : "(nil)",
+      GST_TIME_ARGS (best_time));
+
+}
+
+/*
+ * Function to recalculate mux_data and mux_timestamp. This also calls
+ * gst_mux_pads_recalculate_waiting
+ *
+ * Must be called with parent LOCK and PAD_LOCK.
+ */
+static void
+gst_mux_pads_recalculate_full (GstMuxPads * muxpads)
+{
+  gst_mux_pads_find_best_pad (muxpads);
+  gst_mux_pads_recalculate_waiting (muxpads);
+}
+
+/*
+ * Function for handling pad events
+ */
+static gboolean
+gst_mux_pads_event (GstCollectPads * pads, GstCollectData * cdata,
+    GstEvent * event, gpointer user_data)
+{
+  GstMuxPads *muxpads = GST_MUX_PADS (pads);
+  gboolean eat_event = FALSE;
+  gboolean res = FALSE;
+  GstMuxData *data;
+
+  /* parent event handler has a ref on this */
+  data = (GstMuxData *) cdata;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+    case GST_EVENT_FLUSH_STOP:
+    /* in either case, reset the current pad */
+    {
+      GST_OBJECT_LOCK (pads);
+      GST_COLLECT_PADS_PAD_LOCK (pads);
+
+      gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads),
+          (GstCollectData *) data, TRUE);
+      data->waiting = TRUE;
+      /* if the current pad is affected, reset state, recalculate later */
+      if (muxpads->mux_data == data) {
+        muxpads->mux_data = NULL;
+        muxpads->mux_time = GST_CLOCK_TIME_NONE;
+      }
+      goto done;
+    }
+    case GST_EVENT_NEWSEGMENT:
+    {
+      gint64 start, stop, time;
+      gdouble rate, arate;
+      GstFormat format;
+      gboolean update;
+      gint cmp_res;
+
+      /* proper order: LOCK, then PADS_LOCK */
+      /* former should be held for calling CollectPads functions
+       * and serializes execution,
+       * latter protects against modification of pad collection */
+      GST_OBJECT_LOCK (pads);
+      GST_COLLECT_PADS_PAD_LOCK (pads);
+
+      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+          &start, &stop, &time);
+
+      /* Muxer can not handle other segment formats than time */
+      if (format != GST_FORMAT_TIME) {
+        GST_ERROR_OBJECT (muxpads, "GstMuxPads can handle only time segments.");
+        goto done;
+      }
+
+      /* If oldest time is not known, or current pad got newsegment;
+       * recalculate the state */
+      if (!muxpads->mux_data || muxpads->mux_data == data) {
+        gst_mux_pads_recalculate_full (muxpads);
+        goto newsegment_done;
+      }
+
+      /* if there is not enough info/buffers yet to determine a best pad,
+       * we rely on TIME_NONE << all (!!), so that we turn non-waiting,
+       * so things don't block until we get enough info */
+
+      /* Check if the waiting state of the pad should change. */
+      cmp_res = muxpads->compare_func (muxpads, data, start, muxpads->mux_data,
+          muxpads->mux_time, muxpads->compare_user_data);
+
+      GST_DEBUG_OBJECT (muxpads, "old state: locked %d, waiting %d",
+          data->locked, data->waiting);
+
+      if (data->waiting) {
+        if (!data->locked && cmp_res > 0) {
+          /* Stop waiting */
+          gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads),
+              (GstCollectData *) data, FALSE);
+          data->waiting = FALSE;
+        }
+      } else {
+        if (!data->locked && cmp_res <= 0) {
+          /* Start waiting */
+          gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads),
+              (GstCollectData *) data, TRUE);
+          data->waiting = TRUE;
+        }
+      }
+      GST_DEBUG_OBJECT (muxpads, "new state: waiting %d", data->waiting);
+
+    newsegment_done:
+      eat_event = TRUE;
+      goto done;
+    }
+    default:
+      goto finish;
+  }
+
+done:
+  GST_COLLECT_PADS_PAD_UNLOCK (pads);
+  GST_OBJECT_UNLOCK (pads);
+
+finish:
+  /* through all this, note that CollectPads still holds a ref on data */
+  if (muxpads->event_func)
+    res = muxpads->event_func (muxpads, data, event, muxpads->event_user_data);
+  if (!res && eat_event) {
+    gst_event_unref (event);
+    res = TRUE;
+  }
+
+  return res;
+}
+
+/*
+ * Callback triggered when #GstCollectPads gathered all data
+ *
+ * Should be called with LOCK.
+ */
+static GstFlowReturn
+gst_mux_pads_collected (GstCollectPads * pads, gpointer user_data)
+{
+  GstMuxPads *muxpads = GST_MUX_PADS (pads);
+  GstMuxData *best = NULL;
+  GstBuffer *buffer;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  GST_COLLECT_PADS_PAD_LOCK (pads);
+  /* Find the oldest pad if needed */
+  gst_mux_pads_find_best_pad (muxpads);
+  if (gst_mux_pads_recalculate_waiting (muxpads)) {
+  /* waiting was switched on,
+   * so give another thread a chance to deliver a possibly
+   * older buffer; don't charge on yet with the current oldest */
+    goto done;
+  }
+  best = muxpads->mux_data;
+
+  /* No data collected means EOS. */
+  if (G_UNLIKELY (best == NULL)) {
+    ret = muxpads->func (muxpads, best, NULL, muxpads->user_data);
+    if (ret == GST_FLOW_OK)
+      ret = GST_FLOW_UNEXPECTED;
+    goto done;
+  }
+
+  /* make sure that the pad we take a buffer from is waiting;
+   * otherwise popping a buffer will seem not to have happened
+   * and collectpads can get into a (to be fixed) busy loop */
+  if (!best->waiting && !best->locked) {
+    gst_collect_pads_set_waiting (GST_COLLECT_PADS (muxpads),
+        (GstCollectData *) best, TRUE);
+    best->waiting = TRUE;
+  }
+
+  /* Send buffer */
+  if (muxpads->collect_func) {
+    ret = muxpads->collect_func (muxpads, muxpads->collect_user_data);
+  } else {
+    buffer = gst_collect_pads_pop (pads, (GstCollectData *) best);
+    ret = muxpads->func (muxpads, best, buffer, muxpads->user_data);
+  }
+
+  /* Update waiting states */
+  gst_mux_pads_recalculate_waiting (muxpads);
+
+done:
+  GST_COLLECT_PADS_PAD_UNLOCK (pads);
+  return ret;
+}
+
+/*
+ * Default timestamp compare function.
+ */
+static gint
+gst_mux_pads_default_compare_func (GstMuxPads * muxpads,
+    GstMuxData * data1, GstClockTime timestamp1,
+    GstMuxData * data2, GstClockTime timestamp2, gpointer user_data)
+{
+
+  GST_LOG_OBJECT (muxpads, "comparing %" GST_TIME_FORMAT
+      " and %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp1),
+      GST_TIME_ARGS (timestamp2));
+  /* non-valid timestamps go first as they are probably headers or so */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp1)))
+    return GST_CLOCK_TIME_IS_VALID (timestamp2) ? -1 : 0;
+
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp2)))
+    return 1;
+
+  /* compare timestamp */
+  if (timestamp1 < timestamp2)
+    return -1;
+
+  if (timestamp1 > timestamp2)
+    return 1;
+
+  return 0;
+}
+
+/*
+ * #GstMuxData destroy notify callback
+ */
+static void
+gst_mux_data_destroy_notify (GstCollectData * data)
+{
+  GstMuxData *mux_data = (GstMuxData *) data;
+  GstMuxPads *muxpads = GST_MUX_PADS (data->collect);
+
+  /* hm, CollectPads consistency; this function will (probably) be called
+   * with PADS_LOCK, so that should incidentally synchronize the sequel */
+
+  /* hang on if pad is still being added */
+  g_mutex_lock (muxpads->lock);
+  while (g_slist_find (muxpads->pad_list, data->pad))
+    g_cond_wait (muxpads->cond, muxpads->lock);
+  g_mutex_unlock (muxpads->lock);
+
+  /* Recalculate the state if needed */
+  if (muxpads->mux_data == mux_data) {
+    /* reset; will be recalculated in streaming thread when needed */
+    muxpads->mux_data = NULL;
+    muxpads->mux_time = GST_CLOCK_TIME_NONE;
+  }
+
+  if (mux_data->destroy_notify != NULL)
+    mux_data->destroy_notify (mux_data);
+}
Index: libs/gst/base/gstmuxpads.h
===================================================================
--- libs/gst/base/gstmuxpads.h	(.../tags/0.10.13/gstreamer/libs/gst/base)	(revision 0)
+++ libs/gst/base/gstmuxpads.h	(.../branches/0.10.13/gstreamer/libs/gst/base)	(revision 480)
@@ -0,0 +1,203 @@
+/* GStreamer
+ * Copyright (C) 2007 Michal Benes <michal.benes@itonis.tv>
+ * Copyright (C) 2007 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * gstmuxpads.h:
+ *
+ * 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_MUX_PADS_H__
+#define __GST_MUX_PADS_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MUX_PADS			(gst_mux_pads_get_type())
+#define GST_MUX_PADS(obj)			(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MUX_PADS,GstMuxPads))
+#define GST_MUX_PADS_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MUX_PADS,GstMuxPadsClass))
+#define GST_MUX_PADS_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_MUX_PADS,GstMuxPadsClass))
+#define GST_IS_MUX_PADS(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MUX_PADS))
+#define GST_IS_MUX_PADS_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MUX_PADS))
+
+typedef struct _GstMuxData GstMuxData;
+typedef struct _GstMuxPads GstMuxPads;
+typedef struct _GstMuxPadsClass GstMuxPadsClass;
+
+/**
+ * GstMuxDataDestroyNotify:
+ * @data: the #GstMuxData that will be freed
+ *
+ * A function that will be called when the #GstMuxData will be freed.
+ * It is passed the pointer to the structure and should free any custom
+ * memory and resources allocated for it.
+ */
+typedef void (*GstMuxDataDestroyNotify) (GstMuxData *data);
+
+/**
+ * GstMuxData:
+ * @collect_data: the parent object
+ * @destroy_notify: destroy notify function
+ *
+ * Structure used by the muxpads class.
+ */
+struct _GstMuxData
+{
+  GstCollectData	collect_data;
+
+  /*< private >*/
+  GstMuxDataDestroyNotify destroy_notify;
+  /* with LOCK of @collect of @collect_data */
+  gboolean waiting;
+  gboolean locked;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstMuxPadsFunction:
+ * @muxpads: the #GstMuxPads that trigered the callback
+ * @data: the #GstMuxData of pad that has received the buffer
+ * @buffer: the #GstBuffer
+ * @user_data: user data passed to gst_mux_pads_set_function()
+ *
+ * A function that will be called when a buffer can be muxed.
+ * if all pads have reached EOS, this function is called with NULL @buffer
+ * and NULL @data.
+ *
+ * Returns: #GST_FLOW_OK for success
+ */
+typedef GstFlowReturn (*GstMuxPadsFunction) (GstMuxPads *muxpads, GstMuxData *data, GstBuffer *buffer, gpointer user_data);
+
+/**
+ * GstMuxPadsCollectFunction:
+ * @muxpads: the #GstMuxPads that trigered the callback
+ * @user_data: user data passed to gst_mux_pads_set_function()
+ *
+ * A function that will be called when all waiting pads have received data.
+ *
+ * Returns: #GST_FLOW_OK for success
+ */
+typedef GstFlowReturn (*GstMuxPadsCollectFunction) (GstMuxPads *muxpads, gpointer user_data);
+
+/**
+ * GstMuxPadsEventFunction:
+ * @muxpads: the #GstMuxPads that trigered the callback
+ * @data: the #GstMuxData of pad that recieved an event
+ * @event: the #GstEvent received
+ * @user_data: user data passed to gst_mux_pads_set_event_function()
+ *
+ * A function that will be called after muxpads has processed the event.
+ *
+ * Returns: %TRUE if the pad could handle the event
+ */
+typedef gboolean (*GstMuxPadsEventFunction) (GstMuxPads *muxpads, GstMuxData *data, GstEvent * event, gpointer user_data);
+
+/**
+ * GstMuxPadsCompareFunction:
+ * @muxpads: the #GstMuxPads that is comparing the timestamps
+ * @data1: the first #GstMuxData
+ * @timestamp1: the first timestamp
+ * @data2: the second #GstMuxData
+ * @timestamp2: the second timestamp
+ * @user_data: user data passed to gst_mux_pads_set_compare_function()
+ *
+ * A function for comparing two timestamps of buffers or newsegments collected on one pad.
+ *
+ * Returns: Integer less than zero when first timestamp is deemed older than the second one.
+ *          Zero if the timestamps are deemed equally old.
+ *          Integer greate than zero when second timestamp is deemed older than the first one.
+ */
+typedef gint (*GstMuxPadsCompareFunction) (GstMuxPads *muxpads,
+			GstMuxData * data1, GstClockTime timestamp1,
+			GstMuxData * data2, GstClockTime timestamp2,
+			gpointer user_data);
+
+/**
+ * GstMuxPads:
+ * @pads: the #GstCollectPads parent structure.
+ *
+ * Muxpads object.
+ */
+struct _GstMuxPads {
+  GstCollectPads      pads;
+
+  /*< private >*/
+  GstMuxPadsFunction func;                /* function and user_data for callback */
+  gpointer       user_data;
+
+  GstMuxPadsCollectFunction collect_func; /* function and user_data for collect callback */
+  gpointer       collect_user_data;
+
+  GstMuxPadsEventFunction event_func;     /* function and user_data for event callback */
+  gpointer       event_user_data;
+
+  GstMuxPadsCompareFunction compare_func; /* function and user_data for event callback */
+  gpointer       compare_user_data;
+
+  GstClockTime   mux_time;              /* Current muxing time, protected by PAD_LOCK */
+  GstMuxData   *mux_data;             /* Pad data for current muxing time,
+                                           protected by PAD_LOCK */
+
+  /* some convoluted code to prevent race with pad add/remove */
+  GMutex *lock;
+  GCond  *cond;
+  GSList *pad_list;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstMuxPadsClass {
+  GstCollectPadsClass parent_class;
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_mux_pads_get_type (void);
+
+/* creating the object */
+GstMuxPads*	gst_mux_pads_new (void);
+
+/* set the callbacks */
+void		gst_mux_pads_set_function (GstMuxPads *muxpads, GstMuxPadsFunction func,
+						 gpointer user_data);
+
+void            gst_mux_pads_set_collect_function (GstMuxPads * muxpads,
+                                        GstMuxPadsCollectFunction func, gpointer user_data);
+
+void		gst_mux_pads_set_event_function (GstMuxPads *muxpads, GstMuxPadsEventFunction func,
+						 gpointer user_data);
+
+/* Set compare function */
+void		gst_mux_pads_set_compare_function (GstMuxPads *muxpads, GstMuxPadsCompareFunction func,
+						 gpointer user_data);
+
+/* pad management */
+GstMuxData*	gst_mux_pads_add_pad (GstMuxPads *muxpads, GstPad *pad, guint size);
+GstMuxData*	gst_mux_pads_add_pad_full (GstMuxPads *muxpads, GstPad *pad, guint size, GstMuxDataDestroyNotify destroy_notify);
+gboolean	gst_mux_pads_remove_pad (GstMuxPads *muxpads, GstPad *pad);
+void        gst_mux_pads_set_locked (GstMuxPads * muxpads, GstMuxData * data, gboolean locked);
+
+/* start/stop muxing */
+void		gst_mux_pads_start (GstMuxPads *muxpads);
+void		gst_mux_pads_stop (GstMuxPads *muxpads);
+
+G_END_DECLS
+
+#endif /* __GST_MUX_PADS_H__ */
Index: libs/gst/base/Makefile.am
===================================================================
--- libs/gst/base/Makefile.am	(.../tags/0.10.13/gstreamer/libs/gst/base)	(revision 456)
+++ libs/gst/base/Makefile.am	(.../branches/0.10.13/gstreamer/libs/gst/base)	(working copy)
@@ -8,6 +8,7 @@
 	gstbasesrc.c		\
 	gstbasetransform.c	\
 	gstcollectpads.c	\
+	gstmuxpads.c			\
 	gstpushsrc.c		\
 	gsttypefindhelper.c	\
 	gstdataqueue.c
@@ -25,6 +26,7 @@
 	gstbasesrc.h		\
 	gstbasetransform.h	\
 	gstcollectpads.h	\
+	gstmuxpads.h			\
 	gstpushsrc.h		\
 	gsttypefindhelper.h	\
 	gstdataqueue.h
