tests/network-clock.scm: Commentary update.
authorAndy Wingo <wingo@pobox.com>
Fri, 1 Jul 2005 16:46:59 +0000 (16:46 +0000)
committerAndy Wingo <wingo@pobox.com>
Fri, 1 Jul 2005 16:46:59 +0000 (16:46 +0000)
Original commit message from CVS:
2005-07-01  Andy Wingo  <wingo@pobox.com>

* tests/network-clock.scm: Commentary update.

* gst/elements/gstidentity.c (PROP_DUPLICATE): Gone daddy gone.
Didn't really make sense, not implementable with basetransform,
etc.
(gst_identity_transform): Unref inbuf via make_writable. Feeble
attempt at implementing the sync property, needs an unlock method.

* gst/base/gstbasetransform.c (gst_base_transform_transform_caps):
New func, by default returns the same caps (the identity
transformation).
(gst_base_transform_getcaps): Uses transform_caps to return
something sensible.
(gst_base_transform_setcaps): Complicated logic to get caps on
both pads, even if they are different, and to call set_caps once
for every time both pads get their caps set.
(gst_base_transform_handle_buffer): Give the ref to the transform
function. Allows in-place modification of the buffer.

* gst/base/gstbasetransform.h (transform_caps): New class method.
Given caps on one side, what can I do on the other.
(set_caps): Take two caps, one for each side of the element.

* gst/gstpad.h:
* gst/gstpad.c (gst_pad_fixate_caps): Change prototype to modify
caps in place. This is safe because we can check the mutability of
the caps, and a good idea because fixate functions are just called
as a matter of last resort. (Not actually implemented.)
(gst_pad_set_caps): If the caps we're setting is actually the same
as the existing pad caps, just update the pointer without calling
setcaps. Assert that caps is either NULL or fixed, as per the
docs.

* gst/gstghostpad.c: Update for fixate changes.

18 files changed:
ChangeLog
docs/gst/tmpl/gstbasetransform.sgml
docs/gst/tmpl/gstpad.sgml
gst/base/gstbasetransform.c
gst/base/gstbasetransform.h
gst/elements/gstidentity.c
gst/elements/gstidentity.h
gst/gstcaps.c
gst/gstcaps.h
gst/gstghostpad.c
gst/gstpad.c
gst/gstpad.h
libs/gst/base/gstbasetransform.c
libs/gst/base/gstbasetransform.h
plugins/elements/gstidentity.c
plugins/elements/gstidentity.h
tests/misc/network-clock.scm
tests/network-clock.scm

index 62e7a97..c32c150 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,46 @@
+2005-07-01  Andy Wingo  <wingo@pobox.com>
+
+       * tests/network-clock.scm: Commentary update.
+
+       * gst/elements/gstidentity.c (PROP_DUPLICATE): Gone daddy gone.
+       Didn't really make sense, not implementable with basetransform,
+       etc.
+       (gst_identity_transform): Unref inbuf via make_writable. Feeble
+       attempt at implementing the sync property, needs an unlock method.
+
+       * gst/base/gstbasetransform.c (gst_base_transform_transform_caps):
+       New func, by default returns the same caps (the identity
+       transformation).
+       (gst_base_transform_getcaps): Uses transform_caps to return
+       something sensible.
+       (gst_base_transform_setcaps): Complicated logic to get caps on
+       both pads, even if they are different, and to call set_caps once
+       for every time both pads get their caps set.
+       (gst_base_transform_handle_buffer): Give the ref to the transform
+       function. Allows in-place modification of the buffer.
+
+       * gst/base/gstbasetransform.h (transform_caps): New class method.
+       Given caps on one side, what can I do on the other.
+       (set_caps): Take two caps, one for each side of the element.
+
+       * gst/gstpad.h:
+       * gst/gstpad.c (gst_pad_fixate_caps): Change prototype to modify
+       caps in place. This is safe because we can check the mutability of
+       the caps, and a good idea because fixate functions are just called
+       as a matter of last resort. (Not actually implemented.)
+       (gst_pad_set_caps): If the caps we're setting is actually the same
+       as the existing pad caps, just update the pointer without calling
+       setcaps. Assert that caps is either NULL or fixed, as per the
+       docs.
+
+       * gst/gstghostpad.c: Update for fixate changes.
+
+2005-07-02  Andy Wingo  <wingo@pobox.com>
+
+       * gst/gstcaps.c:
+       * gst/gstcaps.h (gst_static_caps_get): Not const return, having
+       two refcounts makes it immutable, which is enough. Doc more.
+
 2005-07-02  Jan Schmidt  <thaytan@mad.scientist.com>
 
        * gst/gstpad.c: (gst_pad_emit_have_data_signal):
