gst/: Simplify pad activation.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 29 Mar 2005 16:18:12 +0000 (16:18 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 29 Mar 2005 16:18:12 +0000 (16:18 +0000)
Original commit message from CVS:
* gst/base/Makefile.am:
* gst/base/README:
* gst/base/gstbasesink.c: (gst_basesink_get_type),
(gst_basesink_base_init), (gst_basesink_class_init),
(gst_basesink_pad_getcaps), (gst_basesink_init),
(gst_basesink_activate), (gst_basesink_change_state):
* gst/base/gstbasesink.h:
* gst/base/gstbasetransform.c: (gst_base_transform_get_type),
(gst_base_transform_base_init), (gst_base_transform_finalize),
(gst_base_transform_class_init), (gst_base_transform_init),
(gst_base_transform_proxy_getcaps), (gst_base_transform_setcaps),
(gst_base_transform_event), (gst_base_transform_getrange),
(gst_base_transform_chain), (gst_base_transform_handle_buffer),
(gst_base_transform_set_property),
(gst_base_transform_get_property),
(gst_base_transform_sink_activate),
(gst_base_transform_src_activate),
(gst_base_transform_change_state):
* gst/base/gstbasetransform.h:
* gst/elements/gstidentity.c: (gst_identity_finalize),
(gst_identity_class_init), (gst_identity_init),
(gst_identity_event), (gst_identity_check_perfect),
(gst_identity_transform), (gst_identity_set_property),
(gst_identity_get_property), (gst_identity_change_state):
* gst/elements/gstidentity.h:
* gst/gstelement.c: (gst_element_get_state_func),
(gst_element_lost_state), (gst_element_pads_activate):
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
(gst_pad_check_pull_range), (gst_pad_pull_range):
* gst/gstpad.h:
Simplify pad activation.
Added function to check if pull_range can be performed.
Error out when pulling inactive or flushing pads.
Removed const from refcounted types as it does not make sense.
Simplify pad templates in basesink
Added base class for simple 1-to-1 transforms.
Make identity subclass the base transform.

20 files changed:
ChangeLog
gst/base/Makefile.am
gst/base/README
gst/base/gstbasesink.c
gst/base/gstbasesink.h
gst/base/gstbasetransform.c [new file with mode: 0644]
gst/base/gstbasetransform.h [new file with mode: 0644]
gst/elements/gstidentity.c
gst/elements/gstidentity.h
gst/gstelement.c
gst/gstpad.c
gst/gstpad.h
libs/gst/base/Makefile.am
libs/gst/base/README
libs/gst/base/gstbasesink.c
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasetransform.c [new file with mode: 0644]
libs/gst/base/gstbasetransform.h [new file with mode: 0644]
plugins/elements/gstidentity.c
plugins/elements/gstidentity.h

index 3a0a2aeb24be1a67f8c67b802d96e37b802838ca..040875e64b5f80bfd3f3eaf2a1af3190abab7212 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+2005-03-29  Wim Taymans  <wim@fluendo.com>
+
+       * gst/base/Makefile.am:
+       * gst/base/README:
+       * gst/base/gstbasesink.c: (gst_basesink_get_type),
+       (gst_basesink_base_init), (gst_basesink_class_init),
+       (gst_basesink_pad_getcaps), (gst_basesink_init),
+       (gst_basesink_activate), (gst_basesink_change_state):
+       * gst/base/gstbasesink.h:
+       * gst/base/gstbasetransform.c: (gst_base_transform_get_type),
+       (gst_base_transform_base_init), (gst_base_transform_finalize),
+       (gst_base_transform_class_init), (gst_base_transform_init),
+       (gst_base_transform_proxy_getcaps), (gst_base_transform_setcaps),
+       (gst_base_transform_event), (gst_base_transform_getrange),
+       (gst_base_transform_chain), (gst_base_transform_handle_buffer),
+       (gst_base_transform_set_property),
+       (gst_base_transform_get_property),
+       (gst_base_transform_sink_activate),
+       (gst_base_transform_src_activate),
+       (gst_base_transform_change_state):
+       * gst/base/gstbasetransform.h:
+       * gst/elements/gstidentity.c: (gst_identity_finalize),
+       (gst_identity_class_init), (gst_identity_init),
+       (gst_identity_event), (gst_identity_check_perfect),
+       (gst_identity_transform), (gst_identity_set_property),
+       (gst_identity_get_property), (gst_identity_change_state):
+       * gst/elements/gstidentity.h:
+       * gst/gstelement.c: (gst_element_get_state_func),
+       (gst_element_lost_state), (gst_element_pads_activate):
+       * gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
+       (gst_pad_check_pull_range), (gst_pad_pull_range):
+       * gst/gstpad.h:
+       Simplify pad activation.
+       Added function to check if pull_range can be performed.
+       Error out when pulling inactive or flushing pads.
+       Removed const from refcounted types as it does not make sense.
+       Simplify pad templates in basesink
+       Added base class for simple 1-to-1 transforms.
+       Make identity subclass the base transform.
+
 2005-03-29  Andy Wingo  <wingo@pobox.com>
 
        * docs/libs/gstreamer-libs-overrides.txt: 
index 8ba1b85d56e3514262084122c91d969901b819df..dda7031d9a2050568af92d32584d9f0aa66aca5f 100644 (file)
@@ -6,7 +6,8 @@ noinst_DATA = $(as_libtool_noinst_DATA_files)
 
 libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
 libgstbase_@GST_MAJORMINOR@_la_SOURCES =       \
-       gstbasesink.c   
+       gstbasesink.c   \
+       gstbasetransform.c      
 
 libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
 libgstbase_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS)
@@ -16,7 +17,8 @@ libgstbase_@GST_MAJORMINOR@includedir =               \
        $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/base
 
 libgstbase_@GST_MAJORMINOR@include_HEADERS =   \
-       gstbasesink.h   
+       gstbasesink.h   \
+       gstbasetransform.h      
 
 install-data-local: as-libtool-install-data-local
 
index efd6e572a9d2ca59b7da1469c73fd3a2919eefd7..f9c158376debbecc824b7054c60d87794ba6374c 100644 (file)
@@ -14,3 +14,14 @@ GstBaseSink
 
   FIXME: not much point making it operate in pull mode as a generic
   base class I guess... 
+
+GstBaseTransform
+
+  Base class for simple tranform filters
+
+  - one sinkpad and one srcpad
+  - formats the same on sink and source pad.
+  - handles state changes
+  - does flushing
+  - push mode
+  - pull mode if transform can operate on arbitrary data
index a476071fd332effd62ebd2fe1dc7cf05c458bcd3..88d7d978163cf33c9323c768a367bf2344173294 100644 (file)
 #include "gstbasesink.h"
 #include <gst/gstmarshal.h>
 
-static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
-    GST_PAD_SINK,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS_ANY);
-
 GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
 #define GST_CAT_DEFAULT gst_basesink_debug
 
@@ -61,11 +56,35 @@ enum
   PROP_PREROLL_QUEUE_LEN
 };
 
-#define _do_init(bla) \
-    GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
+static GstElementClass *parent_class = NULL;
+
+static void gst_basesink_base_init (gpointer g_class);
+static void gst_basesink_class_init (GstBaseSinkClass * klass);
+static void gst_basesink_init (GstBaseSink * trans, gpointer g_class);
+
+GType
+gst_basesink_get_type (void)
+{
+  static GType basesink_type = 0;
+
+  if (!basesink_type) {
+    static const GTypeInfo basesink_info = {
+      sizeof (GstBaseSinkClass),
+      (GBaseInitFunc) gst_basesink_base_init,
+      NULL,
+      (GClassInitFunc) gst_basesink_class_init,
+      NULL,
+      NULL,
+      sizeof (GstBaseSink),
+      0,
+      (GInstanceInitFunc) gst_basesink_init,
+    };
 
-GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
-    _do_init);
+    basesink_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstBaseSink", &basesink_info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return basesink_type;
+}
 
 static void gst_basesink_set_clock (GstElement * element, GstClock * clock);
 
@@ -74,7 +93,6 @@ static void gst_basesink_set_property (GObject * object, guint prop_id,
 static void gst_basesink_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink);
 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
 static GstBuffer *gst_base_sink_buffer_alloc (GstBaseSink * sink,
@@ -93,32 +111,11 @@ static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
 static inline void gst_basesink_handle_buffer (GstBaseSink * basesink,
     GstBuffer * buf);
 
-static GstStaticPadTemplate *
-gst_basesink_get_template (GstBaseSink * bsink)
-{
-  GstStaticPadTemplate *template = NULL;
-  GstBaseSinkClass *bclass;
-
-  bclass = GST_BASESINK_GET_CLASS (bsink);
-
-  if (bclass->get_template)
-    template = bclass->get_template (bsink);
-
-  if (template == NULL) {
-    template = &sinktemplate;
-  }
-  return template;
-}
-
 static void
 gst_basesink_base_init (gpointer g_class)
 {
-  //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
-  /*
-     gst_element_class_add_pad_template (gstelement_class,
-     gst_static_pad_template_get (&sinktemplate));
-   */
+  GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0,
+      "basesink element");
 }
 
 static void
@@ -130,6 +127,8 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property);
 
@@ -153,7 +152,6 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
 
   klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
   klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
-  klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
   klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
   klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times);
 }
@@ -171,13 +169,15 @@ gst_basesink_pad_getcaps (GstPad * pad)
     caps = bclass->get_caps (bsink);
 
   if (caps == NULL) {
-    GstStaticPadTemplate *stemplate;
-    GstPadTemplate *template;
+    GstPadTemplate *pad_template;
 
-    stemplate = gst_basesink_get_template (bsink);
-    template = gst_static_pad_template_get (stemplate);
-    caps = gst_caps_copy (gst_pad_template_get_caps (template));
+    pad_template =
+        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
+    if (pad_template != NULL) {
+      caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+    }
   }
+
   return caps;
 }
 
@@ -213,15 +213,16 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
 }
 
 static void
-gst_basesink_init (GstBaseSink * basesink)
+gst_basesink_init (GstBaseSink * basesink, gpointer g_class)
 {
-  GstStaticPadTemplate *template;
+  GstPadTemplate *pad_template;
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+  g_return_if_fail (pad_template != NULL);
 
-  template = gst_basesink_get_template (basesink);
+  basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
 
-  basesink->sinkpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (template),
-      "sink");
   gst_pad_set_getcaps_function (basesink->sinkpad,
       GST_DEBUG_FUNCPTR (gst_basesink_pad_getcaps));
   gst_pad_set_setcaps_function (basesink->sinkpad,
@@ -328,12 +329,6 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
   GST_UNLOCK (sink);
 }
 
-static GstStaticPadTemplate *
-gst_base_sink_get_template (GstBaseSink * sink)
-{
-  return &sinktemplate;
-}
-
 static GstCaps *
 gst_base_sink_get_caps (GstBaseSink * sink)
 {
@@ -735,6 +730,7 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode)
     case GST_ACTIVATE_PULL:
       /* if we have a scheduler we can start the task */
       g_return_val_if_fail (basesink->has_loop, FALSE);
