Index: gstbasemux.c
===================================================================
RCS file: gstbasemux.c
diff -N gstbasemux.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gstbasemux.c	11 Mar 2007 22:42:37 -0000
@@ -0,0 +1,307 @@
+/* GStreamer
+ * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstbasemux.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gstbasemux.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_base_mux_debug);
+#define GST_CAT_DEFAULT gst_base_mux_debug
+
+enum
+{
+  ARG_0
+};
+
+static void gst_base_mux_dispose (GObject * object);
+
+static void gst_base_mux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_base_mux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_base_mux_handle_src_event (GstPad *pad, GstEvent *event);
+static GstPad * gst_base_mux_request_new_pad (GstElement *element,
+    GstPadTemplate *template, const gchar *req_name);
+static void gst_base_mux_release_pad (GstElement *element, GstPad *pad);
+static GstStateChangeReturn gst_base_mux_change_state (GstElement *element,
+    GstStateChange transition);
+static GstFlowReturn gst_base_mux_collected (GstCollectPads *cp, gpointer closure);
+static GstBaseMuxStream * gst_base_mux_choose_stream (GstBaseMux *basemux);
+static void gst_base_mux_clear_streams (GstBaseMux *basemux);
+
+
+GST_BOILERPLATE (GstBaseMux, gst_base_mux, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_base_mux_base_init (gpointer g_class)
+{
+  //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+  GST_DEBUG_CATEGORY_INIT (gst_base_mux_debug, "basemux", 0,
+      "basemux");
+}
+
+static void
+gst_base_mux_class_init (GstBaseMuxClass * klass)
+{
+  GstBaseMuxClass *basemux_class = GST_BASE_MUX_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_base_mux_set_property;
+  gobject_class->get_property = gst_base_mux_get_property;
+  gobject_class->dispose = gst_base_mux_dispose;
+
+  gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_base_mux_request_new_pad);
+  gstelement_class->release_pad = GST_DEBUG_FUNCPTR(gst_base_mux_release_pad);
+  gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_base_mux_change_state);
+
+  basemux_class->choose_stream = GST_DEBUG_FUNCPTR(gst_base_mux_choose_stream);
+
+}
+
+static void
+gst_base_mux_init (GstBaseMux * basemux, GstBaseMuxClass * g_class)
+{
+  GstPadTemplate *pad_template;
+
+  pad_template = gst_element_class_get_pad_template (GST_ELEMENT_CLASS(g_class),
+      "src");
+  g_return_if_fail (pad_template != NULL);
+
+  basemux->srcpad = gst_pad_new_from_template (pad_template, "src");
+  gst_pad_set_event_function (basemux->srcpad, gst_base_mux_handle_src_event);
+
+  basemux->collect = gst_collect_pads_new ();
+  gst_collect_pads_set_function (basemux->collect,
+      GST_DEBUG_FUNCPTR (gst_base_mux_collected), basemux);
+
+  gst_element_add_pad (GST_ELEMENT(basemux), basemux->srcpad);
+}
+
+static void
+gst_base_mux_dispose (GObject * object)
+{
+  GstBaseMux *basemux = GST_BASE_MUX (object);
+  GstBaseMuxClass *basemux_class;
+  GList *g;
+
+  basemux_class = GST_BASE_MUX_GET_CLASS (basemux);
+
+  for(g=g_list_first (basemux->streams);g;g = g_list_next(g)) {
+    GstBaseMuxStream *stream = g->data;
+
+    if (basemux_class->finalize_stream) {
+      basemux_class->finalize_stream (basemux, stream);
+    }
+
+    g_free(stream);
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_base_mux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstBaseMux *basemux = GST_BASE_MUX (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_base_mux_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  //GstBaseMux *basemux = GST_BASE_MUX (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstPad *
+gst_base_mux_request_new_pad (GstElement *element,
+    GstPadTemplate *template, const gchar *req_name)
+{
+  GstBaseMux *basemux;
+  GstBaseMuxClass *basemux_class;
+  gchar *name;
+  GstPad *pad;
+
+  g_return_val_if_fail (template != NULL, NULL);
+  g_return_val_if_fail (GST_IS_BASE_MUX (element), NULL);
+
+#if 0
+  if (template->direction != GST_PAD_SINK)
+    goto wrong_direction;
+#endif
+
+  basemux = GST_BASE_MUX (element);
+  basemux_class = GST_BASE_MUX_GET_CLASS (basemux);
+
+  name = g_strdup_printf("sink_%d", basemux->padnum);
+  basemux->padnum++;
+  pad = gst_pad_new_from_template (template, name);
+  g_free(name);
+
+  gst_element_add_pad (element, pad);
+
+  return NULL;
+}
+
+static void
+gst_base_mux_release_pad (GstElement *element, GstPad *pad)
+{
+
+  /* FIXME */
+}
+
+static GstStateChangeReturn
+gst_base_mux_change_state (GstElement *element, GstStateChange transition)
+{
+  GstBaseMux *basemux;
+  GstBaseMuxClass *basemux_class;
+  GstStateChangeReturn ret;
+
+  basemux = GST_BASE_MUX (element);
+  basemux_class = GST_BASE_MUX_GET_CLASS (basemux);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      if (basemux_class->start) {
+        basemux_class->start (basemux);
+      }
+      gst_collect_pads_start (basemux->collect);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_collect_pads_stop (basemux->collect);
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_base_mux_clear_streams (basemux);
+      if (basemux_class->stop) {
+        basemux_class->stop (basemux);
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_base_mux_handle_src_event (GstPad *pad, GstEvent *event)
+{
+  /* FIXME */
+
+  return gst_pad_event_default (pad, event);
+}
+
+static GstFlowReturn
+gst_base_mux_collected (GstCollectPads *pads, gpointer closure)
+{
+  GstBaseMux *basemux;
+  GstBaseMuxClass *basemux_class;
+  GstBaseMuxStream *stream;
+  GstFlowReturn ret;
+
+  basemux = GST_BASE_MUX(closure);
+  basemux_class = GST_BASE_MUX_GET_CLASS(basemux);
+
+  stream = basemux_class->choose_stream (basemux);
+  if (!stream) {
+    return GST_FLOW_ERROR;
+  }
+
+  if (basemux_class->handle_stream) {
+    ret = basemux_class->handle_stream (basemux, stream);
+  } else {
+    /* FIXME this means the derived class isn't implemented correctly */
+    ret = GST_FLOW_ERROR;
+  }
+
+  return ret;
+}
+
+static GstBaseMuxStream *
+gst_base_mux_choose_stream (GstBaseMux *basemux)
+{
+  GList *g;
+  GstBaseMuxStream *stream = NULL;
+
+  /* choose oldest stream */
+  for(g=g_list_first(basemux->streams);g;g=g_list_next(g)) {
+    GstBaseMuxStream *s = g->data;
+
+    if (!s->in_use) continue;
+    if (!stream) {
+      stream=s;
+      continue;
+    }
+    if (s->timestamp < stream->timestamp) {
+      stream=s;
+    }
+  }
+
+  return stream;
+}
+
+static void
+gst_base_mux_clear_streams (GstBaseMux *basemux)
+{
+  /* FIXME */
+}
+
+GstBuffer *
+gst_base_mux_stream_pull_buffer (GstBaseMuxStream *stream)
+{
+  /* FIXME */
+
+  return NULL;
+}
+
Index: gstbasemux.h
===================================================================
RCS file: gstbasemux.h
diff -N gstbasemux.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gstbasemux.h	11 Mar 2007 22:42:37 -0000
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
+ *
+ * gstbasemux.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.
+ */
+
+#ifndef __GST_BASE_MUX_H__
+#define __GST_BASE_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+#define GST_TYPE_BASE_MUX \
+  (gst_base_mux_get_type())
+#define GST_BASE_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_MUX,GstBaseMux))
+#define GST_BASE_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_MUX,GstBaseMuxClass))
+#define GST_IS_BASE_MUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_MUX))
+#define GST_IS_BASE_MUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_MUX))
+#define GST_BASE_MUX_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASE_MUX, GstBaseMuxClass)
+
+typedef struct _GstBaseMux GstBaseMux;
+typedef struct _GstBaseMuxClass GstBaseMuxClass;
+
+typedef struct _GstBaseMuxStream GstBaseMuxStream;
+
+struct _GstBaseMux {
+  GstElement parent;
+
+  /*< public >*/
+  GstPad *srcpad;
+
+  /*< private >*/
+  GstCollectPads *collect;
+  GList *streams;
+  int padnum;
+
+};
+
+struct _GstBaseMuxClass {
+  GstElementClass parent_class;
+
+
+  gboolean (*start) (GstBaseMux *mux); // default NULL
+  gboolean (*stop) (GstBaseMux *mux); // default NULL
+
+  void (*new_stream) (GstBaseMux *mux, GstBaseMuxStream *stream); // default NULL
+  void (*finalize_stream) (GstBaseMux *mux, GstBaseMuxStream *stream); // default NULL
+  GstFlowReturn (*handle_stream) (GstBaseMux *mux, GstBaseMuxStream *stream); // default NULL
+  GstBaseMuxStream *(*choose_stream) (GstBaseMux *mux); // default earliest
+
+};
+
+GType gst_base_mux_get_type(void);
+
+struct _GstBaseMuxStream {
+  GstPad *pad;
+  void *priv;
+  GstClockTime timestamp;
+  gboolean in_use;
+
+
+};
+
+GstBuffer *gst_base_mux_stream_pull_buffer (GstBaseMuxStream *stream);
+
+#endif
+
+
