gst/: Added object to help in making collect pad based elements.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 5 May 2005 09:31:59 +0000 (09:31 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 5 May 2005 09:31:59 +0000 (09:31 +0000)
Original commit message from CVS:
* gst/base/Makefile.am:
* gst/base/gstbasesink.h:
* gst/base/gstbasesrc.c: (gst_basesrc_init),
(gst_basesrc_set_dataflow_funcs), (gst_basesrc_query):
* gst/base/gstcollectpads.c: (gst_collectpads_get_type),
(gst_collectpads_class_init), (gst_collectpads_init),
(gst_collectpads_finalize), (gst_collectpads_new),
(gst_collectpads_set_function), (gst_collectpads_add_pad),
(find_pad), (gst_collectpads_remove_pad),
(gst_collectpads_is_active), (gst_collectpads_collect),
(gst_collectpads_collect_range), (gst_collectpads_start),
(gst_collectpads_stop), (gst_collectpads_peek),
(gst_collectpads_pop), (gst_collectpads_available),
(gst_collectpads_read), (gst_collectpads_flush),
(gst_collectpads_chain):
* gst/base/gstcollectpads.h:
* gst/elements/Makefile.am:
* gst/elements/gstelements.c:
* gst/elements/gstfakesink.c: (gst_fakesink_class_init),
(gst_fakesink_get_times), (gst_fakesink_event),
(gst_fakesink_preroll), (gst_fakesink_render):
* gst/elements/gstfilesink.c: (gst_filesink_class_init),
(gst_filesink_init), (gst_filesink_set_location),
(gst_filesink_open_file), (gst_filesink_close_file),
(gst_filesink_pad_query), (gst_filesink_event),
(gst_filesink_render), (gst_filesink_change_state):
* gst/elements/gstfilesink.h:
Added object to help in making collect pad based elements.
Ported filesink.
Make event function in sink baseclass return gboolean.

21 files changed:
ChangeLog
gst/base/Makefile.am
gst/base/gstbasesink.h
gst/base/gstbasesrc.c
gst/base/gstcollectpads.c [new file with mode: 0644]
gst/base/gstcollectpads.h [new file with mode: 0644]
gst/elements/Makefile.am
gst/elements/gstelements.c
gst/elements/gstfakesink.c
gst/elements/gstfilesink.c
gst/elements/gstfilesink.h
libs/gst/base/Makefile.am
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasesrc.c
libs/gst/base/gstcollectpads.c [new file with mode: 0644]
libs/gst/base/gstcollectpads.h [new file with mode: 0644]
plugins/elements/Makefile.am
plugins/elements/gstelements.c
plugins/elements/gstfakesink.c
plugins/elements/gstfilesink.c
plugins/elements/gstfilesink.h

index 2fcfd2c..3f79e9e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,38 @@
 2005-05-05  Wim Taymans  <wim@fluendo.com>
 
+       * gst/base/Makefile.am:
+       * gst/base/gstbasesink.h:
+       * gst/base/gstbasesrc.c: (gst_basesrc_init),
+       (gst_basesrc_set_dataflow_funcs), (gst_basesrc_query):
+       * gst/base/gstcollectpads.c: (gst_collectpads_get_type),
+       (gst_collectpads_class_init), (gst_collectpads_init),
+       (gst_collectpads_finalize), (gst_collectpads_new),
+       (gst_collectpads_set_function), (gst_collectpads_add_pad),
+       (find_pad), (gst_collectpads_remove_pad),
+       (gst_collectpads_is_active), (gst_collectpads_collect),
+       (gst_collectpads_collect_range), (gst_collectpads_start),
+       (gst_collectpads_stop), (gst_collectpads_peek),
+       (gst_collectpads_pop), (gst_collectpads_available),
+       (gst_collectpads_read), (gst_collectpads_flush),
+       (gst_collectpads_chain):
+       * gst/base/gstcollectpads.h:
+       * gst/elements/Makefile.am:
+       * gst/elements/gstelements.c:
+       * gst/elements/gstfakesink.c: (gst_fakesink_class_init),
+       (gst_fakesink_get_times), (gst_fakesink_event),
+       (gst_fakesink_preroll), (gst_fakesink_render):
+       * gst/elements/gstfilesink.c: (gst_filesink_class_init),
+       (gst_filesink_init), (gst_filesink_set_location),
+       (gst_filesink_open_file), (gst_filesink_close_file),
+       (gst_filesink_pad_query), (gst_filesink_event),
+       (gst_filesink_render), (gst_filesink_change_state):
+       * gst/elements/gstfilesink.h:
+       Added object to help in making collect pad based elements.
+       Ported filesink.
+       Make event function in sink baseclass return gboolean.
+
+2005-05-05  Wim Taymans  <wim@fluendo.com>
+
        * gst/gstbin.c: (gst_bin_send_event), (compare_name),
        (gst_bin_get_by_name):
        * gst/gstbuffer.h:
index c1c12ff..e108353 100644 (file)
@@ -6,6 +6,7 @@ libgstbase_@GST_MAJORMINOR@_la_SOURCES =        \
        gstbasesink.c           \
        gstbasesrc.c            \
        gstbasetransform.c      \
+       gstcollectpads.c        \
        gsttypefindhelper.c     
 
 libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@@ -20,5 +21,6 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS =  \
        gstbasesink.h           \
        gstbasesrc.h            \
        gstbasetransform.h      \
+       gstcollectpads.h        \
        gsttypefindhelper.h     
 
index b3eafad..12c67c5 100644 (file)
@@ -75,7 +75,7 @@ struct _GstBaseSinkClass {
   void         (*get_times)    (GstBaseSink *sink, GstBuffer *buffer, 
                                 GstClockTime *start, GstClockTime *end);
 
-  void          (*event)        (GstBaseSink *sink, GstEvent *event);
+  gboolean      (*event)        (GstBaseSink *sink, GstEvent *event);
   GstFlowReturn (*preroll)      (GstBaseSink *sink, GstBuffer *buffer);
   GstFlowReturn (*render)       (GstBaseSink *sink, GstBuffer *buffer);
 };
index f4908ae..9d83d6d 100644 (file)
@@ -169,6 +169,7 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
   basesrc->srcpad = pad;
   gst_element_add_pad (GST_ELEMENT (basesrc), pad);
 
+  basesrc->random_access = TRUE;
   basesrc->segment_start = -1;
   basesrc->segment_end = -1;
   basesrc->blocksize = DEFAULT_BLOCKSIZE;
@@ -179,6 +180,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
 static void
 gst_basesrc_set_dataflow_funcs (GstBaseSrc * this)
 {
+  GST_DEBUG ("updating dataflow functions");
+
   if (this->has_loop)
     gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop);
   else
@@ -232,7 +235,6 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
         {
           gboolean ret;
 
-          /* FIXME-wim: is this cast right? */
           ret = gst_basesrc_get_size (src, (guint64 *) value);
           GST_DEBUG ("getting length %d %lld", ret, *value);
           return ret;
diff --git a/gst/base/gstcollectpads.c b/gst/base/gstcollectpads.c
new file mode 100644 (file)
index 0000000..71965b8
--- /dev/null
@@ -0,0 +1,538 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstcollectpads.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.
+ */
+
+#include "gstcollectpads.h"
+
+static GstFlowReturn gst_collectpads_chain (GstPad * pad, GstBuffer * buffer);
+
+static void gst_collectpads_class_init (GstCollectPadsClass * klass);
+static void gst_collectpads_init (GstCollectPads * pads);
+static void gst_collectpads_finalize (GObject * object);
+
+static GstObjectClass *parent_class = NULL;
+
+GType
+gst_collectpads_get_type (void)
+{
+  static GType collect_type = 0;
+
+  if (!collect_type) {
+    static const GTypeInfo collect_info = {
+      sizeof (GstCollectPadsClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_collectpads_class_init,
+      NULL,
+      NULL,
+      sizeof (GstCollectPads),
+      0,
+      (GInstanceInitFunc) gst_collectpads_init,
+      NULL
+    };
+
+    collect_type = g_type_register_static (GST_TYPE_OBJECT, "GstCollectPads",
+        &collect_info, 0);
+  }
+  return collect_type;
+}
+
+static void
+gst_collectpads_class_init (GstCollectPadsClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstObjectClass *gstobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstobject_class = (GstObjectClass *) klass;
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collectpads_finalize);
+
+  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+}
+
+static void
+gst_collectpads_init (GstCollectPads * pads)
+{
+  pads->cond = g_cond_new ();
+  pads->data = NULL;
+  pads->cookie = 0;
+  pads->numpads = 0;
+  pads->queuedpads = 0;
+  pads->started = FALSE;
+}
+
+static void
+gst_collectpads_finalize (GObject * object)
+{
+  GstCollectPads *pads = GST_COLLECTPADS (object);
+
+  g_cond_free (pads->cond);
+  /* FIXME, free data */
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * gst_collectpads_new:
+ *
+ * Create a new instance of #GstCollectsPads.
+ * 
+ * Returns: a new #GstCollectPads, or NULL in case of an error.
+ *
+ * MT safe.
+ */
+GstCollectPads *
+gst_collectpads_new (void)
+{
+  GstCollectPads *newcoll;
+
+  newcoll = g_object_new (GST_TYPE_COLLECTPADS, NULL);
+
+  return newcoll;
+}
+
+/**
+ * gst_collectpads_set_function:
+ * @pads: the collectspads 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
+ * all the pads added to the collection have buffers queued.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_set_function (GstCollectPads * pads,
+    GstCollectPadsFunction func, gpointer user_data)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->func = func;
+  pads->user_data = user_data;
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_add_pad:
+ * @pads: the collectspads to use
+ * @pad: the pad to add
+ * @size: the size of the returned GstCollectData structure
+ *
+ * Add a pad to the collection of collect pads. The pad has to be
+ * a sinkpad.
+ *
+ * You specify a size for the returned #GstCollectData structure
+ * so that you can use it to store additional information.
+ *
+ * Returns: a new #GstCollectData to identify the new pad. Or NULL
+ *   if wrong parameters are supplied.
+ *
+ * MT safe.
+ */
+GstCollectData *
+gst_collectpads_add_pad (GstCollectPads * pads, GstPad * pad, guint size)
+{
+  GstCollectData *data;
+
+  g_return_val_if_fail (pads != NULL, 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 (GstCollectData), NULL);
+
+  data = g_malloc0 (size);
+  data->collect = pads;
+  data->pad = pad;
+  data->buffer = NULL;
+
+  GST_LOCK (pads);
+  pads->data = g_slist_append (pads->data, data);
+  gst_pad_set_chain_function (pad, gst_collectpads_chain);
+  gst_pad_set_element_private (pad, data);
+  pads->numpads++;
+  pads->cookie++;
+  GST_UNLOCK (pads);
+
+  return data;
+}
+
+static gint
+find_pad (GstCollectData * data, GstPad * pad)
+{
+  if (data->pad == pad)
+    return 0;
+  return 1;
+}
+
+/**
+ * gst_collectpads_remove_pad:
+ * @pads: the collectspads to use
+ * @pad: the pad to remove
+ *
+ * Remove a pad from the collection of collect pads.
+ *
+ * Returns: TRUE if the pad could be removed.
+ *
+ * MT safe.
+ */
+gboolean
+gst_collectpads_remove_pad (GstCollectPads * pads, GstPad * pad)
+{
+  GSList *list;
+
+  g_return_val_if_fail (pads != NULL, FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  GST_LOCK (pads);
+  list = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
+  if (list) {
+    g_free (list->data);
+    pads->data = g_slist_delete_link (pads->data, list);
+  }
+  pads->numpads--;
+  pads->cookie++;
+  GST_UNLOCK (pads);
+
+  return list != NULL;
+}
+
+/**
+ * gst_collectpads_is_active:
+ * @pads: the collectspads to use
+ * @pad: the pad to check
+ *
+ * Check if a pad is active.
+ *
+ * Returns: TRUE if the pad is active.
+ *
+ * MT safe.
+ */
+gboolean
+gst_collectpads_is_active (GstCollectPads * pads, GstPad * pad)
+{
+  g_return_val_if_fail (pads != NULL, FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  return FALSE;
+}
+
+/**
+ * gst_collectpads_collect:
+ * @pads: the collectspads to use
+ *
+ * Collect data on all pads. This function is usually called
+ * from a GstTask function in an element.
+ *
+ * Returns: GstFlowReturn of the operation.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_collectpads_collect (GstCollectPads * pads)
+{
+  g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
+
+  return GST_FLOW_ERROR;
+}
+
+/**
+ * gst_collectpads_collect_range:
+ * @pads: the collectspads to use
+ * @offset: the offset to collect
+ * @length: the length to collect
+ *
+ * Collect data with @offset and @length on all pads. This function
+ * is typically called in the getrange function of an element.
+ *
+ * Returns: GstFlowReturn of the operation.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_collectpads_collect_range (GstCollectPads * pads, guint64 offset,
+    guint length)
+{
+  g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
+
+  return GST_FLOW_ERROR;
+}
+
+/**
+ * gst_collectpads_start:
+ * @pads: the collectspads to use
+ *
+ * Starts the processing of data in the collectpads.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_start (GstCollectPads * pads)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->started = TRUE;
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_stop:
+ * @pads: the collectspads to use
+ *
+ * Stops the processing of data in the collectpads. this function
+ * will also unblock any blocking operations.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_stop (GstCollectPads * pads)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->started = FALSE;
+  GST_COLLECTPADS_SIGNAL (pads);
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_peek:
+ * @pads: the collectspads to peek
+ * @data: the data to use
+ *
+ * Peek at the buffer currently queued in @data. This function
+ * should be called with the @pads LOCK held, such as in the callback
+ * handler.
+ *
+ * Returns: The buffer in @data or NULL if no buffer is queued. You
+ *  should unref the buffer after usage.
+ *
+ * MT safe.
+ */
+GstBuffer *
+gst_collectpads_peek (GstCollectPads * pads, GstCollectData * data)
+{
+  GstBuffer *result;
+
+  result = data->buffer;
+  gst_buffer_ref (result);
+
+  return result;
+}
+
+/**
+ * gst_collectpads_pop:
+ * @pads: the collectspads to pop
+ * @data: the data to use
+ *
+ * Pop the buffer currently queued in @data. This function
+ * should be called with the @pads LOCK held, such as in the callback
+ * handler.
+ *
+ * Returns: The buffer in @data or NULL if no buffer was queued. The
+ *   You should unref the buffer after usage.
+ *
+ * MT safe.
+ */
+GstBuffer *
+gst_collectpads_pop (GstCollectPads * pads, GstCollectData * data)
+{
+  GstBuffer *result;
+
+  result = data->buffer;
+  gst_buffer_replace (&data->buffer, NULL);
+  data->pos = 0;
+  pads->queuedpads--;
+
+  GST_COLLECTPADS_SIGNAL (pads);
+
+  return result;
+}
+
+/**
+ * gst_collectpads_available:
+ * @pads: the collectspads to query
+ *
+ * Query how much bytes can be read from each queued buffer. This means
+ * that the result of this call is the maximum number of bytes that can
+ * be read from each of the pads.
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The maximum number of bytes queued on all pad. This function 
+ * returns 0 if a pad has no queued buffer.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_available (GstCollectPads * pads)
+{
+  GSList *collected;
+  guint result = G_MAXUINT;
+
+  for (collected = pads->data; collected; collected = g_slist_next (collected)) {
+    GstCollectData *pdata;
+    gint size;
+
+    pdata = (GstCollectData *) collected->data;
+
+    if (pdata->buffer == NULL)
+      goto not_filled;
+
+    size = GST_BUFFER_SIZE (pdata->buffer) - pdata->pos;
+
+    if (size < result)
+      result = size;
+  }
+  return result;
+
+not_filled:
+  {
+    return 0;
+  }
+}
+
+/**
+ * gst_collectpads_read:
+ * @pads: the collectspads to query
+ * @data: the data to use
+ * @bytes: a pointer to a byte array 
+ * @size: the number of bytes to read
+ *
+ * Get a pointer in @bytes where @size bytes can be read from the
+ * given pad data.
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The number of bytes available for consumption in the
+ * memory pointed to by @bytes. This can be less than @size and
+ * is 0 if the pad is end-of-stream.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_read (GstCollectPads * pads, GstCollectData * data,
+    guint8 ** bytes, guint size)
+{
+  guint readsize;
+
+  readsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
+
+  *bytes = GST_BUFFER_DATA (data->buffer) + data->pos;
+
+  return readsize;
+}
+
+/**
+ * gst_collectpads_flush:
+ * @pads: the collectspads to query
+ * @data: the data to use
+ * @size: the number of bytes to flush
+ *
+ * Flush @size bytes from the pad @data. 
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The number of bytes flushed This can be less than @size and
+ * is 0 if the pad was end-of-stream.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_flush (GstCollectPads * pads, GstCollectData * data, guint size)
+{
+  guint flushsize;
+
+  flushsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
+
+  data->pos += size;
+
+  if (data->pos >= GST_BUFFER_SIZE (data->buffer)) {
+    GstBuffer *buf;
+
+    buf = gst_collectpads_pop (pads, data);
+    gst_buffer_unref (buf);
+  }
+
+  return flushsize;
+}
+
+static GstFlowReturn
+gst_collectpads_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstCollectData *data;
+  GstCollectPads *pads;
+  guint64 size;
+  GstFlowReturn ret;
+
+  GST_DEBUG ("chain");
+
+  /* some magic to get the managing collectpads */
+  data = (GstCollectData *) gst_pad_get_element_private (pad);
+  if (data == NULL)
+    goto not_ours;
+
+  pads = data->collect;
+  size = GST_BUFFER_SIZE (buffer);
+
+  GST_LOCK (pads);
+
+  /* if not started, bail out */
+  if (!pads->started)
+    goto not_started;
+
+  /* queue buffer on this pad, block if filled */
+  while (data->buffer != NULL) {
+    GST_COLLECTPADS_WAIT (pads);
+    /* after a signal,  we could be stopped */
+    if (!pads->started)
+      goto not_started;
+  }
+  pads->queuedpads++;
+  gst_buffer_replace (&data->buffer, buffer);
+
+  /* if all pads have data and we have a function, call it */
+  if ((pads->queuedpads == pads->numpads) && pads->func) {
+    ret = pads->func (pads, pads->user_data);
+  } else {
+    ret = GST_FLOW_OK;
+  }
+  GST_UNLOCK (pads);
+
+  return ret;
+
+  /* ERRORS */
+not_ours:
+  {
+    GST_DEBUG ("collectpads not ours");
+    return GST_FLOW_ERROR;
+  }
+not_started:
+  {
+    GST_UNLOCK (pads);
+    GST_DEBUG ("collectpads not started");
+    return GST_FLOW_WRONG_STATE;
+  }
+}
diff --git a/gst/base/gstcollectpads.h b/gst/base/gstcollectpads.h
new file mode 100644 (file)
index 0000000..3ae8c66
--- /dev/null
@@ -0,0 +1,132 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstcollectpads.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_COLLECTPADS_H__
+#define __GST_COLLECTPADS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_COLLECTPADS           (gst_collectpads_get_type())
+#define GST_COLLECTPADS(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COLLECTPADS,GstCollectPads))
+#define GST_COLLECTPADS_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COLLECTPADS,GstCollectPadsClass))
+#define GST_COLLECTPADS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_COLLECTPADS, GstCollectPadsClass))
+#define GST_IS_COLLECTPADS(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECTPADS))
+#define GST_IS_COLLECTPADS_CLASS(obj)          (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECTPADS))
+
+/* manages a set of pads that operate in collect mode. This means
+ * that control is given to the manager of this object when all
+ * pads have data.
+ *
+ * - pads are added to the collection with add/remove_pad. The pad
+ *   has to be a sinkpad. The chain function of the pad is
+ *   overridden. The element_private of the pad is used to store
+ *   private information.
+ * - For each pad, data is queued in the chain function or by
+ *   performing a pull_range.
+ * - When data is queued on all pads, a callback function is
+ *   called.
+ * - Data can be dequeued from the pad with the _pop() method. 
+ *   One can _peek() at the data with the peek function.
+ * - Data can also be dequeued with the available/read/flush
+ *   calls.
+ */
+
+typedef struct _GstCollectPads GstCollectPads;
+typedef struct _GstCollectPadsClass GstCollectPadsClass;
+
+typedef struct _GstCollectData
+{
+  GstCollectPads       *collect;
+  GstPad               *pad;
+  GstBuffer            *buffer;
+  guint                         pos;
+  gboolean              eos;
+} GstCollectData;
+
+/* function will be called when all pads have data */
+typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data);
+
+#define GST_COLLECTPADS_GET_COND(pads) (((GstCollectPads *)pads)->cond)
+#define GST_COLLECTPADS_WAIT(pads)     (g_cond_wait (GST_COLLECTPADS_GET_COND (pads), GST_GET_LOCK (pads)))
+#define GST_COLLECTPADS_SIGNAL(pads)   (g_cond_signal (GST_COLLECTPADS_GET_COND (pads)))
+#define GST_COLLECTPADS_BROADCAST(pads)(g_cond_broadcast (GST_COLLECTPADS_GET_COND (pads)))
+
+struct _GstCollectPads {
+  GstObject      object;
+
+  /*< public >*/ /* with LOCK */
+  GSList       *data;                  /* GstCollectData in this collection */
+  guint32       cookie;
+
+  GCond                *cond;                  /* to signal removal of data */
+
+  /*< private >*/
+  GstCollectPadsFunction func;         /* function and user_data for callback */
+  gpointer      user_data;
+
+  guint                 numpads;               /* number of pads */
+  guint                 queuedpads;            /* number of pads with a buffer */
+
+  gboolean      started;
+};
+
+struct _GstCollectPadsClass {
+  GstObjectClass parent_class;
+
+};
+
+GType gst_collectpads_get_type(void);
+
+/* creating the object */
+GstCollectPads*        gst_collectpads_new             (void);
+
+/* set the callback */
+void           gst_collectpads_set_function    (GstCollectPads *pads, GstCollectPadsFunction func,
+                                                gpointer user_data);
+
+/* pad management */
+GstCollectData*        gst_collectpads_add_pad         (GstCollectPads *pads, GstPad *pad, guint size);
+gboolean       gst_collectpads_remove_pad      (GstCollectPads *pads, GstPad *pad);
+gboolean       gst_collectpads_is_active       (GstCollectPads *pads, GstPad *pad);
+
+/* start/stop collection */
+GstFlowReturn  gst_collectpads_collect         (GstCollectPads *pads);
+GstFlowReturn  gst_collectpads_collect_range   (GstCollectPads *pads, guint64 offset, guint length);
+
+void           gst_collectpads_start           (GstCollectPads *pads);
+void           gst_collectpads_stop            (GstCollectPads *pads);
+
+/* get collected buffers */
+GstBuffer*     gst_collectpads_peek            (GstCollectPads *pads, GstCollectData *data);
+GstBuffer*     gst_collectpads_pop             (GstCollectPads *pads, GstCollectData *data);
+
+/* get collected bytes */
+guint          gst_collectpads_available       (GstCollectPads *pads);
+guint          gst_collectpads_read            (GstCollectPads *pads, GstCollectData *data, 
+                                                guint8 **bytes, guint size);
+guint          gst_collectpads_flush           (GstCollectPads *pads, GstCollectData *data, 
+                                                guint size);
+
+G_END_DECLS
+
+#endif /* __GST_COLLECTPADS_H__ */
index 2d631c7..561aed4 100644 (file)
@@ -15,6 +15,7 @@ libgstelements_la_SOURCES =   \
        gstcapsfilter.c         \
        gstfakesrc.c            \
        gstfakesink.c           \
+       gstfilesink.c           \
        gstfilesrc.c            \
        gstidentity.c           \
        gstelements.c           \
@@ -27,7 +28,6 @@ libgstelements_la_SOURCES =   \
 EXTRA_DIST =                   \
        gstaggregator.c         \
        gstcapsfilter.c         \
-       gstfilesink.c           \
        gstfdsink.c             \
        gstfdsrc.c              \
        gstmd5sink.c            \
index d5b228b..7427256 100644 (file)
@@ -64,7 +64,7 @@ static struct _elements_entry _elements[] = {
   {"identity", GST_RANK_NONE, gst_identity_get_type},
 //  {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
 //  {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
-//  {"filesink", GST_RANK_NONE, gst_filesink_get_type},
+  {"filesink", GST_RANK_NONE, gst_filesink_get_type},
 //  {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
 #ifndef HAVE_WIN32
 //  {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
index 30a8fdb..cbb7dfc 100644 (file)
@@ -116,7 +116,7 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
     GstBuffer * buffer);
 static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
     GstBuffer * buffer);
-static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
+static gboolean gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
 static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
     GstClockTime * start, GstClockTime * end);
 
@@ -269,7 +269,7 @@ gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
   }
 }
 