+      gst_pad_peer_set_active (pad, mode);
       if (GST_ELEMENT_SCHEDULER (basesink)) {
         GST_STREAM_LOCK (pad);
         GST_RPAD_TASK (pad) =
@@ -791,7 +787,7 @@ gst_basesink_change_state (GstElement * element)
       break;
     case GST_STATE_READY_TO_PAUSED:
       /* need to complete preroll before this state change completes, there
-       * is no data flow in READY so we cqn safely assume we need to preroll. */
+       * is no data flow in READY so we can safely assume we need to preroll. */
       basesink->offset = 0;
       GST_PREROLL_LOCK (basesink->sinkpad);
       basesink->preroll_queue = g_queue_new ();
index 3c64f78ed3dfcc54bea0d0cdc844083d6c61bfe6..b3eafade441df6c52a2f695e4794170800c2df28 100644 (file)
@@ -66,8 +66,6 @@ struct _GstBaseSink {
 struct _GstBaseSinkClass {
   GstElementClass parent_class;
 
-  GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
-
   GstCaps*      (*get_caps)     (GstBaseSink *sink);
   gboolean      (*set_caps)     (GstBaseSink *sink, GstCaps *caps);
 
diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c
new file mode 100644 (file)
index 0000000..c6032d6
--- /dev/null
@@ -0,0 +1,404 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstbasetransform.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 <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+#include "gstbasetransform.h"
+#include <gst/gstmarshal.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
+#define GST_CAT_DEFAULT gst_base_transform_debug
+
+/* BaseTransform signals and args */
+enum
+{
+  SIGNAL_HANDOFF,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+};
+
+static GstElementClass *parent_class = NULL;
+
+static void gst_base_transform_base_init (gpointer g_class);
+static void gst_base_transform_class_init (GstBaseTransformClass * klass);
+static void gst_base_transform_init (GstBaseTransform * trans,
+    gpointer g_class);
+
+GType
+gst_base_transform_get_type (void)
+{
+  static GType base_transform_type = 0;
+
+  if (!base_transform_type) {
+    static const GTypeInfo base_transform_info = {
+      sizeof (GstBaseTransformClass),
+      (GBaseInitFunc) gst_base_transform_base_init,
+      NULL,
+      (GClassInitFunc) gst_base_transform_class_init,
+      NULL,
+      NULL,
+      sizeof (GstBaseTransform),
+      0,
+      (GInstanceInitFunc) gst_base_transform_init,
+    };
+
+    base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return base_transform_type;
+}
+
+static void gst_base_transform_finalize (GObject * object);
+static void gst_base_transform_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_base_transform_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_base_transform_src_activate (GstPad * pad,
+    GstActivateMode mode);
+static gboolean gst_base_transform_sink_activate (GstPad * pad,
+    GstActivateMode mode);
+static GstElementStateReturn gst_base_transform_change_state (GstElement *
+    element);
+
+static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
+    guint length, GstBuffer ** buffer);
+static GstFlowReturn gst_base_transform_chain (GstPad * pad,
+    GstBuffer * buffer);
+static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf);
+static GstCaps *gst_base_transform_proxy_getcaps (GstPad * pad);
+static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
+
+/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
+
+static void
+gst_base_transform_base_init (gpointer g_class)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
+      "basetransform element");
+}
+
+static void
+gst_base_transform_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_base_transform_class_init (GstBaseTransformClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
+}
+
+static void
+gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
+{
+  GstPadTemplate *pad_template;
+
+  GST_DEBUG ("gst_base_transform_init");
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+  g_return_if_fail (pad_template != NULL);
+  trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
+  gst_pad_set_getcaps_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
+  gst_pad_set_setcaps_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
+  gst_pad_set_event_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_event));
+  gst_pad_set_chain_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_chain));
+  gst_pad_set_activate_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate));
+  gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
+  g_return_if_fail (pad_template != NULL);
+  trans->srcpad = gst_pad_new_from_template (pad_template, "src");
+  gst_pad_set_getcaps_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
+  gst_pad_set_getrange_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
+  gst_pad_set_activate_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_src_activate));
+  gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
+}
+
+static GstCaps *
+gst_base_transform_proxy_getcaps (GstPad * pad)
+{
+  GstPad *otherpad;
+  GstBaseTransform *trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
+
+  return gst_pad_peer_get_caps (otherpad);
+}
+
+static gboolean
+gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstBaseTransform *trans;
+  GstBaseTransformClass *bclass;
+  gboolean result = TRUE;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (bclass->set_caps)
+    result = bclass->set_caps (trans, caps);
+
+  return result;
+}
+
+static gboolean
+gst_base_transform_event (GstPad * pad, GstEvent * event)
+{
+  GstBaseTransform *trans;
+  GstBaseTransformClass *bclass;
+  gboolean ret = FALSE;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (bclass->event)
+    bclass->event (trans, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH:
+      if (GST_EVENT_FLUSH_DONE (event)) {
+      }
+      GST_STREAM_LOCK (pad);
+      break;
+    case GST_EVENT_EOS:
+      GST_STREAM_LOCK (pad);
+      break;
+    default:
+      break;
+  }
+  ret = gst_pad_event_default (pad, event);
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_getrange (GstPad * pad, guint64 offset,
+    guint length, GstBuffer ** buffer)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn ret;
+  GstBuffer *inbuf;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+
+  GST_STREAM_LOCK (pad);
+
+  ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
+  if (ret == GST_FLOW_OK) {
+    ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
+  }
+
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *outbuf;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+
+  GST_STREAM_LOCK (pad);
+
+  ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
+  if (ret == GST_FLOW_OK) {
+    ret = gst_pad_push (trans->srcpad, outbuf);
+  }
+
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBaseTransformClass *bclass;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  if (bclass->transform)
+    ret = bclass->transform (trans, inbuf, outbuf);
+
+  gst_buffer_unref (inbuf);
+
+  return ret;
+}
+
+static void
+gst_base_transform_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_base_transform_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result = FALSE;
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_PULL:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_NONE:
+      result = TRUE;
+      break;
+  }
+  return result;
+}
+
+static gboolean
+gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result = FALSE;
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_PULL:
+      result = gst_pad_set_active (trans->sinkpad, mode);
+      result = gst_pad_peer_set_active (trans->sinkpad, mode);
+      break;
+    case GST_ACTIVATE_NONE:
+      result = TRUE;
+      break;
+  }
+  return result;
+}
+
+static GstElementStateReturn
+gst_base_transform_change_state (GstElement * element)
+{
+  GstBaseTransform *trans;
+  GstElementState transition;
+  GstElementStateReturn result;
+
+  trans = GST_BASE_TRANSFORM (element);
+  transition = GST_STATE_TRANSITION (element);
+
+  switch (transition) {
+    case GST_STATE_NULL_TO_READY:
+      break;
+    case GST_STATE_READY_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  switch (transition) {
+    case GST_STATE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return result;
+}
diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h
new file mode 100644 (file)
index 0000000..788fe53
--- /dev/null
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstbasetransform.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_BASE_TRANSFORM_H__
+#define __GST_BASE_TRANSFORM_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_BASE_TRANSFORM        (gst_base_transform_get_type())
+#define GST_BASE_TRANSFORM(obj)        (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransform))
+#define GST_BASE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
+#define GST_BASE_TRANSFORM_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
+#define GST_IS_BASE_TRANSFORM(obj)     (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_TRANSFORM))
+#define GST_IS_BASE_TRANSFORM_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_TRANSFORM))
+
+/* the names of the templates for the sink and source pads */
+#define GST_BASE_TRANSFORM_SINK_NAME   "sink"
+#define GST_BASE_TRANSFORM_SRC_NAME    "src"
+
+typedef struct _GstBaseTransform GstBaseTransform;
+typedef struct _GstBaseTransformClass GstBaseTransformClass;
+
+struct _GstBaseTransform {
+  GstElement    element;
+
+  /* source and sink pads */
+  GstPad       *sinkpad;
+  GstPad       *srcpad;
+};
+
+struct _GstBaseTransformClass {
+  GstElementClass parent_class;
+
+  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *caps);
+
+  gboolean      (*event)        (GstBaseTransform *trans, GstEvent *event);
+  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
+};
+
+GType gst_base_transform_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_TRANSFORM_H__ */
index 0b8a6d2f7e2c75b4c06a03df64ad4a62b958abcd..76a61f7e12bfb0b72eb83ee1227310901b1b0b76 100644 (file)
@@ -59,7 +59,6 @@ enum
   LAST_SIGNAL
 };
 
-#define DEFAULT_LOOP_BASED             FALSE
 #define DEFAULT_SLEEP_TIME             0
 #define DEFAULT_DUPLICATE              1
 #define DEFAULT_ERROR_AFTER            -1
@@ -73,11 +72,6 @@ enum
 enum
 {
   PROP_0,
-  PROP_HAS_GETRANGE,
-  PROP_HAS_CHAIN,
-  PROP_HAS_SINK_LOOP,
-  PROP_HAS_SRC_LOOP,
-  PROP_LOOP_BASED,
   PROP_SLEEP_TIME,
   PROP_DUPLICATE,
   PROP_ERROR_AFTER,
@@ -91,14 +85,11 @@ enum
 };
 
 
-typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *);
-
-
 #define _do_init(bla) \
     GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
 
-GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT,
-    _do_init);
+GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstBaseTransform,
+    GST_TYPE_BASE_TRANSFORM, _do_init);
 
 static void gst_identity_finalize (GObject * object);
 static void gst_identity_set_property (GObject * object, guint prop_id,
@@ -107,17 +98,9 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static GstElementStateReturn gst_identity_change_state (GstElement * element);
 
-static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer);
-static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
-static void gst_identity_src_loop (GstPad * pad);
-static void gst_identity_sink_loop (GstPad * pad);
-static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity,
-    GstBuffer * buf);
-static void gst_identity_set_clock (GstElement * element, GstClock * clock);
-static GstCaps *gst_identity_proxy_getcaps (GstPad * pad);
-
+static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
+static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf);
 
 static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
 
@@ -140,9 +123,6 @@ gst_identity_finalize (GObject * object)
 
   identity = GST_IDENTITY (object);
 
