void kms_tree_bin_unlink_input_element_from_tee (KmsTreeBin * self) { GstPad *queue_sink, *peer, *tee_src; GstElement *tee; queue_sink = gst_element_get_static_pad (self->priv->input_element, "sink"); peer = gst_pad_get_peer (queue_sink); if (GST_IS_PROXY_PAD (peer)) { GstProxyPad *ghost; ghost = gst_proxy_pad_get_internal (GST_PROXY_PAD (peer)); tee_src = gst_pad_get_peer (GST_PAD (ghost)); g_object_unref (peer); g_object_unref (ghost); } else { tee_src = peer; } gst_pad_unlink (tee_src, queue_sink); tee = gst_pad_get_parent_element (tee_src); if (tee != NULL) { gst_element_release_request_pad (tee, tee_src); g_object_unref (tee); } g_object_unref (tee_src); g_object_unref (queue_sink); }
static GstPad * _get_peer_pad (GstPad * pad) { GstPad *peer = gst_pad_get_peer (pad); if (!peer) return NULL; while (GST_IS_PROXY_PAD (peer)) { GstPad *next_pad; if (GST_IS_GHOST_PAD (peer)) { next_pad = gst_pad_get_peer (peer); if (next_pad == pad) next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer)); } else { next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (peer))); } if (!next_pad) return NULL; gst_object_unref (peer); peer = next_pad; } return peer; }
/** * gst_proxy_pad_get_internal: * @pad: the #GstProxyPad * * Get the internal pad of @pad. Unref target pad after usage. * * The internal pad of a #GstGhostPad is the internally used * pad of opposite direction, which is used to link to the target. * * Returns: (transfer full): the target #GstProxyPad, can be NULL. * Unref target pad after usage. */ GstProxyPad * gst_proxy_pad_get_internal (GstProxyPad * pad) { GstPad *internal; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); GST_OBJECT_LOCK (pad); internal = GST_PROXY_PAD_INTERNAL (pad); if (internal) gst_object_ref (internal); GST_OBJECT_UNLOCK (pad); return GST_PROXY_PAD_CAST (internal); }
/** * gst_proxy_pad_getrange_default: * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not. * @parent: the parent of @pad * @offset: The start offset of the buffer * @size: The length of the buffer * @buffer: (out callee-allocates): a pointer to hold the #GstBuffer, * returns #GST_FLOW_ERROR if %NULL. * * Invoke the default getrange function of the proxy pad. * * Returns: a #GstFlowReturn from the pad. */ GstFlowReturn gst_proxy_pad_getrange_default (GstPad * pad, GstObject * parent, guint64 offset, guint size, GstBuffer ** buffer) { GstFlowReturn res; GstPad *internal; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_pull_range (internal, offset, size, buffer); return res; }
/** * gst_proxy_pad_chain_list_default: * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. * @parent: the parent of @pad or NULL * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR * if not. * * Invoke the default chain list function of the proxy pad. * * Returns: a #GstFlowReturn from the pad. */ GstFlowReturn gst_proxy_pad_chain_list_default (GstPad * pad, GstObject * parent, GstBufferList * list) { GstFlowReturn res; GstPad *internal; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR); internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_push_list (internal, list); return res; }
/** * gst_proxy_pad_chain_default: * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. * @parent: the parent of @pad or NULL * @buffer: (transfer full): the #GstBuffer to send, return GST_FLOW_ERROR * if not. * * Invoke the default chain function of the proxy pad. * * Returns: a #GstFlowReturn from the pad. */ GstFlowReturn gst_proxy_pad_chain_default (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlowReturn res; GstPad *internal; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_push (internal, buffer); return res; }
/** * gst_proxy_pad_iterate_internal_links_default: * @pad: the #GstPad to get the internal links of. * @parent: the parent of @pad or NULL * * Invoke the default iterate internal links function of the proxy pad. * * Returns: a #GstIterator of #GstPad, or NULL if @pad has no parent. Unref each * returned pad with gst_object_unref(). */ GstIterator * gst_proxy_pad_iterate_internal_links_default (GstPad * pad, GstObject * parent) { GstIterator *res = NULL; GstPad *internal; GValue v = { 0, }; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); internal = GST_PROXY_PAD_INTERNAL (pad); g_value_init (&v, GST_TYPE_PAD); g_value_set_object (&v, internal); res = gst_iterator_new_single (GST_TYPE_PAD, &v); g_value_unset (&v); return res; }
/** * gst_proxy_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. */ static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent) { xmlNodePtr self; GstProxyPad *proxypad; GstPad *pad; GstPad *peer; g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL); self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL); xmlNewChild (self, NULL, (xmlChar *) "name", (xmlChar *) GST_OBJECT_NAME (object)); xmlNewChild (self, NULL, (xmlChar *) "parent", (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object))); proxypad = GST_PROXY_PAD_CAST (object); pad = GST_PAD_CAST (proxypad); peer = GST_PAD_CAST (pad->peer); if (GST_IS_PAD (pad)) { if (GST_PAD_IS_SRC (pad)) xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source"); else if (GST_PAD_IS_SINK (pad)) xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink"); else xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown"); } else { xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown"); } if (GST_IS_PAD (peer)) { gchar *content = g_strdup_printf ("%s.%s", GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)); xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content); g_free (content); } else { xmlNewChild (self, NULL, (xmlChar *) "peer", NULL); } return self; }
/** * gst_ghost_pad_internal_activate_mode_default: * @pad: the #GstPad to activate or deactivate. * @parent: the parent of @pad or NULL * @mode: the requested activation mode * @active: whether the pad should be active or not. * * Invoke the default activate mode function of a proxy pad that is * owned by a ghost pad. * * Returns: %TRUE if the operation was successful. */ gboolean gst_ghost_pad_internal_activate_mode_default (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { gboolean res; g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); switch (mode) { case GST_PAD_MODE_PULL: res = gst_ghost_pad_internal_activate_pull_default (pad, parent, active); break; case GST_PAD_MODE_PUSH: res = gst_ghost_pad_internal_activate_push_default (pad, parent, active); break; default: GST_LOG_OBJECT (pad, "unknown activation mode %d", mode); res = FALSE; break; } return res; }
static void gst_insert_bin_do_change (GstInsertBin * self, GstPad * pad) { struct ChangeData *data; GST_OBJECT_LOCK (self); if (!is_right_direction_for_block (pad)) { GST_WARNING_OBJECT (self, "Block pad does not have the expected direction"); goto next; } while ((data = g_queue_pop_head (&self->priv->change_queue)) != NULL) { GstPad *peer = NULL; GstPad *other_peer = NULL; GST_OBJECT_UNLOCK (self); if (data->action == GST_INSERT_BIN_ACTION_ADD && !validate_element (self, data->element)) goto error; peer = gst_pad_get_peer (pad); if (peer == NULL) { GST_WARNING_OBJECT (self, "Blocked pad has no peer"); goto error; } if (data->action == GST_INSERT_BIN_ACTION_ADD) { GstPad *srcpad = NULL, *sinkpad = NULL; GstPad *peersrcpad, *peersinkpad; /* First let's make sure we have the right pad */ if (data->sibling) { GstElement *parent = NULL; GstPad *siblingpad; if ((gst_pad_get_direction (pad) == GST_PAD_SRC && data->direction == DIRECTION_BEFORE) || (gst_pad_get_direction (pad) == GST_PAD_SINK && data->direction == DIRECTION_AFTER)) siblingpad = peer; else siblingpad = pad; parent = gst_pad_get_parent_element (siblingpad); if (parent != NULL) gst_object_unref (parent); if (parent != data->sibling) goto retry; } else { GstObject *parent; GstPad *ghost; GstPad *proxypad; if (data->direction == DIRECTION_BEFORE) { ghost = self->priv->srcpad; if (gst_pad_get_direction (pad) == GST_PAD_SINK) proxypad = pad; else proxypad = peer; } else { ghost = self->priv->sinkpad; if (gst_pad_get_direction (pad) == GST_PAD_SINK) proxypad = peer; else proxypad = pad; } if (!GST_IS_PROXY_PAD (proxypad)) goto retry; parent = gst_pad_get_parent (proxypad); if (!parent) goto retry; gst_object_unref (parent); if (GST_PAD_CAST (parent) != ghost) goto retry; } if (gst_pad_get_direction (pad) == GST_PAD_SRC) { peersrcpad = pad; peersinkpad = peer; } else { peersrcpad = peer; peersinkpad = pad; } if (GST_IS_PROXY_PAD (peersrcpad)) { GstObject *parent = gst_pad_get_parent (peersrcpad); if (GST_PAD_CAST (parent) == self->priv->sinkpad) peersrcpad = NULL; if (parent) gst_object_unref (parent); } if (GST_IS_PROXY_PAD (peersinkpad)) { GstObject *parent = gst_pad_get_parent (peersinkpad); if (GST_PAD_CAST (parent) == self->priv->srcpad) peersinkpad = NULL; if (parent) gst_object_unref (parent); } if (peersinkpad && peersrcpad) { gst_pad_unlink (peersrcpad, peersinkpad); } else { if (!peersinkpad) gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), NULL); if (!peersrcpad) gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), NULL); } srcpad = get_single_pad (data->element, GST_PAD_SRC); sinkpad = get_single_pad (data->element, GST_PAD_SINK); if (srcpad == NULL || sinkpad == NULL) { GST_WARNING_OBJECT (self, "Can not get element src or sink pad"); goto error; } if (!gst_bin_add (GST_BIN (self), data->element)) { GST_WARNING_OBJECT (self, "Can not add element to bin"); goto error; } if (peersrcpad) { if (GST_PAD_LINK_FAILED (gst_pad_link (peersrcpad, sinkpad))) { GST_WARNING_OBJECT (self, "Can not link sibling's %s:%s pad" " to element's %s:%s pad", GST_DEBUG_PAD_NAME (peersrcpad), GST_DEBUG_PAD_NAME (sinkpad)); goto error; } } else { if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), sinkpad)) { GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s", GST_DEBUG_PAD_NAME (sinkpad), GST_DEBUG_PAD_NAME (self->priv->sinkpad)); goto error; } } if (peersinkpad) { if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, peersinkpad))) { GST_WARNING_OBJECT (self, "Can not link element's %s:%s pad" " to sibling's %s:%s pad", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (peersinkpad)); goto error; } } else { if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), srcpad)) { GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (self->priv->srcpad)); goto error; } } gst_object_unref (srcpad); gst_object_unref (sinkpad); if (!gst_element_sync_state_with_parent (data->element)) { GST_WARNING_OBJECT (self, "Can not sync element's state with parent"); goto error; } } else { GstElement *parent = NULL; GstPad *other_pad; GstCaps *caps = NULL, *peercaps = NULL; gboolean can_intersect; gboolean success; parent = gst_pad_get_parent_element (peer); if (parent != NULL) gst_object_unref (parent); if (parent != data->element) goto retry; if (gst_pad_get_direction (peer) == GST_PAD_SRC) other_pad = get_single_pad (data->element, GST_PAD_SINK); else other_pad = get_single_pad (data->element, GST_PAD_SRC); if (!other_pad) { GST_WARNING_OBJECT (self, "Can not get element's other pad"); goto error; } other_peer = gst_pad_get_peer (other_pad); gst_object_unref (other_pad); if (!other_peer) { GST_WARNING_OBJECT (self, "Can not get element's other peer"); goto error; } /* Get the negotiated caps for the source pad peer, * because renegotiation while the pipeline is playing doesn't work * that fast. */ if (gst_pad_get_direction (pad) == GST_PAD_SRC) caps = gst_pad_get_current_caps (pad); else peercaps = gst_pad_get_current_caps (other_peer); if (!caps) caps = gst_pad_query_caps (pad, NULL); if (!peercaps) peercaps = gst_pad_query_caps (other_peer, NULL); can_intersect = gst_caps_can_intersect (caps, peercaps); gst_caps_unref (caps); gst_caps_unref (peercaps); if (!can_intersect) { GST_WARNING_OBJECT (self, "Pads are incompatible without the element"); goto error; } if (gst_pad_get_direction (other_peer) == GST_PAD_SRC && gst_pad_is_active (other_peer)) { gulong probe_id; probe_id = gst_pad_add_probe (other_peer, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, wait_and_drop_eos_cb, NULL, NULL); gst_pad_send_event (peer, gst_event_new_eos ()); gst_pad_remove_probe (other_peer, probe_id); } gst_element_set_locked_state (data->element, TRUE); gst_element_set_state (data->element, GST_STATE_NULL); if (!gst_bin_remove (GST_BIN (self), data->element)) { GST_WARNING_OBJECT (self, "Element removal rejected"); goto error; } gst_element_set_locked_state (data->element, FALSE); if (gst_pad_get_direction (pad) == GST_PAD_SRC) success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (pad, other_peer, GST_PAD_LINK_CHECK_HIERARCHY | GST_PAD_LINK_CHECK_TEMPLATE_CAPS)); else success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (other_peer, pad, GST_PAD_LINK_CHECK_HIERARCHY | GST_PAD_LINK_CHECK_TEMPLATE_CAPS)); gst_object_unref (other_peer); other_peer = NULL; if (!success) { GST_ERROR_OBJECT (self, "Could not re-link after the element's" " removal"); goto error; } } gst_insert_bin_change_data_complete (self, data, TRUE); gst_object_unref (peer); GST_OBJECT_LOCK (self); continue; done: if (other_peer != NULL) gst_object_unref (other_peer); if (peer != NULL) gst_object_unref (peer); break; retry: GST_OBJECT_LOCK (self); g_queue_push_head (&self->priv->change_queue, data); goto done; error: /* Handle error */ gst_insert_bin_change_data_complete (self, data, FALSE); GST_OBJECT_LOCK (self); goto done; } next: gst_insert_bin_block_pad_unlock (self); }
/* * debug_dump_element: * @bin: the bin that should be analyzed * @out: file to write to * @indent: level of graph indentation * * Helper for gst_debug_bin_to_dot_file() to recursively dump a pipeline. */ static void debug_dump_element (GstBin * bin, GstDebugGraphDetails details, GString * str, const gint indent) { GstIterator *element_iter, *pad_iter; gboolean elements_done, pads_done; GValue item = { 0, }; GValue item2 = { 0, }; GstElement *element; GstPad *pad = NULL; guint src_pads, sink_pads; gchar *element_name; gchar *state_name = NULL; gchar *param_name = NULL; const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)]; element_iter = gst_bin_iterate_elements (bin); elements_done = FALSE; while (!elements_done) { switch (gst_iterator_next (element_iter, &item)) { case GST_ITERATOR_OK: element = g_value_get_object (&item); element_name = debug_dump_make_object_name (GST_OBJECT (element)); if (details & GST_DEBUG_GRAPH_SHOW_STATES) { state_name = debug_dump_get_element_state (GST_ELEMENT (element)); } if (details & GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS) { param_name = debug_dump_get_element_params (GST_ELEMENT (element), details); } /* elements */ g_string_append_printf (str, "%ssubgraph cluster_%s {\n", spc, element_name); g_string_append_printf (str, "%s fontname=\"Bitstream Vera Sans\";\n", spc); g_string_append_printf (str, "%s fontsize=\"8\";\n", spc); g_string_append_printf (str, "%s style=filled;\n", spc); g_string_append_printf (str, "%s color=black;\n\n", spc); g_string_append_printf (str, "%s label=\"%s\\n%s%s%s\";\n", spc, G_OBJECT_TYPE_NAME (element), GST_OBJECT_NAME (element), (state_name ? state_name : ""), (param_name ? param_name : "") ); if (state_name) { g_free (state_name); state_name = NULL; } if (param_name) { g_free (param_name); param_name = NULL; } g_free (element_name); src_pads = sink_pads = 0; if ((pad_iter = gst_element_iterate_sink_pads (element))) { debug_dump_element_pads (pad_iter, pad, element, details, str, indent, &src_pads, &sink_pads); gst_iterator_free (pad_iter); } if ((pad_iter = gst_element_iterate_src_pads (element))) { debug_dump_element_pads (pad_iter, pad, element, details, str, indent, &src_pads, &sink_pads); gst_iterator_free (pad_iter); } if (GST_IS_BIN (element)) { g_string_append_printf (str, "%s fillcolor=\"#ffffff\";\n", spc); /* recurse */ debug_dump_element (GST_BIN (element), details, str, indent + 1); } else { if (src_pads && !sink_pads) g_string_append_printf (str, "%s fillcolor=\"#ffaaaa\";\n", spc); else if (!src_pads && sink_pads) g_string_append_printf (str, "%s fillcolor=\"#aaaaff\";\n", spc); else if (src_pads && sink_pads) g_string_append_printf (str, "%s fillcolor=\"#aaffaa\";\n", spc); else g_string_append_printf (str, "%s fillcolor=\"#ffffff\";\n", spc); } g_string_append_printf (str, "%s}\n\n", spc); if ((pad_iter = gst_element_iterate_pads (element))) { pads_done = FALSE; while (!pads_done) { switch (gst_iterator_next (pad_iter, &item2)) { case GST_ITERATOR_OK: pad = g_value_get_object (&item2); if (gst_pad_is_linked (pad)) { if (gst_pad_get_direction (pad) == GST_PAD_SRC) { debug_dump_element_pad_link (pad, element, details, str, indent); } else { GstPad *peer_pad = gst_pad_get_peer (pad); if (peer_pad) { if (!GST_IS_GHOST_PAD (peer_pad) && GST_IS_PROXY_PAD (peer_pad)) { debug_dump_element_pad_link (peer_pad, NULL, details, str, indent); } gst_object_unref (peer_pad); } } } g_value_reset (&item2); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (pad_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: pads_done = TRUE; break; } } g_value_unset (&item2); gst_iterator_free (pad_iter); } g_value_reset (&item); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (element_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: elements_done = TRUE; break; } } g_value_unset (&item); gst_iterator_free (element_iter); }