pad->getcapsfunc = NULL;
pad->eventfunc = gst_pad_event_default;
- pad->convertfunc = gst_pad_convert_default;
+ pad->querytypefunc = gst_pad_get_query_types_default;
pad->queryfunc = gst_pad_query_default;
pad->intlinkfunc = gst_pad_get_internal_links_default;
- pad->query2func = gst_pad_query2_default;
-
- pad->eventmaskfunc = gst_pad_get_event_masks_default;
- pad->formatsfunc = gst_pad_get_formats_default;
- pad->querytypefunc = gst_pad_get_query_types_default;
-
GST_FLAG_UNSET (pad, GST_PAD_ACTIVE);
pad->preroll_lock = g_mutex_new ();
}
/**
- * gst_pad_set_event_mask_function:
- * @pad: a real #GstPad of either direction.
- * @mask_func: the #GstPadEventMaskFunction to set.
- *
- * Sets the given event mask function for the pad.
- */
-void
-gst_pad_set_event_mask_function (GstPad * pad,
- GstPadEventMaskFunction mask_func)
-{
- g_return_if_fail (GST_IS_REAL_PAD (pad));
-
- GST_RPAD_EVENTMASKFUNC (pad) = mask_func;
-
- GST_CAT_DEBUG (GST_CAT_PADS, "eventmaskfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (mask_func));
-}
-
-/**
- * gst_pad_get_event_masks:
- * @pad: a #GstPad.
- *
- * Gets the array of eventmasks from the given pad.
- *
- * Returns: a zero-terminated array of #GstEventMask, or NULL if the pad does
- * not have an event mask function.
- */
-const GstEventMask *
-gst_pad_get_event_masks (GstPad * pad)
-{
- GstRealPad *rpad;
-
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-
- rpad = GST_PAD_REALIZE (pad);
-
- g_return_val_if_fail (rpad, NULL);
-
- if (GST_RPAD_EVENTMASKFUNC (rpad))
- return GST_RPAD_EVENTMASKFUNC (rpad) (GST_PAD (pad));
-
- return NULL;
-}
-
-static gboolean
-gst_pad_get_event_masks_dispatcher (GstPad * pad, const GstEventMask ** data)
-{
- *data = gst_pad_get_event_masks (pad);
-
- return TRUE;
-}
-
-/**
- * gst_pad_get_event_masks_default:
- * @pad: a #GstPad.
- *
- * Invokes the default event masks dispatcher on the pad.
- *
- * Returns: a zero-terminated array of #GstEventMask, or NULL if none of the
- * internally-linked pads have an event mask function.
- */
-const GstEventMask *
-gst_pad_get_event_masks_default (GstPad * pad)
-{
- GstEventMask *result = NULL;
-
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-
- gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
- gst_pad_get_event_masks_dispatcher, &result);
-
- return result;
-}
-
-/**
- * gst_pad_set_convert_function:
- * @pad: a real #GstPad of either direction.
- * @convert: the #GstPadConvertFunction to set.
- *
- * Sets the given convert function for the pad.
- */
-void
-gst_pad_set_convert_function (GstPad * pad, GstPadConvertFunction convert)
-{
- g_return_if_fail (GST_IS_REAL_PAD (pad));
-
- GST_RPAD_CONVERTFUNC (pad) = convert;
-
- GST_CAT_DEBUG (GST_CAT_PADS, "convertfunc for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (convert));
-}
-
-/**
* gst_pad_set_query_function:
* @pad: a real #GstPad of either direction.
* @query: the #GstPadQueryFunction to set.
}
/**
- * gst_pad_set_query2_function:
- * @pad: a real #GstPad of either direction.
- * @query: the #GstPadQueryFunction to set.
- *
- * Set the given query function for the pad.
- */
-void
-gst_pad_set_query2_function (GstPad * pad, GstPadQuery2Function query)
-{
- g_return_if_fail (GST_IS_REAL_PAD (pad));
-
- GST_RPAD_QUERY2FUNC (pad) = query;
-
- GST_CAT_DEBUG (GST_CAT_PADS, "query2func for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (query));
-}
-
-/**
* gst_pad_set_query_type_function:
* @pad: a real #GstPad of either direction.
* @type_func: the #GstPadQueryTypeFunction to set.
gst_pad_get_query_types (GstPad * pad)
{
GstRealPad *rpad;
+ GstPadQueryTypeFunction func;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (rpad, NULL);
- if (GST_RPAD_QUERYTYPEFUNC (rpad))
- return GST_RPAD_QUERYTYPEFUNC (rpad) (GST_PAD (pad));
+ if (G_UNLIKELY ((func = GST_RPAD_QUERYTYPEFUNC (rpad)) == NULL))
+ goto no_func;
+
+ return func (GST_PAD (rpad));
- return NULL;
+no_func:
+ {
+ return NULL;
+ }
}
static gboolean
}
/**
- * gst_pad_set_formats_function:
- * @pad: a real #GstPad of either direction.
- * @formats: the #GstPadFormatsFunction to set.
- *
- * Sets the given formats function for the pad.
- */
-void
-gst_pad_set_formats_function (GstPad * pad, GstPadFormatsFunction formats)
-{
- g_return_if_fail (GST_IS_REAL_PAD (pad));
-
- GST_RPAD_FORMATSFUNC (pad) = formats;
- GST_CAT_DEBUG (GST_CAT_PADS, "formats function for %s:%s set to %s",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (formats));
-}
-
-/**
* gst_pad_set_link_function:
* @pad: a real #GstPad.
* @link: the #GstPadLinkFunction to set.
*
* Returns: the #GstPadTemplate from which this pad was instantiated, or %NULL
* if this pad has no template.
+ *
+ * FIXME: currently returns an unrefcounted padtemplate.
*/
GstPadTemplate *
gst_pad_get_pad_template (GstPad * pad)
* returned, as opposed to #gst_pad_get_parent().
* Unref the object after use.
*
- * Returns: the parent #GstElement.
+ * Returns: the parent #GstElement. unref after usage.
*
* MT safe.
*/
GST_FLAG_UNSET (realpad, GST_PAD_IN_GETCAPS);
if (result == NULL) {
- g_critical ("pad %s:%s returned NULL caps from getcaps function\n",
+ g_critical ("pad %s:%s returned NULL caps from getcaps function",
GST_DEBUG_PAD_NAME (realpad));
} else {
#ifndef G_DISABLE_ASSERT
}
}
-static void
-gst_real_pad_dispose (GObject * object)
+/**
+ * gst_pad_get_internal_links_default:
+ * @pad: the #GstPad to get the internal links of.
+ *
+ * Gets a list of pads to which the given pad is linked to
+ * inside of the parent element.
+ * This is the default handler, and thus returns a list of all of the
+ * pads inside the parent element with opposite direction.
+ * 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)
{
- GstPad *pad;
+ GList *res = NULL;
+ GstElement *parent;
+ GList *parent_pads;
+ GstPadDirection direction;
GstRealPad *rpad;
- pad = GST_PAD (object);
- rpad = GST_REAL_PAD (object);
-
- /* No linked pad can ever be disposed.
- * It has to have a parent to be linked
- * and a parent would hold a reference */
- /* FIXME: what about if g_object_dispose is explicitly called on the pad? Is
- that legal? otherwise we could assert GST_OBJECT_PARENT (pad) == NULL as
- well... */
- g_assert (GST_PAD_PEER (pad) == NULL);
-
- GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s",
- GST_DEBUG_PAD_NAME (pad));
-
- /* we destroy the ghostpads, because they are nothing without the real pad */
- if (rpad->ghostpads) {
- GList *orig, *ghostpads;
+ g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- orig = ghostpads = g_list_copy (rpad->ghostpads);
+ rpad = GST_PAD_REALIZE (pad);
+ direction = rpad->direction;
- while (ghostpads) {
- GstPad *ghostpad = GST_PAD (ghostpads->data);
+ parent = GST_PAD_PARENT (rpad);
+ parent_pads = parent->pads;
- if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))) {
- GstElement *parent = GST_ELEMENT (GST_OBJECT_PARENT (ghostpad));
+ while (parent_pads) {
+ GstRealPad *parent_pad = GST_PAD_REALIZE (parent_pads->data);
- GST_CAT_DEBUG (GST_CAT_REFCOUNTING,
- "removing ghost pad from element '%s'", GST_OBJECT_NAME (parent));
- gst_element_remove_pad (parent, ghostpad);
- } else {
- /* handle the case where we have some floating ghost pad that was never
- added to an element */
- g_object_set (ghostpad, "real-pad", NULL, NULL);
- }
- ghostpads = g_list_next (ghostpads);
+ if (parent_pad->direction != direction) {
+ res = g_list_prepend (res, parent_pad);
}
- g_list_free (orig);
- /* as the ghost pads are removed, they remove themselves from ->ghostpads.
- So it should be empty now. Let's assert that. */
- g_assert (rpad->ghostpads == NULL);
- }
- /* clear the caps */
- gst_caps_replace (&GST_RPAD_CAPS (pad), NULL);
-
- if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) {
- GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'",
- GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
-
- gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
+ parent_pads = g_list_next (parent_pads);
}
- G_OBJECT_CLASS (real_pad_parent_class)->dispose (object);
+ return res;
}
-static void
-gst_real_pad_finalize (GObject * object)
+/**
+ * gst_pad_get_internal_links:
+ * @pad: the #GstPad to get the internal links of.
+ *
+ * Gets a list of pads to which the given pad is linked to
+ * inside of the parent element.
+ * 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)
{
+ GList *res = NULL;
GstRealPad *rpad;
- rpad = GST_REAL_PAD (object);
+ g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- if (rpad->stream_rec_lock) {
- g_static_rec_mutex_free (rpad->stream_rec_lock);
- rpad->stream_rec_lock = NULL;
- }
- if (rpad->preroll_lock) {
- g_mutex_free (rpad->preroll_lock);
- g_cond_free (rpad->preroll_cond);
- rpad->preroll_lock = NULL;
- rpad->preroll_cond = NULL;
- }
- if (rpad->block_cond) {
- g_cond_free (rpad->block_cond);
- rpad->block_cond = NULL;
- }
+ rpad = GST_PAD_REALIZE (pad);
- G_OBJECT_CLASS (real_pad_parent_class)->finalize (object);
+ if (GST_RPAD_INTLINKFUNC (rpad))
+ res = GST_RPAD_INTLINKFUNC (rpad) (GST_PAD_CAST (rpad));
+
+ return res;
}
-#ifndef GST_DISABLE_LOADSAVE
-/* FIXME: why isn't this on a GstElement ? */
-/**
- * gst_pad_load_and_link:
- * @self: an #xmlNodePtr to read the description from.
- * @parent: the #GstObject element that owns the pad.
- *
- * Reads the pad definition from the XML node and links the given pad
- * in the element to a pad of an element up in the hierarchy.
- */
-void
-gst_pad_load_and_link (xmlNodePtr self, GstObject * parent)
+static gboolean
+gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
{
- xmlNodePtr field = self->xmlChildrenNode;
- GstPad *pad = NULL, *targetpad;
- gchar *peer = NULL;
- gchar **split;
- GstElement *target;
- GstObject *grandparent;
- gchar *name = NULL;
-
- while (field) {
- if (!strcmp ((char *) field->name, "name")) {
- name = (gchar *) xmlNodeGetContent (field);
- pad = gst_element_get_pad (GST_ELEMENT (parent), name);
- g_free (name);
- } else if (!strcmp ((char *) field->name, "peer")) {
- peer = (gchar *) xmlNodeGetContent (field);
- }
- field = field->next;
- }
- g_return_if_fail (pad != NULL);
+ GList *orig, *pads;
+ gboolean result;
- if (peer == NULL)
- return;
+ GST_INFO_OBJECT (pad, "Sending event %p to all internally linked pads",
+ event);
- split = g_strsplit (peer, ".", 2);
+ result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
- if (split[0] == NULL || split[1] == NULL) {
- GST_CAT_DEBUG (GST_CAT_XML,
- "Could not parse peer '%s' for pad %s:%s, leaving unlinked",
- peer, GST_DEBUG_PAD_NAME (pad));
+ orig = pads = gst_pad_get_internal_links (pad);
- g_free (peer);
- return;
- }
- g_free (peer);
-
- g_return_if_fail (split[0] != NULL);
- g_return_if_fail (split[1] != NULL);
-
- grandparent = gst_object_get_parent (parent);
-
- if (grandparent && GST_IS_BIN (grandparent)) {
- target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
- } else
- goto cleanup;
-
- if (target == NULL)
- goto cleanup;
+ while (pads) {
+ GstPad *eventpad = GST_PAD (pads->data);
- targetpad = gst_element_get_pad (target, split[1]);
+ pads = g_list_next (pads);
- if (targetpad == NULL)
- goto cleanup;
+ /* for all of the internally-linked pads that are actually linked */
+ if (GST_PAD_IS_LINKED (eventpad)) {
+ if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
+ /* for each pad we send to, we should ref the event; it's up
+ * to downstream to unref again when handled. */
+ GST_LOG_OBJECT (pad, "Reffing and sending event %p to %s:%s", event,
+ GST_DEBUG_PAD_NAME (eventpad));
+ gst_event_ref (event);
+ gst_pad_push_event (eventpad, event);
+ } else {
+ /* we only send the event on one pad, multi-sinkpad elements
+ * should implement a handler */
+ GST_LOG_OBJECT (pad, "sending event %p to one sink pad %s:%s", event,
+ GST_DEBUG_PAD_NAME (eventpad));
+ result = gst_pad_push_event (eventpad, event);
+ goto done;
+ }
+ }
+ }
+ /* we handled the incoming event so we unref once */
+ GST_LOG_OBJECT (pad, "handled event %p, unreffing", event);
+ gst_event_unref (event);
- gst_pad_link (pad, targetpad);
+done:
+ g_list_free (orig);
-cleanup:
- g_strfreev (split);
+ return result;
}
/**
- * gst_pad_save_thyself:
- * @pad: a #GstPad to save.
- * @parent: the parent #xmlNodePtr to save the description in.
+ * gst_pad_event_default:
+ * @pad: a #GstPad to call the default event handler on.
+ * @event: the #GstEvent to handle.
*
- * Saves the pad into an xml representation.
+ * Invokes the default event handler for the given pad. End-of-stream and
+ * discontinuity events are handled specially, and then the event is sent to all
+ * pads internally linked to @pad. Note that if there are many possible sink
+ * pads that are internally linked to @pad, only one will be sent an event.
+ * Multi-sinkpad elements should implement custom event handlers.
*
- * Returns: the #xmlNodePtr representation of the pad.
+ * Returns: TRUE if the event was sent succesfully.
*/
-static xmlNodePtr
-gst_pad_save_thyself (GstObject * object, xmlNodePtr parent)
+gboolean
+gst_pad_event_default (GstPad * pad, GstEvent * event)
{
- GstRealPad *realpad;
- GstPad *peer;
-
- g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
-
- realpad = GST_REAL_PAD (object);
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
- xmlNewChild (parent, NULL, (xmlChar *) "name",
- (xmlChar *) GST_PAD_NAME (realpad));
- if (GST_RPAD_PEER (realpad) != NULL) {
- gchar *content;
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ {
+ GstRealPad *rpad = GST_PAD_REALIZE (pad);
- peer = GST_PAD (GST_RPAD_PEER (realpad));
- /* first check to see if the peer's parent's parent is the same */
- /* we just save it off */
- content = g_strdup_printf ("%s.%s",
- GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
- xmlNewChild (parent, NULL, (xmlChar *) "peer", (xmlChar *) content);
- g_free (content);
- } else
- xmlNewChild (parent, NULL, (xmlChar *) "peer", NULL);
+ if (GST_RPAD_TASK (rpad)) {
+ GST_DEBUG_OBJECT (rpad, "pausing task because of eos");
+ gst_task_pause (GST_RPAD_TASK (rpad));
+ }
+ }
+ default:
+ break;
+ }
- return parent;
+ return gst_pad_event_default_dispatch (pad, event);
}
/**
- * gst_ghost_pad_save_thyself:
- * @pad: a ghost #GstPad to save.
- * @parent: the parent #xmlNodePtr to save the description in.
+ * gst_pad_dispatcher:
+ * @pad: a #GstPad to dispatch.
+ * @dispatch: the #GstDispatcherFunction to call.
+ * @data: gpointer user data passed to the dispatcher function.
*
- * Saves the ghost pad into an xml representation.
+ * Invokes the given dispatcher function on all pads that are
+ * internally linked to the given pad.
+ * The GstPadDispatcherFunction should return TRUE when no further pads
+ * need to be processed.
*
- * Returns: the #xmlNodePtr representation of the pad.
+ * Returns: TRUE if one of the dispatcher functions returned TRUE.
*/
-xmlNodePtr
-gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent)
+gboolean
+gst_pad_dispatcher (GstPad * pad, GstPadDispatcherFunction dispatch,
+ gpointer data)
{
- xmlNodePtr self;
-
- g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
-
- self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
- xmlNewChild (self, NULL, (xmlChar *) "name", (xmlChar *) GST_PAD_NAME (pad));
- xmlNewChild (self, NULL, (xmlChar *) "parent",
- (xmlChar *) GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
-
- /* FIXME FIXME FIXME! */
-
- return self;
-}
-#endif /* GST_DISABLE_LOADSAVE */
+ gboolean res = FALSE;
+ GList *int_pads, *orig;
-/*
- * should be called with pad lock held
- *
- * MT safe.
- */
-static void
-handle_pad_block (GstRealPad * pad)
-{
- GstPadBlockCallback callback;
- gpointer user_data;
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (dispatch != NULL, FALSE);
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "signal block taken on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+ orig = int_pads = gst_pad_get_internal_links (pad);
- /* need to grab extra ref for the callbacks */
- gst_object_ref (GST_OBJECT (pad));
+ while (int_pads) {
+ GstRealPad *int_rpad = GST_PAD_REALIZE (int_pads->data);
+ GstRealPad *int_peer = GST_RPAD_PEER (int_rpad);
- callback = pad->block_callback;
- if (callback) {
- user_data = pad->block_data;
- GST_UNLOCK (pad);
- callback (GST_PAD_CAST (pad), TRUE, user_data);
- GST_LOCK (pad);
- } else {
- GST_PAD_BLOCK_SIGNAL (pad);
+ if (int_peer) {
+ res = dispatch (GST_PAD (int_peer), data);
+ if (res)
+ break;
+ }
+ int_pads = g_list_next (int_pads);
}
- while (GST_RPAD_IS_BLOCKED (pad))
- GST_PAD_BLOCK_WAIT (pad);
-
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked");
-
- callback = pad->block_callback;
- if (callback) {
- user_data = pad->block_data;
- GST_UNLOCK (pad);
- callback (GST_PAD_CAST (pad), FALSE, user_data);
- GST_LOCK (pad);
- } else {
- GST_PAD_BLOCK_SIGNAL (pad);
- }
+ g_list_free (orig);
- gst_object_unref (GST_OBJECT (pad));
+ return res;
}
/**
- * gst_pad_push:
- * @pad: a source #GstPad.
- * @buffer: the #GstBuffer to push.
+ * gst_pad_query:
+ * @pad: a #GstPad to invoke the default query on.
+ * @query: the #GstQuery to perform.
*
- * Pushes a buffer to the peer of @pad. @pad must be linked.
+ * Dispatches a query to a pad. The query should have been allocated by the
+ * caller via one of the type-specific allocation functions in gstquery.h. The
+ * element is responsible for filling the query with an appropriate response,
+ * which should then be parsed with a type-specific query parsing function.
*
- * Returns: a #GstFlowReturn from the peer pad.
+ * Again, the caller is responsible for both the allocation and deallocation of
+ * the query structure.
*
- * MT safe.
+ * Returns: TRUE if the query could be performed.
*/
-GstFlowReturn
-gst_pad_push (GstPad * pad, GstBuffer * buffer)
+gboolean
+gst_pad_query (GstPad * pad, GstQuery * query)
{
- GstRealPad *peer;
- GstFlowReturn ret;
- GstPadChainFunction chainfunc;
- GstCaps *caps;
- gboolean caps_changed;
-
- g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
- g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC,
- GST_FLOW_ERROR);
- g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
- g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
+ GstRealPad *rpad;
+ GstPadQueryFunction func;
+ g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+ g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
- GST_LOCK (pad);
- while (G_UNLIKELY (GST_RPAD_IS_BLOCKED (pad)))
- handle_pad_block (GST_REAL_PAD_CAST (pad));
+ rpad = GST_PAD_REALIZE (pad);
- if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
- goto not_linked;
+ g_return_val_if_fail (rpad, FALSE);
- if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
- goto not_active;
+ GST_DEBUG ("sending query %p to pad %s:%s", query, GST_DEBUG_PAD_NAME (pad));
- if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer)))
- goto flushing;
+ if ((func = GST_RPAD_QUERYFUNC (rpad)) == NULL)
+ goto no_func;
- gst_object_ref (GST_OBJECT_CAST (peer));
- GST_UNLOCK (pad);
+ return func (GST_PAD_CAST (rpad), query);
- /* FIXME, move capnego this into a base class? */
- caps = GST_BUFFER_CAPS (buffer);
- caps_changed = caps && caps != GST_RPAD_CAPS (peer);
- GST_DEBUG ("caps changed %d %" GST_PTR_FORMAT "\n", caps_changed, caps);
- /* we got a new datatype on the peer pad, see if it can handle it */
- if (G_UNLIKELY (caps_changed)) {
- if (G_UNLIKELY (!gst_pad_configure_sink (GST_PAD_CAST (peer), caps)))
- goto not_negotiated;
+no_func:
+ {
+ GST_DEBUG ("pad had no query function");
+ return FALSE;
}
+}
- /* NOTE: we read the peer chainfunc unlocked.
- * we cannot hold the lock for the peer so we might send
- * the data to the wrong function. This is not really a
- * problem since functions are assigned at creation time
- * and don't change that often... */
- if (G_UNLIKELY ((chainfunc = peer->chainfunc) == NULL))
- goto no_function;
-
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "calling chainfunction &%s of peer pad %s:%s",
- GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_DEBUG_PAD_NAME (peer));
-
- ret = chainfunc (GST_PAD_CAST (peer), buffer);
-
- gst_object_unref (GST_OBJECT_CAST (peer));
-
- return ret;
-
- /* ERROR recovery here */
-not_linked:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing, but it was not linked");
- GST_UNLOCK (pad);
- return GST_FLOW_NOT_CONNECTED;
- }
-not_active:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing, but it was inactive");
- GST_UNLOCK (pad);
- return GST_FLOW_WRONG_STATE;
- }
-flushing:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing, but pad was flushing");
- GST_UNLOCK (pad);
- return GST_FLOW_UNEXPECTED;
- }
-not_negotiated:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing buffer but peer did not accept");
- return GST_FLOW_NOT_NEGOTIATED;
- }
-no_function:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pushing, but not chainhandler");
- GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
- ("push on pad %s:%s but the peer pad %s:%s has no chainfunction",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
- gst_object_unref (GST_OBJECT (peer));
- return GST_FLOW_ERROR;
- }
-}
-
-/**
- * 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)
+gst_pad_query_default (GstPad * pad, GstQuery * query)
{
- GstRealPad *peer;
- gboolean ret;
- GstPadCheckGetRangeFunction checkgetrangefunc;
-
- g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
-
- GST_LOCK (pad);
- if (GST_RPAD_DIRECTION (pad) != GST_PAD_SINK)
- goto wrong_direction;
-
- 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_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
- ret = GST_RPAD_GETRANGEFUNC (peer) != NULL;
- } else {
- 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 */
-wrong_direction:
- {
- GST_UNLOCK (pad);
- return FALSE;
- }
-not_connected:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "checking pull range, but it was not linked");
- GST_UNLOCK (pad);
- return FALSE;
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:
+ case GST_QUERY_SEEKING:
+ case GST_QUERY_FORMATS:
+ case GST_QUERY_LATENCY:
+ case GST_QUERY_JITTER:
+ case GST_QUERY_RATE:
+ case GST_QUERY_CONVERT:
+ default:
+ return gst_pad_dispatcher
+ (pad, (GstPadDispatcherFunction) gst_pad_query, query);
}
}
-/**
- * gst_pad_pull_range:
- * @pad: a sink #GstPad.
- * @buffer: a pointer to hold the #GstBuffer.
- * @offset: The start offset of the buffer
- * @length: The length of the buffer
- *
- * Pulls a buffer from the peer pad. @pad must be linked.
- *
- * Returns: a #GstFlowReturn from the peer pad.
- *
- * MT safe.
- */
-GstFlowReturn
-gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
- GstBuffer ** buffer)
+static void
+gst_real_pad_dispose (GObject * object)
{
- GstRealPad *peer;
- GstFlowReturn ret;
- GstPadGetRangeFunction getrangefunc;
-
- 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);
- g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
-
- GST_LOCK (pad);
-
- while (G_UNLIKELY (GST_RPAD_IS_BLOCKED (pad)))
- handle_pad_block (GST_REAL_PAD_CAST (pad));
-
- if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
- goto not_connected;
-
- if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
- goto not_active;
+ GstPad *pad;
+ GstRealPad *rpad;
- if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer)))
- goto flushing;
+ pad = GST_PAD (object);
+ rpad = GST_REAL_PAD (object);
- gst_object_ref (GST_OBJECT_CAST (peer));
- GST_UNLOCK (pad);
+ /* No linked pad can ever be disposed.
+ * It has to have a parent to be linked
+ * and a parent would hold a reference */
+ /* FIXME: what about if g_object_dispose is explicitly called on the pad? Is
+ that legal? otherwise we could assert GST_OBJECT_PARENT (pad) == NULL as
+ well... */
+ g_assert (GST_PAD_PEER (pad) == NULL);
- /* see note in above function */
- if (G_UNLIKELY ((getrangefunc = peer->getrangefunc) == NULL))
- goto no_function;
+ GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s",
+ GST_DEBUG_PAD_NAME (pad));
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "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);
+ /* we destroy the ghostpads, because they are nothing without the real pad */
+ if (rpad->ghostpads) {
+ GList *orig, *ghostpads;
- ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer);
+ orig = ghostpads = g_list_copy (rpad->ghostpads);
- gst_object_unref (GST_OBJECT_CAST (peer));
+ while (ghostpads) {
+ GstPad *ghostpad = GST_PAD (ghostpads->data);
- return ret;
+ if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))) {
+ GstElement *parent = GST_ELEMENT (GST_OBJECT_PARENT (ghostpad));
- /* ERROR recovery here */
-not_connected:
- {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "pulling range, but it was not linked");
- 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),
- ("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
- gst_object_unref (GST_OBJECT (peer));
- return GST_FLOW_ERROR;
+ GST_CAT_DEBUG (GST_CAT_REFCOUNTING,
+ "removing ghost pad from element '%s'", GST_OBJECT_NAME (parent));
+ gst_element_remove_pad (parent, ghostpad);
+ } else {
+ /* handle the case where we have some floating ghost pad that was never
+ added to an element */
+ g_object_set (ghostpad, "real-pad", NULL, NULL);
+ }
+ ghostpads = g_list_next (ghostpads);
+ }
+ g_list_free (orig);
+ /* as the ghost pads are removed, they remove themselves from ->ghostpads.
+ So it should be empty now. Let's assert that. */
+ g_assert (rpad->ghostpads == NULL);
}
-}
-
-/************************************************************************
- *
- * templates
- *
- */
-static void gst_pad_template_class_init (GstPadTemplateClass * klass);
-static void gst_pad_template_init (GstPadTemplate * templ);
-static void gst_pad_template_dispose (GObject * object);
-GType
-gst_pad_template_get_type (void)
-{
- static GType padtemplate_type = 0;
+ /* clear the caps */
+ gst_caps_replace (&GST_RPAD_CAPS (pad), NULL);
- if (!padtemplate_type) {
- static const GTypeInfo padtemplate_info = {
- sizeof (GstPadTemplateClass), NULL, NULL,
- (GClassInitFunc) gst_pad_template_class_init, NULL, NULL,
- sizeof (GstPadTemplate),
- 0,
- (GInstanceInitFunc) gst_pad_template_init, NULL
- };
+ if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) {
+ GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'",
+ GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
- padtemplate_type =
- g_type_register_static (GST_TYPE_OBJECT, "GstPadTemplate",
- &padtemplate_info, 0);
+ gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
}
- return padtemplate_type;
-}
-static void
-gst_pad_template_class_init (GstPadTemplateClass * klass)
-{
- GObjectClass *gobject_class;
- GstObjectClass *gstobject_class;
-
- gobject_class = (GObjectClass *) klass;
- gstobject_class = (GstObjectClass *) klass;
-
- padtemplate_parent_class = g_type_class_ref (GST_TYPE_OBJECT);
-
- gst_pad_template_signals[TEMPL_PAD_CREATED] =
- g_signal_new ("pad-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GstPadTemplateClass, pad_created),
- NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
-
- gobject_class->dispose = gst_pad_template_dispose;
-
- gstobject_class->path_string_separator = "*";
+ G_OBJECT_CLASS (real_pad_parent_class)->dispose (object);
}
static void
-gst_pad_template_init (GstPadTemplate * templ)
+gst_real_pad_finalize (GObject * object)
{
-}
+ GstRealPad *rpad;
-static void
-gst_pad_template_dispose (GObject * object)
-{
- GstPadTemplate *templ = GST_PAD_TEMPLATE (object);
+ rpad = GST_REAL_PAD (object);
- g_free (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
- if (GST_PAD_TEMPLATE_CAPS (templ)) {
- gst_caps_unref (GST_PAD_TEMPLATE_CAPS (templ));
+ if (rpad->stream_rec_lock) {
+ g_static_rec_mutex_free (rpad->stream_rec_lock);
+ rpad->stream_rec_lock = NULL;
}
-
- G_OBJECT_CLASS (padtemplate_parent_class)->dispose (object);
-}
-
-/* ALWAYS padtemplates cannot have conversion specifications, it doesn't make
- * sense.
- * SOMETIMES padtemplates can do whatever they want, they are provided by the
- * element.
- * REQUEST padtemplates can be reverse-parsed (the user asks for 'sink1', the
- * 'sink%d' template is automatically selected), so we need to restrict their
- * naming.
- */
-static gboolean
-name_is_valid (const gchar * name, GstPadPresence presence)
-{
- const gchar *str;
-
- if (presence == GST_PAD_ALWAYS) {
- if (strchr (name, '%')) {
- g_warning ("invalid name template %s: conversion specifications are not"
- " allowed for GST_PAD_ALWAYS padtemplates", name);
- return FALSE;
- }
- } else if (presence == GST_PAD_REQUEST) {
- if ((str = strchr (name, '%')) && strchr (str + 1, '%')) {
- g_warning ("invalid name template %s: only one conversion specification"
- " allowed in GST_PAD_REQUEST padtemplate", name);
- return FALSE;
- }
- if (str && (*(str + 1) != 's' && *(str + 1) != 'd')) {
- g_warning ("invalid name template %s: conversion specification must be of"
- " type '%%d' or '%%s' for GST_PAD_REQUEST padtemplate", name);
- return FALSE;
- }
- if (str && (*(str + 2) != '\0')) {
- g_warning ("invalid name template %s: conversion specification must"
- " appear at the end of the GST_PAD_REQUEST padtemplate name", name);
- return FALSE;
- }
+ if (rpad->preroll_lock) {
+ g_mutex_free (rpad->preroll_lock);
+ g_cond_free (rpad->preroll_cond);
+ rpad->preroll_lock = NULL;
+ rpad->preroll_cond = NULL;
+ }
+ if (rpad->block_cond) {
+ g_cond_free (rpad->block_cond);
+ rpad->block_cond = NULL;
}
- return TRUE;
+ G_OBJECT_CLASS (real_pad_parent_class)->finalize (object);
}
+
+#ifndef GST_DISABLE_LOADSAVE
+/* FIXME: why isn't this on a GstElement ? */
/**
- * gst_static_pad_template_get:
- * @pad_template: the static pad template
- *
- * Converts a #GstStaticPadTemplate into a #GstPadTemplate.
+ * gst_pad_load_and_link:
+ * @self: an #xmlNodePtr to read the description from.
+ * @parent: the #GstObject element that owns the pad.
*
- * Returns: a new #GstPadTemplate.
+ * Reads the pad definition from the XML node and links the given pad
+ * in the element to a pad of an element up in the hierarchy.
*/
-GstPadTemplate *
-gst_static_pad_template_get (GstStaticPadTemplate * pad_template)
+void
+gst_pad_load_and_link (xmlNodePtr self, GstObject * parent)
{
- GstPadTemplate *new;
-
- if (!name_is_valid (pad_template->name_template, pad_template->presence))
- return NULL;
-
- new = g_object_new (gst_pad_template_get_type (),
- "name", pad_template->name_template, NULL);
-
- GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (pad_template->name_template);
- GST_PAD_TEMPLATE_DIRECTION (new) = pad_template->direction;
- GST_PAD_TEMPLATE_PRESENCE (new) = pad_template->presence;
+ xmlNodePtr field = self->xmlChildrenNode;
+ GstPad *pad = NULL, *targetpad;
+ gchar *peer = NULL;
+ gchar **split;
+ GstElement *target;
+ GstObject *grandparent;
+ gchar *name = NULL;
- GST_PAD_TEMPLATE_CAPS (new) =
- gst_caps_copy (gst_static_caps_get (&pad_template->static_caps));
+ while (field) {
+ if (!strcmp ((char *) field->name, "name")) {
+ name = (gchar *) xmlNodeGetContent (field);
+ pad = gst_element_get_pad (GST_ELEMENT (parent), name);
+ g_free (name);
+ } else if (!strcmp ((char *) field->name, "peer")) {
+ peer = (gchar *) xmlNodeGetContent (field);
+ }
+ field = field->next;
+ }
+ g_return_if_fail (pad != NULL);
- return new;
-}
+ if (peer == NULL)
+ return;
-/**
- * gst_pad_template_new:
- * @name_template: the name template.
- * @direction: the #GstPadDirection of the template.
- * @presence: the #GstPadPresence of the pad.
- * @caps: a #GstCaps set for the template. The caps are taken ownership of.
- *
- * Creates a new pad template with a name according to the given template
- * and with the given arguments. This functions takes ownership of the provided
- * caps, so be sure to not use them afterwards.
- *
- * Returns: a new #GstPadTemplate.
- */
-GstPadTemplate *
-gst_pad_template_new (const gchar * name_template,
- GstPadDirection direction, GstPadPresence presence, GstCaps * caps)
-{
- GstPadTemplate *new;
+ split = g_strsplit (peer, ".", 2);
- g_return_val_if_fail (name_template != NULL, NULL);
- g_return_val_if_fail (caps != NULL, NULL);
- g_return_val_if_fail (direction == GST_PAD_SRC
- || direction == GST_PAD_SINK, NULL);
- g_return_val_if_fail (presence == GST_PAD_ALWAYS
- || presence == GST_PAD_SOMETIMES || presence == GST_PAD_REQUEST, NULL);
+ if (split[0] == NULL || split[1] == NULL) {
+ GST_CAT_DEBUG (GST_CAT_XML,
+ "Could not parse peer '%s' for pad %s:%s, leaving unlinked",
+ peer, GST_DEBUG_PAD_NAME (pad));
- if (!name_is_valid (name_template, presence))
- return NULL;
+ g_free (peer);
+ return;
+ }
+ g_free (peer);
- new = g_object_new (gst_pad_template_get_type (),
- "name", name_template, NULL);
+ g_return_if_fail (split[0] != NULL);
+ g_return_if_fail (split[1] != NULL);
- GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (name_template);
- GST_PAD_TEMPLATE_DIRECTION (new) = direction;
- GST_PAD_TEMPLATE_PRESENCE (new) = presence;
- GST_PAD_TEMPLATE_CAPS (new) = caps;
+ grandparent = gst_object_get_parent (parent);
- return new;
-}
+ if (grandparent && GST_IS_BIN (grandparent)) {
+ target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
+ } else
+ goto cleanup;
-/**
- * gst_static_pad_template_get_caps:
- * @templ: a #GstStaticPadTemplate to get capabilities of.
- *
- * Gets the capabilities of the static pad template.
- *
- * Returns: the #GstCaps of the static pad template. If you need to keep a
- * reference to the caps, take a ref (see gst_caps_ref ()).
- */
-GstCaps *
-gst_static_pad_template_get_caps (GstStaticPadTemplate * templ)
-{
- g_return_val_if_fail (templ, NULL);
+ if (target == NULL)
+ goto cleanup;
- return (GstCaps *) gst_static_caps_get (&templ->static_caps);
-}
+ targetpad = gst_element_get_pad (target, split[1]);
-/**
- * gst_pad_template_get_caps:
- * @templ: a #GstPadTemplate to get capabilities of.
- *
- * Gets the capabilities of the pad template.
- *
- * Returns: the #GstCaps of the pad template. If you need to keep a reference to
- * the caps, take a ref (see gst_caps_ref ()).
- */
-GstCaps *
-gst_pad_template_get_caps (GstPadTemplate * templ)
-{
- g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
+ if (targetpad == NULL)
+ goto cleanup;
- return GST_PAD_TEMPLATE_CAPS (templ);
-}
+ gst_pad_link (pad, targetpad);
-/**
- * gst_pad_set_element_private:
- * @pad: the #GstPad to set the private data of.
- * @priv: The private data to attach to the pad.
- *
- * Set the given private data gpointer on the pad.
- * This function can only be used by the element that owns the pad.
- */
-void
-gst_pad_set_element_private (GstPad * pad, gpointer priv)
-{
- pad->element_private = priv;
+cleanup:
+ g_strfreev (split);
}
/**
- * gst_pad_get_element_private:
- * @pad: the #GstPad to get the private data of.
+ * gst_pad_save_thyself:
+ * @pad: a #GstPad to save.
+ * @parent: the parent #xmlNodePtr to save the description in.
*
- * Gets the private data of a pad.
+ * Saves the pad into an xml representation.
*
- * Returns: a #gpointer to the private data.
+ * Returns: the #xmlNodePtr representation of the pad.
*/
-gpointer
-gst_pad_get_element_private (GstPad * pad)
-{
- return pad->element_private;
-}
-
-gboolean
-gst_pad_start_task (GstPad * pad)
-{
- g_warning ("implement gst_pad_start_task()");
- return FALSE;
-}
-
-gboolean
-gst_pad_pause_task (GstPad * pad)
-{
- g_warning ("implement gst_pad_pause_task()");
- return FALSE;
-}
-
-gboolean
-gst_pad_stop_task (GstPad * pad)
+static xmlNodePtr
+gst_pad_save_thyself (GstObject * object, xmlNodePtr parent)
{
- g_warning ("implement gst_pad_stop_task()");
- return FALSE;
-}
-
-
-/***** ghost pads *****/
-GType _gst_ghost_pad_type = 0;
+ GstRealPad *realpad;
+ GstPad *peer;
-static void gst_ghost_pad_class_init (GstGhostPadClass * klass);
-static void gst_ghost_pad_init (GstGhostPad * pad);
-static void gst_ghost_pad_dispose (GObject * object);
-static void gst_ghost_pad_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_ghost_pad_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
+ g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
-static GstPad *ghost_pad_parent_class = NULL;
+ realpad = GST_REAL_PAD (object);
-/* static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; */
-enum
-{
- GPAD_ARG_0,
- GPAD_ARG_REAL_PAD
- /* fill me */
-};
+ xmlNewChild (parent, NULL, (xmlChar *) "name",
+ (xmlChar *) GST_PAD_NAME (realpad));
+ if (GST_RPAD_PEER (realpad) != NULL) {
+ gchar *content;
-GType
-gst_ghost_pad_get_type (void)
-{
- if (!_gst_ghost_pad_type) {
- static const GTypeInfo pad_info = {
- sizeof (GstGhostPadClass), NULL, NULL,
- (GClassInitFunc) gst_ghost_pad_class_init, NULL, NULL,
- sizeof (GstGhostPad),
- 0,
- (GInstanceInitFunc) gst_ghost_pad_init,
- NULL
- };
+ peer = GST_PAD (GST_RPAD_PEER (realpad));
+ /* first check to see if the peer's parent's parent is the same */
+ /* we just save it off */
+ content = g_strdup_printf ("%s.%s",
+ GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
+ xmlNewChild (parent, NULL, (xmlChar *) "peer", (xmlChar *) content);
+ g_free (content);
+ } else
+ xmlNewChild (parent, NULL, (xmlChar *) "peer", NULL);
- _gst_ghost_pad_type = g_type_register_static (GST_TYPE_PAD, "GstGhostPad",
- &pad_info, 0);
- }
- return _gst_ghost_pad_type;
+ return parent;
}
-static void
-gst_ghost_pad_class_init (GstGhostPadClass * klass)
+/**
+ * gst_ghost_pad_save_thyself:
+ * @pad: a ghost #GstPad to save.
+ * @parent: the parent #xmlNodePtr to save the description in.
+ *
+ * Saves the ghost pad into an xml representation.
+ *
+ * Returns: the #xmlNodePtr representation of the pad.
+ */
+xmlNodePtr
+gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent)
{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
+ xmlNodePtr self;
- ghost_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
+ g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
- gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_set_property);
- gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_get_property);
+ self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
+ xmlNewChild (self, NULL, (xmlChar *) "name", (xmlChar *) GST_PAD_NAME (pad));
+ xmlNewChild (self, NULL, (xmlChar *) "parent",
+ (xmlChar *) GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
- g_object_class_install_property (gobject_class, GPAD_ARG_REAL_PAD,
- g_param_spec_object ("real-pad", "Real pad",
- "The real pad for the ghost pad", GST_TYPE_PAD, G_PARAM_READWRITE));
-}
+ /* FIXME FIXME FIXME! */
-static void
-gst_ghost_pad_init (GstGhostPad * pad)
-{
- /* zeroed by glib */
+ return self;
}
+#endif /* GST_DISABLE_LOADSAVE */
+/*
+ * should be called with pad lock held
+ *
+ * MT safe.
+ */
static void
-gst_ghost_pad_dispose (GObject * object)
+handle_pad_block (GstRealPad * pad)
{
- g_object_set (object, "real-pad", NULL, NULL);
+ GstPadBlockCallback callback;
+ gpointer user_data;
- G_OBJECT_CLASS (ghost_pad_parent_class)->dispose (object);
-}
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "signal block taken on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-static void
-gst_ghost_pad_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstPad *ghostpad = (GstPad *) object;
- GstPad *oldrealpad = (GstPad *) GST_GPAD_REALPAD (ghostpad);
- GstPad *realpad = NULL;
+ /* need to grab extra ref for the callbacks */
+ gst_object_ref (GST_OBJECT (pad));
- switch (prop_id) {
- case GPAD_ARG_REAL_PAD:
- realpad = g_value_get_object (value);
+ callback = pad->block_callback;
+ if (callback) {
+ user_data = pad->block_data;
+ GST_UNLOCK (pad);
+ callback (GST_PAD_CAST (pad), TRUE, user_data);
+ GST_LOCK (pad);
+ } else {
+ GST_PAD_BLOCK_SIGNAL (pad);
+ }
- if (oldrealpad) {
- if (realpad == oldrealpad)
- return;
- else
- gst_pad_remove_ghost_pad (oldrealpad, ghostpad);
- }
+ while (GST_RPAD_IS_BLOCKED (pad))
+ GST_PAD_BLOCK_WAIT (pad);
- if (realpad)
- gst_pad_add_ghost_pad (realpad, ghostpad);
- break;
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked");
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ callback = pad->block_callback;
+ if (callback) {
+ user_data = pad->block_data;
+ GST_UNLOCK (pad);
+ callback (GST_PAD_CAST (pad), FALSE, user_data);
+ GST_LOCK (pad);
+ } else {
+ GST_PAD_BLOCK_SIGNAL (pad);
}
+
+ gst_object_unref (GST_OBJECT (pad));
}
-static void
-gst_ghost_pad_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- switch (prop_id) {
- case GPAD_ARG_REAL_PAD:
- g_value_set_object (value, GST_GPAD_REALPAD (object));
- break;
+/**********************************************************************
+ * Data passing functions
+ */
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
/**
- * gst_ghost_pad_new:
- * @name: the name of the new ghost pad.
- * @pad: the #GstPad to create a ghost pad for.
+ * gst_pad_push:
+ * @pad: a source #GstPad.
+ * @buffer: the #GstBuffer to push.
*
- * Creates a new ghost pad associated with @pad, and named @name. If @name is
- * %NULL, a guaranteed unique name (across all ghost pads) will be assigned.
+ * Pushes a buffer to the peer of @pad. @pad must be linked.
*
- * Returns: a new ghost #GstPad, or %NULL in case of an error.
+ * Returns: a #GstFlowReturn from the peer pad.
+ *
+ * MT safe.
*/
-GstPad *
-gst_ghost_pad_new (const gchar * name, GstPad * pad)
+GstFlowReturn
+gst_pad_push (GstPad * pad, GstBuffer * buffer)
{
- GstPad *gpad;
+ GstRealPad *peer;
+ GstFlowReturn ret;
+ GstPadChainFunction chainfunc;
+ GstCaps *caps;
+ gboolean caps_changed;
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+ g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
+ g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC,
+ GST_FLOW_ERROR);
+ g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
- gpad = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "real-pad", pad, NULL);
- GST_CAT_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\" for pad %s:%s",
- GST_OBJECT_NAME (gpad), GST_DEBUG_PAD_NAME (pad));
+ GST_LOCK (pad);
+ while (G_UNLIKELY (GST_RPAD_IS_BLOCKED (pad)))
+ handle_pad_block (GST_REAL_PAD_CAST (pad));
+
+ if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
+ goto not_linked;
+
+ if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
+ goto not_active;
+
+ if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer)))
+ goto flushing;
- return gpad;
-}
+ gst_object_ref (GST_OBJECT_CAST (peer));
+ GST_UNLOCK (pad);
-/**
- * gst_pad_get_internal_links_default:
- * @pad: the #GstPad to get the internal links of.
- *
- * Gets a list of pads to which the given pad is linked to
- * inside of the parent element.
- * This is the default handler, and thus returns a list of all of the
- * pads inside the parent element with opposite direction.
- * 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)
-{
- GList *res = NULL;
- GstElement *parent;
- GList *parent_pads;
- GstPadDirection direction;
- GstRealPad *rpad;
+ /* FIXME, move capnego this into a base class? */
+ caps = GST_BUFFER_CAPS (buffer);
+ caps_changed = caps && caps != GST_RPAD_CAPS (peer);
+ GST_DEBUG ("caps changed %d %" GST_PTR_FORMAT, caps_changed, caps);
+ /* we got a new datatype on the peer pad, see if it can handle it */
+ if (G_UNLIKELY (caps_changed)) {
+ if (G_UNLIKELY (!gst_pad_configure_sink (GST_PAD_CAST (peer), caps)))
+ goto not_negotiated;
+ }
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+ /* NOTE: we read the peer chainfunc unlocked.
+ * we cannot hold the lock for the peer so we might send
+ * the data to the wrong function. This is not really a
+ * problem since functions are assigned at creation time
+ * and don't change that often... */
+ if (G_UNLIKELY ((chainfunc = peer->chainfunc) == NULL))
+ goto no_function;
- rpad = GST_PAD_REALIZE (pad);
- direction = rpad->direction;
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "calling chainfunction &%s of peer pad %s:%s",
+ GST_DEBUG_FUNCPTR_NAME (chainfunc), GST_DEBUG_PAD_NAME (peer));
- parent = GST_PAD_PARENT (rpad);
- parent_pads = parent->pads;
+ ret = chainfunc (GST_PAD_CAST (peer), buffer);
- while (parent_pads) {
- GstRealPad *parent_pad = GST_PAD_REALIZE (parent_pads->data);
+ gst_object_unref (GST_OBJECT_CAST (peer));
- if (parent_pad->direction != direction) {
- res = g_list_prepend (res, parent_pad);
- }
+ return ret;
- parent_pads = g_list_next (parent_pads);
+ /* ERROR recovery here */
+not_linked:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pushing, but it was not linked");
+ GST_UNLOCK (pad);
+ return GST_FLOW_NOT_CONNECTED;
+ }
+not_active:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pushing, but it was inactive");
+ GST_UNLOCK (pad);
+ return GST_FLOW_WRONG_STATE;
+ }
+flushing:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pushing, but pad was flushing");
+ GST_UNLOCK (pad);
+ return GST_FLOW_UNEXPECTED;
+ }
+not_negotiated:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pushing buffer but peer did not accept");
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+no_function:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pushing, but not chainhandler");
+ GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
+ ("push on pad %s:%s but the peer pad %s:%s has no chainfunction",
+ GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
+ gst_object_unref (GST_OBJECT (peer));
+ return GST_FLOW_ERROR;
}
-
- return res;
}
/**
- * gst_pad_get_internal_links:
- * @pad: the #GstPad to get the internal links of.
+ * gst_pad_check_pull_range:
+ * @pad: a sink #GstRealPad.
*
- * Gets a list of pads to which the given pad is linked to
- * inside of the parent element.
- * The caller must free this list after use.
+ * 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.
*
- * Returns: a newly allocated #GList of pads.
+ * The peer sourcepad can implement a custom #GstPadCheckGetRangeFunction
+ * if it needs to perform some logic to determine if pull_range is
+ * possible.
*
- * Not MT safe.
+ * Returns: a gboolean with the result.
+ *
+ * MT safe.
*/
-GList *
-gst_pad_get_internal_links (GstPad * pad)
+gboolean
+gst_pad_check_pull_range (GstPad * pad)
{
- GList *res = NULL;
- GstRealPad *rpad;
-
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-
- rpad = GST_PAD_REALIZE (pad);
-
- if (GST_RPAD_INTLINKFUNC (rpad))
- res = GST_RPAD_INTLINKFUNC (rpad) (GST_PAD_CAST (rpad));
+ GstRealPad *peer;
+ gboolean ret;
+ GstPadCheckGetRangeFunction checkgetrangefunc;
- return res;
-}
+ g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
+ GST_LOCK (pad);
+ if (GST_RPAD_DIRECTION (pad) != GST_PAD_SINK)
+ goto wrong_direction;
-static gboolean
-gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
-{
- GList *orig, *pads;
- gboolean result;
+ if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
+ goto not_connected;
- GST_INFO_OBJECT (pad, "Sending event %p to all internally linked pads",
- event);
+ gst_object_ref (GST_OBJECT_CAST (peer));
+ GST_UNLOCK (pad);
- result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
+ /* see note in above function */
+ if (G_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
+ ret = GST_RPAD_GETRANGEFUNC (peer) != NULL;
+ } else {
+ 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));
- orig = pads = gst_pad_get_internal_links (pad);
+ ret = checkgetrangefunc (GST_PAD_CAST (peer));
+ }
- while (pads) {
- GstPad *eventpad = GST_PAD (pads->data);
+ gst_object_unref (GST_OBJECT_CAST (peer));
- pads = g_list_next (pads);
+ return ret;
- /* for all of the internally-linked pads that are actually linked */
- if (GST_PAD_IS_LINKED (eventpad)) {
- if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
- /* for each pad we send to, we should ref the event; it's up
- * to downstream to unref again when handled. */
- GST_LOG_OBJECT (pad, "Reffing and sending event %p to %s:%s", event,
- GST_DEBUG_PAD_NAME (eventpad));
- gst_event_ref (event);
- gst_pad_push_event (eventpad, event);
- } else {
- /* we only send the event on one pad, multi-sinkpad elements
- * should implement a handler */
- GST_LOG_OBJECT (pad, "sending event %p to one sink pad %s:%s", event,
- GST_DEBUG_PAD_NAME (eventpad));
- result = gst_pad_push_event (eventpad, event);
- goto done;
- }
- }
+ /* ERROR recovery here */
+wrong_direction:
+ {
+ GST_UNLOCK (pad);
+ return FALSE;
+ }
+not_connected:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "checking pull range, but it was not linked");
+ GST_UNLOCK (pad);
+ return FALSE;
}
- /* we handled the incoming event so we unref once */
- GST_LOG_OBJECT (pad, "handled event %p, unreffing", event);
- gst_event_unref (event);
-
-done:
- g_list_free (orig);
-
- return result;
}
/**
- * gst_pad_event_default:
- * @pad: a #GstPad to call the default event handler on.
- * @event: the #GstEvent to handle.
+ * gst_pad_pull_range:
+ * @pad: a sink #GstPad.
+ * @buffer: a pointer to hold the #GstBuffer.
+ * @offset: The start offset of the buffer
+ * @length: The length of the buffer
*
- * Invokes the default event handler for the given pad. End-of-stream and
- * discontinuity events are handled specially, and then the event is sent to all
- * pads internally linked to @pad. Note that if there are many possible sink
- * pads that are internally linked to @pad, only one will be sent an event.
- * Multi-sinkpad elements should implement custom event handlers.
+ * Pulls a buffer from the peer pad. @pad must be linked.
*
- * Returns: TRUE if the event was sent succesfully.
+ * Returns: a #GstFlowReturn from the peer pad.
+ *
+ * MT safe.
*/
-gboolean
-gst_pad_event_default (GstPad * pad, GstEvent * event)
+GstFlowReturn
+gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
+ GstBuffer ** buffer)
{
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
+ GstRealPad *peer;
+ GstFlowReturn ret;
+ GstPadGetRangeFunction getrangefunc;
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GstRealPad *rpad = GST_PAD_REALIZE (pad);
+ 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);
+ g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
- if (GST_RPAD_TASK (rpad)) {
- GST_DEBUG_OBJECT (rpad, "pausing task because of eos");
- gst_task_pause (GST_RPAD_TASK (rpad));
- }
- }
- default:
- break;
- }
+ GST_LOCK (pad);
+
+ while (G_UNLIKELY (GST_RPAD_IS_BLOCKED (pad)))
+ handle_pad_block (GST_REAL_PAD_CAST (pad));
- return gst_pad_event_default_dispatch (pad, event);
-}
+ if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
+ goto not_connected;
-/**
- * gst_pad_dispatcher:
- * @pad: a #GstPad to dispatch.
- * @dispatch: the #GstDispatcherFunction to call.
- * @data: gpointer user data passed to the dispatcher function.
- *
- * Invokes the given dispatcher function on all pads that are
- * internally linked to the given pad.
- * The GstPadDispatcherFunction should return TRUE when no further pads
- * need to be processed.
- *
- * Returns: TRUE if one of the dispatcher functions returned TRUE.
- */
-gboolean
-gst_pad_dispatcher (GstPad * pad, GstPadDispatcherFunction dispatch,
- gpointer data)
-{
- gboolean res = FALSE;
- GList *int_pads, *orig;
+ if (G_UNLIKELY (!GST_RPAD_IS_ACTIVE (peer)))
+ goto not_active;
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (dispatch != NULL, FALSE);
+ if (G_UNLIKELY (GST_RPAD_IS_FLUSHING (peer)))
+ goto flushing;
- orig = int_pads = gst_pad_get_internal_links (pad);
+ gst_object_ref (GST_OBJECT_CAST (peer));
+ GST_UNLOCK (pad);
- while (int_pads) {
- GstRealPad *int_rpad = GST_PAD_REALIZE (int_pads->data);
- GstRealPad *int_peer = GST_RPAD_PEER (int_rpad);
+ /* see note in above function */
+ if (G_UNLIKELY ((getrangefunc = peer->getrangefunc) == NULL))
+ goto no_function;
- if (int_peer) {
- res = dispatch (GST_PAD (int_peer), data);
- if (res)
- break;
- }
- int_pads = g_list_next (int_pads);
- }
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "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);
- g_list_free (orig);
+ ret = getrangefunc (GST_PAD_CAST (peer), offset, size, buffer);
- return res;
+ gst_object_unref (GST_OBJECT_CAST (peer));
+
+ return ret;
+
+ /* ERROR recovery here */
+not_connected:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "pulling range, but it was not linked");
+ 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),
+ ("pullrange on pad %s:%s but the peer pad %s:%s has no getrangefunction",
+ GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
+ gst_object_unref (GST_OBJECT (peer));
+ return GST_FLOW_ERROR;
+ }
}
/**
}
}
-typedef struct
-{
- GstFormat src_format;
- gint64 src_value;
- GstFormat *dest_format;
- gint64 *dest_value;
-}
-GstPadConvertData;
+/************************************************************************
+ *
+ * templates
+ *
+ */
+static void gst_pad_template_class_init (GstPadTemplateClass * klass);
+static void gst_pad_template_init (GstPadTemplate * templ);
+static void gst_pad_template_dispose (GObject * object);
+
+GType
+gst_pad_template_get_type (void)
+{
+ static GType padtemplate_type = 0;
+
+ if (!padtemplate_type) {
+ static const GTypeInfo padtemplate_info = {
+ sizeof (GstPadTemplateClass), NULL, NULL,
+ (GClassInitFunc) gst_pad_template_class_init, NULL, NULL,
+ sizeof (GstPadTemplate),
+ 0,
+ (GInstanceInitFunc) gst_pad_template_init, NULL
+ };
+
+ padtemplate_type =
+ g_type_register_static (GST_TYPE_OBJECT, "GstPadTemplate",
+ &padtemplate_info, 0);
+ }
+ return padtemplate_type;
+}
+
+static void
+gst_pad_template_class_init (GstPadTemplateClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstObjectClass *gstobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstobject_class = (GstObjectClass *) klass;
+
+ padtemplate_parent_class = g_type_class_ref (GST_TYPE_OBJECT);
+
+ gst_pad_template_signals[TEMPL_PAD_CREATED] =
+ g_signal_new ("pad-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstPadTemplateClass, pad_created),
+ NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
+
+ gobject_class->dispose = gst_pad_template_dispose;
+
+ gstobject_class->path_string_separator = "*";
+}
+
+static void
+gst_pad_template_init (GstPadTemplate * templ)
+{
+}
+
+static void
+gst_pad_template_dispose (GObject * object)
+{
+ GstPadTemplate *templ = GST_PAD_TEMPLATE (object);
+
+ g_free (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
+ if (GST_PAD_TEMPLATE_CAPS (templ)) {
+ gst_caps_unref (GST_PAD_TEMPLATE_CAPS (templ));
+ }
+
+ G_OBJECT_CLASS (padtemplate_parent_class)->dispose (object);
+}
+
+/* ALWAYS padtemplates cannot have conversion specifications, it doesn't make
+ * sense.
+ * SOMETIMES padtemplates can do whatever they want, they are provided by the
+ * element.
+ * REQUEST padtemplates can be reverse-parsed (the user asks for 'sink1', the
+ * 'sink%d' template is automatically selected), so we need to restrict their
+ * naming.
+ */
+static gboolean
+name_is_valid (const gchar * name, GstPadPresence presence)
+{
+ const gchar *str;
+
+ if (presence == GST_PAD_ALWAYS) {
+ if (strchr (name, '%')) {
+ g_warning ("invalid name template %s: conversion specifications are not"
+ " allowed for GST_PAD_ALWAYS padtemplates", name);
+ return FALSE;
+ }
+ } else if (presence == GST_PAD_REQUEST) {
+ if ((str = strchr (name, '%')) && strchr (str + 1, '%')) {
+ g_warning ("invalid name template %s: only one conversion specification"
+ " allowed in GST_PAD_REQUEST padtemplate", name);
+ return FALSE;
+ }
+ if (str && (*(str + 1) != 's' && *(str + 1) != 'd')) {
+ g_warning ("invalid name template %s: conversion specification must be of"
+ " type '%%d' or '%%s' for GST_PAD_REQUEST padtemplate", name);
+ return FALSE;
+ }
+ if (str && (*(str + 2) != '\0')) {
+ g_warning ("invalid name template %s: conversion specification must"
+ " appear at the end of the GST_PAD_REQUEST padtemplate name", name);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_static_pad_template_get:
+ * @pad_template: the static pad template
+ *
+ * Converts a #GstStaticPadTemplate into a #GstPadTemplate.
+ *
+ * Returns: a new #GstPadTemplate.
+ */
+GstPadTemplate *
+gst_static_pad_template_get (GstStaticPadTemplate * pad_template)
+{
+ GstPadTemplate *new;
+
+ if (!name_is_valid (pad_template->name_template, pad_template->presence))
+ return NULL;
+
+ new = g_object_new (gst_pad_template_get_type (),
+ "name", pad_template->name_template, NULL);
+
+ GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (pad_template->name_template);
+ GST_PAD_TEMPLATE_DIRECTION (new) = pad_template->direction;
+ GST_PAD_TEMPLATE_PRESENCE (new) = pad_template->presence;
+
+ GST_PAD_TEMPLATE_CAPS (new) =
+ gst_caps_copy (gst_static_caps_get (&pad_template->static_caps));
+
+ return new;
+}
+
+/**
+ * gst_pad_template_new:
+ * @name_template: the name template.
+ * @direction: the #GstPadDirection of the template.
+ * @presence: the #GstPadPresence of the pad.
+ * @caps: a #GstCaps set for the template. The caps are taken ownership of.
+ *
+ * Creates a new pad template with a name according to the given template
+ * and with the given arguments. This functions takes ownership of the provided
+ * caps, so be sure to not use them afterwards.
+ *
+ * Returns: a new #GstPadTemplate.
+ */
+GstPadTemplate *
+gst_pad_template_new (const gchar * name_template,
+ GstPadDirection direction, GstPadPresence presence, GstCaps * caps)
+{
+ GstPadTemplate *new;
+
+ g_return_val_if_fail (name_template != NULL, NULL);
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (direction == GST_PAD_SRC
+ || direction == GST_PAD_SINK, NULL);
+ g_return_val_if_fail (presence == GST_PAD_ALWAYS
+ || presence == GST_PAD_SOMETIMES || presence == GST_PAD_REQUEST, NULL);
+
+ if (!name_is_valid (name_template, presence))
+ return NULL;
+
+ new = g_object_new (gst_pad_template_get_type (),
+ "name", name_template, NULL);
+
+ GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (name_template);
+ GST_PAD_TEMPLATE_DIRECTION (new) = direction;
+ GST_PAD_TEMPLATE_PRESENCE (new) = presence;
+ GST_PAD_TEMPLATE_CAPS (new) = caps;
-static gboolean
-gst_pad_convert_dispatcher (GstPad * pad, GstPadConvertData * data)
-{
- return gst_pad_convert (pad, data->src_format, data->src_value,
- data->dest_format, data->dest_value);
+ return new;
}
/**
- * gst_pad_convert_default:
- * @pad: a #GstPad to invoke the default converter on.
- * @src_format: the source #GstFormat.
- * @src_value: the source value.
- * @dest_format: a pointer to the destination #GstFormat.
- * @dest_value: a pointer to the destination value.
+ * gst_static_pad_template_get_caps:
+ * @templ: a #GstStaticPadTemplate to get capabilities of.
*
- * Invokes the default converter on a pad.
- * This will forward the call to the pad obtained
- * using the internal link of
- * the element.
+ * Gets the capabilities of the static pad template.
*
- * Returns: TRUE if the conversion could be performed.
+ * Returns: the #GstCaps of the static pad template. If you need to keep a
+ * reference to the caps, take a ref (see gst_caps_ref ()).
*/
-gboolean
-gst_pad_convert_default (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
+GstCaps *
+gst_static_pad_template_get_caps (GstStaticPadTemplate * templ)
{
- GstPadConvertData data;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (dest_format != NULL, FALSE);
- g_return_val_if_fail (dest_value != NULL, FALSE);
-
- data.src_format = src_format;
- data.src_value = src_value;
- data.dest_format = dest_format;
- data.dest_value = dest_value;
+ g_return_val_if_fail (templ, NULL);
- return gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
- gst_pad_convert_dispatcher, &data);
+ return (GstCaps *) gst_static_caps_get (&templ->static_caps);
}
/**
- * gst_pad_convert:
- * @pad: a #GstPad to invoke the default converter on.
- * @src_format: the source #GstFormat.
- * @src_value: the source value.
- * @dest_format: a pointer to the destination #GstFormat.
- * @dest_value: a pointer to the destination value.
+ * gst_pad_template_get_caps:
+ * @templ: a #GstPadTemplate to get capabilities of.
*
- * Invokes a conversion on the pad.
+ * Gets the capabilities of the pad template.
*
- * Returns: TRUE if the conversion could be performed.
+ * Returns: the #GstCaps of the pad template. If you need to keep a reference to
+ * the caps, take a ref (see gst_caps_ref ()).
*/
-gboolean
-gst_pad_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- GstRealPad *rpad;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (dest_format != NULL, FALSE);
- g_return_val_if_fail (dest_value != NULL, FALSE);
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- rpad = GST_PAD_REALIZE (pad);
-
- if (GST_RPAD_CONVERTFUNC (rpad)) {
- return GST_RPAD_CONVERTFUNC (rpad) (GST_PAD (rpad), src_format,
- src_value, dest_format, dest_value);
- }
-
- return FALSE;
-}
-
-typedef struct
+GstCaps *
+gst_pad_template_get_caps (GstPadTemplate * templ)
{
- GstQueryType type;
- GstFormat *format;
- gint64 *value;
-}
-GstPadQueryData;
+ g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
-static gboolean
-gst_pad_query_dispatcher (GstPad * pad, GstPadQueryData * data)
-{
- return gst_pad_query (pad, data->type, data->format, data->value);
+ return GST_PAD_TEMPLATE_CAPS (templ);
}
/**
- * gst_pad_query_default:
- * @pad: a #GstPad to invoke the default query on.
- * @type: the #GstQueryType of the query to perform.
- * @format: a pointer to the #GstFormat of the result.
- * @value: a pointer to the result.
- *
- * Invokes the default query function on a pad.
+ * gst_pad_set_element_private:
+ * @pad: the #GstPad to set the private data of.
+ * @priv: The private data to attach to the pad.
*
- * Returns: TRUE if the query could be performed.
+ * Set the given private data gpointer on the pad.
+ * This function can only be used by the element that owns the pad.
*/
-gboolean
-gst_pad_query_default (GstPad * pad, GstQueryType type,
- GstFormat * format, gint64 * value)
+void
+gst_pad_set_element_private (GstPad * pad, gpointer priv)
{
- GstPadQueryData data;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (format != NULL, FALSE);
- g_return_val_if_fail (value != NULL, FALSE);
-
- data.type = type;
- data.format = format;
- data.value = value;
-
- return gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
- gst_pad_query_dispatcher, &data);
+ pad->element_private = priv;
}
/**
- * gst_pad_query:
- * @pad: a #GstPad to invoke the default query on.
- * @type: the #GstQueryType of the query to perform.
- * @format: a pointer to the #GstFormat asked for.
- * On return contains the #GstFormat used.
- * @value: a pointer to the result.
+ * gst_pad_get_element_private:
+ * @pad: the #GstPad to get the private data of.
*
- * Queries a pad for one of the available properties. The format will be
- * adjusted to the actual format used when specifying formats such as
- * GST_FORMAT_DEFAULT.
- * FIXME: Tell if the format can be adjusted when specifying a definite format.
+ * Gets the private data of a pad.
*
- * Returns: TRUE if the query could be performed.
+ * Returns: a #gpointer to the private data.
*/
-gboolean
-gst_pad_query (GstPad * pad, GstQueryType type,
- GstFormat * format, gint64 * value)
+gpointer
+gst_pad_get_element_private (GstPad * pad)
{
- GstRealPad *rpad;
-
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (format != NULL, FALSE);
- g_return_val_if_fail (value != NULL, FALSE);
-
- rpad = GST_PAD_REALIZE (pad);
-
- g_return_val_if_fail (rpad, FALSE);
+ return pad->element_private;
+}
- if (GST_RPAD_QUERYFUNC (rpad))
- return GST_RPAD_QUERYFUNC (rpad) (GST_PAD_CAST (rpad), type, format, value);
+gboolean
+gst_pad_start_task (GstPad * pad)
+{
+ g_warning ("implement gst_pad_start_task()");
+ return FALSE;
+}
+gboolean
+gst_pad_pause_task (GstPad * pad)
+{
+ g_warning ("implement gst_pad_pause_task()");
return FALSE;
}
-/**
- * gst_pad_query2:
- * @pad: a #GstPad to invoke the default query on.
- * @query: the #GstQuery to perform.
- *
- * Dispatches a query to a pad. The query should have been allocated by the
- * caller via one of the type-specific allocation functions in gstquery.h. The
- * element is responsible for filling the query with an appropriate response,
- * which should then be parsed with a type-specific query parsing function.
- *
- * Again, the caller is responsible for both the allocation and deallocation of
- * the query structure.
- *
- * Returns: TRUE if the query could be performed.
- */
gboolean
-gst_pad_query2 (GstPad * pad, GstQuery * query)
+gst_pad_stop_task (GstPad * pad)
{
- GstRealPad *rpad;
+ g_warning ("implement gst_pad_stop_task()");
+ return FALSE;
+}
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
- rpad = GST_PAD_REALIZE (pad);
+/***** ghost pads *****/
+GType _gst_ghost_pad_type = 0;
- g_return_val_if_fail (rpad, FALSE);
+static void gst_ghost_pad_class_init (GstGhostPadClass * klass);
+static void gst_ghost_pad_init (GstGhostPad * pad);
+static void gst_ghost_pad_dispose (GObject * object);
+static void gst_ghost_pad_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_ghost_pad_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
- if (GST_RPAD_QUERY2FUNC (rpad))
- return GST_RPAD_QUERY2FUNC (rpad) (GST_PAD_CAST (rpad), query);
+static GstPad *ghost_pad_parent_class = NULL;
- return FALSE;
-}
+/* static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; */
+enum
+{
+ GPAD_ARG_0,
+ GPAD_ARG_REAL_PAD
+ /* fill me */
+};
-gboolean
-gst_pad_query2_default (GstPad * pad, GstQuery * query)
+GType
+gst_ghost_pad_get_type (void)
{
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- case GST_QUERY_SEEKING:
- case GST_QUERY_FORMATS:
- case GST_QUERY_LATENCY:
- case GST_QUERY_JITTER:
- case GST_QUERY_RATE:
- case GST_QUERY_CONVERT:
- default:
- return gst_pad_dispatcher
- (pad, (GstPadDispatcherFunction) gst_pad_query2, query);
+ if (!_gst_ghost_pad_type) {
+ static const GTypeInfo pad_info = {
+ sizeof (GstGhostPadClass), NULL, NULL,
+ (GClassInitFunc) gst_ghost_pad_class_init, NULL, NULL,
+ sizeof (GstGhostPad),
+ 0,
+ (GInstanceInitFunc) gst_ghost_pad_init,
+ NULL
+ };
+
+ _gst_ghost_pad_type = g_type_register_static (GST_TYPE_PAD, "GstGhostPad",
+ &pad_info, 0);
}
+ return _gst_ghost_pad_type;
}
-/**
- * gst_pad_query_position:
- * @pad: a #GstPad to invoke the default query on.
- * @format: a pointer to the #GstFormat asked for.
- * On return contains the #GstFormat used.
- * @cur: A location in which to store the current position, or NULL.
- * @end: A location in which to store the end position (length), or NULL.
- *
- * Queries a pad for the stream position and length.
- *
- * Returns: TRUE if the query could be performed.
- */
-gboolean
-gst_pad_query_position (GstPad * pad, GstFormat * format, gint64 * cur,
- gint64 * end)
+static void
+gst_ghost_pad_class_init (GstGhostPadClass * klass)
{
- GstQuery *query;
- gboolean ret;
+ GObjectClass *gobject_class;
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (format != NULL, FALSE);
+ gobject_class = (GObjectClass *) klass;
- query = gst_query_new_position (*format);
- ret = gst_pad_query2 (pad, query);
+ ghost_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
- if (ret)
- gst_query_parse_position_response (query, format, cur, end);
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_get_property);
- gst_query_unref (query);
+ g_object_class_install_property (gobject_class, GPAD_ARG_REAL_PAD,
+ g_param_spec_object ("real-pad", "Real pad",
+ "The real pad for the ghost pad", GST_TYPE_PAD, G_PARAM_READWRITE));
+}
- return ret;
+static void
+gst_ghost_pad_init (GstGhostPad * pad)
+{
+ /* zeroed by glib */
}
-static gboolean
-gst_pad_get_formats_dispatcher (GstPad * pad, const GstFormat ** data)
+static void
+gst_ghost_pad_dispose (GObject * object)
{
- *data = gst_pad_get_formats (pad);
+ g_object_set (object, "real-pad", NULL, NULL);
- return TRUE;
+ G_OBJECT_CLASS (ghost_pad_parent_class)->dispose (object);
}
-/**
- * gst_pad_get_formats_default:
- * @pad: a #GstPad to query
- *
- * Invoke the default format dispatcher for the pad.
- *
- * Returns: An array of GstFormats ended with a 0 value.
- */
-const GstFormat *
-gst_pad_get_formats_default (GstPad * pad)
+static void
+gst_ghost_pad_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
{
- GstFormat *result = NULL;
+ GstPad *ghostpad = (GstPad *) object;
+ GstPad *oldrealpad = (GstPad *) GST_GPAD_REALPAD (ghostpad);
+ GstPad *realpad = NULL;
- g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+ switch (prop_id) {
+ case GPAD_ARG_REAL_PAD:
+ realpad = g_value_get_object (value);
- gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
- gst_pad_get_formats_dispatcher, &result);
+ if (oldrealpad) {
+ if (realpad == oldrealpad)
+ return;
+ else
+ gst_pad_remove_ghost_pad (oldrealpad, ghostpad);
+ }
- return result;
+ if (realpad)
+ gst_pad_add_ghost_pad (realpad, ghostpad);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_ghost_pad_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ case GPAD_ARG_REAL_PAD:
+ g_value_set_object (value, GST_GPAD_REALPAD (object));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
/**
- * gst_pad_get_formats:
- * @pad: a #GstPad to query
+ * gst_ghost_pad_new:
+ * @name: the name of the new ghost pad.
+ * @pad: the #GstPad to create a ghost pad for.
*
- * Gets the list of supported formats from the pad.
+ * Creates a new ghost pad associated with @pad, and named @name. If @name is
+ * %NULL, a guaranteed unique name (across all ghost pads) will be assigned.
*
- * Returns: An array of GstFormats ended with a 0 value.
+ * Returns: a new ghost #GstPad, or %NULL in case of an error.
*/
-const GstFormat *
-gst_pad_get_formats (GstPad * pad)
+GstPad *
+gst_ghost_pad_new (const gchar * name, GstPad * pad)
{
- GstRealPad *rpad;
+ GstPad *gpad;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
- rpad = GST_PAD_REALIZE (pad);
+ gpad = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "real-pad", pad, NULL);
- if (GST_RPAD_FORMATSFUNC (rpad))
- return GST_RPAD_FORMATSFUNC (rpad) (GST_PAD (pad));
+ GST_CAT_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\" for pad %s:%s",
+ GST_OBJECT_NAME (gpad), GST_DEBUG_PAD_NAME (pad));
- return NULL;
+ return gpad;
}