-  g_mutex_free (identity->pen_lock);
-  g_cond_free (identity->pen_cond);
-
   g_free (identity->last_message);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -153,29 +133,15 @@ gst_identity_class_init (GstIdentityClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
+  GstBaseTransformClass *gstbasetrans_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
   gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
 
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
 
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
-      g_param_spec_boolean ("has-getrange", "Has getrange",
-          "If the src pad will implement a getrange function",
-          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
-      g_param_spec_boolean ("has-chain", "Has chain",
-          "If the sink pad will implement a chain function",
-          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP,
-      g_param_spec_boolean ("has-src-loop", "Has src loop",
-          "If the src pad will implement a loop function",
-          FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
-      g_param_spec_boolean ("has-sink-loop", "Has sink loop",
-          "If the sink pad will implement a loop function",
-          FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME,
       g_param_spec_uint ("sleep-time", "Sleep time",
           "Microseconds to sleep between processing", 0, G_MAXUINT,
@@ -220,33 +186,16 @@ gst_identity_class_init (GstIdentityClass * klass)
 
   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
 
-  gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_identity_change_state);
 
+  gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_identity_event);
+  gstbasetrans_class->transform = GST_DEBUG_FUNCPTR (gst_identity_transform);
 }
 
 static void
 gst_identity_init (GstIdentity * identity)
 {
-  identity->sinkpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
-      "sink");
-  gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
-  gst_pad_set_getcaps_function (identity->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
-  gst_pad_set_event_function (identity->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_identity_event));
-
-  identity->srcpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
-      "src");
-  gst_pad_set_getcaps_function (identity->srcpad,
-      GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
-  gst_pad_set_getrange_function (identity->srcpad,
-      GST_DEBUG_FUNCPTR (gst_identity_getrange));
-  gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
-
   identity->sleep_time = DEFAULT_SLEEP_TIME;
   identity->duplicate = DEFAULT_DUPLICATE;
   identity->error_after = DEFAULT_ERROR_AFTER;
@@ -257,279 +206,78 @@ gst_identity_init (GstIdentity * identity)
   identity->check_perfect = DEFAULT_CHECK_PERFECT;
   identity->dump = DEFAULT_DUMP;
   identity->last_message = NULL;
-  identity->srccaps = NULL;
-
-  identity->pen_data = NULL;
-  identity->pen_lock = g_mutex_new ();
-  identity->pen_cond = g_cond_new ();
-  identity->pen_flushing = FALSE;
-}
-
-static void
-gst_identity_set_clock (GstElement * element, GstClock * clock)
-{
-  GstIdentity *identity = GST_IDENTITY (element);
-
-  gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
-}
-
-static GstCaps *
-gst_identity_proxy_getcaps (GstPad * pad)
-{
-  GstPad *otherpad;
-  GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad));
-
-  otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad;
-
-  return gst_pad_peer_get_caps (otherpad);
-}
-
-static gboolean
-identity_queue_push (GstIdentity * identity, GstData * data)
-{
-  gboolean ret;
-
-  g_mutex_lock (identity->pen_lock);
-  while (identity->pen_data && !identity->pen_flushing)
-    g_cond_wait (identity->pen_cond, identity->pen_lock);
-  if (identity->pen_flushing) {
-    gst_data_unref (identity->pen_data);
-    identity->pen_data = NULL;
-    gst_data_unref (data);
-    ret = FALSE;
-  } else {
-    identity->pen_data = data;
-    ret = TRUE;
-  }
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
-
-  return ret;
-}
-
-static GstData *
-identity_queue_pop (GstIdentity * identity)
-{
-  GstData *ret;
-
-  g_mutex_lock (identity->pen_lock);
-  while (!(ret = identity->pen_data) && !identity->pen_flushing)
-    g_cond_wait (identity->pen_cond, identity->pen_lock);
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
-
-  return ret;
-}
-
-static void
-identity_queue_flush (GstIdentity * identity)
-{
-  g_mutex_lock (identity->pen_lock);
-  identity->pen_flushing = TRUE;
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
 }
 
 static gboolean
-gst_identity_event (GstPad * pad, GstEvent * event)
+gst_identity_event (GstBaseTransform * trans, GstEvent * event)
 {
   GstIdentity *identity;
-  gboolean ret;
 
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  identity = GST_IDENTITY (trans);
 
   if (!identity->silent) {
     g_free (identity->last_message);
 
     identity->last_message =
         g_strdup_printf ("chain   ******* (%s:%s)E (type: %d) %p",
-        GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
+        GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), event);
 
     g_object_notify (G_OBJECT (identity), "last_message");
   }
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_FLUSH:
-      /* forward event */
-      gst_pad_event_default (pad, event);
-      if (GST_EVENT_FLUSH_DONE (event)) {
-        if (identity->sink_mode == GST_ACTIVATE_PULL) {
-          /* already have the sink stream lock */
-          gst_task_start (GST_RPAD_TASK (identity->sinkpad));
-        }
-        if (identity->src_mode == GST_ACTIVATE_PUSH) {
-          GST_STREAM_LOCK (identity->srcpad);
-          gst_task_start (GST_RPAD_TASK (identity->srcpad));
-          GST_STREAM_UNLOCK (identity->srcpad);
-        }
-      } else {
-        /* unblock both functions */
-        identity_queue_flush (identity);
-
-      }
-      ret = TRUE;
-      goto done;
-    case GST_EVENT_EOS:
-      if (identity->sink_mode == GST_ACTIVATE_PULL) {
-        /* already have the sink stream lock */
-        gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
-      }
-      break;
-    default:
-      break;
-  }
-
-  if (identity->decoupled) {
-    ret = identity_queue_push (identity, (GstData *) event);
-  } else {
-    ret = gst_pad_push_event (identity->srcpad, event);
-  }
-
-done:
-  GST_STREAM_UNLOCK (pad);
-  return ret;
-}
-
-static GstFlowReturn
-gst_identity_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer)
-{
-  GstIdentity *identity;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer);
-
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_identity_chain (GstPad * pad, GstBuffer * buffer)
-{
-  GstIdentity *identity;
-  GstFlowReturn ret = GST_FLOW_OK;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_identity_handle_buffer (identity, buffer);
-
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
+  return TRUE;
 }
 
-#define DEFAULT_PULL_SIZE 1024
-
 static void
-gst_identity_sink_loop (GstPad * pad)
+gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
 {
-  GstIdentity *identity;
-  GstBuffer *buffer;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer);
-  if (ret != GST_FLOW_OK)
-    goto sink_loop_pause;
-
-  ret = gst_identity_handle_buffer (identity, buffer);
-  if (ret != GST_FLOW_OK)
-    goto sink_loop_pause;
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-sink_loop_pause:
-  gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
-  GST_STREAM_UNLOCK (pad);
-  return;
-}
+  GstClockTime timestamp;
 
-static void
-gst_identity_src_loop (GstPad * pad)
-{
-  GstIdentity *identity;
-  GstData *data;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  data = identity_queue_pop (identity);
-  if (!data)                    /* we're getting flushed */
-    goto src_loop_pause;
-
-  if (GST_IS_EVENT (data)) {
-    if (GST_EVENT_TYPE (data) == GST_EVENT_EOS)
-      gst_task_pause (GST_RPAD_TASK (identity->srcpad));
-    gst_pad_push_event (identity->srcpad, GST_EVENT (data));
-  } else {
-    ret = gst_pad_push (identity->srcpad, (GstBuffer *) data);
-    if (ret != GST_FLOW_OK)
-      goto src_loop_pause;
-  }
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-src_loop_pause:
-  gst_task_pause (GST_RPAD_TASK (identity->srcpad));
-  GST_STREAM_UNLOCK (pad);
-  return;
-}
-
-static GstFlowReturn
-gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
 
   /* see if we need to do perfect stream checking */
   /* invalid timestamp drops us out of check.  FIXME: maybe warn ? */
-  if (identity->check_perfect &&
-      GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
+  if (timestamp != GST_CLOCK_TIME_NONE) {
     /* check if we had a previous buffer to compare to */
     if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) {
-      if (identity->prev_timestamp + identity->prev_duration !=
-          GST_BUFFER_TIMESTAMP (buf)) {
+      guint64 offset;
+
+      if (identity->prev_timestamp + identity->prev_duration != timestamp) {
         GST_WARNING_OBJECT (identity,
             "Buffer not time-contiguous with previous one: " "prev ts %"
             GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %"
             GST_TIME_FORMAT, GST_TIME_ARGS (identity->prev_timestamp),
-            GST_TIME_ARGS (identity->prev_duration),
-            GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+            GST_TIME_ARGS (identity->prev_duration), GST_TIME_ARGS (timestamp));
       }
-      if (identity->prev_offset_end != GST_BUFFER_OFFSET (buf)) {
+
+      offset = GST_BUFFER_OFFSET (buf);
+      if (identity->prev_offset_end != offset) {
         GST_WARNING_OBJECT (identity,
             "Buffer not data-contiguous with previous one: "
             "prev offset_end %" G_GINT64_FORMAT ", new offset %"
-            G_GINT64_FORMAT, identity->prev_offset_end,
-            GST_BUFFER_OFFSET (buf));
+            G_GINT64_FORMAT, identity->prev_offset_end, offset);
       }
     }
     /* update prev values */
-    identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf);
+    identity->prev_timestamp = timestamp;
     identity->prev_duration = GST_BUFFER_DURATION (buf);
     identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
   }
+}
+
+static GstFlowReturn
+gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstIdentity *identity = GST_IDENTITY (trans);
+  guint i;
+
+  if (identity->check_perfect)
+    gst_identity_check_perfect (identity, inbuf);
 
   if (identity->error_after >= 0) {
     identity->error_after--;
     if (identity->error_after == 0) {
-      gst_buffer_unref (buf);
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
       return GST_FLOW_ERROR;
@@ -543,18 +291,18 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
           g_strdup_printf ("dropping   ******* (%s:%s)i (%d bytes, timestamp: %"
           GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
           G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
-          GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
-          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-          GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
+          GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
+          GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
+          GST_BUFFER_FLAGS (inbuf), inbuf);
       g_object_notify (G_OBJECT (identity), "last-message");
-      gst_buffer_unref (buf);
       return GST_FLOW_OK;
     }
   }
 
   if (identity->dump) {
-    gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+    gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
   }
 
   for (i = identity->duplicate; i; i--) {
@@ -566,76 +314,48 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
           g_strdup_printf ("chain   ******* (%s:%s)i (%d bytes, timestamp: %"
           GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
           G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
-          GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
-          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-          GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
+          GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
+          GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
+          GST_BUFFER_FLAGS (inbuf), inbuf);
       g_object_notify (G_OBJECT (identity), "last-message");
     }
 
-    time = GST_BUFFER_TIMESTAMP (buf);
+    time = GST_BUFFER_TIMESTAMP (inbuf);
 
     if (identity->datarate > 0) {
       time = identity->offset * GST_SECOND / identity->datarate;
 
-      GST_BUFFER_TIMESTAMP (buf) = time;
-      GST_BUFFER_DURATION (buf) =
-          GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate;
+      GST_BUFFER_TIMESTAMP (inbuf) = time;
+      GST_BUFFER_DURATION (inbuf) =
+          GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate;
     }
 
     g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-        buf);
+        inbuf);
 
     if (i > 1)
-      gst_buffer_ref (buf);
+      gst_buffer_ref (inbuf);
 
     if (identity->sync) {
-      if (identity->clock) {
+      if (GST_ELEMENT (identity)->clock) {
         /* gst_element_wait (GST_ELEMENT (identity), time); */
       }
     }
 
-    identity->offset += GST_BUFFER_SIZE (buf);
-    if (identity->decoupled) {
-      if (!identity_queue_push (identity, (GstData *) buf))
-        return GST_FLOW_UNEXPECTED;
-    } else {
-      ret = gst_pad_push (identity->srcpad, buf);
-      if (ret != GST_FLOW_OK)
-        return ret;
-    }
+    identity->offset += GST_BUFFER_SIZE (inbuf);
 
     if (identity->sleep_time)
       g_usleep (identity->sleep_time);
+
+    gst_buffer_ref (inbuf);
+    *outbuf = inbuf;
   }
 
   return ret;
 }
 