-static void
+static gboolean
 gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
 {
   GstFakeSink *sink = GST_FAKESINK (bsink);
@@ -283,6 +283,8 @@ gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
 
     g_object_notify (G_OBJECT (sink), "last_message");
   }
+
+  return TRUE;
 }
 
 static GstFlowReturn
index 1386758..162f649 100644 (file)
@@ -99,17 +99,19 @@ static void gst_filesink_get_property (GObject * object, guint prop_id,
 static gboolean gst_filesink_open_file (GstFileSink * sink);
 static void gst_filesink_close_file (GstFileSink * sink);
 
-static gboolean gst_filesink_handle_event (GstPad * pad, GstEvent * event);
+static gboolean gst_filesink_event (GstBaseSink * sink, GstEvent * event);
+static GstFlowReturn gst_filesink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+
 static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     GstFormat * format, gint64 * value);
-static void gst_filesink_chain (GstPad * pad, GstData * _data);
 
 static void gst_filesink_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
 
 static GstElementStateReturn gst_filesink_change_state (GstElement * element);
 
-static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
+//static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
 
 static void
 _do_init (GType filesink_type)
@@ -126,10 +128,9 @@ _do_init (GType filesink_type)
       "filesink element");
 }
 
-GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstElement, GST_TYPE_ELEMENT,
+GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstBaseSink, GST_TYPE_BASESINK,
     _do_init);
 