index ce816ed..a9eaaa2 100644 (file)
@@ -26,6 +26,7 @@ GstBaseTransform
 </para>
 
 @parent_class: 
+@transform_caps: 
 @set_caps: 
 @start: 
 @stop: 
index 0c0568d..fc15412 100644 (file)
@@ -90,8 +90,8 @@ Last reviewed on December 13th, 2002 (0.5.0.1)
 @queryfunc: 
 @intlinkfunc: 
 @bufferallocfunc: 
-@emit_buffer_signals: 
-@emit_event_signals: 
+@do_buffer_signals: 
+@do_event_signals: 
 
 <!-- ##### SIGNAL GstPad::have-data ##### -->
 <para>
index 0a29b36..feff3a1 100644 (file)
@@ -98,7 +98,7 @@ 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 GstCaps *gst_base_transform_getcaps (GstPad * pad);
 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
 
 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
@@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   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_DEBUG_FUNCPTR (gst_base_transform_getcaps));
   gst_pad_set_setcaps_function (trans->sinkpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
   gst_pad_set_event_function (trans->sinkpad,
@@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   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_DEBUG_FUNCPTR (gst_base_transform_getcaps));
+  gst_pad_set_setcaps_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
   gst_pad_set_getrange_function (trans->srcpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
   gst_pad_set_activatepull_function (trans->srcpad,
@@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
 }
 
 static GstCaps *
-gst_base_transform_proxy_getcaps (GstPad * pad)
+gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
+    GstCaps * caps)
+{
+  GstBaseTransformClass *klass;
+
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (klass->transform_caps)
+    return klass->transform_caps (trans, pad, caps);
+  else
+    return gst_caps_ref (caps);
+}
+
+static GstCaps *
+gst_base_transform_getcaps (GstPad * pad)
 {
-  GstPad *otherpad;
   GstBaseTransform *trans;
+  GstPad *otherpad;
   GstCaps *caps;
-  const GstCaps *templcaps;
 
-  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
 
-  otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
+  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
 
-  /* we can do whatever the peer can do */
+  /* we can do what the peer can */
   caps = gst_pad_peer_get_caps (otherpad);
-  templcaps = gst_pad_get_pad_template_caps (pad);
 
-  if (caps == NULL) {
-    /* no peer, then the padtemplate is enough */
-    return gst_caps_copy (templcaps);
-  } else {
-    GstCaps *ret = gst_caps_intersect (caps, templcaps);
+  if (caps) {
+    GstCaps *temp;
 
+    temp = gst_base_transform_transform_caps (trans, otherpad, caps);
     gst_caps_unref (caps);
-    return ret;
+    caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad));
+    gst_caps_unref (temp);
+  } else {
+    /* no peer, our padtemplate is enough then */
+    caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
   }
+
+  return caps;
 }
 
 static gboolean
 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstBaseTransform *trans;
-  GstBaseTransformClass *bclass;
-  gboolean result = TRUE;
+  GstBaseTransformClass *klass;
+  GstStructure *structure;
+  GstPad *otherpad, *otherpeer;
+  gboolean ret = TRUE;
 
   trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
 
-  if (bclass->set_caps)
-    result = bclass->set_caps (trans, caps);
+  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
+  otherpeer = gst_pad_get_peer (otherpad);
 