-static void
-gst_identity_set_dataflow_funcs (GstIdentity * identity)
-{
-  if (identity->has_getrange)
-    gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange);
-  else
-    gst_pad_set_getrange_function (identity->srcpad, NULL);
-
-  if (identity->has_chain)
-    gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
-  else
-    gst_pad_set_chain_function (identity->sinkpad, NULL);
-
-  if (identity->has_src_loop)
-    gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop);
-  else
-    gst_pad_set_loop_function (identity->srcpad, NULL);
-
-  if (identity->has_sink_loop)
-    gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop);
-  else
-    gst_pad_set_loop_function (identity->sinkpad, NULL);
-}
-
 static void
 gst_identity_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -645,22 +365,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
   identity = GST_IDENTITY (object);
 
   switch (prop_id) {
-    case PROP_HAS_GETRANGE:
-      identity->has_getrange = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_CHAIN:
-      identity->has_chain = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_SRC_LOOP:
-      identity->has_src_loop = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_SINK_LOOP:
-      identity->has_sink_loop = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
     case PROP_SLEEP_TIME:
       identity->sleep_time = g_value_get_uint (value);
       break;
@@ -703,18 +407,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
   identity = GST_IDENTITY (object);
 
   switch (prop_id) {
-    case PROP_HAS_GETRANGE:
-      g_value_set_boolean (value, identity->has_getrange);
-      break;
-    case PROP_HAS_CHAIN:
-      g_value_set_boolean (value, identity->has_chain);
-      break;
-    case PROP_HAS_SRC_LOOP:
-      g_value_set_boolean (value, identity->has_src_loop);
-      break;
-    case PROP_HAS_SINK_LOOP:
-      g_value_set_boolean (value, identity->has_sink_loop);
-      break;
     case PROP_SLEEP_TIME:
       g_value_set_uint (value, identity->sleep_time);
       break;
@@ -755,12 +447,15 @@ static GstElementStateReturn
 gst_identity_change_state (GstElement * element)
 {
   GstIdentity *identity;
+  GstElementState transition;
+  GstElementStateReturn result;
 
   g_return_val_if_fail (GST_IS_IDENTITY (element), GST_STATE_FAILURE);
 
   identity = GST_IDENTITY (element);
+  transition = GST_STATE_TRANSITION (element);
 
-  switch (GST_STATE_TRANSITION (element)) {
+  switch (transition) {
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
@@ -770,6 +465,14 @@ gst_identity_change_state (GstElement * element)
       identity->prev_offset_end = -1;
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  switch (transition) {
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
@@ -782,8 +485,5 @@ gst_identity_change_state (GstElement * element)
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
-  return GST_STATE_SUCCESS;
+  return result;
 }
index e187f2e2c2e25cf8a870f3343b04b69fb2a7a4bc..4a51a070b4328c933d456ed7e233366a58f27e30 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
 
 G_BEGIN_DECLS
 
@@ -45,24 +46,8 @@ typedef struct _GstIdentity GstIdentity;
 typedef struct _GstIdentityClass GstIdentityClass;
 
 struct _GstIdentity {
-  GstElement    element;
+  GstBaseTransform      element;
 
-  GstPad       *sinkpad;
-  GstPad       *srcpad;
-
-  GstData      *pen_data;
-  GMutex       *pen_lock;
-  GCond                *pen_cond;
-  gboolean      pen_flushing;
-
-  gboolean      has_chain;
-  gboolean      has_getrange;
-  gboolean      has_src_loop;
-  gboolean      has_sink_loop;
-  GstActivateMode sink_mode;
-  GstActivateMode src_mode;
-  gboolean       decoupled;
-  
   guint         duplicate;
   gint                  error_after;
   gfloat        drop_probability;
@@ -75,15 +60,12 @@ struct _GstIdentity {
   GstClockTime   prev_timestamp;
   GstClockTime   prev_duration;
   guint64        prev_offset_end;
-  GstClock     *clock;
   gchar        *last_message;
-  GstCaps      *srccaps;
-
-  guint64       offset;
+  guint64        offset;
 };
 
 struct _GstIdentityClass {
-  GstElementClass parent_class;
+  GstBaseTransformClass parent_class;
 
   /* signals */
   void (*handoff) (GstElement *element, GstBuffer *buf);
index 6eaecf1e227aa0ba85945f4c3fa0632f657956a7..287e7a534ea9ead7a11ec2890679bb45593fc7ff 100644 (file)
@@ -1983,7 +1983,7 @@ restart:
     if (GST_IS_REAL_PAD (pad)) {
       GstRealPad *peer;
       gboolean pad_loop, pad_get;
-      gboolean delay = FALSE;
+      gboolean done = FALSE;
 
       /* see if the pad has a loop function and grab
        * the peer */
@@ -2003,38 +2003,24 @@ restart:
         /* see if the peer has a loop function */
         peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL;
 
-        /* sinkpads with a loop function are delayed since they
-         * need the srcpad to be active first */
-        if (GST_PAD_IS_SINK (pad) && pad_loop && peer_get) {
+        /* If the pad is a sink with loop and the peer has a get function,
+         * we can activate the sinkpad */
+        if ((GST_PAD_IS_SINK (pad) && pad_loop && peer_get) ||
+            (GST_PAD_IS_SRC (pad) && peer_loop && pad_get)) {
           GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
-              "delaying pad %s", GST_OBJECT_NAME (pad));
-          delay = TRUE;
-        } else if (GST_PAD_IS_SRC (pad) && peer_loop && pad_get) {
-          /* If the pad is a source and the peer has a loop function,
-           * we can activate the srcpad and then the loopbased sinkpad */
-          GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
-              "%sactivating pad %s", (active ? "" : "(de)"),
+              "%sactivating pad %s pull mode", (active ? "" : "(de)"),
               GST_OBJECT_NAME (pad));
           result &= gst_pad_set_active (pad,
               (active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
-
-          GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
-              "%sactivating delayed pad %s", (active ? "" : "(de)"),
-              GST_OBJECT_NAME (peer));
-          result &= gst_pad_set_active (GST_PAD (peer),
-              (active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE));
-
-          /* set flag here since we don't want the code below to activate
-           * the pad again */
-          delay = TRUE;
+          done = TRUE;
         }
         gst_object_unref (GST_OBJECT (peer));
       }
 
-      /* all other conditions are just push based pads */
-      if (!delay) {
+      if (!done) {
+        /* all other conditions are just push based pads */
         GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
-            "%sactivating pad %s", (active ? "" : "(de)"),
+            "%sactivating pad %s push mode", (active ? "" : "(de)"),
             GST_OBJECT_NAME (pad));
 
         result &= gst_pad_set_active (pad,
index 72ffefaaf5e20757b190541b7be8f2b8db7696aa..35fe79384351dcffaeb5feb9528aadc28a1f2334 100644 (file)
@@ -437,9 +437,15 @@ lost_ghostpad:
 /**
  * gst_pad_set_active:
  * @pad: the #GstPad to activate or deactivate.
- * @active: TRUE to activate the pad.
+ * @mode: the mode of the pad.
  *
- * Activates or deactivates the given pad.
+ * Activates or deactivates the given pad in the given mode.
+ *
+ * For a source pad: PULL mode will call the getrange function,
+ * PUSH mode will require the element to call _push() on the pad.
+ *
+ * For a sink pad: PULL mode will require the element to call
+ * the _pull_range() function, PUSH mode will call the chain function.
  *
  * Returns: TRUE if the operation was successfull.
  *
@@ -457,13 +463,12 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode)
 
   GST_PAD_REALIZE_AND_LOCK (pad, realpad, lost_ghostpad);
 
-  active = (mode != GST_ACTIVATE_NONE);
-
+  active = GST_PAD_MODE_ACTIVATE (mode);
   old = GST_PAD_IS_ACTIVE (realpad);
 
   /* if nothing changed, we can just exit */
   if (G_UNLIKELY (old == active))
-    goto exit;
+    goto was_ok;
 
   /* make sure data is disallowed when going inactive */
   if (!active) {
@@ -475,14 +480,16 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode)
   }
 
   if (active) {
-    if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
+    if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) {
       if (mode == GST_ACTIVATE_PULL) {
         if (!realpad->getrangefunc)
           goto wrong_mode;
       } else {
-        /* we can push if driven by a chain or loop on the sink pad */
+        /* we can push if driven by a chain or loop on the sink pad.
+         * peer pad is assumed to be active now. */
       }
-    } else {                    /* sink pads */
+    } else {
+      /* sink pads */
       if (mode == GST_ACTIVATE_PULL) {
         /* the src can drive us with getrange */
       } else {
@@ -509,18 +516,23 @@ gst_pad_set_active (GstPad * pad, GstActivateMode mode)
       goto activate_error;
   }
 
-  /* when going to active alow data passing now */
+  /* when going to active allow data passing now */
   if (active) {
-    GST_CAT_DEBUG (GST_CAT_PADS, "activating pad %s:%s",
-        GST_DEBUG_PAD_NAME (realpad));
+    GST_CAT_DEBUG (GST_CAT_PADS, "activating pad %s:%s in mode %d",
+        GST_DEBUG_PAD_NAME (realpad), mode);
     GST_FLAG_SET (realpad, GST_PAD_ACTIVE);
   }
-
-exit:
   GST_UNLOCK (realpad);
 
   return TRUE;
 
+was_ok:
+  {
+    GST_CAT_DEBUG (GST_CAT_PADS,
+        "pad %s:%s was active", GST_DEBUG_PAD_NAME (realpad));
+    GST_UNLOCK (realpad);
+    return TRUE;
+  }
   /* errors */
 lost_ghostpad:
   {
@@ -544,6 +556,42 @@ activate_error:
   }
 }
 
+/**
+ * gst_pad_peer_set_active:
+ * @pad: the #GstPad to activate or deactivate the peer of.
+ * @mode: the mode of the pad.
+ *
+ * Activates or deactivates the given peer of a pad. Elements
+ * that will perform a _pull_range() on their sinkpads need
+ * to call this function when the sinkpad is activated or when
+ * an internally linked source pad is activated in pull mode.
+ *
+ * Returns: TRUE if the operation was successfull.
+ *
+ * MT safe.
+ */
+gboolean
+gst_pad_peer_set_active (GstPad * pad, GstActivateMode mode)
+{
+  GstPad *peer;
+  gboolean result = FALSE;
+
+  peer = gst_pad_get_peer (pad);
+  if (!peer)
+    goto no_peer;
+
+  result = gst_pad_set_active (peer, mode);
+  gst_object_unref (GST_OBJECT_CAST (peer));
+
+  return result;
+
+  /* errors */
+no_peer:
+  {
+    return FALSE;
+  }
+}
+
 /**
  * gst_pad_is_active:
  * @pad: the #GstPad to query
@@ -2909,6 +2957,74 @@ no_function:
   }
 }
 
+
+/**
+ * gst_pad_check_pull_range:
+ * @pad: a sink #GstRealPad.
+ *
+ * Checks if a #gst_pad_pull_range() can be performed on the peer
+ * source pad. This function is used by plugins that want to check
+ * if they can use random access on the peer source pad. 
+ *
+ * The peer sourcepad can implement a custom #GstPadCheckGetRangeFunction
+ * if it needs to perform some logic to determine if pull_range is
+ * possible.
+ *
+ * Returns: a gboolean with the result.
+ *
+ * MT safe.
+ */
+gboolean
+gst_pad_check_pull_range (GstPad * pad)
+{
+  GstRealPad *peer;
+  gboolean ret;
+  GstPadCheckGetRangeFunction checkgetrangefunc;
+
+  g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK,
+      GST_FLOW_ERROR);
+
+  GST_LOCK (pad);
+
+  if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
+    goto not_connected;
+
+  gst_object_ref (GST_OBJECT_CAST (peer));
+  GST_UNLOCK (pad);
+
+  /* see note in above function */
+  if (G_UNLIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL))
+    goto no_function;
+
+  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+      "calling checkgetrangefunc %s of peer pad %s:%s",
+      GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer));
+
+  ret = checkgetrangefunc (GST_PAD_CAST (peer));
+
+  gst_object_unref (GST_OBJECT_CAST (peer));
+
+  return ret;
+
+  /* ERROR recovery here */
+not_connected:
+  {
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "checkinh pull range, but it was not linked");
+    GST_UNLOCK (pad);
+    return FALSE;
+  }
+no_function:
+  {
+    GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+        ("pad %s:%s checked pull_range but the peer pad %s:%s has no checkgetrangefunction",
+            GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
+    gst_object_unref (GST_OBJECT (peer));
+    return FALSE;
+  }
+}
+
 /**
  * gst_pad_pull_range:
  * @pad: a sink #GstPad.
@@ -2943,6 +3059,12 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
   if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
     goto not_connected;
 
+  if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
+    goto not_active;
+
+  if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer)))
+    goto flushing;
+
   gst_object_ref (GST_OBJECT_CAST (peer));
   GST_UNLOCK (pad);
 
@@ -2951,8 +3073,10 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
     goto no_function;
 
   GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-      "calling getrangefunc %s of peer pad %s:%s",
-      GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer));
+      "calling getrangefunc %s of peer pad %s:%s, offset %"
+      G_GUINT64_FORMAT ", size %u",
+      GST_DEBUG_FUNCPTR_NAME (getrangefunc), GST_DEBUG_PAD_NAME (peer),
+      offset, size);
 
   ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer);
 
@@ -2968,6 +3092,20 @@ not_connected:
     GST_UNLOCK (pad);
     return GST_FLOW_NOT_CONNECTED;
   }
+not_active:
+  {
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "pulling range, but it was inactive");
+    GST_UNLOCK (pad);
+    return GST_FLOW_WRONG_STATE;
+  }
+flushing:
+  {
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "pulling range, but pad was flushing");
+    GST_UNLOCK (pad);
+    return GST_FLOW_UNEXPECTED;
+  }
 no_function:
   {
     GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
@@ -3163,9 +3301,9 @@ gst_pad_template_new (const gchar * name_template,
  * Gets the capabilities of the pad template.
  *
  * Returns: the #GstCaps of the pad template. If you need to keep a reference to
- * the caps, make a copy (see gst_caps_copy ()).
+ * the caps, take a ref (see gst_caps_ref ()).
  */
-const GstCaps *
+GstCaps *
 gst_pad_template_get_caps (GstPadTemplate * templ)
 {
   g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
@@ -3354,6 +3492,8 @@ gst_ghost_pad_new (const gchar * name, GstPad * pad)
  * The caller must free this list after use.
  *
  * Returns: a newly allocated #GList of pads.
+ *
+ * Not MT safe.
  */
 GList *
 gst_pad_get_internal_links_default (GstPad * pad)
@@ -3394,6 +3534,8 @@ gst_pad_get_internal_links_default (GstPad * pad)
  * The caller must free this list after use.
  *
  * Returns: a newly allocated #GList of pads.
+ *
+ * Not MT safe.
  */
 GList *
 gst_pad_get_internal_links (GstPad * pad)
index fc28d5d7866b135888fa38244f67b1a7724fa134..7cfd561d3cb997e8e31f9f289d48d1160d9ffcd2 100644 (file)
@@ -96,8 +96,8 @@ typedef enum {
   GST_PAD_LINK_OK               =  0,  /* link ok */
 } GstPadLinkReturn;
 
-#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK)
-#define GST_PAD_LINK_SUCCESSFUL(ret) (ret >= GST_PAD_LINK_OK)
+#define GST_PAD_LINK_FAILED(ret) ((ret) < GST_PAD_LINK_OK)
+#define GST_PAD_LINK_SUCCESSFUL(ret) ((ret) >= GST_PAD_LINK_OK)
 
 typedef enum {
   GST_FLOW_OK            =  0,         /* data passing was ok */
@@ -116,6 +116,8 @@ typedef enum {
   GST_ACTIVATE_PULL,
 } GstActivateMode;
 
+#define GST_PAD_MODE_ACTIVATE(mode) ((mode) != GST_ACTIVATE_NONE)
+
 /* convenience functions */
 #ifdef G_HAVE_ISO_VARARGS
 #define GST_PAD_QUERY_TYPE_FUNCTION(functionname, ...)  GST_QUERY_TYPE_FUNCTION (GstPad *, functionname, __VA_ARGS__);
@@ -136,6 +138,7 @@ typedef void                        (*GstPadLoopFunction)           (GstPad *pad);
 typedef GstFlowReturn          (*GstPadChainFunction)          (GstPad *pad, GstBuffer *buffer);
 typedef GstFlowReturn          (*GstPadGetRangeFunction)       (GstPad *pad, guint64 offset, 
                                                                 guint length, GstBuffer **buffer);
+typedef gboolean               (*GstPadCheckGetRangeFunction)  (GstPad *pad); 
 typedef gboolean               (*GstPadEventFunction)          (GstPad *pad, GstEvent *event);
 
 /* convert/query/format functions */
@@ -237,6 +240,7 @@ struct _GstRealPad {
   /* data transport functions */
   GstPadLoopFunction            loopfunc;
   GstPadChainFunction           chainfunc;
+  GstPadCheckGetRangeFunction   checkgetrangefunc;
   GstPadGetRangeFunction        getrangefunc;
   GstPadEventFunction           eventfunc;
 
@@ -301,6 +305,7 @@ struct _GstGhostPadClass {
 #define GST_RPAD_ACTIVATEFUNC(pad)     (GST_REAL_PAD_CAST(pad)->activatefunc)
 #define GST_RPAD_LOOPFUNC(pad)         (GST_REAL_PAD_CAST(pad)->loopfunc)
 #define GST_RPAD_CHAINFUNC(pad)                (GST_REAL_PAD_CAST(pad)->chainfunc)
+#define GST_RPAD_CHECKGETRANGEFUNC(pad)        (GST_REAL_PAD_CAST(pad)->checkgetrangefunc)
 #define GST_RPAD_GETRANGEFUNC(pad)     (GST_REAL_PAD_CAST(pad)->getrangefunc)
 #define GST_RPAD_EVENTFUNC(pad)                (GST_REAL_PAD_CAST(pad)->eventfunc)
 #define GST_RPAD_CONVERTFUNC(pad)      (GST_REAL_PAD_CAST(pad)->convertfunc)
@@ -458,6 +463,7 @@ GstElement*         gst_pad_get_real_parent                 (GstPad *pad);
 GstPadDirection                gst_pad_get_direction                   (GstPad *pad);
 
 gboolean               gst_pad_set_active                      (GstPad *pad, GstActivateMode mode);
+gboolean               gst_pad_peer_set_active                 (GstPad *pad, GstActivateMode mode);
 gboolean               gst_pad_is_active                       (GstPad *pad);
 gboolean               gst_pad_set_blocked                     (GstPad *pad, gboolean blocked);
 gboolean               gst_pad_set_blocked_async               (GstPad *pad, gboolean blocked,
@@ -524,6 +530,7 @@ GstCaps *           gst_pad_get_filter_caps                 (GstPad * pad);
 
 /* data passing functions */
 GstFlowReturn          gst_pad_push                            (GstPad *pad, GstBuffer *buffer);
+gboolean               gst_pad_check_pull_range                (GstPad *pad);
 GstFlowReturn          gst_pad_pull_range                      (GstPad *pad, guint64 offset, guint size,
                                                                 GstBuffer **buffer);
 gboolean               gst_pad_push_event                      (GstPad *pad, GstEvent *event);
@@ -593,7 +600,7 @@ GstPadTemplate*             gst_pad_template_new                    (const gchar *name_template,
                                                                 GstCaps *caps);
 
 GstPadTemplate *       gst_static_pad_template_get             (GstStaticPadTemplate *pad_template);
-const GstCaps*         gst_pad_template_get_caps               (GstPadTemplate *templ);
+GstCaps*               gst_pad_template_get_caps               (GstPadTemplate *templ);
 
 #ifndef GST_DISABLE_LOADSAVE
 xmlNodePtr              gst_ghost_pad_save_thyself             (GstPad *pad,
index 8ba1b85d56e3514262084122c91d969901b819df..dda7031d9a2050568af92d32584d9f0aa66aca5f 100644 (file)
@@ -6,7 +6,8 @@ noinst_DATA = $(as_libtool_noinst_DATA_files)
 
 libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
 libgstbase_@GST_MAJORMINOR@_la_SOURCES =       \
-       gstbasesink.c   
+       gstbasesink.c   \
+       gstbasetransform.c      
 
 libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
 libgstbase_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS)
@@ -16,7 +17,8 @@ libgstbase_@GST_MAJORMINOR@includedir =               \
        $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/base
 
 libgstbase_@GST_MAJORMINOR@include_HEADERS =   \
-       gstbasesink.h   
+       gstbasesink.h   \
+       gstbasetransform.h      
 
 install-data-local: as-libtool-install-data-local
 
index efd6e572a9d2ca59b7da1469c73fd3a2919eefd7..f9c158376debbecc824b7054c60d87794ba6374c 100644 (file)
@@ -14,3 +14,14 @@ GstBaseSink
 
   FIXME: not much point making it operate in pull mode as a generic
   base class I guess... 
+
+GstBaseTransform
+
+  Base class for simple tranform filters
+
+  - one sinkpad and one srcpad
+  - formats the same on sink and source pad.
+  - handles state changes
+  - does flushing
+  - push mode
+  - pull mode if transform can operate on arbitrary data
index a476071fd332effd62ebd2fe1dc7cf05c458bcd3..88d7d978163cf33c9323c768a367bf2344173294 100644 (file)
 #include "gstbasesink.h"
 #include <gst/gstmarshal.h>
 
-static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
-    GST_PAD_SINK,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS_ANY);
-
 GST_DEBUG_CATEGORY_STATIC (gst_basesink_debug);
 #define GST_CAT_DEFAULT gst_basesink_debug
 
@@ -61,11 +56,35 @@ enum
   PROP_PREROLL_QUEUE_LEN
 };
 
-#define _do_init(bla) \
-    GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0, "basesink element");
+static GstElementClass *parent_class = NULL;
+
+static void gst_basesink_base_init (gpointer g_class);
+static void gst_basesink_class_init (GstBaseSinkClass * klass);
+static void gst_basesink_init (GstBaseSink * trans, gpointer g_class);
+
+GType
+gst_basesink_get_type (void)
+{
+  static GType basesink_type = 0;
+
+  if (!basesink_type) {
+    static const GTypeInfo basesink_info = {
+      sizeof (GstBaseSinkClass),
+      (GBaseInitFunc) gst_basesink_base_init,
+      NULL,
+      (GClassInitFunc) gst_basesink_class_init,
+      NULL,
+      NULL,
+      sizeof (GstBaseSink),
+      0,
+      (GInstanceInitFunc) gst_basesink_init,
+    };
 
-GST_BOILERPLATE_FULL (GstBaseSink, gst_basesink, GstElement, GST_TYPE_ELEMENT,
-    _do_init);
+    basesink_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstBaseSink", &basesink_info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return basesink_type;
+}
 
 static void gst_basesink_set_clock (GstElement * element, GstClock * clock);
 
@@ -74,7 +93,6 @@ static void gst_basesink_set_property (GObject * object, guint prop_id,
 static void gst_basesink_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstStaticPadTemplate *gst_base_sink_get_template (GstBaseSink * sink);
 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
 static GstBuffer *gst_base_sink_buffer_alloc (GstBaseSink * sink,
@@ -93,32 +111,11 @@ static gboolean gst_basesink_event (GstPad * pad, GstEvent * event);
 static inline void gst_basesink_handle_buffer (GstBaseSink * basesink,
     GstBuffer * buf);
 
-static GstStaticPadTemplate *
-gst_basesink_get_template (GstBaseSink * bsink)
-{
-  GstStaticPadTemplate *template = NULL;
-  GstBaseSinkClass *bclass;
-
-  bclass = GST_BASESINK_GET_CLASS (bsink);
-
-  if (bclass->get_template)
-    template = bclass->get_template (bsink);
-
-  if (template == NULL) {
-    template = &sinktemplate;
-  }
-  return template;
-}
-
 static void
 gst_basesink_base_init (gpointer g_class)
 {
-  //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
-  /*
-     gst_element_class_add_pad_template (gstelement_class,
-     gst_static_pad_template_get (&sinktemplate));
-   */
+  GST_DEBUG_CATEGORY_INIT (gst_basesink_debug, "basesink", 0,
+      "basesink element");
 }
 
 static void
@@ -130,6 +127,8 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesink_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesink_get_property);
 
@@ -153,7 +152,6 @@ gst_basesink_class_init (GstBaseSinkClass * klass)
 
   klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
   klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
-  klass->get_template = GST_DEBUG_FUNCPTR (gst_base_sink_get_template);
   klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
   klass->get_times = GST_DEBUG_FUNCPTR (gst_basesink_get_times);
 }
@@ -171,13 +169,15 @@ gst_basesink_pad_getcaps (GstPad * pad)
     caps = bclass->get_caps (bsink);
 
   if (caps == NULL) {
-    GstStaticPadTemplate *stemplate;
-    GstPadTemplate *template;
+    GstPadTemplate *pad_template;
 
-    stemplate = gst_basesink_get_template (bsink);
-    template = gst_static_pad_template_get (stemplate);
-    caps = gst_caps_copy (gst_pad_template_get_caps (template));
+    pad_template =
+        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
+    if (pad_template != NULL) {
+      caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+    }
   }
+
   return caps;
 }
 
@@ -213,15 +213,16 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
 }
 
 static void
-gst_basesink_init (GstBaseSink * basesink)
+gst_basesink_init (GstBaseSink * basesink, gpointer g_class)
 {
-  GstStaticPadTemplate *template;
+  GstPadTemplate *pad_template;
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+  g_return_if_fail (pad_template != NULL);
 
-  template = gst_basesink_get_template (basesink);
+  basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
 
-  basesink->sinkpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (template),
-      "sink");
   gst_pad_set_getcaps_function (basesink->sinkpad,
       GST_DEBUG_FUNCPTR (gst_basesink_pad_getcaps));
   gst_pad_set_setcaps_function (basesink->sinkpad,
@@ -328,12 +329,6 @@ gst_basesink_get_property (GObject * object, guint prop_id, GValue * value,
   GST_UNLOCK (sink);
 }
 
-static GstStaticPadTemplate *
-gst_base_sink_get_template (GstBaseSink * sink)
-{
-  return &sinktemplate;
-}
-
 static GstCaps *
 gst_base_sink_get_caps (GstBaseSink * sink)
 {
@@ -735,6 +730,7 @@ gst_basesink_activate (GstPad * pad, GstActivateMode mode)
     case GST_ACTIVATE_PULL:
       /* if we have a scheduler we can start the task */
       g_return_val_if_fail (basesink->has_loop, FALSE);
+      gst_pad_peer_set_active (pad, mode);
       if (GST_ELEMENT_SCHEDULER (basesink)) {
         GST_STREAM_LOCK (pad);
         GST_RPAD_TASK (pad) =
@@ -791,7 +787,7 @@ gst_basesink_change_state (GstElement * element)
       break;
     case GST_STATE_READY_TO_PAUSED:
       /* need to complete preroll before this state change completes, there
-       * is no data flow in READY so we cqn safely assume we need to preroll. */
+       * is no data flow in READY so we can safely assume we need to preroll. */
       basesink->offset = 0;
       GST_PREROLL_LOCK (basesink->sinkpad);
       basesink->preroll_queue = g_queue_new ();
index 3c64f78ed3dfcc54bea0d0cdc844083d6c61bfe6..b3eafade441df6c52a2f695e4794170800c2df28 100644 (file)
@@ -66,8 +66,6 @@ struct _GstBaseSink {
 struct _GstBaseSinkClass {
   GstElementClass parent_class;
 
-  GstStaticPadTemplate* (*get_template) (GstBaseSink *sink);
-
   GstCaps*      (*get_caps)     (GstBaseSink *sink);
   gboolean      (*set_caps)     (GstBaseSink *sink, GstCaps *caps);
 
diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c
new file mode 100644 (file)
index 0000000..c6032d6
--- /dev/null
@@ -0,0 +1,404 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstbasetransform.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 <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "../gst-i18n-lib.h"
+#include "gstbasetransform.h"
+#include <gst/gstmarshal.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
+#define GST_CAT_DEFAULT gst_base_transform_debug
+
+/* BaseTransform signals and args */
+enum
+{
+  SIGNAL_HANDOFF,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+};
+
+static GstElementClass *parent_class = NULL;
+
+static void gst_base_transform_base_init (gpointer g_class);
+static void gst_base_transform_class_init (GstBaseTransformClass * klass);
+static void gst_base_transform_init (GstBaseTransform * trans,
+    gpointer g_class);
+
+GType
+gst_base_transform_get_type (void)
+{
+  static GType base_transform_type = 0;
+
+  if (!base_transform_type) {
+    static const GTypeInfo base_transform_info = {
+      sizeof (GstBaseTransformClass),
+      (GBaseInitFunc) gst_base_transform_base_init,
+      NULL,
+      (GClassInitFunc) gst_base_transform_class_init,
+      NULL,
+      NULL,
+      sizeof (GstBaseTransform),
+      0,
+      (GInstanceInitFunc) gst_base_transform_init,
+    };
+
+    base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return base_transform_type;
+}
+
+static void gst_base_transform_finalize (GObject * object);
+static void gst_base_transform_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_base_transform_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static gboolean gst_base_transform_src_activate (GstPad * pad,
+    GstActivateMode mode);
+static gboolean gst_base_transform_sink_activate (GstPad * pad,
+    GstActivateMode mode);
+static GstElementStateReturn gst_base_transform_change_state (GstElement *
+    element);
+
+static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
+    guint length, GstBuffer ** buffer);
+static GstFlowReturn gst_base_transform_chain (GstPad * pad,
+    GstBuffer * buffer);
+static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf);
+static GstCaps *gst_base_transform_proxy_getcaps (GstPad * pad);
+static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
+
+/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
+
+static void
+gst_base_transform_base_init (gpointer g_class)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
+      "basetransform element");
+}
+
+static void
+gst_base_transform_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_base_transform_class_init (GstBaseTransformClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  gobject_class->set_property =
+      GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
+}
+
+static void
+gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
+{
+  GstPadTemplate *pad_template;
+
+  GST_DEBUG ("gst_base_transform_init");
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
+  g_return_if_fail (pad_template != NULL);
+  trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
+  gst_pad_set_getcaps_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
+  gst_pad_set_setcaps_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
+  gst_pad_set_event_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_event));
+  gst_pad_set_chain_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_chain));
+  gst_pad_set_activate_function (trans->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate));
+  gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
+
+  pad_template =
+      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
+  g_return_if_fail (pad_template != NULL);
+  trans->srcpad = gst_pad_new_from_template (pad_template, "src");
+  gst_pad_set_getcaps_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
+  gst_pad_set_getrange_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
+  gst_pad_set_activate_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_src_activate));
+  gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
+}
+
+static GstCaps *
+gst_base_transform_proxy_getcaps (GstPad * pad)
+{
+  GstPad *otherpad;
+  GstBaseTransform *trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
+
+  return gst_pad_peer_get_caps (otherpad);
+}
+
+static gboolean
+gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstBaseTransform *trans;
+  GstBaseTransformClass *bclass;
+  gboolean result = TRUE;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (bclass->set_caps)
+    result = bclass->set_caps (trans, caps);
+
+  return result;
+}
+
+static gboolean
+gst_base_transform_event (GstPad * pad, GstEvent * event)
+{
+  GstBaseTransform *trans;
+  GstBaseTransformClass *bclass;
+  gboolean ret = FALSE;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (bclass->event)
+    bclass->event (trans, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH:
+      if (GST_EVENT_FLUSH_DONE (event)) {
+      }
+      GST_STREAM_LOCK (pad);
+      break;
+    case GST_EVENT_EOS:
+      GST_STREAM_LOCK (pad);
+      break;
+    default:
+      break;
+  }
+  ret = gst_pad_event_default (pad, event);
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_getrange (GstPad * pad, guint64 offset,
+    guint length, GstBuffer ** buffer)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn ret;
+  GstBuffer *inbuf;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+
+  GST_STREAM_LOCK (pad);
+
+  ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
+  if (ret == GST_FLOW_OK) {
+    ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
+  }
+
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstBaseTransform *trans;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBuffer *outbuf;
+
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+
+  GST_STREAM_LOCK (pad);
+
+  ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
+  if (ret == GST_FLOW_OK) {
+    ret = gst_pad_push (trans->srcpad, outbuf);
+  }
+
+  GST_STREAM_UNLOCK (pad);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstBaseTransformClass *bclass;
+
+  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  if (bclass->transform)
+    ret = bclass->transform (trans, inbuf, outbuf);
+
+  gst_buffer_unref (inbuf);
+
+  return ret;
+}
+
+static void
+gst_base_transform_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_base_transform_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result = FALSE;
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_PULL:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_NONE:
+      result = TRUE;
+      break;
+  }
+  return result;
+}
+
+static gboolean
+gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result = FALSE;
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+      result = TRUE;
+      break;
+    case GST_ACTIVATE_PULL:
+      result = gst_pad_set_active (trans->sinkpad, mode);
+      result = gst_pad_peer_set_active (trans->sinkpad, mode);
+      break;
+    case GST_ACTIVATE_NONE:
+      result = TRUE;
+      break;
+  }
+  return result;
+}
+
+static GstElementStateReturn
+gst_base_transform_change_state (GstElement * element)
+{
+  GstBaseTransform *trans;
+  GstElementState transition;
+  GstElementStateReturn result;
+
+  trans = GST_BASE_TRANSFORM (element);
+  transition = GST_STATE_TRANSITION (element);
+
+  switch (transition) {
+    case GST_STATE_NULL_TO_READY:
+      break;
+    case GST_STATE_READY_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  switch (transition) {
+    case GST_STATE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return result;
+}
diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h
new file mode 100644 (file)
index 0000000..788fe53
--- /dev/null
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2005 Wim Taymans <wim@fluendo.com>
+ *
+ * gstbasetransform.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_BASE_TRANSFORM_H__
+#define __GST_BASE_TRANSFORM_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_BASE_TRANSFORM        (gst_base_transform_get_type())
+#define GST_BASE_TRANSFORM(obj)        (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransform))
+#define GST_BASE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
+#define GST_BASE_TRANSFORM_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
+#define GST_IS_BASE_TRANSFORM(obj)     (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_TRANSFORM))
+#define GST_IS_BASE_TRANSFORM_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_TRANSFORM))
+
+/* the names of the templates for the sink and source pads */
+#define GST_BASE_TRANSFORM_SINK_NAME   "sink"
+#define GST_BASE_TRANSFORM_SRC_NAME    "src"
+
+typedef struct _GstBaseTransform GstBaseTransform;
+typedef struct _GstBaseTransformClass GstBaseTransformClass;
+
+struct _GstBaseTransform {
+  GstElement    element;
+
+  /* source and sink pads */
+  GstPad       *sinkpad;
+  GstPad       *srcpad;
+};
+
+struct _GstBaseTransformClass {
+  GstElementClass parent_class;
+
+  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *caps);
+
+  gboolean      (*event)        (GstBaseTransform *trans, GstEvent *event);
+  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
+};
+
+GType gst_base_transform_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_BASE_TRANSFORM_H__ */
index 0b8a6d2f7e2c75b4c06a03df64ad4a62b958abcd..76a61f7e12bfb0b72eb83ee1227310901b1b0b76 100644 (file)
@@ -59,7 +59,6 @@ enum
   LAST_SIGNAL
 };
 
