/////////////////////////////////////////////////////////////////////////////////////////////////// /// gst_element_get_first_sink_pad() /// /// Get an element's first sink pad by using gst_element_iterate_sink_pads. The pad's ref count is /// NOT incremented. /////////////////////////////////////////////////////////////////////////////////////////////////// GstPad* gst_element_get_first_sink_pad(GstElement* element) { GstIterator *iter = gst_element_iterate_sink_pads(element); GValue vPad = G_VALUE_INIT; GstPad* ret = NULL; if (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK) { ret = GST_PAD(g_value_get_object(&vPad)); } gst_iterator_free(iter); return ret; } // END gst_element_get_first_sink_pad()
/////////////////////////////////////////////////////////////////////////////////////////////////// /// gst_element_count_sink_pads() /// /// Count the element's sink pads by using gst_element_iterate_sink_pads. /////////////////////////////////////////////////////////////////////////////////////////////////// gsize gst_element_count_sink_pads(GstElement* element) { GstIterator *iter = gst_element_iterate_sink_pads(element); GValue vPad = G_VALUE_INIT; gsize ret = 0; while (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK) { ret++; } gst_iterator_free(iter); return ret; } // END gst_element_count_sink_pads()
gboolean kms_element_for_each_sink_pad (GstElement * element, KmsPadCallback action, gpointer data) { GstIterator *it = gst_element_iterate_sink_pads (element); gboolean ret; ret = kms_element_iterate_pads (it, action, data); gst_iterator_free (it); return ret; }
static GstCaps * gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter) { GstCaps *caps = NULL; GstIterator *iter = NULL; GValue v = { 0 }; GstIteratorResult res; GstCaps *peercaps; GstCaps *othercaps; GstCaps *tcaps; peercaps = gst_pad_peer_query_caps (mux->srcpad, filter); if (peercaps) { tcaps = gst_pad_get_pad_template_caps (pad); othercaps = gst_caps_intersect_full (peercaps, tcaps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (peercaps); } else { tcaps = gst_pad_get_pad_template_caps (mux->srcpad); if (filter) othercaps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST); else othercaps = gst_caps_copy (tcaps); } gst_caps_unref (tcaps); clear_caps (othercaps, FALSE); g_value_init (&v, GST_TYPE_CAPS); iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux)); do { gst_value_set_caps (&v, othercaps); res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad); gst_iterator_resync (iter); } while (res == GST_ITERATOR_RESYNC); gst_iterator_free (iter); caps = (GstCaps *) gst_value_get_caps (&v); if (res == GST_ITERATOR_ERROR) { gst_caps_unref (caps); caps = gst_caps_new_empty (); } gst_caps_unref (othercaps); return caps; }
static void release_sink_pads (GstElement * audiomixer) { GValue val = G_VALUE_INIT; GstIterator *it; gboolean done = FALSE; it = gst_element_iterate_sink_pads (audiomixer); do { switch (gst_iterator_next (it, &val)) { case GST_ITERATOR_OK: { GstPad *sinkpad, *srcpad; GstElement *agnosticbin; sinkpad = g_value_get_object (&val); srcpad = gst_pad_get_peer (sinkpad); agnosticbin = gst_pad_get_parent_element (srcpad); GST_DEBUG ("Unlink %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, agnosticbin, audiomixer); if (!gst_pad_unlink (srcpad, sinkpad)) { GST_ERROR ("Can not unlink %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, srcpad, sinkpad); } gst_element_release_request_pad (audiomixer, sinkpad); gst_element_release_request_pad (agnosticbin, srcpad); gst_object_unref (srcpad); gst_object_unref (agnosticbin); g_value_reset (&val); break; } case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: GST_ERROR ("Error iterating over %s's src pads", GST_ELEMENT_NAME (audiomixer)); case GST_ITERATOR_DONE: g_value_unset (&val); done = TRUE; break; } } while (!done); gst_iterator_free (it); }
/* forwards the event to all sinkpads, takes ownership of the * event * * Returns: TRUE if the event could be forwarded on all * sinkpads. */ static gboolean forward_event (GstAdder * adder, GstEvent * event, gboolean flush) { gboolean ret; GstIterator *it; GstIteratorResult ires; GValue vret = { 0 }; EventData data; GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event, GST_EVENT_TYPE_NAME (event)); data.event = event; data.flush = flush; g_value_init (&vret, G_TYPE_BOOLEAN); g_value_set_boolean (&vret, FALSE); it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); while (TRUE) { ires = gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret, &data); switch (ires) { case GST_ITERATOR_RESYNC: GST_WARNING ("resync"); gst_iterator_resync (it); g_value_set_boolean (&vret, TRUE); break; case GST_ITERATOR_OK: case GST_ITERATOR_DONE: ret = g_value_get_boolean (&vret); goto done; default: ret = FALSE; goto done; } } done: gst_iterator_free (it); GST_LOG_OBJECT (adder, "Forwarded event %p (%s), ret=%d", event, GST_EVENT_TYPE_NAME (event), ret); gst_event_unref (event); return ret; }
static gboolean forward_event (GstInterleave * self, GstEvent * event) { GstIterator *it; GValue vret = { 0 }; GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event, GST_EVENT_TYPE_NAME (event)); g_value_init (&vret, G_TYPE_BOOLEAN); g_value_set_boolean (&vret, TRUE); it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret, event); gst_iterator_free (it); gst_event_unref (event); return g_value_get_boolean (&vret); }
/////////////////////////////////////////////////////////////////////////////////////////////////// /// gst_element_find_sink_pad_by_name() /// /// Find an element's sink pad by name by using gst_element_iterate_sink_pads and comparing the /// element's name with that provided. /////////////////////////////////////////////////////////////////////////////////////////////////// GstPad* gst_element_find_sink_pad_by_name(GstElement* element, const gchar* name) { GstIterator *iter = gst_element_iterate_sink_pads(element); GValue vPad = G_VALUE_INIT; GstPad* ret = NULL; while (gst_iterator_next(iter, &vPad) == GST_ITERATOR_OK) { GstPad* pad = GST_PAD(g_value_get_object(&vPad)); const gchar* pad_name = gst_pad_get_name(pad); if (g_strcmp0(pad_name, name) == 0) { ret = pad; } g_free(const_cast<gchar*>(pad_name)); if (ret != NULL) { break; } } gst_iterator_free(iter); return ret; } // END gst_element_find_sink_pad_by_name()
static gboolean fs_funnel_src_event (GstPad * pad, GstEvent * event) { GstElement *funnel; GstIterator *iter; GstPad *sinkpad; gboolean result = FALSE; gboolean done = FALSE; funnel = gst_pad_get_parent_element (pad); g_return_val_if_fail (funnel != NULL, FALSE); iter = gst_element_iterate_sink_pads (funnel); while (!done) { switch (gst_iterator_next (iter, (gpointer) &sinkpad)) { case GST_ITERATOR_OK: gst_event_ref (event); result |= gst_pad_push_event (sinkpad, event); gst_object_unref (sinkpad); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); result = FALSE; break; case GST_ITERATOR_ERROR: GST_WARNING_OBJECT (funnel, "Error iterating sinkpads"); case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iter); gst_object_unref (funnel); gst_event_unref (event); return result; }
static gboolean _gst_context_run_query (GstElement * element, GstQuery * query, GstPadDirection direction) { GstIteratorFoldFunction const func = context_pad_query; GstIterator *it; GValue res = { 0 }; g_value_init (&res, G_TYPE_BOOLEAN); g_value_set_boolean (&res, FALSE); /* Ask neighbour */ if (direction == GST_PAD_SRC) it = gst_element_iterate_src_pads (element); else it = gst_element_iterate_sink_pads (element); while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) gst_iterator_resync (it); gst_iterator_free (it); return g_value_get_boolean (&res); }
static gboolean gst_adder_query_latency (GstAdder * adder, GstQuery * query) { GstClockTime min, max; gboolean live; gboolean res; GstIterator *it; gboolean done; res = TRUE; done = FALSE; live = FALSE; min = 0; max = GST_CLOCK_TIME_NONE; /* Take maximum of all latency values */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); while (!done) { GstIteratorResult ires; gpointer item; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (item); GstQuery *peerquery; GstClockTime min_cur, max_cur; gboolean live_cur; peerquery = gst_query_new_latency (); /* Ask peer for latency */ res &= gst_pad_peer_query (pad, peerquery); /* take max from all valid return values */ if (res) { gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur); if (min_cur > min) min = min_cur; if (max_cur != GST_CLOCK_TIME_NONE && ((max != GST_CLOCK_TIME_NONE && max_cur > max) || (max == GST_CLOCK_TIME_NONE))) max = max_cur; live = live || live_cur; } gst_query_unref (peerquery); gst_object_unref (pad); break; } case GST_ITERATOR_RESYNC: live = FALSE; min = 0; max = GST_CLOCK_TIME_NONE; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) { /* store the results */ GST_DEBUG_OBJECT (adder, "Calculated total latency: live %s, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } return res; }
static void suboverlay_child_added_cb (GstElement * suboverlay, GstElement * child, InsanityTest * test) { GstIterator *it = NULL; GstPad *render_sub_sink, *tmppad; GstElementFactory *fact; const gchar *klass, *name; gulong probe_id; GValue value = { 0, }; gboolean is_renderer = FALSE; /* cc-ed from -base/gstsubtitleoveraly.c */ fact = gst_element_get_factory (child); klass = gst_element_factory_get_metadata (fact, GST_ELEMENT_METADATA_KLASS); if (GST_IS_BIN (child)) return; name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (fact)); if (g_strrstr (klass, "Overlay/Subtitle") != NULL || g_strrstr (klass, "Overlay/SubPicture") != NULL) is_renderer = TRUE; else if (g_strcmp0 (name, "textoverlay") == 0) is_renderer = TRUE; if (is_renderer == FALSE) goto done; LOG (test, "Renderer found: %s", name); /* Now adding the probe to the renderer "subtitle" sink pad */ it = gst_element_iterate_sink_pads (child); if (gst_iterator_find_custom (it, (GCompareFunc) find_renderer_subtitle_sinkpad, &value, NULL)) { render_sub_sink = g_value_get_object (&value); } else { goto done; } if (insanity_gst_test_add_data_probe (INSANITY_GST_TEST (test), GST_BIN (glob_pipeline), GST_OBJECT_NAME (child), GST_ELEMENT_NAME (render_sub_sink), &tmppad, &probe_id, &renderer_probe_cb, NULL, NULL) == TRUE) { glob_renderer_sink_probe = g_slice_new0 (ProbeContext); glob_renderer_sink_probe->probe_id = probe_id; glob_renderer_sink_probe->pad = render_sub_sink; glob_renderer_sink_probe->element = child; glob_renderer_sink_probe->test = test; glob_renderer_sink_probe->waiting_first_segment = TRUE; insanity_test_validate_checklist_item (test, "install-probes", TRUE, NULL); } else { insanity_test_validate_checklist_item (test, "install-probes", FALSE, "Failed to attach probe to fakesink"); insanity_test_done (test); goto done; } done: if (it) gst_iterator_free (it); }
/* FIXME, the duration query should reflect how long you will produce * data, that is the amount of stream time until you will emit EOS. * * For synchronized mixing this is always the max of all the durations * of upstream since we emit EOS when all of them finished. * * We don't do synchronized mixing so this really depends on where the * streams where punched in and what their relative offsets are against * eachother which we can get from the first timestamps we see. * * When we add a new stream (or remove a stream) the duration might * also become invalid again and we need to post a new DURATION * message to notify this fact to the parent. * For now we take the max of all the upstream elements so the simple * cases work at least somewhat. */ static gboolean gst_adder_query_duration (GstAdder * adder, GstQuery * query) { gint64 max; gboolean res; GstFormat format; GstIterator *it; gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); max = -1; res = TRUE; done = FALSE; it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); while (!done) { GstIteratorResult ires; gpointer item; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (item); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_query_peer_duration (pad, &format, &duration); /* take max from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { max = duration; done = TRUE; } /* else see if bigger than current max */ else if (duration > max) max = duration; } gst_object_unref (pad); break; } case GST_ITERATOR_RESYNC: max = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) { /* and store the max */ GST_DEBUG_OBJECT (adder, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max)); gst_query_set_duration (query, format, max); } return res; }
/** * gst_aggregator_iterate_sinkpads: * @self: The #GstAggregator * @func: The function to call. * @user_data: The data to pass to @func. * * Iterate the sinkpads of aggregator to call a function on them. * * This method guarantees that @func will be called only once for each * sink pad. */ gboolean gst_aggregator_iterate_sinkpads (GstAggregator * self, GstAggregatorPadForeachFunc func, gpointer user_data) { gboolean result = FALSE; GstIterator *iter; gboolean done = FALSE; GValue item = { 0, }; GList *seen_pads = NULL; iter = gst_element_iterate_sink_pads (GST_ELEMENT (self)); if (!iter) goto no_iter; while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: { GstPad *pad; pad = g_value_get_object (&item); /* if already pushed, skip. FIXME, find something faster to tag pads */ if (pad == NULL || g_list_find (seen_pads, pad)) { g_value_reset (&item); break; } GST_LOG_OBJECT (self, "calling function on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); result = func (self, pad, user_data); done = !result; seen_pads = g_list_prepend (seen_pads, pad); g_value_reset (&item); break; } case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: GST_ERROR_OBJECT (self, "Could not iterate over internally linked pads"); done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } g_value_unset (&item); gst_iterator_free (iter); if (seen_pads == NULL) { GST_DEBUG_OBJECT (self, "No pad seen"); return FALSE; } g_list_free (seen_pads); no_iter: return result; }
static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout) { GstIterator *it; BOOL done = FALSE, found = FALSE; int ret; TRACE("%p %p %p %p\n", This, amt, capsin, capsout); mark_wine_thread(); This->filter = gst_element_factory_make(This->gstreamer_name, NULL); if (!This->filter) { FIXME("Could not make %s filter\n", This->gstreamer_name); return E_FAIL; } This->my_src = gst_pad_new("yuvsrc", GST_PAD_SRC); gst_pad_set_element_private (This->my_src, This); gst_pad_set_active(This->my_src, 1); This->my_sink = gst_pad_new("yuvsink", GST_PAD_SINK); gst_pad_set_chain_function(This->my_sink, got_data_wrapper); gst_pad_set_element_private (This->my_sink, This); gst_pad_set_active(This->my_sink, 1); it = gst_element_iterate_sink_pads(This->filter); while (!done) { GValue item = {0}; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_sink = g_value_get_object(&item); gst_object_ref(This->their_sink); g_value_reset(&item); case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free(it); if (!This->their_sink) { ERR("Could not find sink on filter %s\n", This->gstreamer_name); return E_FAIL; } it = gst_element_iterate_src_pads(This->filter); gst_iterator_resync(it); done = FALSE; while (!done) { GValue item = {0}; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_src = g_value_get_object(&item); gst_object_ref(This->their_src); g_value_reset(&item); case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free(it); found = !!This->their_src; if (!found) g_signal_connect(This->filter, "pad-added", G_CALLBACK(Gstreamer_transform_pad_added_wrapper), This); ret = gst_pad_link(This->my_src, This->their_sink); if (ret < 0) { WARN("Failed to link with %i\n", ret); return E_FAIL; } ret = gst_pad_set_caps(This->my_src, capsin); if (ret < 0) { WARN("Failed to set caps on own source with %i\n", ret); return E_FAIL; } if (found) Gstreamer_transform_pad_added(This->filter, This->their_src, This); if (!gst_pad_is_linked(This->my_sink)) return E_FAIL; ret = gst_pad_set_caps(This->my_sink, capsout); if (ret < 0) { WARN("Failed to set caps on own sink with %i\n", ret); return E_FAIL; } TRACE("Connected\n"); return S_OK; }
static gboolean validate_codec_profile (FsCodec *codec,const gchar *bin_description, gboolean is_send) { GError *error = NULL; GstElement *bin = NULL; guint src_pad_count = 0, sink_pad_count = 0; GstCaps *caps; gpointer matching_pad = NULL; GstIterator *iter; bin = parse_bin_from_description_all_linked (bin_description, &src_pad_count, &sink_pad_count, &error); /* if could not build bin, fail */ if (!bin) { GST_WARNING ("Could not build profile (%s): %s", bin_description, error->message); g_clear_error (&error); return FALSE; } g_clear_error (&error); caps = fs_codec_to_gst_caps (codec); if (is_send) iter = gst_element_iterate_src_pads (bin); else iter = gst_element_iterate_sink_pads (bin); matching_pad = gst_iterator_find_custom (iter, find_matching_pad, caps); gst_iterator_free (iter); if (!matching_pad) { GST_WARNING ("Invalid profile (%s), has no %s pad that matches the codec" " details", is_send ? "src" : "sink", bin_description); gst_caps_unref (caps); gst_object_unref (bin); return FALSE; } gst_caps_unref (caps); gst_object_unref (bin); if (is_send) { if (src_pad_count == 0) { GST_WARNING ("Invalid profile (%s), has 0 src pad", bin_description); return FALSE; } } else { if (src_pad_count != 1) { GST_WARNING ("Invalid profile (%s), has %u src pads, should have one", bin_description, src_pad_count); return FALSE; } } if (sink_pad_count != 1) { GST_WARNING ("Invalid profile (%s), has %u sink pads, should have one", bin_description, sink_pad_count); return FALSE; } return TRUE; }
static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout) { GstIterator *it; int done = 0, found = 0, ret; This->filter = gst_element_factory_make(This->gstreamer_name, NULL); if (!This->filter) { FIXME("Could not make %s filter\n", This->gstreamer_name); return E_FAIL; } This->my_src = gst_pad_new(NULL, GST_PAD_SRC); gst_pad_set_element_private (This->my_src, This); This->my_sink = gst_pad_new(NULL, GST_PAD_SINK); gst_pad_set_chain_function(This->my_sink, got_data); gst_pad_set_bufferalloc_function(This->my_sink, request_buffer); gst_pad_set_element_private (This->my_sink, This); ret = gst_pad_set_caps(This->my_src, capsin); if (ret < 0) { WARN("Failed to set caps on own source with %i\n", ret); return E_FAIL; } ret = gst_pad_set_caps(This->my_sink, capsout); if (ret < 0) { WARN("Failed to set caps on own sink with %i\n", ret); return E_FAIL; } it = gst_element_iterate_sink_pads(This->filter); while (!done) { gpointer item; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_sink = item; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = 1; break; } } gst_iterator_free(it); if (!This->their_sink) { ERR("Could not find sink on filter %s\n", This->gstreamer_name); return E_FAIL; } it = gst_element_iterate_src_pads(This->filter); gst_iterator_resync(it); done = 0; while (!done) { gpointer item; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_src = item; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = 1; break; } } gst_iterator_free(it); found = !!This->their_src; if (!found) g_signal_connect(This->filter, "pad-added", G_CALLBACK(Gstreamer_transform_pad_added), This); ret = gst_pad_link(This->my_src, This->their_sink); if (ret < 0) { WARN("Failed to link with %i\n", ret); return E_FAIL; } if (found) Gstreamer_transform_pad_added(This->filter, This->their_src, This); if (!gst_pad_is_linked(This->my_sink)) return E_FAIL; TRACE("Connected\n"); return S_OK; }
static gboolean gst_live_adder_query_pos_dur (GstLiveAdder * adder, GstFormat informat, gboolean position, gint64 * outvalue) { gint64 max = G_MININT64; gboolean res = TRUE; GstIterator *it; gboolean done = FALSE; it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); while (!done) { GstIteratorResult ires; gpointer item; GstFormat format = informat; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (item); gint64 value; gboolean curres; /* ask sink peer for duration */ if (position) curres = gst_pad_query_peer_position (pad, &format, &value); else curres = gst_pad_query_peer_duration (pad, &format, &value); /* take max from all valid return values */ /* Only if the format is the one we requested, otherwise ignore it ? */ if (curres && format == informat) { res &= curres; /* valid unknown length, stop searching */ if (value == -1) { max = value; done = TRUE; } else if (value > max) { max = value; } } break; } case GST_ITERATOR_RESYNC: max = -1; res = TRUE; break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) *outvalue = max; return res; }
static gboolean gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query) { gint64 max; gboolean res; GstFormat format; GstIterator *it; gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); max = -1; res = TRUE; done = FALSE; /* Take maximum of all durations */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); while (!done) { GstIteratorResult ires; GValue item = { 0, }; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item)); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_peer_query_duration (pad, format, &duration); /* take max from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { max = duration; done = TRUE; } /* else see if bigger than current max */ else if (duration > max) max = duration; } gst_object_unref (pad); g_value_unset (&item); break; } case GST_ITERATOR_RESYNC: max = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) { /* If in bytes format we have to multiply with the number of channels * to get the correct results. All other formats should be fine */ if (format == GST_FORMAT_BYTES && max != -1) max *= self->channels; /* and store the max */ GST_DEBUG_OBJECT (self, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max)); gst_query_set_duration (query, format, max); } return res; }
/* * 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); }
static gboolean gst_frei0r_mixer_src_query_duration (GstFrei0rMixer * self, GstQuery * query) { gint64 min; gboolean res; GstFormat format; GstIterator *it; gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); min = -1; res = TRUE; done = FALSE; /* Take minimum of all durations */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); while (!done) { GstIteratorResult ires; GValue item = { 0 }; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&item); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_peer_query_duration (pad, format, &duration); /* take min from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { min = duration; done = TRUE; } /* else see if smaller than current min */ else if (duration < min) min = duration; } g_value_reset (&item); break; } case GST_ITERATOR_RESYNC: min = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } g_value_unset (&item); } gst_iterator_free (it); if (res) { /* and store the min */ GST_DEBUG_OBJECT (self, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (min)); gst_query_set_duration (query, format, min); } return res; }
/* Fetches a compatible pad on the target element which isn't already * linked */ static GstPad * get_compatible_unlinked_pad (GstElement * element, GstPad * pad) { GstPad *res = NULL; GstIterator *pads; gboolean done = FALSE; GstCaps *srccaps; if (G_UNLIKELY (pad == NULL)) goto no_pad; GST_DEBUG ("element : %s, pad %s:%s", GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad)); if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) pads = gst_element_iterate_sink_pads (element); else pads = gst_element_iterate_src_pads (element); srccaps = gst_pad_get_caps_reffed (pad); GST_DEBUG ("srccaps %" GST_PTR_FORMAT, srccaps); while (!done) { gpointer padptr; switch (gst_iterator_next (pads, &padptr)) { case GST_ITERATOR_OK: { GstPad *testpad = (GstPad *) padptr; if (gst_pad_is_linked (testpad)) { gst_object_unref (testpad); } else { GstCaps *sinkcaps = gst_pad_get_caps_reffed (testpad); GST_DEBUG ("sinkccaps %" GST_PTR_FORMAT, sinkcaps); if (gst_caps_can_intersect (srccaps, sinkcaps)) { res = testpad; done = TRUE; } else gst_object_unref (testpad); gst_caps_unref (sinkcaps); } } break; case GST_ITERATOR_DONE: case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_RESYNC: gst_iterator_resync (pads); break; } } gst_iterator_free (pads); gst_caps_unref (srccaps); return res; no_pad: { GST_ERROR ("No pad to check against"); return NULL; } }
static gboolean mpegtsmux_src_event (GstPad * pad, GstEvent * event) { MpegTsMux *mux = GST_MPEG_TSMUX (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_UPSTREAM: { GstIterator *iter; GstIteratorResult iter_ret; GstPad *sinkpad; GstClockTime running_time; gboolean all_headers, done; guint count; if (!gst_video_event_is_force_key_unit (event)) break; gst_video_event_parse_upstream_force_key_unit (event, &running_time, &all_headers, &count); GST_INFO_OBJECT (mux, "received upstream force-key-unit event, " "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d", gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), all_headers, count); if (!all_headers) break; mux->pending_key_unit_ts = running_time; gst_event_replace (&mux->force_key_unit_event, event); iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux)); done = FALSE; while (!done) { gboolean res = FALSE, tmp; iter_ret = gst_iterator_next (iter, (gpointer *) & sinkpad); switch (iter_ret) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: GST_INFO_OBJECT (mux, "forwarding to %s", gst_pad_get_name (sinkpad)); tmp = gst_pad_push_event (sinkpad, gst_event_ref (event)); GST_INFO_OBJECT (mux, "result %d", tmp); /* succeed if at least one pad succeeds */ res |= tmp; gst_object_unref (sinkpad); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_RESYNC: break; } } gst_event_unref (event); break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (mux); return res; }
static HRESULT WINAPI Gstreamer_YUV_SetMediaType(TransformFilter *tf, PIN_DIRECTION dir, const AM_MEDIA_TYPE *amt) { GstTfImpl *This = (GstTfImpl*)tf; GstCaps *capsin, *capsout; AM_MEDIA_TYPE *outpmt = &This->tf.pmt; HRESULT hr; int avgtime; LONG width, height; if (dir != PINDIR_INPUT) return S_OK; if (Gstreamer_YUV_QueryConnect(&This->tf, amt) == S_FALSE || !amt->pbFormat) return E_FAIL; FreeMediaType(outpmt); CopyMediaType(outpmt, amt); if (IsEqualGUID(&amt->formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *vih = (VIDEOINFOHEADER*)outpmt->pbFormat; avgtime = vih->AvgTimePerFrame; width = vih->bmiHeader.biWidth; height = vih->bmiHeader.biHeight; if (vih->bmiHeader.biHeight > 0) vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; vih->bmiHeader.biBitCount = 24; vih->bmiHeader.biCompression = BI_RGB; vih->bmiHeader.biSizeImage = width * abs(height) * 3; } else { VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2*)outpmt->pbFormat; avgtime = vih->AvgTimePerFrame; width = vih->bmiHeader.biWidth; height = vih->bmiHeader.biHeight; if (vih->bmiHeader.biHeight > 0) vih->bmiHeader.biHeight = -vih->bmiHeader.biHeight; vih->bmiHeader.biBitCount = 24; vih->bmiHeader.biCompression = BI_RGB; vih->bmiHeader.biSizeImage = width * abs(height) * 3; } if (!avgtime) avgtime = 10000000 / 30; outpmt->subtype = MEDIASUBTYPE_RGB24; capsin = gst_caps_new_simple("video/x-raw-yuv", "format", GST_TYPE_FOURCC, amt->subtype.Data1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, 10000000, (int)avgtime, NULL); capsout = gst_caps_new_simple("video/x-raw-rgb", "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24, "endianness", G_TYPE_INT, 4321, "red_mask", G_TYPE_INT, 0xff, "green_mask", G_TYPE_INT, 0xff00, "blue_mask", G_TYPE_INT, 0xff0000, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, 10000000, (int)avgtime, NULL); This->filter2 = gst_element_factory_make("videoflip", NULL); if (This->filter2) { GstIterator *it; int done = 0; g_object_set(This->filter2, "method", 5, NULL); it = gst_element_iterate_sink_pads(This->filter2); while (!done) { gpointer item; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_sink2 = item; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = 1; break; } } gst_iterator_free(it); done = 0; it = gst_element_iterate_src_pads(This->filter2); while (!done) { gpointer item; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: This->their_src2 = item; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = 1; break; } } gst_iterator_free(it); if (!This->their_src2 || !This->their_sink2) { if (This->their_src2) gst_object_unref(This->their_src2); if (This->their_sink2) gst_object_unref(This->their_sink2); gst_object_unref(This->filter2); This->filter2 = 0; } } hr = Gstreamer_transform_ConnectInput(This, amt, capsin, capsout); gst_caps_unref(capsin); gst_caps_unref(capsout); This->cbBuffer = width * height * 4; return hr; }
/** * gst_composite_adjust_pip: * @param composite The GstComposite instance * @param x the X position of the PIP * @param y the Y position of the PIP * @param w the width of the PIP * @param h the height of the PIP * @return PIP has been changed succefully * * Change the PIP position and size. */ gboolean gst_composite_adjust_pip (GstComposite * composite, gint x, gint y, gint w, gint h) { gboolean result = FALSE; GstIterator *iter = NULL; GValue value = { 0 }; GstElement *element = NULL; gboolean done = FALSE; g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE); GST_COMPOSITE_LOCK (composite); if (composite->adjusting) { WARN ("last PIP adjustment request is progressing"); goto end; } composite->b_x = x; composite->b_y = y; if (composite->b_width != w || composite->b_height != h) { composite->b_width = w; composite->b_height = h; composite->adjusting = TRUE; gst_worker_stop (GST_WORKER (composite)); result = TRUE; goto end; } element = gst_worker_get_element (GST_WORKER (composite), "mix"); iter = gst_element_iterate_sink_pads (element); while (iter && !done) { switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&value); if (g_strcmp0 (gst_pad_get_name (pad), "sink_1") == 0) { g_object_set (pad, "xpos", composite->b_x, "ypos", composite->b_y, NULL); done = TRUE; result = TRUE; } g_value_reset (&value); } break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); break; case GST_ITERATOR_DONE: done = TRUE; break; default: /* iterator returned _ERROR or premature end with _OK, * mark an error and exit */ done = TRUE; result = FALSE; break; } } if (G_IS_VALUE (&value)) g_value_unset (&value); if (iter) gst_iterator_free (iter); composite->adjusting = FALSE; /* if (!result) { WARN ("failed to adjust PIP: %d, %d, %d, %d", x, y, w, h); } */ end: GST_COMPOSITE_UNLOCK (composite); return result; }
static gboolean gst_live_adder_query (GstPad * pad, GstQuery * query) { GstLiveAdder *adder; gboolean res = FALSE; adder = GST_LIVE_ADDER (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { /* We need to send the query upstream and add the returned latency to our * own */ GstClockTime min_latency = 0, max_latency = G_MAXUINT64; gpointer item; GstIterator *iter = NULL; gboolean done = FALSE; iter = gst_element_iterate_sink_pads (GST_ELEMENT (adder)); while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: { GstPad *sinkpad = item; GstClockTime pad_min_latency, pad_max_latency; gboolean pad_us_live; if (gst_pad_peer_query (sinkpad, query)) { gst_query_parse_latency (query, &pad_us_live, &pad_min_latency, &pad_max_latency); res = TRUE; GST_DEBUG_OBJECT (adder, "Peer latency for pad %s: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_PAD_NAME (sinkpad), GST_TIME_ARGS (pad_min_latency), GST_TIME_ARGS (pad_max_latency)); min_latency = MAX (pad_min_latency, min_latency); max_latency = MIN (pad_max_latency, max_latency); } gst_object_unref (item); } break; case GST_ITERATOR_RESYNC: min_latency = 0; max_latency = G_MAXUINT64; gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: GST_ERROR_OBJECT (adder, "Error looping sink pads"); done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iter); if (res) { GstClockTime my_latency = adder->latency_ms * GST_MSECOND; GST_OBJECT_LOCK (adder); adder->peer_latency = min_latency; min_latency += my_latency; GST_OBJECT_UNLOCK (adder); /* Make sure we don't risk an overflow */ if (max_latency < G_MAXUINT64 - my_latency) max_latency += my_latency; else max_latency = G_MAXUINT64; gst_query_set_latency (query, TRUE, min_latency, max_latency); GST_DEBUG_OBJECT (adder, "Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); } break; } case GST_QUERY_DURATION: res = gst_live_adder_query_duration (adder, query); break; case GST_QUERY_POSITION: res = gst_live_adder_query_position (adder, query); break; default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (adder); return res; }