| /* GStreamer |
| * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
| * 2000 Wim Taymans <wtay@chello.be> |
| * |
| * gstpad.c: Pads for connecting elements together |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| //#define GST_DEBUG_ENABLED |
| #include "gst_private.h" |
| |
| #include "gstpad.h" |
| #include "gstelement.h" |
| #include "gsttype.h" |
| #include "gstbin.h" |
| |
| |
| /***** Start with the base GstPad class *****/ |
| static void gst_pad_class_init (GstPadClass *klass); |
| static void gst_pad_init (GstPad *pad); |
| |
| static xmlNodePtr gst_pad_save_thyself (GstObject *object, xmlNodePtr parent); |
| |
| static GstObject *pad_parent_class = NULL; |
| |
| GtkType |
| gst_pad_get_type(void) { |
| static GtkType pad_type = 0; |
| |
| if (!pad_type) { |
| static const GtkTypeInfo pad_info = { |
| "GstPad", |
| sizeof(GstPad), |
| sizeof(GstPadClass), |
| (GtkClassInitFunc)gst_pad_class_init, |
| (GtkObjectInitFunc)gst_pad_init, |
| (GtkArgSetFunc)NULL, |
| (GtkArgGetFunc)NULL, |
| (GtkClassInitFunc)NULL, |
| }; |
| pad_type = gtk_type_unique(GST_TYPE_OBJECT,&pad_info); |
| } |
| return pad_type; |
| } |
| |
| static void |
| gst_pad_class_init (GstPadClass *klass) |
| { |
| pad_parent_class = gtk_type_class(GST_TYPE_OBJECT); |
| } |
| |
| static void |
| gst_pad_init (GstPad *pad) |
| { |
| pad->element_private = NULL; |
| |
| pad->padtemplate = NULL; |
| } |
| |
| |
| |
| /***** Then do the Real Pad *****/ |
| /* Pad signals and args */ |
| enum { |
| REAL_SET_ACTIVE, |
| REAL_CAPS_CHANGED, |
| /* FILL ME */ |
| REAL_LAST_SIGNAL |
| }; |
| |
| enum { |
| REAL_ARG_0, |
| REAL_ARG_ACTIVE, |
| /* FILL ME */ |
| }; |
| |
| static void gst_real_pad_class_init (GstRealPadClass *klass); |
| static void gst_real_pad_init (GstRealPad *pad); |
| |
| static void gst_real_pad_set_arg (GtkObject *object,GtkArg *arg,guint id); |
| static void gst_real_pad_get_arg (GtkObject *object,GtkArg *arg,guint id); |
| |
| static void gst_real_pad_destroy (GtkObject *object); |
| |
| static void gst_pad_push_func (GstPad *pad, GstBuffer *buf); |
| static gboolean gst_pad_eos_func (GstPad *pad); |
| |
| |
| static GstPad *real_pad_parent_class = NULL; |
| static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 }; |
| |
| GtkType |
| gst_real_pad_get_type(void) { |
| static GtkType pad_type = 0; |
| |
| if (!pad_type) { |
| static const GtkTypeInfo pad_info = { |
| "GstRealPad", |
| sizeof(GstRealPad), |
| sizeof(GstRealPadClass), |
| (GtkClassInitFunc)gst_real_pad_class_init, |
| (GtkObjectInitFunc)gst_real_pad_init, |
| (GtkArgSetFunc)NULL, |
| (GtkArgGetFunc)NULL, |
| (GtkClassInitFunc)NULL, |
| }; |
| pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info); |
| } |
| return pad_type; |
| } |
| |
| static void |
| gst_real_pad_class_init (GstRealPadClass *klass) |
| { |
| GtkObjectClass *gtkobject_class; |
| GstObjectClass *gstobject_class; |
| |
| gtkobject_class = (GtkObjectClass*)klass; |
| gstobject_class = (GstObjectClass*)klass; |
| |
| real_pad_parent_class = gtk_type_class(GST_TYPE_PAD); |
| |
| gst_real_pad_signals[REAL_SET_ACTIVE] = |
| gtk_signal_new ("set_active", GTK_RUN_LAST, gtkobject_class->type, |
| GTK_SIGNAL_OFFSET (GstRealPadClass, set_active), |
| gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1, |
| GTK_TYPE_BOOL); |
| gst_real_pad_signals[REAL_CAPS_CHANGED] = |
| gtk_signal_new ("caps_changed", GTK_RUN_LAST, gtkobject_class->type, |
| GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed), |
| gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, |
| GTK_TYPE_POINTER); |
| gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL); |
| |
| gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL, |
| GTK_ARG_READWRITE, REAL_ARG_ACTIVE); |
| |
| gtkobject_class->destroy = gst_real_pad_destroy; |
| gtkobject_class->set_arg = gst_real_pad_set_arg; |
| gtkobject_class->get_arg = gst_real_pad_get_arg; |
| |
| gstobject_class->save_thyself = gst_pad_save_thyself; |
| gstobject_class->path_string_separator = "."; |
| } |
| |
| static void |
| gst_real_pad_init (GstRealPad *pad) |
| { |
| pad->direction = GST_PAD_UNKNOWN; |
| pad->peer = NULL; |
| |
| pad->chainfunc = NULL; |
| pad->getfunc = NULL; |
| pad->getregionfunc = NULL; |
| pad->qosfunc = NULL; |
| pad->eosfunc = gst_pad_eos_func; |
| |
| pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func); |
| pad->pullfunc = NULL; |
| pad->pullregionfunc = NULL; |
| |
| pad->ghostpads = NULL; |
| pad->caps = NULL; |
| } |
| |
| static void |
| gst_real_pad_set_arg (GtkObject *object, GtkArg *arg, guint id) |
| { |
| g_return_if_fail(GST_IS_PAD(object)); |
| |
| switch (id) { |
| case REAL_ARG_ACTIVE: |
| if (GTK_VALUE_BOOL(*arg)) { |
| gst_info("gstpad: activating pad\n"); |
| GST_FLAG_UNSET(object,GST_PAD_DISABLED); |
| } else { |
| gst_info("gstpad: de-activating pad\n"); |
| GST_FLAG_SET(object,GST_PAD_DISABLED); |
| } |
| gtk_signal_emit(GTK_OBJECT(object), gst_real_pad_signals[REAL_SET_ACTIVE], |
| ! GST_FLAG_IS_SET(object,GST_PAD_DISABLED)); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void |
| gst_real_pad_get_arg (GtkObject *object, GtkArg *arg, guint id) |
| { |
| /* it's not null if we got it, but it might not be ours */ |
| g_return_if_fail (GST_IS_PAD (object)); |
| |
| switch (id) { |
| case REAL_ARG_ACTIVE: |
| GTK_VALUE_BOOL (*arg) = ! GST_FLAG_IS_SET (object, GST_PAD_DISABLED); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| |
| /** |
| * gst_pad_new: |
| * @name: name of new pad |
| * @direction: either GST_PAD_SRC or GST_PAD_SINK |
| * |
| * Create a new pad with given name. |
| * |
| * Returns: new pad |
| */ |
| GstPad* |
| gst_pad_new (gchar *name, |
| GstPadDirection direction) |
| { |
| GstRealPad *pad; |
| |
| g_return_val_if_fail (name != NULL, NULL); |
| g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL); |
| |
| pad = gtk_type_new (gst_real_pad_get_type ()); |
| gst_object_set_name (GST_OBJECT (pad), name); |
| GST_RPAD_DIRECTION(pad) = direction; |
| |
| return GST_PAD(pad); |
| } |
| |
| /** |
| * gst_pad_new_from_template: |
| * @templ: the pad template to use |
| * @name: the name of the element |
| * |
| * Create a new pad with given name from the given template. |
| * |
| * Returns: new pad |
| */ |
| GstPad* |
| gst_pad_new_from_template (GstPadTemplate *templ, |
| gchar *name) |
| { |
| GstPad *pad; |
| |
| g_return_val_if_fail (name != NULL, NULL); |
| g_return_val_if_fail (templ != NULL, NULL); |
| |
| pad = gst_pad_new (name, templ->direction); |
| GST_PAD_PADTEMPLATE(pad) = templ; |
| |
| return pad; |
| } |
| |
| /** |
| * gst_pad_get_direction: |
| * @pad: the Pad to get the direction from |
| * |
| * Get the direction of the pad. |
| * |
| * Returns: the direction of the pad |
| */ |
| GstPadDirection |
| gst_pad_get_direction (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN); |
| g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN); |
| |
| return GST_PAD_DIRECTION(pad); |
| } |
| |
| /** |
| * gst_pad_set_name: |
| * @pad: the pad to set the name of |
| * @name: the name of the pad |
| * |
| * Set the name of a pad. |
| */ |
| void |
| gst_pad_set_name (GstPad *pad, |
| const gchar *name) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_PAD (pad)); |
| |
| gst_object_set_name (GST_OBJECT (pad), name); |
| } |
| |
| /** |
| * gst_pad_get_name: |
| * @pad: the pad to get the name of |
| * |
| * Get the name of a pad. |
| * |
| * Returns: the name of the pad, don't free. |
| */ |
| const gchar* |
| gst_pad_get_name (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_OBJECT_NAME (pad); |
| } |
| |
| /** |
| * gst_pad_set_chain_function: |
| * @pad: the pad to set the chain function for |
| * @chain: the chain function |
| * |
| * Set the given chain function for the pad. |
| */ |
| void gst_pad_set_chain_function (GstPad *pad, |
| GstPadChainFunction chain) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_CHAINFUNC(pad) = chain; |
| GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain); |
| } |
| |
| /** |
| * gst_pad_set_get_function: |
| * @pad: the pad to set the get function for |
| * @get: the get function |
| * |
| * Set the given get function for the pad. |
| */ |
| void |
| gst_pad_set_get_function (GstPad *pad, |
| GstPadGetFunction get) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_GETFUNC(pad) = get; |
| GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETFUNC(pad),get); |
| } |
| |
| /** |
| * gst_pad_set_getregion_function: |
| * @pad: the pad to set the getregion function for |
| * @getregion: the getregion function |
| * |
| * Set the given getregion function for the pad. |
| */ |
| void |
| gst_pad_set_getregion_function (GstPad *pad, |
| GstPadGetRegionFunction getregion) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_GETREGIONFUNC(pad) = getregion; |
| GST_DEBUG (0,"getregionfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETREGIONFUNC(pad),getregion); |
| } |
| |
| /** |
| * gst_pad_set_qos_function: |
| * @pad: the pad to set the qos function for |
| * @qos: the qos function |
| * |
| * Set the given qos function for the pad. |
| */ |
| void |
| gst_pad_set_qos_function (GstPad *pad, |
| GstPadQoSFunction qos) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_QOSFUNC(pad) = qos; |
| GST_DEBUG (0,"qosfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_QOSFUNC(pad),qos); |
| } |
| |
| /** |
| * gst_pad_set_eos_function: |
| * @pad: the pad to set the eos function for |
| * @eos: the eos function |
| * |
| * Set the given EOS function for the pad. |
| */ |
| void |
| gst_pad_set_eos_function (GstPad *pad, |
| GstPadEOSFunction eos) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_EOSFUNC(pad) = eos; |
| GST_DEBUG (0,"eosfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_EOSFUNC(pad),eos); |
| } |
| |
| /** |
| * gst_pad_set_negotiate_function: |
| * @pad: the pad to set the negotiate function for |
| * @nego: the negotiate function |
| * |
| * Set the given negotiate function for the pad. |
| */ |
| void |
| gst_pad_set_negotiate_function (GstPad *pad, |
| GstPadNegotiateFunction nego) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_NEGOTIATEFUNC(pad) = nego; |
| GST_DEBUG (0,"negotiatefunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEGOTIATEFUNC(pad),nego); |
| } |
| |
| |
| /** |
| * gst_pad_set_newcaps_function: |
| * @pad: the pad to set the newcaps function for |
| * @newcaps: the newcaps function |
| * |
| * Set the given newcaps function for the pad. |
| */ |
| void |
| gst_pad_set_newcaps_function (GstPad *pad, |
| GstPadNewCapsFunction newcaps) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_REAL_PAD (pad)); |
| |
| GST_RPAD_NEWCAPSFUNC (pad) = newcaps; |
| GST_DEBUG (0,"newcapsfunc for %s:%s(@%p) at %p is set to %p\n", |
| GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEWCAPSFUNC(pad),newcaps); |
| } |
| |
| |
| |
| static void |
| gst_pad_push_func(GstPad *pad, GstBuffer *buf) |
| { |
| if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) { |
| GST_DEBUG (0,"calling chain function\n"); |
| (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf); |
| } else { |
| GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n"); |
| } |
| } |
| |
| |
| /** |
| * gst_pad_handle_qos: |
| * @pad: the pad to handle the QoS message |
| * @qos_message: the QoS message to handle |
| * |
| * Pass the qos message downstream. |
| */ |
| void |
| gst_pad_handle_qos(GstPad *pad, |
| glong qos_message) |
| { |
| GstElement *element; |
| GList *pads; |
| GstPad *target_pad; |
| |
| GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message); |
| |
| if (GST_RPAD_QOSFUNC(pad)) { |
| (GST_RPAD_QOSFUNC(pad)) (pad,qos_message); |
| } else { |
| element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad))); |
| |
| pads = element->pads; |
| GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message); |
| while (pads) { |
| target_pad = GST_PAD (pads->data); |
| if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) { |
| gst_pad_handle_qos (target_pad, qos_message); |
| } |
| pads = g_list_next (pads); |
| } |
| } |
| |
| return; |
| } |
| |
| /** |
| * gst_pad_disconnect: |
| * @srcpad: the source pad to disconnect |
| * @sinkpad: the sink pad to disconnect |
| * |
| * Disconnects the source pad from the sink pad. |
| */ |
| void |
| gst_pad_disconnect (GstPad *srcpad, |
| GstPad *sinkpad) |
| { |
| GstRealPad *realsrc, *realsink; |
| |
| /* generic checks */ |
| g_return_if_fail (srcpad != NULL); |
| g_return_if_fail (GST_IS_PAD (srcpad)); |
| g_return_if_fail (sinkpad != NULL); |
| g_return_if_fail (GST_IS_PAD (sinkpad)); |
| |
| // now we need to deal with the real/ghost stuff |
| realsrc = GST_PAD_REALIZE(srcpad); |
| realsink = GST_PAD_REALIZE(sinkpad); |
| |
| g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL); |
| g_return_if_fail (GST_RPAD_PEER(realsink) != NULL); |
| |
| g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) && |
| (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK)); |
| |
| /* first clear peers */ |
| GST_RPAD_PEER(realsrc) = NULL; |
| GST_RPAD_PEER(realsink) = NULL; |
| |
| GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s", |
| GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); |
| } |
| |
| /** |
| * gst_pad_connect: |
| * @srcpad: the source pad to connect |
| * @sinkpad: the sink pad to connect |
| * |
| * Connects the source pad to the sink pad. |
| * |
| * Returns: TRUE if the pad could be connected |
| */ |
| gboolean |
| gst_pad_connect (GstPad *srcpad, |
| GstPad *sinkpad) |
| { |
| GstRealPad *realsrc, *realsink; |
| GstRealPad *temppad; |
| gboolean negotiated = FALSE; |
| |
| /* generic checks */ |
| g_return_val_if_fail(srcpad != NULL, FALSE); |
| g_return_val_if_fail(GST_IS_PAD(srcpad), FALSE); |
| g_return_val_if_fail(sinkpad != NULL, FALSE); |
| g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE); |
| |
| GST_INFO (GST_CAT_ELEMENT_PADS, "about to connect %s:%s and %s:%s", |
| GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); |
| |
| // now we need to deal with the real/ghost stuff |
| realsrc = GST_PAD_REALIZE(srcpad); |
| realsink = GST_PAD_REALIZE(sinkpad); |
| |
| g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE); |
| g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE); |
| |
| /* check for reversed directions and swap if necessary */ |
| if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) && |
| (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) { |
| temppad = realsrc; |
| realsrc = realsink; |
| realsink = temppad; |
| } |
| g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) && |
| (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE); |
| |
| |
| /* first set peers */ |
| GST_RPAD_PEER(realsrc) = realsink; |
| GST_RPAD_PEER(realsink) = realsrc; |
| |
| /* FIXME: set connected flag */ |
| |
| GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s", |
| GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); |
| |
| if (GST_PAD_CAPS (srcpad)) { |
| negotiated = gst_pad_renegotiate (srcpad); |
| } |
| else if (GST_PAD_CAPS (sinkpad)) { |
| negotiated = gst_pad_renegotiate (sinkpad); |
| } |
| else |
| negotiated = TRUE; |
| |
| if (!negotiated) { |
| gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink)); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| /** |
| * gst_pad_set_parent: |
| * @pad: the pad to set the parent |
| * @parent: the object to set the parent to |
| * |
| * Sets the parent object of a pad. |
| */ |
| void |
| gst_pad_set_parent (GstPad *pad, |
| GstObject *parent) |
| { |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_PAD (pad)); |
| g_return_if_fail (GST_PAD_PARENT (pad) == NULL); |
| g_return_if_fail (parent != NULL); |
| g_return_if_fail (GTK_IS_OBJECT (parent)); |
| g_return_if_fail ((gpointer)pad != (gpointer)parent); |
| |
| gst_object_set_parent (GST_OBJECT (pad), parent); |
| } |
| |
| /** |
| * gst_pad_get_padtemplate: |
| * @pad: the pad to get the padtemplate from |
| * |
| * Get the padtemplate object of this pad. |
| * |
| * Returns: the padtemplate object |
| */ |
| GstPadTemplate* |
| gst_pad_get_padtemplate (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_PAD_PADTEMPLATE (pad); |
| } |
| |
| /** |
| * gst_pad_get_parent: |
| * @pad: the pad to get the parent from |
| * |
| * Get the parent object of this pad. |
| * |
| * Returns: the parent object |
| */ |
| GstObject* |
| gst_pad_get_parent (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_OBJECT_PARENT (pad); |
| } |
| |
| /** |
| * gst_pad_get_real_parent: |
| * @pad: the pad to get the parent from |
| * |
| * Get the real parent object of this pad. If the pad |
| * is a ghostpad, the actual owner of the real pad is |
| * returned, as opposed to the gst_pad_get_parent. |
| * |
| * Returns: the parent object |
| */ |
| GstObject* |
| gst_pad_get_real_parent (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad))); |
| } |
| |
| /** |
| * gst_pad_add_ghost_pad: |
| * @pad: the pad to set the ghost parent |
| * @ghostpad: the ghost pad to add |
| * |
| * Add a ghost pad to a pad. |
| */ |
| void |
| gst_pad_add_ghost_pad (GstPad *pad, |
| GstPad *ghostpad) |
| { |
| GstRealPad *realpad; |
| |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_PAD (pad)); |
| g_return_if_fail (ghostpad != NULL); |
| g_return_if_fail (GST_IS_GHOST_PAD (ghostpad)); |
| |
| realpad = GST_PAD_REALIZE(pad); |
| |
| realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad); |
| } |
| |
| |
| /** |
| * gst_pad_remove_ghost_pad: |
| * @pad: the pad to remove the ghost parent |
| * @ghostpad: the ghost pad to remove from the pad |
| * |
| * Remove a ghost pad from a pad. |
| */ |
| void |
| gst_pad_remove_ghost_pad (GstPad *pad, |
| GstPad *ghostpad) |
| { |
| GstRealPad *realpad; |
| |
| g_return_if_fail (pad != NULL); |
| g_return_if_fail (GST_IS_PAD (pad)); |
| g_return_if_fail (ghostpad != NULL); |
| g_return_if_fail (GST_IS_GHOST_PAD (ghostpad)); |
| |
| realpad = GST_PAD_REALIZE (pad); |
| |
| realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad); |
| } |
| |
| /** |
| * gst_pad_get_ghost_pad_list: |
| * @pad: the pad to get the ghost parents from |
| * |
| * Get the ghost parents of this pad. |
| * |
| * Returns: a GList of ghost pads |
| */ |
| GList* |
| gst_pad_get_ghost_pad_list (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_PAD_REALIZE(pad)->ghostpads; |
| } |
| |
| /** |
| * gst_pad_set_caps: |
| * @pad: the pad to set the caps to |
| * @caps: the capabilities to attach to this pad |
| * |
| * Set the capabilities of this pad. |
| * |
| * Returns: a boolean indicating the caps could be set on the pad |
| */ |
| gboolean |
| gst_pad_set_caps (GstPad *pad, |
| GstCaps *caps) |
| { |
| g_return_val_if_fail (pad != NULL, FALSE); |
| g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE); // NOTE this restriction |
| |
| if (!gst_caps_check_compatibility (caps, gst_pad_get_padtemplate_caps (pad))) { |
| g_warning ("pad %s:%s tried to set caps incompatible with its padtemplate\n", |
| GST_DEBUG_PAD_NAME (pad)); |
| //return FALSE; |
| } |
| |
| if (GST_PAD_CAPS (pad)) |
| gst_caps_unref (GST_PAD_CAPS (pad)); |
| |
| if (caps) |
| gst_caps_ref (caps); |
| GST_PAD_CAPS(pad) = caps; |
| |
| return gst_pad_renegotiate (pad); |
| } |
| |
| /** |
| * gst_pad_get_caps: |
| * @pad: the pad to get the capabilities from |
| * |
| * Get the capabilities of this pad. |
| * |
| * Returns: the capabilities of this pad |
| */ |
| GstCaps* |
| gst_pad_get_caps (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| if (GST_PAD_CAPS (pad)) |
| return GST_PAD_CAPS (pad); |
| else if (GST_PAD_PADTEMPLATE (pad)) |
| return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad)); |
| |
| return NULL; |
| } |
| |
| /** |
| * gst_pad_get_padtemplate_caps: |
| * @pad: the pad to get the capabilities from |
| * |
| * Get the capabilities of this pad. |
| * |
| * Returns: a list of the capabilities of this pad |
| */ |
| GstCaps* |
| gst_pad_get_padtemplate_caps (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| if (GST_PAD_PADTEMPLATE (pad)) |
| return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad)); |
| |
| return NULL; |
| } |
| |
| |
| /** |
| * gst_padtemplate_get_caps_by_name: |
| * @templ: the padtemplate to get the capabilities from |
| * @name: the name of the capability to get |
| * |
| * Get the capability with the given name from this padtemplate. |
| * |
| * Returns: a capability or NULL if not found |
| */ |
| GstCaps* |
| gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *name) |
| { |
| GstCaps *caps; |
| |
| g_return_val_if_fail (templ != NULL, NULL); |
| |
| caps = GST_PADTEMPLATE_CAPS (templ); |
| if (!caps) |
| return NULL; |
| |
| return gst_caps_get_by_name (caps, name); |
| } |
| |
| /** |
| * gst_pad_check_compatibility: |
| * @srcpad: the srcpad to check |
| * @sinkpad: the sinkpad to check against |
| * |
| * Check if two pads have compatible capabilities. |
| * |
| * Returns: TRUE if they are compatible or the capabilities |
| * could not be checked |
| */ |
| gboolean |
| gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad) |
| { |
| g_return_val_if_fail (srcpad != NULL, FALSE); |
| g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE); |
| g_return_val_if_fail (sinkpad != NULL, FALSE); |
| g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE); |
| |
| if (GST_PAD_CAPS(srcpad) && GST_PAD_CAPS(sinkpad)) { |
| if (!gst_caps_check_compatibility (GST_PAD_CAPS(srcpad), GST_PAD_CAPS(sinkpad))) { |
| return FALSE; |
| } |
| else { |
| return TRUE; |
| } |
| } |
| else { |
| GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n", |
| GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), |
| GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad)); |
| return TRUE; |
| } |
| } |
| |
| /** |
| * gst_pad_get_peer: |
| * @pad: the pad to get the peer from |
| * |
| * Get the peer pad of this pad. |
| * |
| * Returns: the peer pad |
| */ |
| GstPad* |
| gst_pad_get_peer (GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD (pad), NULL); |
| |
| return GST_PAD(GST_PAD_PEER(pad)); |
| } |
| |
| // FIXME this needs to be rethought soon |
| static void |
| gst_real_pad_destroy (GtkObject *object) |
| { |
| GstPad *pad = GST_PAD (object); |
| |
| // g_print("in gst_pad_real_destroy()\n"); |
| |
| g_list_free (GST_REAL_PAD(pad)->ghostpads); |
| } |
| |
| |
| /** |
| * gst_pad_load_and_connect: |
| * @self: the XML node to read the description from |
| * @parent: the element that has the pad |
| * |
| * Read the pad definition from the XML node and connect the given pad |
| * in element to a pad of an element up in the hierarchy. |
| */ |
| void |
| gst_pad_load_and_connect (xmlNodePtr self, |
| GstObject *parent) |
| { |
| xmlNodePtr field = self->xmlChildrenNode; |
| GstPad *pad = NULL, *targetpad; |
| guchar *peer = NULL; |
| gchar **split; |
| GstElement *target; |
| GstObject *grandparent; |
| |
| while (field) { |
| if (!strcmp (field->name, "name")) { |
| pad = gst_element_get_pad (GST_ELEMENT (parent), xmlNodeGetContent (field)); |
| } |
| else if (!strcmp(field->name, "peer")) { |
| peer = g_strdup (xmlNodeGetContent (field)); |
| } |
| field = field->next; |
| } |
| g_return_if_fail (pad != NULL); |
| |
| if (peer == NULL) return; |
| |
| split = g_strsplit (peer, ".", 2); |
| |
| 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; |
| |
| targetpad = gst_element_get_pad (target, split[1]); |
| |
| if (targetpad == NULL) goto cleanup; |
| |
| gst_pad_connect (pad, targetpad); |
| |
| cleanup: |
| g_strfreev (split); |
| } |
| |
| static gboolean |
| gst_pad_renegotiate_func (GstPad *pad, gpointer *data1, GstPad *peerpad, gpointer *data2, GstCaps **newcaps) |
| { |
| GstRealPad *currentpad, *otherpad; |
| gpointer *currentdata, *otherdata; |
| GstPadNegotiateReturn result; |
| gint counter = 0; |
| |
| g_return_val_if_fail (pad != NULL, FALSE); |
| |
| currentpad = GST_PAD_REALIZE (pad); |
| otherpad = GST_REAL_PAD (peerpad); |
| currentdata = data1; |
| otherdata = data2; |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s data:%p\n", |
| GST_DEBUG_PAD_NAME(currentpad), GST_DEBUG_PAD_NAME(otherpad), currentdata); |
| |
| do { |
| gboolean matchtempl; |
| |
| if (!*newcaps) { |
| if (otherpad->negotiatefunc) { |
| GstRealPad *temp; |
| gpointer *tempdata; |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "requesting other caps from pad %s:%s data:%p\n", |
| GST_DEBUG_PAD_NAME(otherpad), otherdata); |
| otherpad->negotiatefunc (GST_PAD (otherpad), newcaps, otherdata); |
| |
| temp = otherpad; |
| otherpad = currentpad; |
| currentpad = temp; |
| |
| tempdata = otherdata; |
| otherdata = currentdata; |
| currentdata = tempdata; |
| } |
| } |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "checking compatibility with pad %s:%s\n", |
| GST_DEBUG_PAD_NAME(otherpad)); |
| matchtempl = gst_caps_check_compatibility (*newcaps, gst_pad_get_padtemplate_caps (GST_PAD (otherpad))); |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "caps compatibility check %s\n", (matchtempl?"ok":"fail")); |
| |
| if (matchtempl) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "checking if other pad %s:%s can negotiate data:%p\n", |
| GST_DEBUG_PAD_NAME(otherpad), otherdata); |
| if (otherpad->negotiatefunc) { |
| GstRealPad *temp; |
| gpointer *tempdata; |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "switching pad for next phase\n"); |
| |
| temp = currentpad; |
| currentpad = otherpad; |
| otherpad = temp; |
| |
| tempdata = otherdata; |
| otherdata = currentdata; |
| currentdata = tempdata; |
| } |
| else if (gst_caps_check_compatibility (*newcaps, GST_PAD_CAPS (otherpad))) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n"); |
| return TRUE; |
| } |
| else { |
| *newcaps = GST_PAD_CAPS (otherpad); |
| if (*newcaps) gst_caps_ref(*newcaps); |
| } |
| } |
| else { |
| *newcaps = GST_PAD_CAPS (otherpad); |
| if (*newcaps) gst_caps_ref(*newcaps); |
| } |
| |
| counter++; |
| |
| if (currentpad->negotiatefunc) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "calling negotiate function on pad %s:%s data: %p\n", |
| GST_DEBUG_PAD_NAME (currentpad), currentdata); |
| result = currentpad->negotiatefunc (GST_PAD (currentpad), newcaps, currentdata); |
| |
| switch (result) { |
| case GST_PAD_NEGOTIATE_FAIL: |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed\n"); |
| return FALSE; |
| case GST_PAD_NEGOTIATE_AGREE: |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n"); |
| return TRUE; |
| case GST_PAD_NEGOTIATE_TRY: |
| GST_DEBUG (GST_CAT_NEGOTIATION, "try another option\n"); |
| break; |
| default: |
| GST_DEBUG (GST_CAT_NEGOTIATION, "invalid return\n"); |
| break; |
| } |
| } |
| else { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, no more options\n"); |
| return FALSE; |
| } |
| |
| } while (counter < 100); |
| |
| g_warning ("negotiation between (%s:%s) and (%s:%s) failed: too many attempts (%d)\n", |
| GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad), counter); |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, too many attempts\n"); |
| |
| return FALSE; |
| } |
| |
| /** |
| * gst_pad_renegotiate: |
| * @pad: the pad to perform the negotiation on |
| * |
| * Perform the negotiation process with the peer pad. |
| * |
| * Returns: TRUE if the negotiation process succeded |
| */ |
| gboolean |
| gst_pad_renegotiate (GstPad *pad) |
| { |
| GstCaps *newcaps = NULL; |
| GstRealPad *peerpad, *currentpad, *otherpad; |
| gboolean result; |
| gpointer data1 = NULL, data2 = NULL; |
| |
| g_return_val_if_fail (pad != NULL, FALSE); |
| |
| peerpad = GST_PAD_PEER (pad); |
| |
| currentpad = GST_PAD_REALIZE (pad); |
| |
| if (!peerpad) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "no peer pad for pad %s:%s\n", |
| GST_DEBUG_PAD_NAME(currentpad)); |
| return TRUE; |
| } |
| |
| otherpad = GST_REAL_PAD (peerpad); |
| |
| GST_INFO (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s", |
| GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad)); |
| |
| newcaps = GST_PAD_CAPS (pad); |
| |
| result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps); |
| |
| if (result) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n"); |
| |
| /* here we have some sort of aggreement of the caps */ |
| GST_PAD_CAPS (currentpad) = newcaps; |
| if (GST_RPAD_NEWCAPSFUNC (currentpad)) |
| GST_RPAD_NEWCAPSFUNC (currentpad) (GST_PAD (currentpad), newcaps); |
| |
| GST_PAD_CAPS (otherpad) = newcaps; |
| if (GST_RPAD_NEWCAPSFUNC (otherpad)) |
| GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * gst_pad_negotiate_proxy: |
| * @srcpad: the pad that proxies |
| * @destpad: the pad to proxy the negotiation to |
| * @caps: the current caps |
| * |
| * Proxies the negotiation pad from srcpad to destpad. Further |
| * negotiation is done on the peers of both pad instead. |
| * |
| * Returns: the result of the negotiation preocess. |
| */ |
| GstPadNegotiateReturn |
| gst_pad_negotiate_proxy (GstPad *srcpad, GstPad *destpad, GstCaps **caps) |
| { |
| GstRealPad *srcpeer; |
| GstRealPad *destpeer; |
| gboolean result; |
| gpointer data1 = NULL, data2 = NULL; |
| |
| g_return_val_if_fail (srcpad != NULL, GST_PAD_NEGOTIATE_FAIL); |
| g_return_val_if_fail (destpad != NULL, GST_PAD_NEGOTIATE_FAIL); |
| |
| GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation proxied from pad (%s:%s) to pad (%s:%s)\n", |
| GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); |
| |
| srcpeer = GST_RPAD_PEER (srcpad); |
| destpeer = GST_RPAD_PEER (destpad); |
| |
| if (srcpeer && destpeer) { |
| result = gst_pad_renegotiate_func (GST_PAD (srcpeer), &data1, GST_PAD (destpeer), &data2, caps); |
| |
| if (result) { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "pads (%s:%s) and (%s:%s) aggreed on caps :)\n", |
| GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad)); |
| |
| /* here we have some sort of aggreement of the caps */ |
| GST_PAD_CAPS (destpeer) = *caps; |
| if (GST_RPAD_NEWCAPSFUNC (destpeer)) |
| GST_RPAD_NEWCAPSFUNC (destpeer) (GST_PAD (destpeer), *caps); |
| |
| GST_PAD_CAPS (destpad) = *caps; |
| if (GST_RPAD_NEWCAPSFUNC (destpad)) |
| GST_RPAD_NEWCAPSFUNC (destpad) (GST_PAD (destpad), *caps); |
| } |
| else { |
| GST_DEBUG (GST_CAT_NEGOTIATION, "pads did not aggree on caps :(\n"); |
| return GST_PAD_NEGOTIATE_FAIL; |
| } |
| } |
| |
| return GST_PAD_NEGOTIATE_AGREE; |
| } |
| |
| /** |
| * gst_pad_save_thyself: |
| * @pad: the pad to save |
| * @parent: the parent XML node to save the description in |
| * |
| * Saves the pad into an xml representation |
| * |
| * Returns: the xml representation of the pad |
| */ |
| static xmlNodePtr |
| gst_pad_save_thyself (GstObject *object, |
| xmlNodePtr parent) |
| { |
| GstRealPad *realpad; |
| GstPad *peer; |
| |
| g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL); |
| |
| realpad = GST_REAL_PAD(object); |
| |
| xmlNewChild(parent,NULL,"name", GST_PAD_NAME (realpad)); |
| if (GST_RPAD_PEER(realpad) != 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 |
| xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s", |
| GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer))); |
| } else |
| xmlNewChild(parent,NULL,"peer",""); |
| |
| return parent; |
| } |
| |
| /** |
| * gst_pad_ghost_save_thyself: |
| * @pad: the pad to save |
| * @bin: the bin |
| * @parent: the parent XML node to save the description in |
| * |
| * Saves the ghost pad into an xml representation. |
| * |
| * Returns: the xml representation of the pad |
| */ |
| xmlNodePtr |
| gst_pad_ghost_save_thyself (GstPad *pad, |
| GstElement *bin, |
| xmlNodePtr parent) |
| { |
| xmlNodePtr self; |
| |
| g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL); |
| |
| self = xmlNewChild(parent,NULL,"ghostpad",NULL); |
| xmlNewChild(self,NULL,"name", GST_PAD_NAME (pad)); |
| xmlNewChild(self,NULL,"parent", GST_OBJECT_NAME (GST_PAD_PARENT (pad))); |
| |
| // FIXME FIXME FIXME! |
| |
| return self; |
| } |
| |
| #ifndef gst_pad_push |
| /** |
| * gst_pad_push: |
| * @pad: the pad to push |
| * @buf: the buffer to push |
| * |
| * Push a buffer to the peer of the pad. |
| */ |
| void |
| gst_pad_push (GstPad *pad, GstBuffer *buf) |
| { |
| GstRealPad *peer = GST_RPAD_PEER (pad); |
| |
| g_return_if_fail (peer != NULL); |
| |
| GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); |
| |
| if (peer->pushfunc) { |
| GST_DEBUG (0, "calling pushfunc &%s of peer pad %s:%s\n", |
| GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer))); |
| (peer->pushfunc) (((GstPad*)peer), buf); |
| } else |
| GST_DEBUG (0, "no pushfunc\n"); |
| } |
| #endif |
| |
| #ifndef gst_pad_pull |
| /** |
| * gst_pad_pull: |
| * @pad: the pad to pull |
| * |
| * Pull a buffer from the peer pad. |
| * |
| * Returns: a new buffer from the peer pad. |
| */ |
| GstBuffer* |
| gst_pad_pull (GstPad *pad) |
| { |
| GstRealPad *peer = GST_RPAD_PEER(pad); |
| |
| g_return_val_if_fail (peer != NULL, NULL); |
| |
| GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad)); |
| |
| if (peer->pullfunc) { |
| GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n", |
| GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer))); |
| return (peer->pullfunc)(((GstPad*)peer)); |
| } else { |
| GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc); |
| return NULL; |
| } |
| } |
| #endif |
| |
| #ifndef gst_pad_pullregion |
| /** |
| * gst_pad_pullregion: |
| * @pad: the pad to pull the region from |
| * @type: the regiontype |
| * @offset: the offset/start of the buffer to pull |
| * @len: the length of the buffer to pull |
| * |
| * Pull a buffer region from the peer pad. The region to pull can be |
| * specified with a offset/lenght pair or with a start/legnth time |
| * indicator as specified by the type parameter. |
| * |
| * Returns: a new buffer from the peer pad with data in the specified |
| * region. |
| */ |
| GstBuffer* |
| gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len) |
| { |
| GstRealPad *peer = GST_RPAD_PEER(pad); |
| |
| g_return_val_if_fail (peer != NULL, NULL); |
| |
| GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len); |
| |
| if (peer->pullregionfunc) { |
| GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n", |
| GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer))); |
| return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len); |
| } else { |
| GST_DEBUG (0,"no pullregionfunc\n"); |
| return NULL; |
| } |
| } |
| #endif |
| |
| /************************************************************************ |
| * |
| * templates |
| * |
| */ |
| static void gst_padtemplate_class_init (GstPadTemplateClass *klass); |
| static void gst_padtemplate_init (GstPadTemplate *templ); |
| |
| enum { |
| TEMPL_PAD_CREATED, |
| /* FILL ME */ |
| TEMPL_LAST_SIGNAL |
| }; |
| |
| static GstObject *padtemplate_parent_class = NULL; |
| static guint gst_padtemplate_signals[TEMPL_LAST_SIGNAL] = { 0 }; |
| |
| GtkType |
| gst_padtemplate_get_type (void) |
| { |
| static GtkType padtemplate_type = 0; |
| |
| if (!padtemplate_type) { |
| static const GtkTypeInfo padtemplate_info = { |
| "GstPadTemplate", |
| sizeof(GstPadTemplate), |
| sizeof(GstPadTemplateClass), |
| (GtkClassInitFunc)gst_padtemplate_class_init, |
| (GtkObjectInitFunc)gst_padtemplate_init, |
| (GtkArgSetFunc)NULL, |
| (GtkArgGetFunc)NULL, |
| (GtkClassInitFunc)NULL, |
| }; |
| padtemplate_type = gtk_type_unique(GST_TYPE_OBJECT,&padtemplate_info); |
| } |
| return padtemplate_type; |
| } |
| |
| static void |
| gst_padtemplate_class_init (GstPadTemplateClass *klass) |
| { |
| GtkObjectClass *gtkobject_class; |
| GstObjectClass *gstobject_class; |
| |
| gtkobject_class = (GtkObjectClass*)klass; |
| gstobject_class = (GstObjectClass*)klass; |
| |
| padtemplate_parent_class = gtk_type_class(GST_TYPE_OBJECT); |
| |
| gst_padtemplate_signals[TEMPL_PAD_CREATED] = |
| gtk_signal_new ("pad_created", GTK_RUN_LAST, gtkobject_class->type, |
| GTK_SIGNAL_OFFSET (GstPadTemplateClass, pad_created), |
| gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, |
| GST_TYPE_PAD); |
| |
| gtk_object_class_add_signals (gtkobject_class, gst_padtemplate_signals, TEMPL_LAST_SIGNAL); |
| |
| gstobject_class->path_string_separator = "*"; |
| } |
| |
| static void |
| gst_padtemplate_init (GstPadTemplate *templ) |
| { |
| } |
| |
| /** |
| * gst_padtemplate_new: |
| * @factory: the padfactory to use |
| * |
| * Creates a new padtemplate from the factory. |
| * |
| * Returns: the new padtemplate |
| */ |
| GstPadTemplate* |
| gst_padtemplate_new (GstPadFactory *factory) |
| { |
| GstPadTemplate *new; |
| GstPadFactoryEntry tag; |
| gint i = 0; |
| guint counter = 0; |
| |
| g_return_val_if_fail (factory != NULL, NULL); |
| |
| new = gtk_type_new (gst_padtemplate_get_type ()); |
| |
| tag = (*factory)[i++]; |
| g_return_val_if_fail (tag != NULL, new); |
| new->name_template = g_strdup ((gchar *)tag); |
| |
| tag = (*factory)[i++]; |
| new->direction = GPOINTER_TO_UINT (tag); |
| |
| tag = (*factory)[i++]; |
| new->presence = GPOINTER_TO_UINT (tag); |
| |
| tag = (*factory)[i++]; |
| |
| while (GPOINTER_TO_INT (tag) == GST_PAD_FACTORY_CAPS_ID) { |
| GST_PADTEMPLATE_CAPS (new) = gst_caps_append (GST_PADTEMPLATE_CAPS (new), |
| gst_caps_register_count ((GstCapsFactory *)&(*factory)[i], &counter)); |
| i+=counter; |
| tag = (*factory)[i++]; |
| } |
| |
| return new; |
| } |
| |
| /** |
| * gst_padtemplate_create: |
| * @name_template: the name template |
| * @direction: the direction for the template |
| * @presence: the presence of the pad |
| * @caps: a list of capabilities for the template |
| * |
| * Creates a new padtemplate from the given arguments. |
| * |
| * Returns: the new padtemplate |
| */ |
| GstPadTemplate* |
| gst_padtemplate_create (gchar *name_template, |
| GstPadDirection direction, GstPadPresence presence, |
| GstCaps *caps) |
| { |
| GstPadTemplate *new; |
| |
| g_return_val_if_fail (name_template != NULL, NULL); |
| |
| new = gtk_type_new (gst_padtemplate_get_type ()); |
| |
| GST_PADTEMPLATE_NAME_TEMPLATE (new) = name_template; |
| GST_PADTEMPLATE_DIRECTION (new) = direction; |
| GST_PADTEMPLATE_PRESENCE (new) = presence; |
| GST_PADTEMPLATE_CAPS (new) = caps; |
| |
| return new; |
| } |
| |
| /** |
| * gst_padtemplate_get_caps: |
| * @templ: the padtemplate to use |
| * |
| * Get the capabilities of the padtemplate |
| * |
| * Returns: a GstCaps* |
| */ |
| GstCaps* |
| gst_padtemplate_get_caps (GstPadTemplate *templ) |
| { |
| g_return_val_if_fail (templ != NULL, NULL); |
| |
| return GST_PADTEMPLATE_CAPS (templ); |
| } |
| |
| /** |
| * gst_padtemplate_save_thyself: |
| * @templ: the padtemplate to save |
| * @parent: the parent XML tree |
| * |
| * Saves the padtemplate into XML. |
| * |
| * Returns: the new XML tree |
| */ |
| xmlNodePtr |
| gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent) |
| { |
| xmlNodePtr subtree; |
| guchar *presence; |
| |
| GST_DEBUG (0,"saving padtemplate %s\n", templ->name_template); |
| |
| xmlNewChild(parent,NULL,"nametemplate", templ->name_template); |
| xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src")); |
| |
| switch (templ->presence) { |
| case GST_PAD_ALWAYS: |
| presence = "always"; |
| break; |
| case GST_PAD_SOMETIMES: |
| presence = "sometimes"; |
| break; |
| case GST_PAD_REQUEST: |
| presence = "request"; |
| break; |
| default: |
| presence = "unknown"; |
| break; |
| } |
| xmlNewChild(parent,NULL,"presence", presence); |
| |
| if (GST_PADTEMPLATE_CAPS (templ)) { |
| subtree = xmlNewChild (parent, NULL, "caps", NULL); |
| gst_caps_save_thyself (GST_PADTEMPLATE_CAPS (templ), subtree); |
| } |
| |
| return parent; |
| } |
| |
| /** |
| * gst_padtemplate_load_thyself: |
| * @parent: the source XML tree |
| * |
| * Loads a padtemplate from the XML tree. |
| * |
| * Returns: the new padtemplate |
| */ |
| GstPadTemplate* |
| gst_padtemplate_load_thyself (xmlNodePtr parent) |
| { |
| xmlNodePtr field = parent->xmlChildrenNode; |
| GstPadTemplate *factory; |
| gchar *name_template = NULL; |
| GstPadDirection direction = GST_PAD_UNKNOWN; |
| GstPadPresence presence = GST_PAD_ALWAYS; |
| GstCaps *caps = NULL; |
| |
| while (field) { |
| if (!strcmp(field->name, "nametemplate")) { |
| name_template = xmlNodeGetContent(field); |
| } |
| if (!strcmp(field->name, "direction")) { |
| gchar *value = xmlNodeGetContent(field); |
| |
| if (!strcmp(value, "sink")) { |
| direction = GST_PAD_SINK; |
| } |
| else if (!strcmp(value, "src")) { |
| direction = GST_PAD_SRC; |
| } |
| g_free (value); |
| } |
| if (!strcmp(field->name, "presence")) { |
| gchar *value = xmlNodeGetContent(field); |
| |
| if (!strcmp(value, "always")) { |
| presence = GST_PAD_ALWAYS; |
| } |
| else if (!strcmp(value, "sometimes")) { |
| presence = GST_PAD_SOMETIMES; |
| } |
| else if (!strcmp(value, "request")) { |
| presence = GST_PAD_REQUEST; |
| } |
| g_free (value); |
| } |
| else if (!strcmp(field->name, "caps")) { |
| caps = gst_caps_load_thyself (field); |
| } |
| field = field->next; |
| } |
| |
| factory = gst_padtemplate_create (name_template, direction, presence, caps); |
| |
| return factory; |
| } |
| |
| |
| static gboolean |
| gst_pad_eos_func(GstPad *pad) |
| { |
| GstElement *element; |
| GList *pads; |
| GstPad *srcpad; |
| gboolean result = TRUE, success; |
| |
| g_return_val_if_fail (pad != NULL, FALSE); |
| g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE); // NOTE the restriction |
| |
| GST_INFO (GST_CAT_PADS,"attempting to set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad)); |
| |
| element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad))); |
| // g_return_val_if_fail (element != NULL, FALSE); |
| // g_return_val_if_fail (GST_IS_ELEMENT(element), FALSE); |
| |
| pads = gst_element_get_pad_list(element); |
| while (pads) { |
| srcpad = GST_PAD(pads->data); |
| pads = g_list_next(pads); |
| |
| if (gst_pad_get_direction(srcpad) == GST_PAD_SRC) { |
| result = gst_pad_eos(GST_REAL_PAD(srcpad)); |
| if (result == FALSE) success = FALSE; |
| } |
| } |
| |
| if (result == FALSE) return FALSE; |
| |
| GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad)); |
| GST_FLAG_SET (pad, GST_PAD_EOS); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_pad_set_eos: |
| * @pad: the pad to set to eos |
| * |
| * Sets the given pad to the EOS state. |
| * |
| * Returns: TRUE if it succeeded |
| */ |
| gboolean |
| gst_pad_set_eos(GstPad *pad) |
| { |
| g_return_val_if_fail (pad != NULL, FALSE); |
| g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE); // NOTE the restriction |
| g_return_val_if_fail (GST_PAD_CONNECTED(pad), FALSE); |
| |
| GST_INFO (GST_CAT_PADS,"attempting to set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad)); |
| |
| if (!gst_pad_eos(GST_REAL_PAD(pad))) { |
| return FALSE; |
| } |
| |
| GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad)); |
| GST_FLAG_SET (pad, GST_PAD_EOS); |
| |
| gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad))); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_pad_set_element_private: |
| * @pad: the pad to set the private data to |
| * @priv: The private data to attach to the pad |
| * |
| * Set the given private data pointer to the pad. This |
| * function can only be used by the element that own the |
| * pad. |
| */ |
| void |
| gst_pad_set_element_private (GstPad *pad, gpointer priv) |
| { |
| pad->element_private = priv; |
| } |
| |
| /** |
| * gst_pad_get_element_private: |
| * @pad: the pad to get the private data of |
| * |
| * Get the private data of a pad. The private data can |
| * only be set by the parent element of this pad. |
| * |
| * Returns: a pointer to the private data. |
| */ |
| gpointer |
| gst_pad_get_element_private (GstPad *pad) |
| { |
| return pad->element_private; |
| } |
| |
| |
| /***** ghost pads *****/ |
| |
| static void gst_ghost_pad_class_init (GstGhostPadClass *klass); |
| static void gst_ghost_pad_init (GstGhostPad *pad); |
| |
| static GstPad *ghost_pad_parent_class = NULL; |
| //static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; |
| |
| GtkType |
| gst_ghost_pad_get_type(void) { |
| static GtkType pad_type = 0; |
| |
| if (!pad_type) { |
| static const GtkTypeInfo pad_info = { |
| "GstGhostPad", |
| sizeof(GstGhostPad), |
| sizeof(GstGhostPadClass), |
| (GtkClassInitFunc)gst_ghost_pad_class_init, |
| (GtkObjectInitFunc)gst_ghost_pad_init, |
| (GtkArgSetFunc)NULL, |
| (GtkArgGetFunc)NULL, |
| (GtkClassInitFunc)NULL, |
| }; |
| pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info); |
| } |
| return pad_type; |
| } |
| |
| static void |
| gst_ghost_pad_class_init (GstGhostPadClass *klass) |
| { |
| GtkObjectClass *gtkobject_class; |
| |
| gtkobject_class = (GtkObjectClass*)klass; |
| |
| ghost_pad_parent_class = gtk_type_class(GST_TYPE_PAD); |
| } |
| |
| static void |
| gst_ghost_pad_init (GstGhostPad *pad) |
| { |
| pad->realpad = NULL; |
| } |
| |
| /** |
| * gst_ghost_pad_new: |
| * @name: name of the new ghost pad |
| * @pad: the pad to create a ghost pad of |
| * |
| * Create a new ghost pad associated with the given pad. |
| * |
| * Returns: new ghost pad |
| */ |
| GstPad* |
| gst_ghost_pad_new (gchar *name, |
| GstPad *pad) |
| { |
| GstGhostPad *ghostpad; |
| |
| g_return_val_if_fail (name != NULL, NULL); |
| g_return_val_if_fail (GST_IS_PAD(pad), NULL); |
| |
| ghostpad = gtk_type_new (gst_ghost_pad_get_type ()); |
| gst_pad_set_name (GST_PAD (ghostpad), name); |
| GST_GPAD_REALPAD(ghostpad) = GST_PAD_REALIZE(pad); |
| |
| // add ourselves to the real pad's list of ghostpads |
| gst_pad_add_ghost_pad (pad, GST_PAD(ghostpad)); |
| |
| // FIXME need to ref the real pad here... ? |
| |
| GST_DEBUG(0,"created ghost pad \"%s\"\n",name); |
| |
| return GST_PAD(ghostpad); |
| } |