-
 static void
 gst_filesink_base_init (gpointer g_class)
 {
@@ -144,6 +145,7 @@ static void
 gst_filesink_class_init (GstFileSinkClass * klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gstbasesink_class = GST_BASESINK_CLASS (klass);
 
   gobject_class->set_property = gst_filesink_set_property;
   gobject_class->get_property = gst_filesink_get_property;
@@ -152,25 +154,17 @@ gst_filesink_class_init (GstFileSinkClass * klass)
       g_param_spec_string ("location", "File Location",
           "Location of the file to write", NULL, G_PARAM_READWRITE));
 
-  gst_filesink_signals[SIGNAL_HANDOFF] =
-      g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstFileSinkClass, handoff), NULL, NULL,
-      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
   gobject_class->dispose = gst_filesink_dispose;
+
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_filesink_render);
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_filesink_event);
 }
 static void
 gst_filesink_init (GstFileSink * filesink)
 {
   GstPad *pad;
 
-  pad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
-      "sink");
-  gst_element_add_pad (GST_ELEMENT (filesink), pad);
-  gst_pad_set_chain_function (pad, gst_filesink_chain);
-
-  GST_FLAG_SET (GST_ELEMENT (filesink), GST_ELEMENT_EVENT_AWARE);
+  pad = GST_BASESINK_PAD (filesink);
 
   gst_pad_set_query_function (pad, gst_filesink_pad_query);
   gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