-  return result;
+  if (GST_PAD_IS_IN_SETCAPS (otherpad))
+    goto done;
+
+  if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) {
+
+    /* the peer accepts the caps as they are */
+    gst_pad_set_caps (otherpad, caps);
+
+    /* let the element know */
+    if (klass->set_caps)
+      klass->set_caps (trans, caps, caps);
+
+    ret = TRUE;
+  } else {
+    GstCaps *peercaps;
+    GstCaps *intersect;
+    GstCaps *transform = NULL;
+    GstCaps *othercaps;
+
+    ret = FALSE;
+
+    /* other pad has a peer, so we have to figure out how to do the conversion
+     */
+    /* see how we can transform the input caps */
+    transform = gst_base_transform_transform_caps (trans, pad, caps);
+
+    if (!transform)
+      goto done;
+
+    /* see what the peer can do */
+    peercaps = gst_pad_get_caps (otherpeer);
+
+    GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps);
+    GST_DEBUG ("transform %" GST_PTR_FORMAT, transform);
+
+    /* filter against our possibilities */
+    intersect = gst_caps_intersect (peercaps, transform);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (transform);
+
+    GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect);
+
+    /* take first possibility */
+    othercaps = gst_caps_copy_nth (intersect, 0);
+    gst_caps_unref (intersect);
+    structure = gst_caps_get_structure (othercaps, 0);
+
+    /* and fixate if necessary */
+    gst_pad_fixate_caps (otherpad, othercaps);
+
+    g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
+
+    gst_pad_set_caps (otherpad, othercaps);
+
+    /* let the element know */
+    if (klass->set_caps) {
+      if (pad == trans->sinkpad) {
+        klass->set_caps (trans, caps, othercaps);
+      } else {
+        klass->set_caps (trans, othercaps, caps);
+      }
+    }
+
+    ret = TRUE;
+  }
+
+done:
+
+  if (otherpeer)
+    gst_object_unref (otherpeer);
+
+  return ret;
 }
 
 static gboolean
@@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
   if (bclass->transform)
     ret = bclass->transform (trans, inbuf, outbuf);
 
-  gst_buffer_unref (inbuf);
-
   return ret;
 }
 
index 66b4176..e0581e6 100644 (file)
@@ -57,9 +57,13 @@ struct _GstBaseTransformClass {
   /*< public >*/
   /* virtual methods for subclasses */
 
+  /* given caps on one pad, what can I do on the other pad */
+  GstCaps*     (*transform_caps) (GstBaseTransform *trans, GstPad *pad,
+                                   GstCaps *caps);
 
   /* notify the subclass of new caps */
-  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *caps);
+  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *incaps,
+                                 GstCaps *outcaps);
 
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
@@ -68,7 +72,8 @@ struct _GstBaseTransformClass {
   gboolean      (*event)        (GstBaseTransform *trans, GstEvent *event);
 
   /* transform one incoming buffer to one outgoing buffer */
-  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
+  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf,
+                                 GstBuffer **outbuf);
 };
 
 GType gst_base_transform_get_type (void);
index 37c42de..7c2ac82 100644 (file)
@@ -73,7 +73,6 @@ enum
 {
   PROP_0,
   PROP_SLEEP_TIME,
-  PROP_DUPLICATE,
   PROP_ERROR_AFTER,
   PROP_DROP_PROBABILITY,
   PROP_DATARATE,
@@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass)
       g_param_spec_uint ("sleep-time", "Sleep time",
           "Microseconds to sleep between processing", 0, G_MAXUINT,
           DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
-      g_param_spec_uint ("duplicate", "Duplicate Buffers",
-          "Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
-          G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
       g_param_spec_int ("error_after", "Error After", "Error after N buffers",
           G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
@@ -196,7 +191,6 @@ static void
 gst_identity_init (GstIdentity * identity)
 {
   identity->sleep_time = DEFAULT_SLEEP_TIME;
-  identity->duplicate = DEFAULT_DUPLICATE;
   identity->error_after = DEFAULT_ERROR_AFTER;
   identity->drop_probability = DEFAULT_DROP_PROBABILITY;
   identity->datarate = DEFAULT_DATARATE;
@@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstIdentity *identity = GST_IDENTITY (trans);
-  guint i;
 
   if (identity->check_perfect)
     gst_identity_check_perfect (identity, inbuf);
@@ -281,6 +274,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     if (identity->error_after == 0) {
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
+      gst_buffer_unref (inbuf);
       return GST_FLOW_ERROR;
     }
   }
@@ -300,6 +294,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
           GST_BUFFER_FLAGS (inbuf), inbuf);
       GST_UNLOCK (identity);
       g_object_notify (G_OBJECT (identity), "last-message");
+      gst_buffer_unref (inbuf);
       return GST_FLOW_OK;
     }
   }
@@ -308,55 +303,65 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
   }
 