-#define DEFAULT_LOOP_BASED             FALSE
 #define DEFAULT_SLEEP_TIME             0
 #define DEFAULT_DUPLICATE              1
 #define DEFAULT_ERROR_AFTER            -1
@@ -73,11 +72,6 @@ enum
 enum
 {
   PROP_0,
-  PROP_HAS_GETRANGE,
-  PROP_HAS_CHAIN,
-  PROP_HAS_SINK_LOOP,
-  PROP_HAS_SRC_LOOP,
-  PROP_LOOP_BASED,
   PROP_SLEEP_TIME,
   PROP_DUPLICATE,
   PROP_ERROR_AFTER,
@@ -91,14 +85,11 @@ enum
 };
 
 
-typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *);
-
-
 #define _do_init(bla) \
     GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
 
-GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT,
-    _do_init);
+GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstBaseTransform,
+    GST_TYPE_BASE_TRANSFORM, _do_init);
 
 static void gst_identity_finalize (GObject * object);
 static void gst_identity_set_property (GObject * object, guint prop_id,
@@ -107,17 +98,9 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static GstElementStateReturn gst_identity_change_state (GstElement * element);
 
-static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer);
-static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
-static void gst_identity_src_loop (GstPad * pad);
-static void gst_identity_sink_loop (GstPad * pad);
-static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity,
-    GstBuffer * buf);
-static void gst_identity_set_clock (GstElement * element, GstClock * clock);
-static GstCaps *gst_identity_proxy_getcaps (GstPad * pad);
-
+static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
+static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf);
 
 static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
 