@@ -196,10 +190,7 @@ static gboolean
 gst_filesink_set_location (GstFileSink * sink, const gchar * location)
 {
   /* the element must be stopped or paused in order to do this */
-  if (GST_STATE (sink) > GST_STATE_PAUSED)
-    return FALSE;
-  if (GST_STATE (sink) == GST_STATE_PAUSED &&
-      GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
+  if (GST_STATE (sink) >= GST_STATE_PAUSED)
     return FALSE;
 
   g_free (sink->filename);
@@ -212,9 +203,6 @@ gst_filesink_set_location (GstFileSink * sink, const gchar * location)
     sink->uri = NULL;
   }
 
-  if (GST_STATE (sink) == GST_STATE_PAUSED)
-    gst_filesink_open_file (sink);
-
   return TRUE;
 }
 static void
@@ -260,8 +248,6 @@ gst_filesink_get_property (GObject * object, guint prop_id, GValue * value,
 static gboolean
 gst_filesink_open_file (GstFileSink * sink)
 {
-  g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
-
   /* open the file */
   if (sink->filename == NULL || sink->filename[0] == '\0') {
     GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
@@ -277,8 +263,6 @@ gst_filesink_open_file (GstFileSink * sink)
     return FALSE;
   }
 
-  GST_FLAG_SET (sink, GST_FILESINK_OPEN);
-
   sink->data_written = 0;
 
   return TRUE;
@@ -287,13 +271,9 @@ gst_filesink_open_file (GstFileSink * sink)
 static void
 gst_filesink_close_file (GstFileSink * sink)
 {
-  g_return_if_fail (GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
-
   if (fclose (sink->file) != 0) {
     GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
         (_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
-  } else {
-    GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
   }
 }
 
@@ -307,11 +287,9 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     case GST_QUERY_TOTAL:
       switch (*format) {
         case GST_FORMAT_BYTES:
-          if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
-            *value = sink->data_written;        /* FIXME - doesn't the kernel provide
-                                                   such a function? */
-            break;
-          }
+          *value = sink->data_written;  /* FIXME - doesn't the kernel provide
+                                           such a function? */
+          break;
         default:
           return FALSE;
       }
@@ -319,10 +297,8 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     case GST_QUERY_POSITION:
       switch (*format) {
         case GST_FORMAT_BYTES:
-          if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
-            *value = ftell (sink->file);
-            break;
-          }
+          *value = ftell (sink->file);
+          break;
         default:
           return FALSE;
       }
@@ -336,30 +312,23 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
 
 /* handle events (search) */
 static gboolean
-gst_filesink_handle_event (GstPad * pad, GstEvent * event)
+gst_filesink_event (GstBaseSink * sink, GstEvent * event)
 {
   GstEventType type;
   GstFileSink *filesink;
 
-  filesink = GST_FILESINK (gst_pad_get_parent (pad));
-
-  if (!(GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))) {
-    gst_event_unref (event);
-    return FALSE;
-  }
+  filesink = GST_FILESINK (sink);
 
   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
 
   switch (type) {
     case GST_EVENT_SEEK:
       if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
-        gst_event_unref (event);
         return FALSE;
       }
 
       if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
         if (fflush (filesink->file)) {
-          gst_event_unref (event);
           GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
               (_("Error while writing to file \"%s\"."), filesink->filename),
               GST_ERROR_SYSTEM);
@@ -381,33 +350,24 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
           g_warning ("unknown seek method!");
           break;
       }
-      gst_event_unref (event);
       break;
     case GST_EVENT_DISCONTINUOUS:
     {
-      gint64 offset;
-
-      if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
-        fseek (filesink->file, offset, SEEK_SET);
+      gint64 soffset, eoffset;
 
-      gst_event_unref (event);
+      if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
+              &eoffset))
+        fseek (filesink->file, soffset, SEEK_SET);
       break;
     }
     case GST_EVENT_FLUSH:
       if (fflush (filesink->file)) {
-        gst_event_unref (event);
         GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
             (_("Error while writing to file \"%s\"."), filesink->filename),
             GST_ERROR_SYSTEM);
       }
       break;
-    case GST_EVENT_EOS:
-      gst_event_unref (event);
-      gst_filesink_close_file (filesink);
-      gst_element_set_eos (GST_ELEMENT (filesink));
-      break;
     default:
-      gst_pad_event_default (pad, event);
       break;
   }
 
@@ -421,75 +381,80 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
  *
  * take the buffer from the pad and write to file if it's open
  */
-static void
-gst_filesink_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_filesink_render (GstBaseSink * sink, GstBuffer * buffer)
 {
-  GstBuffer *buf = GST_BUFFER (_data);
   GstFileSink *filesink;
+  guint bytes_written = 0, back_pending = 0;
+  guint size;
 
-  g_return_if_fail (pad != NULL);
-  g_return_if_fail (GST_IS_PAD (pad));
-  g_return_if_fail (buf != NULL);
+  size = GST_BUFFER_SIZE (buffer);
 
-  filesink = GST_FILESINK (gst_pad_get_parent (pad));
+  filesink = GST_FILESINK (sink);
 
-  if (GST_IS_EVENT (buf)) {
-    gst_filesink_handle_event (pad, GST_EVENT (buf));
-    return;
-  }
+  if (ftell (filesink->file) < filesink->data_written)
+    back_pending = filesink->data_written - ftell (filesink->file);
 
-  if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) {
-    guint bytes_written = 0, back_pending = 0;
+  while (bytes_written < size) {
+    size_t wrote = fwrite (GST_BUFFER_DATA (buffer) + bytes_written, 1,
+        size - bytes_written, filesink->file);
 
-    if (ftell (filesink->file) < filesink->data_written)
-      back_pending = filesink->data_written - ftell (filesink->file);
-    while (bytes_written < GST_BUFFER_SIZE (buf)) {
-      size_t wrote = fwrite (GST_BUFFER_DATA (buf) + bytes_written, 1,
-          GST_BUFFER_SIZE (buf) - bytes_written,
-          filesink->file);
-
-      if (wrote <= 0) {
-        GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
-            (_("Error while writing to file \"%s\"."), filesink->filename),
-            ("Only %d of %d bytes written: %s",
-                bytes_written, GST_BUFFER_SIZE (buf), strerror (errno)));
-        break;
-      }
-      bytes_written += wrote;
+    if (wrote <= 0) {
+      GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
+          (_("Error while writing to file \"%s\"."), filesink->filename),
+          ("Only %d of %d bytes written: %s",
+              bytes_written, size, strerror (errno)));
+      break;
     }
-
-    filesink->data_written += bytes_written - back_pending;
+    bytes_written += wrote;
   }
 
-  gst_buffer_unref (buf);
+  filesink->data_written += bytes_written - back_pending;
 
-  g_signal_emit (G_OBJECT (filesink),
-      gst_filesink_signals[SIGNAL_HANDOFF], 0, filesink);
+  return GST_FLOW_OK;
 }
 
 static GstElementStateReturn
 gst_filesink_change_state (GstElement * element)
 {
-  g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE);
+  GstElementStateReturn ret;
+  gint transition;
 
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_PAUSED_TO_READY:
-      if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN))
-        gst_filesink_close_file (GST_FILESINK (element));
-      break;
+  transition = GST_STATE_TRANSITION (element);
 