-  for (i = identity->duplicate; i; i--) {
-    GstClockTime time;
+  if (!identity->silent) {
+    GST_LOCK (identity);
+    g_free (identity->last_message);
+    identity->last_message =
+        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 (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);
+    GST_UNLOCK (identity);
+    g_object_notify (G_OBJECT (identity), "last-message");
+  }
 
-    if (!identity->silent) {
-      GST_LOCK (identity);
-      g_free (identity->last_message);
-      identity->last_message =
-          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 (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);
-      GST_UNLOCK (identity);
-      g_object_notify (G_OBJECT (identity), "last-message");
-    }
+  *outbuf = gst_buffer_make_writable (inbuf);
+  /* inbuf is no longer usable */
 
-    time = GST_BUFFER_TIMESTAMP (inbuf);
+  if (identity->datarate > 0) {
+    GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
 
-    if (identity->datarate > 0) {
-      time = identity->offset * GST_SECOND / identity->datarate;
+    GST_BUFFER_TIMESTAMP (*outbuf) = time;
+    GST_BUFFER_DURATION (*outbuf) =
+        GST_BUFFER_SIZE (*outbuf) * 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,
+      *outbuf);
 
-    g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-        inbuf);
+  if (identity->sync) {
+    GstClock *clock;
+    GstClockReturn cret;
 
-    if (i > 1)
-      gst_buffer_ref (inbuf);
+    clock = GST_ELEMENT (identity)->clock;
 
-    if (identity->sync) {
-      if (GST_ELEMENT (identity)->clock) {
-        /* gst_element_wait (GST_ELEMENT (identity), time); */
+    if (clock) {
+      /* save id if we need to unlock */
+      /* FIXME: actually unlock this somewhere if the state changes */
+      GST_LOCK (identity);
+      identity->clock_id = gst_clock_new_single_shot_id (clock,
+          GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
+      GST_UNLOCK (identity);
+      cret = gst_clock_id_wait (identity->clock_id, NULL);
+      GST_LOCK (identity);
+      if (identity->clock_id) {
+        gst_clock_id_unref (identity->clock_id);
+        identity->clock_id = NULL;
       }
+      GST_UNLOCK (identity);
+      if (cret == GST_CLOCK_UNSCHEDULED)
+        ret = GST_FLOW_UNEXPECTED;
     }
+  }
 
-    identity->offset += GST_BUFFER_SIZE (inbuf);
+  identity->offset += GST_BUFFER_SIZE (*outbuf);
 
-    if (identity->sleep_time)
-      g_usleep (identity->sleep_time);
-
-    gst_buffer_ref (inbuf);
-    *outbuf = inbuf;
-  }
+  if (identity->sleep_time && ret == GST_FLOW_OK)
+    g_usleep (identity->sleep_time);
 
   return ret;
 }
@@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
     case PROP_SILENT:
       identity->silent = g_value_get_boolean (value);
       break;
-    case PROP_DUPLICATE:
-      identity->duplicate = g_value_get_uint (value);
-      break;
     case PROP_DUMP:
       identity->dump = g_value_get_boolean (value);
       break;
@@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_SLEEP_TIME:
       g_value_set_uint (value, identity->sleep_time);
       break;
-    case PROP_DUPLICATE:
-      g_value_set_uint (value, identity->duplicate);
-      break;
     case PROP_ERROR_AFTER:
       g_value_set_int (value, identity->error_after);
       break;
index 4a51a07..79ffac3 100644 (file)
@@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass;
 struct _GstIdentity {
   GstBaseTransform      element;
 
-  guint         duplicate;
+  GstClockID     clock_id;
   gint                  error_after;
   gfloat        drop_probability;
   gint          datarate;
index caeaa5b..3188930 100644 (file)
@@ -347,9 +347,11 @@ gst_caps_unref (GstCaps * caps)
  *
  * Converts a #GstStaticCaps to a #GstCaps.
  *
- * Returns: the new #GstCaps
+ * Returns: A pointer to the #GstCaps. Although you do not have a reference on
+ * the caps, the core will never drop its references. (The core has two
+ * references on the caps so it will be immutable.)
  */
-const GstCaps *
+GstCaps *
 gst_static_caps_get (GstStaticCaps * static_caps)
 {
   GstCaps *caps = (GstCaps *) static_caps;
index de458af..c15f558 100644 (file)
@@ -98,7 +98,7 @@ GstCaps *                gst_caps_copy                                        (const GstCaps * caps);
 GstCaps *                gst_caps_make_writable                        (GstCaps *caps);
 void                     gst_caps_unref                                (GstCaps* caps);
 
-G_CONST_RETURN GstCaps * gst_static_caps_get                            (GstStaticCaps *static_caps);
+GstCaps *               gst_static_caps_get                            (GstStaticCaps *static_caps);
 
 /* manipulation */
 void                     gst_caps_append                                (GstCaps       *caps1,
index 0aa5dd1..7dbb12c 100644 (file)
@@ -279,14 +279,14 @@ gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
   return gst_pad_accept_caps (target, caps);
 }
 
-static GstCaps *
+static void
 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
 {
   GstPad *target = GST_PROXY_PAD_TARGET (pad);
 
-  g_return_val_if_fail (target != NULL, NULL);
+  g_return_if_fail (target != NULL);
 
-  return gst_pad_fixate_caps (target, caps);
+  gst_pad_fixate_caps (target, caps);
 }
 
 static gboolean
index 9f632bc..cf420b9 100644 (file)
@@ -1748,15 +1748,13 @@ was_dispatching:
  * gst_pad_fixate_caps:
  * @pad: a  #GstPad to fixate
  *
- * Fixate a caps on the given pad.
- *
- * Returns: a fixated #GstCaps.
+ * Fixate a caps on the given pad. Modifies the caps in place, so you should be
+ * that the caps are actually writable (see gst_caps_make_writable()).
  */
-GstCaps *
+void
 gst_pad_fixate_caps (GstPad * pad, GstCaps * caps)
 {
   /* FIXME, implement me, call the fixate function for the pad */
-  return caps;
 }
 
 /**
@@ -1857,12 +1855,20 @@ gboolean
 gst_pad_set_caps (GstPad * pad, GstCaps * caps)
 {
   GstPadSetCapsFunction setcaps;
+  GstCaps *existing;
 
   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+  g_return_val_if_fail (caps == NULL || gst_caps_is_fixed (caps), FALSE);
 
   GST_LOCK (pad);
   setcaps = GST_PAD_SETCAPSFUNC (pad);
 
+  existing = GST_PAD_CAPS (pad);
+  if (caps == existing)
+    goto setting_same_caps;
+  else if (caps && existing && gst_caps_is_equal (caps, existing))
+    goto setting_same_caps;
+
   /* call setcaps function to configure the pad */
   if (setcaps != NULL && caps) {
     if (!GST_PAD_IS_IN_SETCAPS (pad)) {
@@ -1887,6 +1893,15 @@ gst_pad_set_caps (GstPad * pad, GstCaps * caps)
 
   return TRUE;
 
+setting_same_caps:
+  {
+    GST_UNLOCK (pad);
+    gst_caps_replace (&GST_PAD_CAPS (pad), caps);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
+        "caps %" GST_PTR_FORMAT " same as existing, updating ptr only", caps);
+    return TRUE;
+  }
+/* errors */
 could_not_set:
   {
     GST_LOCK (pad);
index 29c2c1a..9e827d2 100644 (file)
@@ -117,7 +117,7 @@ typedef void                        (*GstPadUnlinkFunction)         (GstPad *pad);
 typedef GstCaps*               (*GstPadGetCapsFunction)        (GstPad *pad);
 typedef gboolean               (*GstPadSetCapsFunction)        (GstPad *pad, GstCaps *caps);
 typedef gboolean               (*GstPadAcceptCapsFunction)     (GstPad *pad, GstCaps *caps);
-typedef GstCaps*               (*GstPadFixateCapsFunction)     (GstPad *pad, GstCaps *caps);
+typedef void                   (*GstPadFixateCapsFunction)     (GstPad *pad, GstCaps *caps);
 typedef GstFlowReturn          (*GstPadBufferAllocFunction)    (GstPad *pad, guint64 offset, guint size,
                                                                 GstCaps *caps, GstBuffer **buf);
 /* misc */
@@ -414,7 +414,7 @@ G_CONST_RETURN GstCaps*     gst_pad_get_pad_template_caps           (GstPad *pad);
 
 /* capsnego function for connected/unconnected pads */
 GstCaps *              gst_pad_get_caps                        (GstPad * pad);
-GstCaps*               gst_pad_fixate_caps                     (GstPad * pad, GstCaps *caps);
+void                   gst_pad_fixate_caps                     (GstPad * pad, GstCaps *caps);
 gboolean               gst_pad_accept_caps                     (GstPad * pad, GstCaps *caps);
 gboolean               gst_pad_set_caps                        (GstPad * pad, GstCaps *caps);
 
index 0a29b36..feff3a1 100644 (file)
@@ -98,7 +98,7 @@ 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 GstCaps *gst_base_transform_getcaps (GstPad * pad);
 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
 
 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
@@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   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_DEBUG_FUNCPTR (gst_base_transform_getcaps));
   gst_pad_set_setcaps_function (trans->sinkpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
   gst_pad_set_event_function (trans->sinkpad,
@@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
   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_DEBUG_FUNCPTR (gst_base_transform_getcaps));
+  gst_pad_set_setcaps_function (trans->srcpad,
+      GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
   gst_pad_set_getrange_function (trans->srcpad,
       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
   gst_pad_set_activatepull_function (trans->srcpad,
@@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
 }
 
 static GstCaps *
-gst_base_transform_proxy_getcaps (GstPad * pad)
+gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
+    GstCaps * caps)
+{
+  GstBaseTransformClass *klass;
+
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+
+  if (klass->transform_caps)
+    return klass->transform_caps (trans, pad, caps);
+  else
+    return gst_caps_ref (caps);
+}
+
+static GstCaps *
+gst_base_transform_getcaps (GstPad * pad)
 {
-  GstPad *otherpad;
   GstBaseTransform *trans;
+  GstPad *otherpad;
   GstCaps *caps;
-  const GstCaps *templcaps;
 
-  trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+  trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
 
-  otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
+  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
 
-  /* we can do whatever the peer can do */
+  /* we can do what the peer can */
   caps = gst_pad_peer_get_caps (otherpad);
-  templcaps = gst_pad_get_pad_template_caps (pad);
 
-  if (caps == NULL) {
-    /* no peer, then the padtemplate is enough */
-    return gst_caps_copy (templcaps);
-  } else {
-    GstCaps *ret = gst_caps_intersect (caps, templcaps);
+  if (caps) {
+    GstCaps *temp;
 
+    temp = gst_base_transform_transform_caps (trans, otherpad, caps);
     gst_caps_unref (caps);
-    return ret;
+    caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad));
+    gst_caps_unref (temp);
+  } else {
+    /* no peer, our padtemplate is enough then */
+    caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
   }
+
+  return caps;
 }
 
 static gboolean
 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstBaseTransform *trans;
-  GstBaseTransformClass *bclass;
-  gboolean result = TRUE;
+  GstBaseTransformClass *klass;
+  GstStructure *structure;
+  GstPad *otherpad, *otherpeer;
+  gboolean ret = TRUE;
 
   trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
-  bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
+  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
 
-  if (bclass->set_caps)
-    result = bclass->set_caps (trans, caps);
+  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
+  otherpeer = gst_pad_get_peer (otherpad);
 
-  return result;
+  if (GST_PAD_IS_IN_SETCAPS (otherpad))
+    goto done;
+
+  if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) {
+
+    /* the peer accepts the caps as they are */
+    gst_pad_set_caps (otherpad, caps);
+
+    /* let the element know */
+    if (klass->set_caps)
+      klass->set_caps (trans, caps, caps);
+
+    ret = TRUE;
+  } else {
+    GstCaps *peercaps;
+    GstCaps *intersect;
+    GstCaps *transform = NULL;
+    GstCaps *othercaps;
+
+    ret = FALSE;
+
+    /* other pad has a peer, so we have to figure out how to do the conversion
+     */
+    /* see how we can transform the input caps */
+    transform = gst_base_transform_transform_caps (trans, pad, caps);
+
+    if (!transform)
+      goto done;
+
+    /* see what the peer can do */
+    peercaps = gst_pad_get_caps (otherpeer);
+
+    GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps);
+    GST_DEBUG ("transform %" GST_PTR_FORMAT, transform);
+
+    /* filter against our possibilities */
+    intersect = gst_caps_intersect (peercaps, transform);
+    gst_caps_unref (peercaps);
+    gst_caps_unref (transform);
+
+    GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect);
+
+    /* take first possibility */
+    othercaps = gst_caps_copy_nth (intersect, 0);
+    gst_caps_unref (intersect);
+    structure = gst_caps_get_structure (othercaps, 0);
+
+    /* and fixate if necessary */
+    gst_pad_fixate_caps (otherpad, othercaps);
+
+    g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
+
+    gst_pad_set_caps (otherpad, othercaps);
+
+    /* let the element know */
+    if (klass->set_caps) {
+      if (pad == trans->sinkpad) {
+        klass->set_caps (trans, caps, othercaps);
+      } else {
+        klass->set_caps (trans, othercaps, caps);
+      }
+    }
+
+    ret = TRUE;
+  }
+
+done:
+
+  if (otherpeer)
+    gst_object_unref (otherpeer);
+
+  return ret;
 }
 
 static gboolean
@@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
   if (bclass->transform)
     ret = bclass->transform (trans, inbuf, outbuf);
 
-  gst_buffer_unref (inbuf);
-
   return ret;
 }
 
index 66b4176..e0581e6 100644 (file)
@@ -57,9 +57,13 @@ struct _GstBaseTransformClass {
   /*< public >*/
   /* virtual methods for subclasses */
 
+  /* given caps on one pad, what can I do on the other pad */
+  GstCaps*     (*transform_caps) (GstBaseTransform *trans, GstPad *pad,
+                                   GstCaps *caps);
 
   /* notify the subclass of new caps */
-  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *caps);
+  gboolean      (*set_caps)     (GstBaseTransform *trans, GstCaps *incaps,
+                                 GstCaps *outcaps);
 
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseTransform *trans);
@@ -68,7 +72,8 @@ struct _GstBaseTransformClass {
   gboolean      (*event)        (GstBaseTransform *trans, GstEvent *event);
 
   /* transform one incoming buffer to one outgoing buffer */
-  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
+  GstFlowReturn (*transform)    (GstBaseTransform *trans, GstBuffer *inbuf,
+                                 GstBuffer **outbuf);
 };
 
 GType gst_base_transform_get_type (void);