@@ -140,9 +123,6 @@ gst_identity_finalize (GObject * object)
 
   identity = GST_IDENTITY (object);
 
-  g_mutex_free (identity->pen_lock);
-  g_cond_free (identity->pen_cond);
-
   g_free (identity->last_message);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -153,29 +133,15 @@ gst_identity_class_init (GstIdentityClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
+  GstBaseTransformClass *gstbasetrans_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
   gstelement_class = GST_ELEMENT_CLASS (klass);
+  gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
 
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
 
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
-      g_param_spec_boolean ("has-getrange", "Has getrange",
-          "If the src pad will implement a getrange function",
-          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
-      g_param_spec_boolean ("has-chain", "Has chain",
-          "If the sink pad will implement a chain function",
-          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP,
-      g_param_spec_boolean ("has-src-loop", "Has src loop",
-          "If the src pad will implement a loop function",
-          FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
-      g_param_spec_boolean ("has-sink-loop", "Has sink loop",
-          "If the sink pad will implement a loop function",
-          FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME,
       g_param_spec_uint ("sleep-time", "Sleep time",
           "Microseconds to sleep between processing", 0, G_MAXUINT,
@@ -220,33 +186,16 @@ gst_identity_class_init (GstIdentityClass * klass)
 
   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
 
-  gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_identity_change_state);
 
+  gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_identity_event);
+  gstbasetrans_class->transform = GST_DEBUG_FUNCPTR (gst_identity_transform);
 }
 
 static void
 gst_identity_init (GstIdentity * identity)
 {
-  identity->sinkpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
-      "sink");
-  gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
-  gst_pad_set_getcaps_function (identity->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
-  gst_pad_set_event_function (identity->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_identity_event));
-
-  identity->srcpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
-      "src");
-  gst_pad_set_getcaps_function (identity->srcpad,
-      GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
-  gst_pad_set_getrange_function (identity->srcpad,
-      GST_DEBUG_FUNCPTR (gst_identity_getrange));
-  gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
-
   identity->sleep_time = DEFAULT_SLEEP_TIME;
   identity->duplicate = DEFAULT_DUPLICATE;
   identity->error_after = DEFAULT_ERROR_AFTER;
@@ -257,279 +206,78 @@ gst_identity_init (GstIdentity * identity)
   identity->check_perfect = DEFAULT_CHECK_PERFECT;
   identity->dump = DEFAULT_DUMP;
   identity->last_message = NULL;
-  identity->srccaps = NULL;
-
-  identity->pen_data = NULL;
-  identity->pen_lock = g_mutex_new ();
-  identity->pen_cond = g_cond_new ();
-  identity->pen_flushing = FALSE;
-}
-
-static void
-gst_identity_set_clock (GstElement * element, GstClock * clock)
-{
-  GstIdentity *identity = GST_IDENTITY (element);
-
-  gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
-}
-
-static GstCaps *
-gst_identity_proxy_getcaps (GstPad * pad)
-{
-  GstPad *otherpad;
-  GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad));
-
-  otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad;
-
-  return gst_pad_peer_get_caps (otherpad);
-}
-
-static gboolean
-identity_queue_push (GstIdentity * identity, GstData * data)
-{
-  gboolean ret;
-
-  g_mutex_lock (identity->pen_lock);
-  while (identity->pen_data && !identity->pen_flushing)
-    g_cond_wait (identity->pen_cond, identity->pen_lock);
-  if (identity->pen_flushing) {
-    gst_data_unref (identity->pen_data);
-    identity->pen_data = NULL;
-    gst_data_unref (data);
-    ret = FALSE;
-  } else {
-    identity->pen_data = data;
-    ret = TRUE;
-  }
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
-
-  return ret;
-}
-
-static GstData *
-identity_queue_pop (GstIdentity * identity)
-{
-  GstData *ret;
-
-  g_mutex_lock (identity->pen_lock);
-  while (!(ret = identity->pen_data) && !identity->pen_flushing)
-    g_cond_wait (identity->pen_cond, identity->pen_lock);
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
-
-  return ret;
-}
-
-static void
-identity_queue_flush (GstIdentity * identity)
-{
-  g_mutex_lock (identity->pen_lock);
-  identity->pen_flushing = TRUE;
-  g_cond_signal (identity->pen_cond);
-  g_mutex_unlock (identity->pen_lock);
 }
 
 static gboolean
