* to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
* association later on.
*
+ * Note that GhostPads add overhead to the data processing of a pipeline.
+ *
* Last reviewed on 2005-11-18 (0.9.5)
*/
#define GST_IS_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
#define GST_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
#define GST_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
+#define GST_PROXY_PAD_CAST(obj) ((GstProxyPad *)obj)
+
#define GST_PROXY_PAD_TARGET(pad) (GST_PROXY_PAD (pad)->target)
#define GST_PROXY_PAD_INTERNAL(pad) (GST_PROXY_PAD (pad)->internal)
GstCaps *res;
if (target) {
+ /* if we have a real target, proxy the call */
+ GST_DEBUG_OBJECT (pad, "get caps of target");
res = gst_pad_get_caps (target);
gst_object_unref (target);
} else {
+ GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
+
+ /* else, if we have a template, use that */
+ if (templ) {
+ res = GST_PAD_TEMPLATE_CAPS (templ);
+ GST_DEBUG_OBJECT (pad,
+ "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
+ res);
+ res = gst_caps_ref (res);
+ goto done;
+ }
+
+ /* last resort, any caps */
+ GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
res = gst_caps_new_any ();
}
+
+done:
return res;
}
res = gst_pad_set_caps (target, caps);
gst_object_unref (target);
} else {
- /*
- We don't have any target, but we shouldn't return FALSE since this
- would stop the actual push of a buffer (which might trigger a pad block
- or probe, or properly return GST_FLOW_NOT_LINKED.
+ /* We don't have any target, but we shouldn't return FALSE since this
+ * would stop the actual push of a buffer (which might trigger a pad block
+ * or probe, or properly return GST_FLOW_NOT_LINKED.
*/
res = TRUE;
}
if (target) {
GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
- if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target))) {
- GST_ERROR_OBJECT (pad,
- "target pad doesn't have the same direction as ourself");
- return FALSE;
- }
+
+ if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
+ goto wrong_direction;
} else
GST_LOG_OBJECT (pad, "clearing target");
GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
return TRUE;
+
+wrong_direction:
+ {
+ GST_ERROR_OBJECT (pad,
+ "target pad doesn't have the same direction as ourself");
+ return FALSE;
+ }
}
static gboolean
/* remove and unref the target */
target_p = &GST_PROXY_PAD_TARGET (pad);
gst_object_replace ((GstObject **) target_p, NULL);
- /*
- The internal is only cleared by GstGhostPad::dispose, since it is the
- parent of non-ghost GstProxyPad and owns the refcount on the internal.
+ /* The internal is only cleared by GstGhostPad::dispose, since it is the
+ * parent of non-ghost GstProxyPad and owns the refcount on the internal.
*/
GST_PROXY_UNLOCK (pad);
G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
}
-/**
- * gst_ghost_pad_new_no_target:
- * @name: the name of the new pad, or NULL to assign a default name.
- * @dir: the direction of the ghostpad
- *
- * Create a new ghostpad without a target with the given direction.
- * A target can be set on the ghostpad later with the
- * gst_ghost_pad_set_target() function.
- *
- * The created ghostpad will not have a padtemplate.
- *
- * Returns: a new #GstPad, or NULL in case of an error.
- */
-GstPad *
-gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
+static GstPad *
+gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
+ GstPadTemplate * templ)
{
GstPad *ret;
GstPad *internal;
- GST_LOG ("name:%s, direction:%d", name, dir);
+ g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
/* OBJECT CREATION */
-
- ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "direction", dir, NULL);
+ if (templ) {
+ ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
+ "direction", dir, "template", templ, NULL);
+ } else {
+ ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
+ "direction", dir, NULL);
+ }
/* Set directional padfunctions for ghostpad */
if (dir == GST_PAD_SINK) {
This is why we don't take extra refcounts in the assignments below
*/
GST_PROXY_PAD_INTERNAL (ret) = internal;
- GST_PROXY_PAD_INTERNAL (GST_PROXY_PAD_INTERNAL (ret)) = GST_PAD (ret);
+ GST_PROXY_PAD_INTERNAL (internal) = GST_PAD (ret);
/* could be more general here, iterating over all writable properties...
* taking the short road for now tho */
}
/**
+ * gst_ghost_pad_new_no_target:
+ * @name: the name of the new pad, or NULL to assign a default name.
+ * @dir: the direction of the ghostpad
+ *
+ * Create a new ghostpad without a target with the given direction.
+ * A target can be set on the ghostpad later with the
+ * gst_ghost_pad_set_target() function.
+ *
+ * The created ghostpad will not have a padtemplate.
+ *
+ * Returns: a new #GstPad, or NULL in case of an error.
+ */
+GstPad *
+gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
+{
+ g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
+
+ GST_LOG ("name:%s, direction:%d", name, dir);
+
+ return gst_ghost_pad_new_full (name, dir, NULL);
+}
+
+/**
* gst_ghost_pad_new:
* @name: the name of the new pad, or NULL to assign a default name.
* @target: the pad to ghost.
g_return_val_if_fail (GST_IS_PAD (target), NULL);
g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
- if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target)))) {
- gst_ghost_pad_set_target (GST_GHOST_PAD (ret), target);
+ if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
+ if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
+ goto set_target_failed;
+
+ return ret;
+
+ /* ERRORS */
+set_target_failed:
+ {
+ gst_object_unref (ret);
+ return NULL;
}
+}
+
+/**
+ * gst_ghost_pad_new_from_template:
+ * @name: the name of the new pad, or NULL to assign a default name.
+ * @target: the pad to ghost.
+ * @templ: the #GstPadTemplate to use on the ghostpad.
+ *
+ * Create a new ghostpad with @target as the target. The direction will be taken
+ * from the target pad. The template used on the ghostpad will be @template.
+ *
+ * Will ref the target.
+ *
+ * Returns: a new #GstPad, or NULL in case of an error.
+ *
+ * Since: 0.10.10
+ */
+
+GstPad *
+gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
+ GstPadTemplate * templ)
+{
+ GstPad *ret;
+
+ g_return_val_if_fail (GST_IS_PAD (target), NULL);
+ g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
+ g_return_val_if_fail (templ != NULL, NULL);
+ g_return_val_if_fail (templ->direction == GST_PAD_DIRECTION (target), NULL);
+
+ if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
+ if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
+ goto set_target_failed;
+
+ return ret;
+
+ /* ERRORS */
+set_target_failed:
+ {
+ gst_object_unref (ret);
+ return NULL;
+ }
+}
+
+/**
+ * gst_ghost_pad_new_no_target_from_template:
+ * @name: the name of the new pad, or NULL to assign a default name.
+ * @templ: the #GstPadTemplate to create the ghostpad from.
+ *
+ * Create a new ghostpad based on @templ, without setting a target. The
+ * direction will be taken from @templ.
+ *
+ * Returns: a new #GstPad, or NULL in case of an error.
+ *
+ * Since: 0.10.10
+ */
+
+GstPad *
+gst_ghost_pad_new_no_target_from_template (const gchar * name,
+ GstPadTemplate * templ)
+{
+ GstPad *ret;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+
+ ret =
+ gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
+
return ret;
}
GST_END_TEST;
+GST_START_TEST (test_ghost_pads_new_from_template)
+{
+ GstPad *sinkpad, *ghostpad;
+ GstPadTemplate *padtempl, *ghosttempl;
+ GstCaps *padcaps, *ghostcaps, *newcaps;
+
+ padcaps = gst_caps_from_string ("some/caps");
+ fail_unless (padcaps != NULL);
+ ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
+ fail_unless (ghostcaps != NULL);
+
+ padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
+ GST_PAD_ALWAYS, padcaps);
+ fail_unless (padtempl != NULL);
+ ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
+ GST_PAD_ALWAYS, ghostcaps);
+
+ sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
+ fail_unless (sinkpad != NULL);
+
+ ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
+ fail_unless (ghostpad != NULL);
+
+ /* check template is properly set */
+ fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
+
+ /* check ghostpad caps are from the sinkpad */
+ newcaps = gst_pad_get_caps (ghostpad);
+ fail_unless (newcaps != NULL);
+ fail_unless (gst_caps_is_equal (newcaps, padcaps));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_ghost_pads_new_no_target_from_template)
+{
+ GstPad *sinkpad, *ghostpad;
+ GstPadTemplate *padtempl, *ghosttempl;
+ GstCaps *padcaps, *ghostcaps, *newcaps;
+
+ padcaps = gst_caps_from_string ("some/caps");
+ fail_unless (padcaps != NULL);
+ ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
+ fail_unless (ghostcaps != NULL);
+
+ padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
+ GST_PAD_ALWAYS, padcaps);
+ fail_unless (padtempl != NULL);
+ ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
+ GST_PAD_ALWAYS, ghostcaps);
+
+ sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
+ fail_unless (sinkpad != NULL);
+
+ ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
+ fail_unless (ghostpad != NULL);
+
+ /* check template is properly set */
+ fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
+
+ /* check ghostpad caps are from the ghostpad template */
+ newcaps = gst_pad_get_caps (ghostpad);
+ fail_unless (newcaps != NULL);
+ fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
+ gst_caps_unref (newcaps);
+
+ fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
+
+ /* check ghostpad caps are now from the target pad */
+ newcaps = gst_pad_get_caps (ghostpad);
+ fail_unless (newcaps != NULL);
+ fail_unless (gst_caps_is_equal (newcaps, padcaps));
+ gst_caps_unref (newcaps);
+
+}
+
+GST_END_TEST;
+
Suite *
gst_ghost_pad_suite (void)
{
/* tcase_add_test (tc_chain, test_ghost_pad_notarget); */
tcase_add_test (tc_chain, test_ghost_pads_block);
tcase_add_test (tc_chain, test_ghost_pads_probes);
+ tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
+ tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
return s;
}