/** * helper for gst_goo_util_find_goo_component() to iterate and search * the members of a bin */ static GooComponent * find_goo_component_in_bin (GstBin *bin, SearchContext *ctx) { GstIterator *itr; gpointer item; GooComponent *component = NULL; GST_INFO ("bin=%s (%s)", gst_element_get_name (bin), G_OBJECT_TYPE_NAME (bin)); /* note: we don't handle the case of the underlying data structure changing * while iterating.. we just bail out and the user needs to restart. */ for( itr = gst_bin_iterate_elements (bin); gst_iterator_next (itr, &item) == GST_ITERATOR_OK && !component; gst_object_unref (item) ) { GstElement *elem = GST_ELEMENT (item); component = check_for_goo_component (elem, ctx); if( component == NULL ) { component = find_goo_component (elem, ctx); } } gst_iterator_free (itr); return component; }
/** * Utility to search the pipeline that @elem is a member of find the element * with the specified @type * * Note: if underlying pipeline structure changes as we iterate thru it, * it could cause us to bail out early before iterating thru the entire * pipeline.. basically the caller should listen for changes to the pipeline * structure, and call this again if new elements are added and the caller * hasn't yet found the peer element it is looking for. */ GooComponent * gst_goo_util_find_goo_component (GstElement *elem, GType type) { SearchContext ctx; /* only needed until this fxn returns, so alloc on stack */ GST_INFO("type=%s", g_type_name(type)); ctx.type = type; ctx.visited_nodes = g_hash_table_new (g_direct_hash, g_direct_equal); GooComponent *component = find_goo_component (elem, &ctx); g_hash_table_destroy (ctx.visited_nodes); return component; }
/** * recursively iterate all our pads and search adjacent elements */ static GooComponent * find_goo_component_in_elem (GstElement *elem, SearchContext *ctx) { GstIterator *itr; gpointer item; GooComponent *component = NULL; /* check if we've already examined this element, to prevent loops: */ if (already_visited (ctx->visited_nodes, elem)) { GST_INFO ("already visited elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem)); return NULL; } GST_INFO ("elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem)); /* note: we don't handle the case of the underlying data structure changing * while iterating.. we just bail out and the user needs to restart. */ for( itr = gst_element_iterate_pads (elem); gst_iterator_next (itr, &item) == GST_ITERATOR_OK && !component; gst_object_unref (item) ) { GstElement *adjacent_elem = NULL; GstPad *pad = GST_PAD (item); GstPad *peer = gst_pad_get_peer (pad); GST_INFO ("found pad: %s (%s)", gst_pad_get_name (pad), G_OBJECT_TYPE_NAME (pad)); if (G_UNLIKELY (peer == NULL)) { GST_INFO ("NULL peer.. not connected yet?"); continue; } /* in the case of GstGhostPad (and probably other proxy pads) * the parent is actually the pad we are a proxy for, so * keep looping until we find the GstElement */ while(TRUE) { GstObject *obj = gst_pad_get_parent (peer); if( GST_IS_PAD(obj) ) { gst_object_unref (peer); peer = GST_PAD (obj); } else { adjacent_elem = GST_ELEMENT (obj); break; } } if (G_UNLIKELY (adjacent_elem == NULL)) { gst_object_unref (peer); GST_INFO ("Cannot find a adjacent element"); continue; } GST_INFO ("found adjacent_elem: %s", gst_element_get_name (adjacent_elem)); component = find_goo_component (adjacent_elem, ctx); /* cleanup: */ gst_object_unref (adjacent_elem); gst_object_unref (peer); } gst_iterator_free (itr); return component; }