-gst_identity_event (GstPad * pad, GstEvent * event)
+gst_identity_event (GstBaseTransform * trans, GstEvent * event)
 {
   GstIdentity *identity;
-  gboolean ret;
 
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
+  identity = GST_IDENTITY (trans);
 
   if (!identity->silent) {
     g_free (identity->last_message);
 
     identity->last_message =
         g_strdup_printf ("chain   ******* (%s:%s)E (type: %d) %p",
-        GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
+        GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), event);
 
     g_object_notify (G_OBJECT (identity), "last_message");
   }
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_FLUSH:
-      /* forward event */
-      gst_pad_event_default (pad, event);
-      if (GST_EVENT_FLUSH_DONE (event)) {
-        if (identity->sink_mode == GST_ACTIVATE_PULL) {
-          /* already have the sink stream lock */
-          gst_task_start (GST_RPAD_TASK (identity->sinkpad));
-        }
-        if (identity->src_mode == GST_ACTIVATE_PUSH) {
-          GST_STREAM_LOCK (identity->srcpad);
-          gst_task_start (GST_RPAD_TASK (identity->srcpad));
-          GST_STREAM_UNLOCK (identity->srcpad);
-        }
-      } else {
-        /* unblock both functions */
-        identity_queue_flush (identity);
-
-      }
-      ret = TRUE;
-      goto done;
-    case GST_EVENT_EOS:
-      if (identity->sink_mode == GST_ACTIVATE_PULL) {
-        /* already have the sink stream lock */
-        gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
-      }
-      break;
-    default:
-      break;
-  }
-
-  if (identity->decoupled) {
-    ret = identity_queue_push (identity, (GstData *) event);
-  } else {
-    ret = gst_pad_push_event (identity->srcpad, event);
-  }
-
-done:
-  GST_STREAM_UNLOCK (pad);
-  return ret;
-}
-
-static GstFlowReturn
-gst_identity_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer)
-{
-  GstIdentity *identity;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer);
-
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_identity_chain (GstPad * pad, GstBuffer * buffer)
-{
-  GstIdentity *identity;
-  GstFlowReturn ret = GST_FLOW_OK;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_identity_handle_buffer (identity, buffer);
-
-  GST_STREAM_UNLOCK (pad);
-
-  return ret;
+  return TRUE;
 }
 