+  switch (transition) {
+    case GST_STATE_NULL_TO_READY:
+      break;
     case GST_STATE_READY_TO_PAUSED:
-      if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) {
-        if (!gst_filesink_open_file (GST_FILESINK (element)))
-          return GST_STATE_FAILURE;
-      }
+      if (!gst_filesink_open_file (GST_FILESINK (element)))
+        goto open_error;
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
 
-  return GST_STATE_SUCCESS;
+  switch (transition) {
+    case GST_STATE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      gst_filesink_close_file (GST_FILESINK (element));
+      break;
+    case GST_STATE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+open_error:
+  {
+    return GST_STATE_FAILURE;
+  }
 }
 
 /*** GSTURIHANDLER INTERFACE *************************************************/
index bd85a1d..54090ef 100644 (file)
 #define __GST_FILESINK_H__
 
 #include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
 
 G_BEGIN_DECLS
 
-
 #define GST_TYPE_FILESINK \
   (gst_filesink_get_type())
 #define GST_FILESINK(obj) \
@@ -43,14 +43,8 @@ G_BEGIN_DECLS
 typedef struct _GstFileSink GstFileSink;
 typedef struct _GstFileSinkClass GstFileSinkClass;
 
-typedef enum {
-  GST_FILESINK_OPEN             = GST_ELEMENT_FLAG_LAST,
-
-  GST_FILESINK_FLAG_LAST       = GST_ELEMENT_FLAG_LAST + 2
-} GstFileSinkFlags;
-
 struct _GstFileSink {
-  GstElement element;
+  GstBaseSink parent;
 
   gchar *filename;
   gchar *uri;
@@ -60,10 +54,7 @@ struct _GstFileSink {
 };
 
 struct _GstFileSinkClass {
-  GstElementClass parent_class;
-
-  /* signals */
-  void (*handoff) (GstElement *element, GstPad *pad);
+  GstBaseSinkClass parent_class;
 };
 
 GType gst_filesink_get_type(void);
index c1c12ff..e108353 100644 (file)
@@ -6,6 +6,7 @@ libgstbase_@GST_MAJORMINOR@_la_SOURCES =        \
        gstbasesink.c           \
        gstbasesrc.c            \
        gstbasetransform.c      \
+       gstcollectpads.c        \
        gsttypefindhelper.c     
 
 libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@@ -20,5 +21,6 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS =  \
        gstbasesink.h           \
        gstbasesrc.h            \
        gstbasetransform.h      \
+       gstcollectpads.h        \
        gsttypefindhelper.h     
 
index b3eafad..12c67c5 100644 (file)
@@ -75,7 +75,7 @@ struct _GstBaseSinkClass {
   void         (*get_times)    (GstBaseSink *sink, GstBuffer *buffer, 
                                 GstClockTime *start, GstClockTime *end);
 
-  void          (*event)        (GstBaseSink *sink, GstEvent *event);
+  gboolean      (*event)        (GstBaseSink *sink, GstEvent *event);
   GstFlowReturn (*preroll)      (GstBaseSink *sink, GstBuffer *buffer);
   GstFlowReturn (*render)       (GstBaseSink *sink, GstBuffer *buffer);
 };
index f4908ae..9d83d6d 100644 (file)
@@ -169,6 +169,7 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
   basesrc->srcpad = pad;
   gst_element_add_pad (GST_ELEMENT (basesrc), pad);
 
+  basesrc->random_access = TRUE;
   basesrc->segment_start = -1;
   basesrc->segment_end = -1;
   basesrc->blocksize = DEFAULT_BLOCKSIZE;
@@ -179,6 +180,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
 static void
 gst_basesrc_set_dataflow_funcs (GstBaseSrc * this)
 {
+  GST_DEBUG ("updating dataflow functions");
+
   if (this->has_loop)
     gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop);
   else
@@ -232,7 +235,6 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
         {
           gboolean ret;
 
-          /* FIXME-wim: is this cast right? */
           ret = gst_basesrc_get_size (src, (guint64 *) value);
           GST_DEBUG ("getting length %d %lld", ret, *value);
           return ret;
diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c
new file mode 100644 (file)
index 0000000..71965b8
--- /dev/null
@@ -0,0 +1,538 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstcollectpads.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.
+ */
+
+#include "gstcollectpads.h"
+
+static GstFlowReturn gst_collectpads_chain (GstPad * pad, GstBuffer * buffer);
+
+static void gst_collectpads_class_init (GstCollectPadsClass * klass);
+static void gst_collectpads_init (GstCollectPads * pads);
+static void gst_collectpads_finalize (GObject * object);
+
+static GstObjectClass *parent_class = NULL;
+
+GType
+gst_collectpads_get_type (void)
+{
+  static GType collect_type = 0;
+
+  if (!collect_type) {
+    static const GTypeInfo collect_info = {
+      sizeof (GstCollectPadsClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_collectpads_class_init,
+      NULL,
+      NULL,
+      sizeof (GstCollectPads),
+      0,
+      (GInstanceInitFunc) gst_collectpads_init,
+      NULL
+    };
+
+    collect_type = g_type_register_static (GST_TYPE_OBJECT, "GstCollectPads",
+        &collect_info, 0);
+  }
+  return collect_type;
+}
+
+static void
+gst_collectpads_class_init (GstCollectPadsClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstObjectClass *gstobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstobject_class = (GstObjectClass *) klass;
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collectpads_finalize);
+
+  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+}
+
+static void
+gst_collectpads_init (GstCollectPads * pads)
+{
+  pads->cond = g_cond_new ();
+  pads->data = NULL;
+  pads->cookie = 0;
+  pads->numpads = 0;
+  pads->queuedpads = 0;
+  pads->started = FALSE;
+}
+
+static void
+gst_collectpads_finalize (GObject * object)
+{
+  GstCollectPads *pads = GST_COLLECTPADS (object);
+
+  g_cond_free (pads->cond);
+  /* FIXME, free data */
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * gst_collectpads_new:
+ *
+ * Create a new instance of #GstCollectsPads.
+ * 
+ * Returns: a new #GstCollectPads, or NULL in case of an error.
+ *
+ * MT safe.
+ */
+GstCollectPads *
+gst_collectpads_new (void)
+{
+  GstCollectPads *newcoll;
+
+  newcoll = g_object_new (GST_TYPE_COLLECTPADS, NULL);
+
+  return newcoll;
+}
+
+/**
+ * gst_collectpads_set_function:
+ * @pads: the collectspads 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
+ * all the pads added to the collection have buffers queued.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_set_function (GstCollectPads * pads,
+    GstCollectPadsFunction func, gpointer user_data)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->func = func;
+  pads->user_data = user_data;
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_add_pad:
+ * @pads: the collectspads to use
+ * @pad: the pad to add
+ * @size: the size of the returned GstCollectData structure
+ *
+ * Add a pad to the collection of collect pads. The pad has to be
+ * a sinkpad.
+ *
+ * You specify a size for the returned #GstCollectData structure
+ * so that you can use it to store additional information.
+ *
+ * Returns: a new #GstCollectData to identify the new pad. Or NULL
+ *   if wrong parameters are supplied.
+ *
+ * MT safe.
+ */
+GstCollectData *
+gst_collectpads_add_pad (GstCollectPads * pads, GstPad * pad, guint size)
+{
+  GstCollectData *data;
+
+  g_return_val_if_fail (pads != NULL, 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 (GstCollectData), NULL);
+
+  data = g_malloc0 (size);
+  data->collect = pads;
+  data->pad = pad;
+  data->buffer = NULL;
+
+  GST_LOCK (pads);
+  pads->data = g_slist_append (pads->data, data);
+  gst_pad_set_chain_function (pad, gst_collectpads_chain);
+  gst_pad_set_element_private (pad, data);
+  pads->numpads++;
+  pads->cookie++;
+  GST_UNLOCK (pads);
+
+  return data;
+}
+
+static gint
+find_pad (GstCollectData * data, GstPad * pad)
+{
+  if (data->pad == pad)
+    return 0;
+  return 1;
+}
+
+/**
+ * gst_collectpads_remove_pad:
+ * @pads: the collectspads to use
+ * @pad: the pad to remove
+ *
+ * Remove a pad from the collection of collect pads.
+ *
+ * Returns: TRUE if the pad could be removed.
+ *
+ * MT safe.
+ */
+gboolean
+gst_collectpads_remove_pad (GstCollectPads * pads, GstPad * pad)
+{
+  GSList *list;
+
+  g_return_val_if_fail (pads != NULL, FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  GST_LOCK (pads);
+  list = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
+  if (list) {
+    g_free (list->data);
+    pads->data = g_slist_delete_link (pads->data, list);
+  }
+  pads->numpads--;
+  pads->cookie++;
+  GST_UNLOCK (pads);
+
+  return list != NULL;
+}
+
+/**
+ * gst_collectpads_is_active:
+ * @pads: the collectspads to use
+ * @pad: the pad to check
+ *
+ * Check if a pad is active.
+ *
+ * Returns: TRUE if the pad is active.
+ *
+ * MT safe.
+ */
+gboolean
+gst_collectpads_is_active (GstCollectPads * pads, GstPad * pad)
+{
+  g_return_val_if_fail (pads != NULL, FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  return FALSE;
+}
+
+/**
+ * gst_collectpads_collect:
+ * @pads: the collectspads to use
+ *
+ * Collect data on all pads. This function is usually called
+ * from a GstTask function in an element.
+ *
+ * Returns: GstFlowReturn of the operation.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_collectpads_collect (GstCollectPads * pads)
+{
+  g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
+
+  return GST_FLOW_ERROR;
+}
+
+/**
+ * gst_collectpads_collect_range:
+ * @pads: the collectspads to use
+ * @offset: the offset to collect
+ * @length: the length to collect
+ *
+ * Collect data with @offset and @length on all pads. This function
+ * is typically called in the getrange function of an element.
+ *
+ * Returns: GstFlowReturn of the operation.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_collectpads_collect_range (GstCollectPads * pads, guint64 offset,
+    guint length)
+{
+  g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
+
+  return GST_FLOW_ERROR;
+}
+
+/**
+ * gst_collectpads_start:
+ * @pads: the collectspads to use
+ *
+ * Starts the processing of data in the collectpads.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_start (GstCollectPads * pads)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->started = TRUE;
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_stop:
+ * @pads: the collectspads to use
+ *
+ * Stops the processing of data in the collectpads. this function
+ * will also unblock any blocking operations.
+ *
+ * MT safe.
+ */
+void
+gst_collectpads_stop (GstCollectPads * pads)
+{
+  g_return_if_fail (pads != NULL);
+
+  GST_LOCK (pads);
+  pads->started = FALSE;
+  GST_COLLECTPADS_SIGNAL (pads);
+  GST_UNLOCK (pads);
+}
+
+/**
+ * gst_collectpads_peek:
+ * @pads: the collectspads to peek
+ * @data: the data to use
+ *
+ * Peek at the buffer currently queued in @data. This function
+ * should be called with the @pads LOCK held, such as in the callback
+ * handler.
+ *
+ * Returns: The buffer in @data or NULL if no buffer is queued. You
+ *  should unref the buffer after usage.
+ *
+ * MT safe.
+ */
+GstBuffer *
+gst_collectpads_peek (GstCollectPads * pads, GstCollectData * data)
+{
+  GstBuffer *result;
+
+  result = data->buffer;
+  gst_buffer_ref (result);
+
+  return result;
+}
+
+/**
+ * gst_collectpads_pop:
+ * @pads: the collectspads to pop
+ * @data: the data to use
+ *
+ * Pop the buffer currently queued in @data. This function
+ * should be called with the @pads LOCK held, such as in the callback
+ * handler.
+ *
+ * Returns: The buffer in @data or NULL if no buffer was queued. The
+ *   You should unref the buffer after usage.
+ *
+ * MT safe.
+ */
+GstBuffer *
+gst_collectpads_pop (GstCollectPads * pads, GstCollectData * data)
+{
+  GstBuffer *result;
+
+  result = data->buffer;
+  gst_buffer_replace (&data->buffer, NULL);
+  data->pos = 0;
+  pads->queuedpads--;
+
+  GST_COLLECTPADS_SIGNAL (pads);
+
+  return result;
+}
+
+/**
+ * gst_collectpads_available:
+ * @pads: the collectspads to query
+ *
+ * Query how much bytes can be read from each queued buffer. This means
+ * that the result of this call is the maximum number of bytes that can
+ * be read from each of the pads.
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The maximum number of bytes queued on all pad. This function 
+ * returns 0 if a pad has no queued buffer.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_available (GstCollectPads * pads)
+{
+  GSList *collected;
+  guint result = G_MAXUINT;
+
+  for (collected = pads->data; collected; collected = g_slist_next (collected)) {
+    GstCollectData *pdata;
+    gint size;
+
+    pdata = (GstCollectData *) collected->data;
+
+    if (pdata->buffer == NULL)
+      goto not_filled;
+
+    size = GST_BUFFER_SIZE (pdata->buffer) - pdata->pos;
+
+    if (size < result)
+      result = size;
+  }
+  return result;
+
+not_filled:
+  {
+    return 0;
+  }
+}
+
+/**
+ * gst_collectpads_read:
+ * @pads: the collectspads to query
+ * @data: the data to use
+ * @bytes: a pointer to a byte array 
+ * @size: the number of bytes to read
+ *
+ * Get a pointer in @bytes where @size bytes can be read from the
+ * given pad data.
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The number of bytes available for consumption in the
+ * memory pointed to by @bytes. This can be less than @size and
+ * is 0 if the pad is end-of-stream.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_read (GstCollectPads * pads, GstCollectData * data,
+    guint8 ** bytes, guint size)
+{
+  guint readsize;
+
+  readsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
+
+  *bytes = GST_BUFFER_DATA (data->buffer) + data->pos;
+
+  return readsize;
+}
+
+/**
+ * gst_collectpads_flush:
+ * @pads: the collectspads to query
+ * @data: the data to use
+ * @size: the number of bytes to flush
+ *
+ * Flush @size bytes from the pad @data. 
+ *
+ * This function should be called with @pads LOCK held, such as
+ * in the callback.
+ *
+ * Returns: The number of bytes flushed This can be less than @size and
+ * is 0 if the pad was end-of-stream.
+ *
+ * MT safe.
+ */
+guint
+gst_collectpads_flush (GstCollectPads * pads, GstCollectData * data, guint size)
+{
+  guint flushsize;
+
+  flushsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
+
+  data->pos += size;
+
+  if (data->pos >= GST_BUFFER_SIZE (data->buffer)) {
+    GstBuffer *buf;
+
+    buf = gst_collectpads_pop (pads, data);
+    gst_buffer_unref (buf);
+  }
+
+  return flushsize;
+}
+
+static GstFlowReturn
+gst_collectpads_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstCollectData *data;
+  GstCollectPads *pads;
+  guint64 size;
+  GstFlowReturn ret;
+
+  GST_DEBUG ("chain");
+
+  /* some magic to get the managing collectpads */
+  data = (GstCollectData *) gst_pad_get_element_private (pad);
+  if (data == NULL)
+    goto not_ours;
+
+  pads = data->collect;
+  size = GST_BUFFER_SIZE (buffer);
+
+  GST_LOCK (pads);
+
+  /* if not started, bail out */
+  if (!pads->started)
+    goto not_started;
+
+  /* queue buffer on this pad, block if filled */
+  while (data->buffer != NULL) {
+    GST_COLLECTPADS_WAIT (pads);
+    /* after a signal,  we could be stopped */
+    if (!pads->started)
+      goto not_started;
+  }
+  pads->queuedpads++;
+  gst_buffer_replace (&data->buffer, buffer);
+
+  /* if all pads have data and we have a function, call it */
+  if ((pads->queuedpads == pads->numpads) && pads->func) {
+    ret = pads->func (pads, pads->user_data);
+  } else {
+    ret = GST_FLOW_OK;
+  }
+  GST_UNLOCK (pads);
+
+  return ret;
+
+  /* ERRORS */
+not_ours:
+  {
+    GST_DEBUG ("collectpads not ours");
+    return GST_FLOW_ERROR;
+  }
+not_started:
+  {
+    GST_UNLOCK (pads);
+    GST_DEBUG ("collectpads not started");
+    return GST_FLOW_WRONG_STATE;
+  }
+}
diff --git a/libs/gst/base/gstcollectpads.h b/libs/gst/base/gstcollectpads.h
new file mode 100644 (file)
index 0000000..3ae8c66
--- /dev/null
@@ -0,0 +1,132 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstcollectpads.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_COLLECTPADS_H__
+#define __GST_COLLECTPADS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_COLLECTPADS           (gst_collectpads_get_type())
+#define GST_COLLECTPADS(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COLLECTPADS,GstCollectPads))
+#define GST_COLLECTPADS_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COLLECTPADS,GstCollectPadsClass))
+#define GST_COLLECTPADS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_COLLECTPADS, GstCollectPadsClass))
+#define GST_IS_COLLECTPADS(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECTPADS))
+#define GST_IS_COLLECTPADS_CLASS(obj)          (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECTPADS))
+
+/* manages a set of pads that operate in collect mode. This means
+ * that control is given to the manager of this object when all
+ * pads have data.
+ *
+ * - pads are added to the collection with add/remove_pad. The pad
+ *   has to be a sinkpad. The chain function of the pad is
+ *   overridden. The element_private of the pad is used to store
+ *   private information.
+ * - For each pad, data is queued in the chain function or by
+ *   performing a pull_range.
+ * - When data is queued on all pads, a callback function is
+ *   called.
+ * - Data can be dequeued from the pad with the _pop() method. 
+ *   One can _peek() at the data with the peek function.
+ * - Data can also be dequeued with the available/read/flush
+ *   calls.
+ */
+
+typedef struct _GstCollectPads GstCollectPads;
+typedef struct _GstCollectPadsClass GstCollectPadsClass;
+
+typedef struct _GstCollectData
+{
+  GstCollectPads       *collect;
+  GstPad               *pad;
+  GstBuffer            *buffer;
+  guint                         pos;
+  gboolean              eos;
+} GstCollectData;
+
+/* function will be called when all pads have data */
+typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data);
+
+#define GST_COLLECTPADS_GET_COND(pads) (((GstCollectPads *)pads)->cond)
+#define GST_COLLECTPADS_WAIT(pads)     (g_cond_wait (GST_COLLECTPADS_GET_COND (pads), GST_GET_LOCK (pads)))
+#define GST_COLLECTPADS_SIGNAL(pads)   (g_cond_signal (GST_COLLECTPADS_GET_COND (pads)))
+#define GST_COLLECTPADS_BROADCAST(pads)(g_cond_broadcast (GST_COLLECTPADS_GET_COND (pads)))
+
+struct _GstCollectPads {
+  GstObject      object;
+
+  /*< public >*/ /* with LOCK */
+  GSList       *data;                  /* GstCollectData in this collection */
+  guint32       cookie;
+
+  GCond                *cond;                  /* to signal removal of data */
+
+  /*< private >*/
+  GstCollectPadsFunction func;         /* function and user_data for callback */
+  gpointer      user_data;
+
+  guint                 numpads;               /* number of pads */
+  guint                 queuedpads;            /* number of pads with a buffer */
+
+  gboolean      started;
+};
+
+struct _GstCollectPadsClass {
+  GstObjectClass parent_class;
+
+};
+
+GType gst_collectpads_get_type(void);
+
+/* creating the object */
+GstCollectPads*        gst_collectpads_new             (void);
+
+/* set the callback */
+void           gst_collectpads_set_function    (GstCollectPads *pads, GstCollectPadsFunction func,
+                                                gpointer user_data);
+
+/* pad management */
+GstCollectData*        gst_collectpads_add_pad         (GstCollectPads *pads, GstPad *pad, guint size);
+gboolean       gst_collectpads_remove_pad      (GstCollectPads *pads, GstPad *pad);
+gboolean       gst_collectpads_is_active       (GstCollectPads *pads, GstPad *pad);
+
+/* start/stop collection */
+GstFlowReturn  gst_collectpads_collect         (GstCollectPads *pads);
+GstFlowReturn  gst_collectpads_collect_range   (GstCollectPads *pads, guint64 offset, guint length);
+
+void           gst_collectpads_start           (GstCollectPads *pads);
+void           gst_collectpads_stop            (GstCollectPads *pads);
+
+/* get collected buffers */
+GstBuffer*     gst_collectpads_peek            (GstCollectPads *pads, GstCollectData *data);
+GstBuffer*     gst_collectpads_pop             (GstCollectPads *pads, GstCollectData *data);
+
+/* get collected bytes */
+guint          gst_collectpads_available       (GstCollectPads *pads);
+guint          gst_collectpads_read            (GstCollectPads *pads, GstCollectData *data, 
+                                                guint8 **bytes, guint size);
+guint          gst_collectpads_flush           (GstCollectPads *pads, GstCollectData *data, 
+                                                guint size);
+
+G_END_DECLS
+
+#endif /* __GST_COLLECTPADS_H__ */
index 2d631c7..561aed4 100644 (file)
@@ -15,6 +15,7 @@ libgstelements_la_SOURCES =   \
        gstcapsfilter.c         \
        gstfakesrc.c            \
        gstfakesink.c           \
+       gstfilesink.c           \
        gstfilesrc.c            \
        gstidentity.c           \
        gstelements.c           \
@@ -27,7 +28,6 @@ libgstelements_la_SOURCES =   \
 EXTRA_DIST =                   \
        gstaggregator.c         \
        gstcapsfilter.c         \
-       gstfilesink.c           \
        gstfdsink.c             \
        gstfdsrc.c              \
        gstmd5sink.c            \
index d5b228b..7427256 100644 (file)
@@ -64,7 +64,7 @@ static struct _elements_entry _elements[] = {
   {"identity", GST_RANK_NONE, gst_identity_get_type},
 //  {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
 //  {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
-//  {"filesink", GST_RANK_NONE, gst_filesink_get_type},
+  {"filesink", GST_RANK_NONE, gst_filesink_get_type},
 //  {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
 #ifndef HAVE_WIN32
 //  {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
index 30a8fdb..cbb7dfc 100644 (file)
@@ -116,7 +116,7 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
     GstBuffer * buffer);
 static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
     GstBuffer * buffer);
-static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
+static gboolean gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
 static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
     GstClockTime * start, GstClockTime * end);
 
@@ -269,7 +269,7 @@ gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
   }
 }
 
-static void
+static gboolean
 gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
 {
   GstFakeSink *sink = GST_FAKESINK (bsink);
@@ -283,6 +283,8 @@ gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
 
     g_object_notify (G_OBJECT (sink), "last_message");
   }
+
+  return TRUE;
 }
 
 static GstFlowReturn
index 1386758..162f649 100644 (file)
@@ -99,17 +99,19 @@ static void gst_filesink_get_property (GObject * object, guint prop_id,
 static gboolean gst_filesink_open_file (GstFileSink * sink);
 static void gst_filesink_close_file (GstFileSink * sink);
 
-static gboolean gst_filesink_handle_event (GstPad * pad, GstEvent * event);
+static gboolean gst_filesink_event (GstBaseSink * sink, GstEvent * event);
+static GstFlowReturn gst_filesink_render (GstBaseSink * sink,
+    GstBuffer * buffer);
+
 static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     GstFormat * format, gint64 * value);
-static void gst_filesink_chain (GstPad * pad, GstData * _data);
 
 static void gst_filesink_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
 
 static GstElementStateReturn gst_filesink_change_state (GstElement * element);
 
-static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
+//static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
 
 static void
 _do_init (GType filesink_type)
@@ -126,10 +128,9 @@ _do_init (GType filesink_type)
       "filesink element");
 }
 
-GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstElement, GST_TYPE_ELEMENT,
+GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstBaseSink, GST_TYPE_BASESINK,
     _do_init);
 
-
 static void
 gst_filesink_base_init (gpointer g_class)
 {
@@ -144,6 +145,7 @@ static void
 gst_filesink_class_init (GstFileSinkClass * klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gstbasesink_class = GST_BASESINK_CLASS (klass);
 
   gobject_class->set_property = gst_filesink_set_property;
   gobject_class->get_property = gst_filesink_get_property;
@@ -152,25 +154,17 @@ gst_filesink_class_init (GstFileSinkClass * klass)
       g_param_spec_string ("location", "File Location",
           "Location of the file to write", NULL, G_PARAM_READWRITE));
 
-  gst_filesink_signals[SIGNAL_HANDOFF] =
-      g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstFileSinkClass, handoff), NULL, NULL,
-      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
   gobject_class->dispose = gst_filesink_dispose;
+
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_filesink_render);
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_filesink_event);
 }
 static void
 gst_filesink_init (GstFileSink * filesink)
 {
   GstPad *pad;
 
-  pad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
-      "sink");
-  gst_element_add_pad (GST_ELEMENT (filesink), pad);
-  gst_pad_set_chain_function (pad, gst_filesink_chain);
-
-  GST_FLAG_SET (GST_ELEMENT (filesink), GST_ELEMENT_EVENT_AWARE);
+  pad = GST_BASESINK_PAD (filesink);
 
   gst_pad_set_query_function (pad, gst_filesink_pad_query);
   gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
@@ -196,10 +190,7 @@ static gboolean
 gst_filesink_set_location (GstFileSink * sink, const gchar * location)
 {
   /* the element must be stopped or paused in order to do this */
-  if (GST_STATE (sink) > GST_STATE_PAUSED)
-    return FALSE;
-  if (GST_STATE (sink) == GST_STATE_PAUSED &&
-      GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
+  if (GST_STATE (sink) >= GST_STATE_PAUSED)
     return FALSE;
 
   g_free (sink->filename);
@@ -212,9 +203,6 @@ gst_filesink_set_location (GstFileSink * sink, const gchar * location)
     sink->uri = NULL;
   }
 
-  if (GST_STATE (sink) == GST_STATE_PAUSED)
-    gst_filesink_open_file (sink);
-
   return TRUE;
 }
 static void