index 37c42de..7c2ac82 100644 (file)
@@ -73,7 +73,6 @@ enum
 {
   PROP_0,
   PROP_SLEEP_TIME,
-  PROP_DUPLICATE,
   PROP_ERROR_AFTER,
   PROP_DROP_PROBABILITY,
   PROP_DATARATE,
@@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass)
       g_param_spec_uint ("sleep-time", "Sleep time",
           "Microseconds to sleep between processing", 0, G_MAXUINT,
           DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
-      g_param_spec_uint ("duplicate", "Duplicate Buffers",
-          "Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
-          G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
       g_param_spec_int ("error_after", "Error After", "Error after N buffers",
           G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
@@ -196,7 +191,6 @@ static void
 gst_identity_init (GstIdentity * identity)
 {
   identity->sleep_time = DEFAULT_SLEEP_TIME;
-  identity->duplicate = DEFAULT_DUPLICATE;
   identity->error_after = DEFAULT_ERROR_AFTER;
   identity->drop_probability = DEFAULT_DROP_PROBABILITY;
   identity->datarate = DEFAULT_DATARATE;
@@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstIdentity *identity = GST_IDENTITY (trans);
-  guint i;
 
   if (identity->check_perfect)
     gst_identity_check_perfect (identity, inbuf);
@@ -281,6 +274,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     if (identity->error_after == 0) {
       GST_ELEMENT_ERROR (identity, CORE, FAILED,
           (_("Failed after iterations as requested.")), (NULL));
+      gst_buffer_unref (inbuf);
       return GST_FLOW_ERROR;
     }
   }
@@ -300,6 +294,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
           GST_BUFFER_FLAGS (inbuf), inbuf);
       GST_UNLOCK (identity);
       g_object_notify (G_OBJECT (identity), "last-message");
+      gst_buffer_unref (inbuf);
       return GST_FLOW_OK;
     }
   }