-#define DEFAULT_PULL_SIZE 1024
-
 static void
-gst_identity_sink_loop (GstPad * pad)
+gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
 {
-  GstIdentity *identity;
-  GstBuffer *buffer;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer);
-  if (ret != GST_FLOW_OK)
-    goto sink_loop_pause;
-
-  ret = gst_identity_handle_buffer (identity, buffer);
-  if (ret != GST_FLOW_OK)
-    goto sink_loop_pause;
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-sink_loop_pause:
-  gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
-  GST_STREAM_UNLOCK (pad);
-  return;
-}
+  GstClockTime timestamp;
 
-static void
-gst_identity_src_loop (GstPad * pad)
-{
-  GstIdentity *identity;
-  GstData *data;
-  GstFlowReturn ret;
-
-  identity = GST_IDENTITY (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  data = identity_queue_pop (identity);
-  if (!data)                    /* we're getting flushed */
-    goto src_loop_pause;
-
-  if (GST_IS_EVENT (data)) {
-    if (GST_EVENT_TYPE (data) == GST_EVENT_EOS)
-      gst_task_pause (GST_RPAD_TASK (identity->srcpad));
-    gst_pad_push_event (identity->srcpad, GST_EVENT (data));
-  } else {
-    ret = gst_pad_push (identity->srcpad, (GstBuffer *) data);
-    if (ret != GST_FLOW_OK)
-      goto src_loop_pause;
-  }
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-src_loop_pause:
-  gst_task_pause (GST_RPAD_TASK (identity->srcpad));
-  GST_STREAM_UNLOCK (pad);
-  return;
-}
-
-static GstFlowReturn
-gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
+  timestamp = GST_BUFFER_TIMESTAMP (buf);
 
   /* see if we need to do perfect stream checking */
   /* invalid timestamp drops us out of check.  FIXME: maybe warn ? */
-  if (identity->check_perfect &&
-      GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
+  if (timestamp != GST_CLOCK_TIME_NONE) {
     /* check if we had a previous buffer to compare to */
     if (identity->prev_timestamp != GST_CLOCK_TIME_NONE) {
-      if (identity->prev_timestamp + identity->prev_duration !=
-          GST_BUFFER_TIMESTAMP (buf)) {
+      guint64 offset;
+
+      if (identity->prev_timestamp + identity->prev_duration != timestamp) {
         GST_WARNING_OBJECT (identity,
             "Buffer not time-contiguous with previous one: " "prev ts %"
             GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %"
             GST_TIME_FORMAT, GST_TIME_ARGS (identity->prev_timestamp),
-            GST_TIME_ARGS (identity->prev_duration),
-            GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+            GST_TIME_ARGS (identity->prev_duration), GST_TIME_ARGS (timestamp));
       }
-      if (identity->prev_offset_end != GST_BUFFER_OFFSET (buf)) {
+
+      offset = GST_BUFFER_OFFSET (buf);
+      if (identity->prev_offset_end != offset) {
         GST_WARNING_OBJECT (identity,
             "Buffer not data-contiguous with previous one: "
             "prev offset_end %" G_GINT64_FORMAT ", new offset %"
-            G_GINT64_FORMAT, identity->prev_offset_end,
-            GST_BUFFER_OFFSET (buf));
+            G_GINT64_FORMAT, identity->prev_offset_end, offset);
       }
     }
     /* update prev values */
-    identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf);
+    identity->prev_timestamp = timestamp;
     identity->prev_duration = GST_BUFFER_DURATION (buf);
     identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf);
   }
+}
+
+static GstFlowReturn
+gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer ** outbuf)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstIdentity *identity = GST_IDENTITY (trans);
+  guint i;
+
+  if (identity->check_perfect)
+    gst_identity_check_perfect (identity, inbuf);
 
   if (identity->error_after >= 0) {
     identity->error_after--;
     if (identity->error_after == 0) {
-      gst_buffer_unref (buf);
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
       return GST_FLOW_ERROR;
@@ -543,18 +291,18 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
           g_strdup_printf ("dropping   ******* (%s:%s)i (%d bytes, timestamp: %"
           GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
           G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
-          GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
-          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-          GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
+          GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
+          GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
+          GST_BUFFER_FLAGS (inbuf), inbuf);
       g_object_notify (G_OBJECT (identity), "last-message");
-      gst_buffer_unref (buf);
       return GST_FLOW_OK;
     }
   }
 
   if (identity->dump) {
-    gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+    gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
   }
 
   for (i = identity->duplicate; i; i--) {
@@ -566,76 +314,48 @@ gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
           g_strdup_printf ("chain   ******* (%s:%s)i (%d bytes, timestamp: %"
           GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
           G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
-          GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
-          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-          GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-          GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
+          GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
+          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+          GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
+          GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
+          GST_BUFFER_FLAGS (inbuf), inbuf);
       g_object_notify (G_OBJECT (identity), "last-message");
     }
 
-    time = GST_BUFFER_TIMESTAMP (buf);
+    time = GST_BUFFER_TIMESTAMP (inbuf);
 
     if (identity->datarate > 0) {
       time = identity->offset * GST_SECOND / identity->datarate;
 
-      GST_BUFFER_TIMESTAMP (buf) = time;
-      GST_BUFFER_DURATION (buf) =
-          GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate;
+      GST_BUFFER_TIMESTAMP (inbuf) = time;
+      GST_BUFFER_DURATION (inbuf) =
+          GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate;
     }
 
     g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-        buf);
+        inbuf);
 
     if (i > 1)
-      gst_buffer_ref (buf);
+      gst_buffer_ref (inbuf);
 
     if (identity->sync) {
-      if (identity->clock) {
+      if (GST_ELEMENT (identity)->clock) {
         /* gst_element_wait (GST_ELEMENT (identity), time); */
       }
     }
 
-    identity->offset += GST_BUFFER_SIZE (buf);
-    if (identity->decoupled) {
-      if (!identity_queue_push (identity, (GstData *) buf))
-        return GST_FLOW_UNEXPECTED;
-    } else {
-      ret = gst_pad_push (identity->srcpad, buf);
-      if (ret != GST_FLOW_OK)
-        return ret;
-    }
+    identity->offset += GST_BUFFER_SIZE (inbuf);
 
     if (identity->sleep_time)
       g_usleep (identity->sleep_time);
+
+    gst_buffer_ref (inbuf);
+    *outbuf = inbuf;
   }
 
   return ret;
 }
 
-static void
-gst_identity_set_dataflow_funcs (GstIdentity * identity)
-{
-  if (identity->has_getrange)
-    gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange);
-  else
-    gst_pad_set_getrange_function (identity->srcpad, NULL);
-
-  if (identity->has_chain)
-    gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
-  else
-    gst_pad_set_chain_function (identity->sinkpad, NULL);
-
-  if (identity->has_src_loop)
-    gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop);
-  else
-    gst_pad_set_loop_function (identity->srcpad, NULL);
-
-  if (identity->has_sink_loop)
-    gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop);
-  else
-    gst_pad_set_loop_function (identity->sinkpad, NULL);
-}
-
 static void
 gst_identity_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -645,22 +365,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
   identity = GST_IDENTITY (object);
 
   switch (prop_id) {
-    case PROP_HAS_GETRANGE:
-      identity->has_getrange = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_CHAIN:
-      identity->has_chain = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_SRC_LOOP:
-      identity->has_src_loop = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
-    case PROP_HAS_SINK_LOOP:
-      identity->has_sink_loop = g_value_get_boolean (value);
-      gst_identity_set_dataflow_funcs (identity);
-      break;
     case PROP_SLEEP_TIME:
       identity->sleep_time = g_value_get_uint (value);
       break;
@@ -703,18 +407,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
   identity = GST_IDENTITY (object);
 
   switch (prop_id) {
-    case PROP_HAS_GETRANGE:
-      g_value_set_boolean (value, identity->has_getrange);
-      break;
-    case PROP_HAS_CHAIN:
-      g_value_set_boolean (value, identity->has_chain);
-      break;
-    case PROP_HAS_SRC_LOOP:
-      g_value_set_boolean (value, identity->has_src_loop);
-      break;
-    case PROP_HAS_SINK_LOOP:
-      g_value_set_boolean (value, identity->has_sink_loop);
-      break;
     case PROP_SLEEP_TIME:
       g_value_set_uint (value, identity->sleep_time);
       break;
@@ -755,12 +447,15 @@ static GstElementStateReturn
 gst_identity_change_state (GstElement * element)
 {
   GstIdentity *identity;
+  GstElementState transition;
+  GstElementStateReturn result;
 
   g_return_val_if_fail (GST_IS_IDENTITY (element), GST_STATE_FAILURE);
 
   identity = GST_IDENTITY (element);
+  transition = GST_STATE_TRANSITION (element);
 
-  switch (GST_STATE_TRANSITION (element)) {
+  switch (transition) {
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
@@ -770,6 +465,14 @@ gst_identity_change_state (GstElement * element)
       identity->prev_offset_end = -1;
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  switch (transition) {
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
@@ -782,8 +485,5 @@ gst_identity_change_state (GstElement * element)
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
-  return GST_STATE_SUCCESS;
+  return result;
 }
index e187f2e2c2e25cf8a870f3343b04b69fb2a7a4bc..4a51a070b4328c933d456ed7e233366a58f27e30 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
 
 G_BEGIN_DECLS
 
@@ -45,24 +46,8 @@ typedef struct _GstIdentity GstIdentity;
 typedef struct _GstIdentityClass GstIdentityClass;
 
 struct _GstIdentity {
-  GstElement    element;
+  GstBaseTransform      element;
 
-  GstPad       *sinkpad;
-  GstPad       *srcpad;
-
-  GstData      *pen_data;
-  GMutex       *pen_lock;
-  GCond                *pen_cond;
-  gboolean      pen_flushing;
-
-  gboolean      has_chain;
-  gboolean      has_getrange;
-  gboolean      has_src_loop;
-  gboolean      has_sink_loop;
-  GstActivateMode sink_mode;
-  GstActivateMode src_mode;
-  gboolean       decoupled;
-  
   guint         duplicate;
   gint                  error_after;
   gfloat        drop_probability;
@@ -75,15 +60,12 @@ struct _GstIdentity {
   GstClockTime   prev_timestamp;
   GstClockTime   prev_duration;
   guint64        prev_offset_end;
-  GstClock     *clock;
   gchar        *last_message;
-  GstCaps      *srccaps;
-
-  guint64       offset;
+  guint64        offset;
 };
 
 struct _GstIdentityClass {
-  GstElementClass parent_class;
+  GstBaseTransformClass parent_class;
 
   /* signals */
   void (*handoff) (GstElement *element, GstBuffer *buf);