@@ -260,8 +248,6 @@ gst_filesink_get_property (GObject * object, guint prop_id, GValue * value,
 static gboolean
 gst_filesink_open_file (GstFileSink * sink)
 {
-  g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
-
   /* open the file */
   if (sink->filename == NULL || sink->filename[0] == '\0') {
     GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
@@ -277,8 +263,6 @@ gst_filesink_open_file (GstFileSink * sink)
     return FALSE;
   }
 
-  GST_FLAG_SET (sink, GST_FILESINK_OPEN);
-
   sink->data_written = 0;
 
   return TRUE;
@@ -287,13 +271,9 @@ gst_filesink_open_file (GstFileSink * sink)
 static void
 gst_filesink_close_file (GstFileSink * sink)
 {
-  g_return_if_fail (GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
-
   if (fclose (sink->file) != 0) {
     GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
         (_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
-  } else {
-    GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
   }
 }
 
@@ -307,11 +287,9 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     case GST_QUERY_TOTAL:
       switch (*format) {
         case GST_FORMAT_BYTES:
-          if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
-            *value = sink->data_written;        /* FIXME - doesn't the kernel provide
-                                                   such a function? */
-            break;
-          }
+          *value = sink->data_written;  /* FIXME - doesn't the kernel provide
+                                           such a function? */
+          break;
         default:
           return FALSE;
       }
@@ -319,10 +297,8 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
     case GST_QUERY_POSITION:
       switch (*format) {
         case GST_FORMAT_BYTES:
-          if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) {
-            *value = ftell (sink->file);
-            break;
-          }
+          *value = ftell (sink->file);
+          break;
         default:
           return FALSE;
       }
@@ -336,30 +312,23 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
 
 /* handle events (search) */
 static gboolean
-gst_filesink_handle_event (GstPad * pad, GstEvent * event)
+gst_filesink_event (GstBaseSink * sink, GstEvent * event)
 {
   GstEventType type;
   GstFileSink *filesink;
 
-  filesink = GST_FILESINK (gst_pad_get_parent (pad));
-
-  if (!(GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))) {
-    gst_event_unref (event);
-    return FALSE;
-  }
+  filesink = GST_FILESINK (sink);
 
   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
 
   switch (type) {
     case GST_EVENT_SEEK:
       if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
-        gst_event_unref (event);
         return FALSE;
       }
 
       if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
         if (fflush (filesink->file)) {
-          gst_event_unref (event);
           GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
               (_("Error while writing to file \"%s\"."), filesink->filename),
               GST_ERROR_SYSTEM);
@@ -381,33 +350,24 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
           g_warning ("unknown seek method!");
           break;
       }
-      gst_event_unref (event);
       break;
     case GST_EVENT_DISCONTINUOUS:
     {
-      gint64 offset;
-
-      if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
-        fseek (filesink->file, offset, SEEK_SET);
+      gint64 soffset, eoffset;
 
-      gst_event_unref (event);
+      if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
+              &eoffset))
+        fseek (filesink->file, soffset, SEEK_SET);
       break;
     }
     case GST_EVENT_FLUSH:
       if (fflush (filesink->file)) {
-        gst_event_unref (event);
         GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
             (_("Error while writing to file \"%s\"."), filesink->filename),
             GST_ERROR_SYSTEM);
       }
       break;
-    case GST_EVENT_EOS:
-      gst_event_unref (event);
-      gst_filesink_close_file (filesink);
-      gst_element_set_eos (GST_ELEMENT (filesink));
-      break;
     default:
-      gst_pad_event_default (pad, event);
       break;
   }
 
@@ -421,75 +381,80 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
  *
  * take the buffer from the pad and write to file if it's open
  */
-static void
-gst_filesink_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_filesink_render (GstBaseSink * sink, GstBuffer * buffer)
 {
-  GstBuffer *buf = GST_BUFFER (_data);
   GstFileSink *filesink;
+  guint bytes_written = 0, back_pending = 0;
+  guint size;
 
-  g_return_if_fail (pad != NULL);
-  g_return_if_fail (GST_IS_PAD (pad));
-  g_return_if_fail (buf != NULL);
+  size = GST_BUFFER_SIZE (buffer);
 
-  filesink = GST_FILESINK (gst_pad_get_parent (pad));
+  filesink = GST_FILESINK (sink);
 
-  if (GST_IS_EVENT (buf)) {
-    gst_filesink_handle_event (pad, GST_EVENT (buf));
-    return;
-  }
+  if (ftell (filesink->file) < filesink->data_written)
+    back_pending = filesink->data_written - ftell (filesink->file);
 
-  if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) {
-    guint bytes_written = 0, back_pending = 0;
+  while (bytes_written < size) {
+    size_t wrote = fwrite (GST_BUFFER_DATA (buffer) + bytes_written, 1,
+        size - bytes_written, filesink->file);
 
-    if (ftell (filesink->file) < filesink->data_written)
-      back_pending = filesink->data_written - ftell (filesink->file);
-    while (bytes_written < GST_BUFFER_SIZE (buf)) {
-      size_t wrote = fwrite (GST_BUFFER_DATA (buf) + bytes_written, 1,
-          GST_BUFFER_SIZE (buf) - bytes_written,
-          filesink->file);
-
-      if (wrote <= 0) {
-        GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
-            (_("Error while writing to file \"%s\"."), filesink->filename),
-            ("Only %d of %d bytes written: %s",
-                bytes_written, GST_BUFFER_SIZE (buf), strerror (errno)));
-        break;
-      }
-      bytes_written += wrote;
+    if (wrote <= 0) {
+      GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
+          (_("Error while writing to file \"%s\"."), filesink->filename),
+          ("Only %d of %d bytes written: %s",
+              bytes_written, size, strerror (errno)));
+      break;
     }
-
-    filesink->data_written += bytes_written - back_pending;
+    bytes_written += wrote;
   }
 
-  gst_buffer_unref (buf);
+  filesink->data_written += bytes_written - back_pending;
 
-  g_signal_emit (G_OBJECT (filesink),
-      gst_filesink_signals[SIGNAL_HANDOFF], 0, filesink);
+  return GST_FLOW_OK;
 }
 
 static GstElementStateReturn
 gst_filesink_change_state (GstElement * element)
 {
-  g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE);
+  GstElementStateReturn ret;
+  gint transition;
 
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_PAUSED_TO_READY:
-      if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN))
-        gst_filesink_close_file (GST_FILESINK (element));
-      break;
+  transition = GST_STATE_TRANSITION (element);
 
+  switch (transition) {
+    case GST_STATE_NULL_TO_READY:
+      break;
     case GST_STATE_READY_TO_PAUSED:
-      if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) {
-        if (!gst_filesink_open_file (GST_FILESINK (element)))
-          return GST_STATE_FAILURE;
-      }
+      if (!gst_filesink_open_file (GST_FILESINK (element)))
+        goto open_error;
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
 
-  return GST_STATE_SUCCESS;
+  switch (transition) {
+    case GST_STATE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      gst_filesink_close_file (GST_FILESINK (element));
+      break;
+    case GST_STATE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+open_error:
+  {
+    return GST_STATE_FAILURE;
+  }
 }
 
 /*** GSTURIHANDLER INTERFACE *************************************************/
index bd85a1d..54090ef 100644 (file)
 #define __GST_FILESINK_H__
 
 #include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
 
 G_BEGIN_DECLS
 
-
 #define GST_TYPE_FILESINK \
   (gst_filesink_get_type())
 #define GST_FILESINK(obj) \
@@ -43,14 +43,8 @@ G_BEGIN_DECLS
 typedef struct _GstFileSink GstFileSink;
 typedef struct _GstFileSinkClass GstFileSinkClass;
 
-typedef enum {
-  GST_FILESINK_OPEN             = GST_ELEMENT_FLAG_LAST,
-
-  GST_FILESINK_FLAG_LAST       = GST_ELEMENT_FLAG_LAST + 2
-} GstFileSinkFlags;
-
 struct _GstFileSink {
-  GstElement element;
+  GstBaseSink parent;
 
   gchar *filename;
   gchar *uri;
@@ -60,10 +54,7 @@ struct _GstFileSink {
 };
 
 struct _GstFileSinkClass {
-  GstElementClass parent_class;
-
-  /* signals */
-  void (*handoff) (GstElement *element, GstPad *pad);
+  GstBaseSinkClass parent_class;
 };
 
 GType gst_filesink_get_type(void);