@@ -308,55 +303,65 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
     gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
   }
 
-  for (i = identity->duplicate; i; i--) {
-    GstClockTime time;
+  if (!identity->silent) {
+    GST_LOCK (identity);
+    g_free (identity->last_message);
+    identity->last_message =
+        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 (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);
+    GST_UNLOCK (identity);
+    g_object_notify (G_OBJECT (identity), "last-message");
+  }
 
-    if (!identity->silent) {
-      GST_LOCK (identity);
-      g_free (identity->last_message);
-      identity->last_message =
-          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 (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);
-      GST_UNLOCK (identity);
-      g_object_notify (G_OBJECT (identity), "last-message");
-    }
+  *outbuf = gst_buffer_make_writable (inbuf);
+  /* inbuf is no longer usable */
 
-    time = GST_BUFFER_TIMESTAMP (inbuf);
+  if (identity->datarate > 0) {
+    GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
 
-    if (identity->datarate > 0) {
-      time = identity->offset * GST_SECOND / identity->datarate;
+    GST_BUFFER_TIMESTAMP (*outbuf) = time;
+    GST_BUFFER_DURATION (*outbuf) =
+        GST_BUFFER_SIZE (*outbuf) * 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,
+      *outbuf);
 
-    g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
-        inbuf);
+  if (identity->sync) {
+    GstClock *clock;
+    GstClockReturn cret;
 
-    if (i > 1)
-      gst_buffer_ref (inbuf);
+    clock = GST_ELEMENT (identity)->clock;
 
-    if (identity->sync) {
-      if (GST_ELEMENT (identity)->clock) {
-        /* gst_element_wait (GST_ELEMENT (identity), time); */
+    if (clock) {
+      /* save id if we need to unlock */
+      /* FIXME: actually unlock this somewhere if the state changes */
+      GST_LOCK (identity);
+      identity->clock_id = gst_clock_new_single_shot_id (clock,
+          GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
+      GST_UNLOCK (identity);
+      cret = gst_clock_id_wait (identity->clock_id, NULL);
+      GST_LOCK (identity);
+      if (identity->clock_id) {
+        gst_clock_id_unref (identity->clock_id);
+        identity->clock_id = NULL;
       }
+      GST_UNLOCK (identity);
+      if (cret == GST_CLOCK_UNSCHEDULED)
+        ret = GST_FLOW_UNEXPECTED;
     }
+  }
 
-    identity->offset += GST_BUFFER_SIZE (inbuf);
+  identity->offset += GST_BUFFER_SIZE (*outbuf);
 
-    if (identity->sleep_time)
-      g_usleep (identity->sleep_time);
-
-    gst_buffer_ref (inbuf);
-    *outbuf = inbuf;
-  }
+  if (identity->sleep_time && ret == GST_FLOW_OK)
+    g_usleep (identity->sleep_time);
 
   return ret;
 }
@@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
     case PROP_SILENT:
       identity->silent = g_value_get_boolean (value);
       break;
-    case PROP_DUPLICATE:
-      identity->duplicate = g_value_get_uint (value);
-      break;
     case PROP_DUMP:
       identity->dump = g_value_get_boolean (value);
       break;
@@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_SLEEP_TIME:
       g_value_set_uint (value, identity->sleep_time);
       break;
-    case PROP_DUPLICATE:
-      g_value_set_uint (value, identity->duplicate);
-      break;
     case PROP_ERROR_AFTER:
       g_value_set_int (value, identity->error_after);
       break;
index 4a51a07..79ffac3 100644 (file)
@@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass;
 struct _GstIdentity {
   GstBaseTransform      element;
 
-  guint         duplicate;
+  GstClockID     clock_id;
   gint                  error_after;
   gfloat        drop_probability;
   gint          datarate;
index c575645..5139773 100755 (executable)
@@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@"
 ;; second argument, rather deferring that calculation until stream-cdr
 ;; is called. In that way all times are actually infinite series.
 ;;
-;; Knobs: sample rate, send delay, receive delay, send noise, receive
-;; noise, queue length, rate of remote clock, rate of local clock. See
-;; network-clock.scm --help.
+;; Usage: See network-clock.scm --help.
 ;;
 ;;; Code:
 
index c575645..5139773 100755 (executable)
@@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@"
 ;; second argument, rather deferring that calculation until stream-cdr
 ;; is called. In that way all times are actually infinite series.
 ;;
-;; Knobs: sample rate, send delay, receive delay, send noise, receive
-;; noise, queue length, rate of remote clock, rate of local clock. See
-;; network-clock.scm --help.
+;; Usage: See network-clock.scm --help.
 ;;
 ;;; Code: