static void gst_validate_element_set_media_descriptor (GstValidateMonitor * monitor, GstValidateMediaDescriptor * media_descriptor) { gboolean done; GstPad *pad; GstValidateMonitor *pmonitor; GstIterator *iterator; GstElement *elem = GST_ELEMENT (gst_validate_monitor_get_target (monitor)); iterator = gst_element_iterate_pads (elem); gst_object_unref (elem); done = FALSE; while (!done) { GValue value = { 0, }; switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: pad = g_value_get_object (&value); pmonitor = g_object_get_data ((GObject *) pad, "validate-monitor"); if (pmonitor) gst_validate_monitor_set_media_descriptor (pmonitor, media_descriptor); g_value_reset (&value); break; case GST_ITERATOR_RESYNC: /* TODO how to handle this? */ gst_iterator_resync (iterator); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iterator); }
static void _bin_unparented_cb (GstObject *object, GstObject *parent, gpointer user_data) { GstIterator *iter = NULL; gboolean done; /* Return if there was no handler connected */ if (g_signal_handlers_disconnect_by_func (object, _element_added_callback, user_data) == 0) return; iter = gst_bin_iterate_elements (GST_BIN (object)); done = FALSE; while (!done) { gpointer item; switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: if (GST_IS_BIN (item)) _bin_unparented_cb (GST_OBJECT (item), object, user_data); gst_object_unref (item); break; case GST_ITERATOR_RESYNC: // We don't rollback anything, we just ignore already processed ones gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: g_error ("Wrong parameters were given?"); done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iter); }
static void debug_dump_element_pads (GstIterator * pad_iter, GstPad * pad, GstElement * element, GstDebugGraphDetails details, GString * str, const gint indent, guint * num_pads, gchar * cluster_name, gchar ** first_pad_name) { GValue item = { 0, }; gboolean pads_done; const gchar *spc = MAKE_INDENT (indent); pads_done = FALSE; while (!pads_done) { switch (gst_iterator_next (pad_iter, &item)) { case GST_ITERATOR_OK: pad = g_value_get_object (&item); if (!*num_pads) { g_string_append_printf (str, "%ssubgraph cluster_%s {\n", spc, cluster_name); g_string_append_printf (str, "%s label=\"\";\n", spc); g_string_append_printf (str, "%s style=\"invis\";\n", spc); (*first_pad_name) = debug_dump_make_object_name (GST_OBJECT (pad)); } debug_dump_element_pad (pad, element, details, str, indent); (*num_pads)++; g_value_reset (&item); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (pad_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: pads_done = TRUE; break; } } if (*num_pads) { g_string_append_printf (str, "%s}\n\n", spc); } }
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); }
/* * 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, FILE * out, const gint indent) { GstIterator *element_iter, *pad_iter; gboolean elements_done, pads_done; GstElement *element, *peer_element, *target_element; GstPad *pad, *peer_pad, *target_pad; GstPadDirection dir; GstCaps *caps; GstStructure *structure; gboolean free_caps, free_media; guint src_pads, sink_pads; gchar *media = NULL; gchar *pad_name, *element_name; gchar *peer_pad_name, *peer_element_name; gchar *target_pad_name, *target_element_name; gchar *color_name; gchar *state_name = NULL; gchar *param_name = NULL; gchar *spc = NULL; spc = g_malloc (1 + indent * 2); memset (spc, 32, indent * 2); spc[indent * 2] = '\0'; element_iter = gst_bin_iterate_elements (bin); elements_done = FALSE; while (!elements_done) { switch (gst_iterator_next (element_iter, (gpointer) & element)) { case GST_ITERATOR_OK: 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)); } /* elements */ fprintf (out, "%ssubgraph cluster_%s {\n", spc, element_name); fprintf (out, "%s fontname=\"Bitstream Vera Sans\";\n", spc); fprintf (out, "%s fontsize=\"8\";\n", spc); fprintf (out, "%s style=filled;\n", spc); fprintf (out, "%s color=black;\n\n", spc); fprintf (out, "%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_pads (element))) { pads_done = FALSE; while (!pads_done) { switch (gst_iterator_next (pad_iter, (gpointer) & pad)) { case GST_ITERATOR_OK: dir = gst_pad_get_direction (pad); pad_name = debug_dump_make_object_name (GST_OBJECT (pad)); element_name = debug_dump_make_object_name (GST_OBJECT (element)); if (GST_IS_GHOST_PAD (pad)) { color_name = (dir == GST_PAD_SRC) ? "#ffdddd" : ((dir == GST_PAD_SINK) ? "#ddddff" : "#ffffff"); } else { color_name = (dir == GST_PAD_SRC) ? "#ffaaaa" : ((dir == GST_PAD_SINK) ? "#aaaaff" : "#cccccc"); } /* pads */ fprintf (out, "%s %s_%s [color=black, fillcolor=\"%s\", label=\"%s\"];\n", spc, element_name, pad_name, color_name, GST_OBJECT_NAME (pad)); if (dir == GST_PAD_SRC) src_pads++; else if (dir == GST_PAD_SINK) sink_pads++; g_free (pad_name); g_free (element_name); gst_object_unref (pad); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (pad_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: pads_done = TRUE; break; } } gst_iterator_free (pad_iter); } if (GST_IS_BIN (element)) { fprintf (out, "%s fillcolor=\"#ffffff\";\n", spc); /* recurse */ debug_dump_element (GST_BIN (element), details, out, indent + 1); } else { if (src_pads && !sink_pads) fprintf (out, "%s fillcolor=\"#ffaaaa\";\n", spc); else if (!src_pads && sink_pads) fprintf (out, "%s fillcolor=\"#aaaaff\";\n", spc); else if (src_pads && sink_pads) fprintf (out, "%s fillcolor=\"#aaffaa\";\n", spc); else fprintf (out, "%s fillcolor=\"#ffffff\";\n", spc); } fprintf (out, "%s}\n\n", spc); if ((pad_iter = gst_element_iterate_pads (element))) { pads_done = FALSE; while (!pads_done) { switch (gst_iterator_next (pad_iter, (gpointer) & pad)) { case GST_ITERATOR_OK: if (gst_pad_is_linked (pad) && gst_pad_get_direction (pad) == GST_PAD_SRC) { if ((peer_pad = gst_pad_get_peer (pad))) { free_media = FALSE; if ((details & GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE) || (details & GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS) ) { if ((caps = gst_pad_get_negotiated_caps (pad))) { free_caps = TRUE; } else { free_caps = FALSE; if (!(caps = (GstCaps *) gst_pad_get_pad_template_caps (pad))) { /* this should not happen */ media = "?"; } } if (caps) { if (details & GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS) { gchar *tmp = g_strdelimit (gst_caps_to_string (caps), ",", '\n'); media = g_strescape (tmp, NULL); free_media = TRUE; g_free (tmp); } else { if (GST_CAPS_IS_SIMPLE (caps)) { structure = gst_caps_get_structure (caps, 0); media = (gchar *) gst_structure_get_name (structure); } else media = "*"; } if (free_caps) { gst_caps_unref (caps); } } } pad_name = debug_dump_make_object_name (GST_OBJECT (pad)); element_name = debug_dump_make_object_name (GST_OBJECT (element)); peer_pad_name = debug_dump_make_object_name (GST_OBJECT (peer_pad)); if ((peer_element = gst_pad_get_parent_element (peer_pad))) { peer_element_name = debug_dump_make_object_name (GST_OBJECT (peer_element)); } else { peer_element_name = ""; } /* pad link */ if (media) { fprintf (out, "%s%s_%s -> %s_%s [label=\"%s\"]\n", spc, element_name, pad_name, peer_element_name, peer_pad_name, media); if (free_media) { g_free (media); } } else { fprintf (out, "%s%s_%s -> %s_%s\n", spc, element_name, pad_name, peer_element_name, peer_pad_name); } if (GST_IS_GHOST_PAD (pad)) { if ((target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)))) { target_pad_name = debug_dump_make_object_name (GST_OBJECT (target_pad)); if ((target_element = gst_pad_get_parent_element (target_pad))) { target_element_name = debug_dump_make_object_name (GST_OBJECT (target_element)); } else { target_element_name = ""; } /* src ghostpad relationship */ fprintf (out, "%s%s_%s -> %s_%s [style=dashed]\n", spc, target_element_name, target_pad_name, element_name, pad_name); g_free (target_pad_name); if (target_element) { g_free (target_element_name); gst_object_unref (target_element); } gst_object_unref (target_pad); } } if (GST_IS_GHOST_PAD (peer_pad)) { if ((target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer_pad)))) { target_pad_name = debug_dump_make_object_name (GST_OBJECT (target_pad)); if ((target_element = gst_pad_get_parent_element (target_pad))) { target_element_name = debug_dump_make_object_name (GST_OBJECT (target_element)); } else { target_element_name = ""; } /* sink ghostpad relationship */ fprintf (out, "%s%s_%s -> %s_%s [style=dashed]\n", spc, peer_element_name, peer_pad_name, target_element_name, target_pad_name); g_free (target_pad_name); if (target_element) { g_free (target_element_name); gst_object_unref (target_element); } gst_object_unref (target_pad); } } g_free (pad_name); g_free (element_name); g_free (peer_pad_name); if (peer_element) { g_free (peer_element_name); gst_object_unref (peer_element); } gst_object_unref (peer_pad); } } gst_object_unref (pad); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (pad_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: pads_done = TRUE; break; } } gst_iterator_free (pad_iter); } gst_object_unref (element); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (element_iter); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: elements_done = TRUE; break; } } gst_iterator_free (element_iter); g_free (spc); }
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 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 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_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 check_and_remove_input_selector_counters (GstElement * element, gchar ** error_message) { GstIterator *iterator; gboolean done = FALSE; GstPad *pad; GValue value = { 0, }; guint id, ncounters = 0, total_sink_count = 0; BufferCountData *bcd, **bcds = g_malloc0 (sizeof (BufferCountData *) * element->numpads); gboolean ret = TRUE; /* First gather all counts, and free memory, etc */ iterator = gst_element_iterate_pads (element); while (!done) { switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: pad = g_value_get_object (&value); bcd = g_object_get_data (G_OBJECT (pad), "buffer-count-data"); if (GST_PAD_IS_SINK (pad)) { bcds[++ncounters] = bcd; total_sink_count += bcd->counter; } else { bcds[0] = bcd; } gst_pad_remove_probe (pad, bcd->probe_id); g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iterator); break; case GST_ITERATOR_ERROR: done = TRUE; *error_message = g_strdup ("Failed to iterate through pads"); ret = FALSE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iterator); if (!ret) { g_free (bcds); return FALSE; } /* Now bcd[0] contains the total number of buffers received, and subsequent bcd slots contain the total number of buffers sent by each source pad. Check that the totals match, and that every source pad got at least one buffer. Or that's the theory. It doesn't work in practice, the number of raw buffers flowing is non deterministic. */ #if 0 if (bcds[0]->counter != total_sink_count) { *error_message = g_strdup_printf ("%u buffers received, %u buffers sent", total_sink_count, bcds[0]->counter); ret = FALSE; } for (id = 1; id < element->numpads; ++id) { if (bcds[id]->counter == 0) { *error_message = g_strdup_printf ("Sink pad %s got no buffers", GST_PAD_NAME (bcds[id]->pad)); ret = FALSE; } } #endif /* We at least check that at least one buffer was sent while the selected sink was a given sink, for all sinks */ for (id = 1; id < element->numpads; ++id) { if (bcds[id]->back_counter == 0) { *error_message = g_strdup_printf ("No buffer was sent while sink pad %s was active", GST_PAD_NAME (bcds[id]->pad)); ret = FALSE; } } for (id = 0; id < element->numpads; ++id) { gst_object_unref (bcds[id]->pad); g_slice_free (BufferCountData, bcds[id]); } g_free (bcds); return ret; }
static gboolean gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) { GstIterator *iterator; gboolean done; GstPad *pad; GstValidateElementMonitor *elem_monitor; GstElement *element; GstObject *target = gst_validate_monitor_get_target (monitor); if (!GST_IS_ELEMENT (target)) { gst_object_unref (target); GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " "type of object"); return FALSE; } elem_monitor = GST_VALIDATE_ELEMENT_MONITOR_CAST (monitor); GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, target); element = GST_ELEMENT_CAST (target); if (g_object_get_data ((GObject *) element, "validate-monitor")) { GST_DEBUG_OBJECT (elem_monitor, "Pad already has a validate-monitor associated"); gst_object_unref (target); return FALSE; } gst_validate_element_monitor_inspect (elem_monitor); elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", G_CALLBACK (_validate_element_pad_added), monitor); iterator = gst_element_iterate_pads (element); done = FALSE; while (!done) { GValue value = { 0, }; switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: pad = g_value_get_object (&value); gst_validate_element_monitor_wrap_pad (elem_monitor, pad); g_value_reset (&value); break; case GST_ITERATOR_RESYNC: /* TODO how to handle this? */ gst_iterator_resync (iterator); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (iterator); gst_object_unref (target); set_config_properties (monitor, element); return TRUE; }
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; }
static GstElement *find_color_balance_element() { GstIterator *iterator = gst_bin_iterate_all_by_interface( GST_BIN(pipeline), GST_TYPE_COLOR_BALANCE); GstElement *color_balance_element = NULL; gboolean done = FALSE, hardware = FALSE; #if GST_CHECK_VERSION(1, 0, 0) GValue item = G_VALUE_INIT; #else gpointer item; #endif while (!done) { switch (gst_iterator_next(iterator, &item)) { case GST_ITERATOR_OK : { #if GST_CHECK_VERSION(1, 0, 0) GstElement *element = g_value_get_object(&item); #else GstElement *element = GST_ELEMENT(item); #endif if (is_valid_color_balance_element(element)) { if (!color_balance_element) { color_balance_element = GST_ELEMENT_CAST( gst_object_ref(element)); hardware = (gst_color_balance_get_balance_type(GST_COLOR_BALANCE (element)) == GST_COLOR_BALANCE_HARDWARE); } else if (!hardware) { gboolean tmp = (gst_color_balance_get_balance_type(GST_COLOR_BALANCE (element)) == GST_COLOR_BALANCE_HARDWARE); if (tmp) { if (color_balance_element) gst_object_unref(color_balance_element); color_balance_element = GST_ELEMENT_CAST(gst_object_ref(element)); hardware = TRUE; } } } #if GST_CHECK_VERSION(1, 0, 0) g_value_reset(&item); #endif if (hardware && color_balance_element) done = TRUE; break; } case GST_ITERATOR_RESYNC : gst_iterator_resync(iterator); done = FALSE; hardware = FALSE; if (color_balance_element) gst_object_unref(color_balance_element); color_balance_element = NULL; break; case GST_ITERATOR_DONE: case GST_ITERATOR_ERROR: default: done = TRUE; } } #if GST_CHECK_VERSION(1, 0, 0) g_value_unset(&item); #endif gst_iterator_free(iterator); return color_balance_element; }
static void gst_wrapper_camera_bin_reset_video_src_caps (GstWrapperCameraBinSrc * self, GstCaps * caps) { GstClock *clock; gint64 base_time; GST_DEBUG_OBJECT (self, "Resetting src caps to %" GST_PTR_FORMAT, caps); if (self->src_vid_src) { GstCaps *old_caps; g_object_get (G_OBJECT (self->src_filter), "caps", &old_caps, NULL); if (gst_caps_is_equal (caps, old_caps)) { GST_DEBUG_OBJECT (self, "old and new caps are same, do not reset it"); if (old_caps) gst_caps_unref (old_caps); return; } if (old_caps) gst_caps_unref (old_caps); clock = gst_element_get_clock (self->src_vid_src); base_time = gst_element_get_base_time (self->src_vid_src); /* Ideally, we should only need to get the source to READY here, * but it seems v4l2src isn't happy with this. Putting to NULL makes * it work. * * TODO fix this in v4l2src */ gst_element_set_state (self->src_vid_src, GST_STATE_NULL); set_capsfilter_caps (self, caps); self->drop_newseg = TRUE; GST_DEBUG_OBJECT (self, "Bringing source up"); if (!gst_element_sync_state_with_parent (self->src_vid_src)) { GST_WARNING_OBJECT (self, "Failed to reset source caps"); gst_element_set_state (self->src_vid_src, GST_STATE_NULL); } if (clock) { gst_element_set_clock (self->src_vid_src, clock); gst_element_set_base_time (self->src_vid_src, base_time); if (GST_IS_BIN (self->src_vid_src)) { GstIterator *it = gst_bin_iterate_elements (GST_BIN (self->src_vid_src)); gpointer item = NULL; gboolean done = FALSE; while (!done) { switch (gst_iterator_next (it, &item)) { case GST_ITERATOR_OK: gst_element_set_base_time (GST_ELEMENT (item), base_time); gst_object_unref (item); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); } gst_object_unref (clock); } } }
static void filter_resync (GstIteratorFilter * it) { gst_iterator_resync (it->slave); }
/*! * \brief CvVideoWriter_GStreamer::open * \param filename filename to output to * \param fourcc desired codec fourcc * \param fps desired framerate * \param frameSize the size of the expected frames * \param is_color color or grayscale * \return success * * We support 2 modes of operation. Either the user enters a filename and a fourcc * code, or enters a manual pipeline description like in CvVideoCapture_Gstreamer. * In the latter case, we just push frames on the appsink with appropriate caps. * In the former case, we try to deduce the correct container from the filename, * and the correct encoder from the fourcc profile. * * If the file extension did was not recognize, an avi container is used * */ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc, double fps, CvSize frameSize, bool is_color ) { CV_FUNCNAME("CvVideoWriter_GStreamer::open"); // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // init gstreamer gst_initializer::init(); // init vars bool manualpipeline = true; int bufsize = 0; GError *err = NULL; const char* mime = NULL; GstStateChangeReturn stateret; GstCaps* caps = NULL; GstCaps* videocaps = NULL; #if FULL_GST_VERSION >= VERSION_NUM(0,10,32) GstCaps* containercaps = NULL; GstEncodingContainerProfile* containerprofile = NULL; GstEncodingVideoProfile* videoprofile = NULL; #endif GstIterator* it = NULL; gboolean done = FALSE; GstElement *element = NULL; gchar* name = NULL; GstElement* splitter = NULL; GstElement* combiner = NULL; // we first try to construct a pipeline from the given string. // if that fails, we assume it is an ordinary filename __BEGIN__; encodebin = gst_parse_launch(filename, &err); manualpipeline = (encodebin != NULL); if(manualpipeline) { #if GST_VERSION_MAJOR == 0 it = gst_bin_iterate_sources(GST_BIN(encodebin)); if(gst_iterator_next(it, (gpointer *)&source) != GST_ITERATOR_OK) { CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } #else it = gst_bin_iterate_sources (GST_BIN(encodebin)); GValue value = G_VALUE_INIT; while (!done) { switch (gst_iterator_next (it, &value)) { case GST_ITERATOR_OK: element = GST_ELEMENT (g_value_get_object (&value)); name = gst_element_get_name(element); if (name){ if(strstr(name, "opencvsrc") != NULL || strstr(name, "appsrc") != NULL) { source = GST_ELEMENT ( gst_object_ref (element) ); done = TRUE; } g_free(name); } g_value_unset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); if (!source){ CV_ERROR(CV_StsError, "GStreamer: cannot find appsrc in manual pipeline\n"); return false; } #endif pipeline = encodebin; } else { pipeline = gst_pipeline_new (NULL); // we just got a filename and a fourcc code. // first, try to guess the container from the filename //encodebin = gst_element_factory_make("encodebin", NULL); //proxy old non existing fourcc ids. These were used in previous opencv versions, //but do not even exist in gstreamer any more if (fourcc == CV_FOURCC('M','P','1','V')) fourcc = CV_FOURCC('M', 'P', 'G' ,'1'); if (fourcc == CV_FOURCC('M','P','2','V')) fourcc = CV_FOURCC('M', 'P', 'G' ,'2'); if (fourcc == CV_FOURCC('D','R','A','C')) fourcc = CV_FOURCC('d', 'r', 'a' ,'c'); //create encoder caps from fourcc videocaps = gst_riff_create_video_caps(fourcc, NULL, NULL, NULL, NULL, NULL); if (!videocaps){ CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer Opencv backend does not support this codec."); } //create container caps from file extension mime = filenameToMimetype(filename); if (!mime) { CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer Opencv backend does not support this file type."); } #if FULL_GST_VERSION >= VERSION_NUM(0,10,32) containercaps = gst_caps_from_string(mime); //create encodebin profile containerprofile = gst_encoding_container_profile_new("container", "container", containercaps, NULL); videoprofile = gst_encoding_video_profile_new(videocaps, NULL, NULL, 1); gst_encoding_container_profile_add_profile(containerprofile, (GstEncodingProfile *) videoprofile); #endif //create pipeline elements encodebin = gst_element_factory_make("encodebin", NULL); #if FULL_GST_VERSION >= VERSION_NUM(0,10,32) g_object_set(G_OBJECT(encodebin), "profile", containerprofile, NULL); #endif source = gst_element_factory_make("appsrc", NULL); file = gst_element_factory_make("filesink", NULL); g_object_set(G_OBJECT(file), "location", filename, NULL); } if (is_color) { input_pix_fmt = GST_VIDEO_FORMAT_BGR; bufsize = frameSize.width * frameSize.height * 3; #if GST_VERSION_MAJOR == 0 caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_BGR, frameSize.width, frameSize.height, int(fps), 1, 1, 1); #else caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGR", "width", G_TYPE_INT, frameSize.width, "height", G_TYPE_INT, frameSize.height, "framerate", GST_TYPE_FRACTION, int(fps), 1, NULL); caps = gst_caps_fixate(caps); #endif } else { #if FULL_GST_VERSION >= VERSION_NUM(0,10,29) input_pix_fmt = GST_VIDEO_FORMAT_GRAY8; bufsize = frameSize.width * frameSize.height; #if GST_VERSION_MAJOR == 0 caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_GRAY8, frameSize.width, frameSize.height, int(fps), 1, 1, 1); #else caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "GRAY8", "width", G_TYPE_INT, frameSize.width, "height", G_TYPE_INT, frameSize.height, "framerate", GST_TYPE_FRACTION, int(fps), 1, NULL); caps = gst_caps_fixate(caps); #endif #else CV_Assert(!"Gstreamer 0.10.29 or newer is required for grayscale input"); #endif } gst_app_src_set_caps(GST_APP_SRC(source), caps); gst_app_src_set_stream_type(GST_APP_SRC(source), GST_APP_STREAM_TYPE_STREAM); gst_app_src_set_size (GST_APP_SRC(source), -1); g_object_set(G_OBJECT(source), "format", GST_FORMAT_TIME, NULL); g_object_set(G_OBJECT(source), "block", 1, NULL); g_object_set(G_OBJECT(source), "is-live", 0, NULL); if(!manualpipeline) { g_object_set(G_OBJECT(file), "buffer-size", bufsize, NULL); gst_bin_add_many(GST_BIN(pipeline), source, encodebin, file, NULL); if(!gst_element_link_many(source, encodebin, file, NULL)) { CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n"); } } #if GST_VERSION_MAJOR == 0 // HACK: remove streamsplitter and streamcombiner from // encodebin pipeline to prevent early EOF event handling // We always fetch BGR or gray-scale frames, so combiner->spliter // endge in graph is useless. it = gst_bin_iterate_recurse (GST_BIN(encodebin)); while (!done) { switch (gst_iterator_next (it, (void**)&element)) { case GST_ITERATOR_OK: name = gst_element_get_name(element); if (strstr(name, "streamsplitter")) splitter = element; else if (strstr(name, "streamcombiner")) combiner = element; break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: done = true; break; case GST_ITERATOR_DONE: done = true; break; } } gst_iterator_free (it); if (splitter && combiner) { gst_element_unlink(splitter, combiner); GstPad* src = gst_element_get_pad(combiner, "src"); GstPad* sink = gst_element_get_pad(combiner, "encodingsink"); GstPad* srcPeer = gst_pad_get_peer(src); GstPad* sinkPeer = gst_pad_get_peer(sink); gst_pad_unlink(sinkPeer, sink); gst_pad_unlink(src, srcPeer); gst_pad_link(sinkPeer, srcPeer); src = gst_element_get_pad(splitter, "encodingsrc"); sink = gst_element_get_pad(splitter, "sink"); srcPeer = gst_pad_get_peer(src); sinkPeer = gst_pad_get_peer(sink); gst_pad_unlink(sinkPeer, sink); gst_pad_unlink(src, srcPeer); gst_pad_link(sinkPeer, srcPeer); } #endif stateret = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING); if(stateret == GST_STATE_CHANGE_FAILURE) { handleMessage(pipeline); CV_ERROR(CV_StsError, "GStreamer: cannot put pipeline to play\n"); } framerate = fps; num_frames = 0; handleMessage(pipeline); __END__; return true; }
/* 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; } }
/*! * \brief CvCapture_GStreamer::open Open the given file with gstreamer * \param type CvCapture type. One of CV_CAP_GSTREAMER_* * \param filename Filename to open in case of CV_CAP_GSTREAMER_FILE * \return boolean. Specifies if opening was succesful. * * In case of CV_CAP_GSTREAMER_V4L(2), a pipelin is constructed as follows: * v4l2src ! autoconvert ! appsink * * * The 'filename' parameter is not limited to filesystem paths, and may be one of the following: * * - a normal filesystem path: * e.g. video.avi or /path/to/video.avi or C:\\video.avi * - an uri: * e.g. file:///path/to/video.avi or rtsp:///path/to/stream.asf * - a gstreamer pipeline description: * e.g. videotestsrc ! videoconvert ! appsink * the appsink name should be either 'appsink0' (the default) or 'opencvsink' * * When dealing with a file, CvCapture_GStreamer will not drop frames if the grabbing interval * larger than the framerate period. (Unlike the uri or manual pipeline description, which assume * a live source) * * The pipeline will only be started whenever the first frame is grabbed. Setting pipeline properties * is really slow if we need to restart the pipeline over and over again. * * TODO: the 'type' parameter is imo unneeded. for v4l2, filename 'v4l2:///dev/video0' can be used. * I expect this to be the same for CV_CAP_GSTREAMER_1394. Is anyone actually still using v4l (v1)? * */ bool CvCapture_GStreamer::open( int type, const char* filename ) { CV_FUNCNAME("cvCaptureFromCAM_GStreamer"); __BEGIN__; gst_initializer::init(); bool file = false; bool stream = false; bool manualpipeline = false; char *uri = NULL; uridecodebin = NULL; GstElementFactory * testfac; GstStateChangeReturn status; if (type == CV_CAP_GSTREAMER_V4L){ testfac = gst_element_factory_find("v4lsrc"); if (!testfac){ return false; } g_object_unref(G_OBJECT(testfac)); filename = "v4lsrc ! "COLOR_ELEM" ! appsink"; } if (type == CV_CAP_GSTREAMER_V4L2){ testfac = gst_element_factory_find("v4l2src"); if (!testfac){ return false; } g_object_unref(G_OBJECT(testfac)); filename = "v4l2src ! "COLOR_ELEM" ! appsink"; } // test if we have a valid uri. If so, open it with an uridecodebin // else, we might have a file or a manual pipeline. // if gstreamer cannot parse the manual pipeline, we assume we were given and // ordinary file path. if(!gst_uri_is_valid(filename)) { uri = realpath(filename, NULL); stream = false; if(uri) { uri = g_filename_to_uri(uri, NULL, NULL); if(uri) { file = true; } else { CV_WARN("GStreamer: Error opening file\n"); close(); return false; } } else { GError *err = NULL; uridecodebin = gst_parse_launch(filename, &err); if(!uridecodebin) { fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message); return false; } stream = true; manualpipeline = true; } } else { stream = true; uri = g_strdup(filename); } bool element_from_uri = false; if(!uridecodebin) { // At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation. // This means that we cannot use an uridecodebin when dealing with v4l2, since setting // capture properties will not work. // The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2. gchar * protocol = gst_uri_get_protocol(uri); if (!strcasecmp(protocol , "v4l2")) { #if GST_VERSION_MAJOR == 0 uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src"); #else uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src", NULL); #endif element_from_uri = true; }else{ uridecodebin = gst_element_factory_make("uridecodebin", NULL); g_object_set(G_OBJECT(uridecodebin), "uri", uri, NULL); } g_free(protocol); if(!uridecodebin) { //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message); close(); return false; } } if(manualpipeline) { GstIterator *it = NULL; #if GST_VERSION_MAJOR == 0 it = gst_bin_iterate_sinks(GST_BIN(uridecodebin)); if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) { CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } #else it = gst_bin_iterate_sinks (GST_BIN(uridecodebin)); gboolean done = FALSE; GstElement *element = NULL; gchar* name = NULL; GValue value = G_VALUE_INIT; while (!done) { switch (gst_iterator_next (it, &value)) { case GST_ITERATOR_OK: element = GST_ELEMENT (g_value_get_object (&value)); name = gst_element_get_name(element); if (name){ if(strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) { sink = GST_ELEMENT ( gst_object_ref (element) ); done = TRUE; } g_free(name); } g_value_unset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); if (!sink){ CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } #endif pipeline = uridecodebin; } else { pipeline = gst_pipeline_new(NULL); // videoconvert (in 0.10: ffmpegcolorspace, in 1.x autovideoconvert) //automatically selects the correct colorspace conversion based on caps. color = gst_element_factory_make(COLOR_ELEM, NULL); sink = gst_element_factory_make("appsink", NULL); gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL); if(element_from_uri) { if(!gst_element_link(uridecodebin, color)) { CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); pipeline = NULL; return false; } }else{ g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color); } if(!gst_element_link(color, sink)) { CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); pipeline = NULL; return false; } } //TODO: is 1 single buffer really high enough? gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1); gst_app_sink_set_drop (GST_APP_SINK(sink), stream); //do not emit signals: all calls will be synchronous and blocking gst_app_sink_set_emit_signals (GST_APP_SINK(sink), 0); #if GST_VERSION_MAJOR == 0 caps = gst_caps_new_simple("video/x-raw-rgb", "bpp", G_TYPE_INT, 24, "red_mask", G_TYPE_INT, 0x0000FF, "green_mask", G_TYPE_INT, 0x00FF00, "blue_mask", G_TYPE_INT, 0xFF0000, NULL); #else // support 1 and 3 channel 8 bit data, as well as bayer (also 1 channel, 8bit) caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}"); #endif gst_app_sink_set_caps(GST_APP_SINK(sink), caps); gst_caps_unref(caps); // For video files only: set pipeline to PAUSED state to get its duration if (file) { status = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PAUSED); if (status == GST_STATE_CHANGE_ASYNC) { // wait for status update GstState st1; GstState st2; status = gst_element_get_state(pipeline, &st1, &st2, GST_CLOCK_TIME_NONE); } if (status == GST_STATE_CHANGE_FAILURE) { handleMessage(pipeline); gst_object_unref(pipeline); pipeline = NULL; CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n"); return false; } GstFormat format; format = GST_FORMAT_DEFAULT; #if GST_VERSION_MAJOR == 0 if(!gst_element_query_duration(sink, &format, &duration)) #else if(!gst_element_query_duration(sink, format, &duration)) #endif { handleMessage(pipeline); CV_WARN("GStreamer: unable to query duration of stream"); duration = -1; return true; } } else { duration = -1; } __END__; return true; }
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; }
static void set_tags (GstElement *pipeline, track_info_t *track) { GstIterator *iter; GstTagSetter *tagger; gboolean done = FALSE; iter = gst_bin_iterate_all_by_interface( GST_BIN(pipeline), GST_TYPE_TAG_SETTER ); while (!done) { switch (gst_iterator_next(iter, (gpointer)&tagger)) { case GST_ITERATOR_OK: gst_tag_setter_add_tags( tagger, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, track->title, GST_TAG_ARTIST, track->artist, GST_TAG_TRACK_NUMBER, track->track_num, GST_TAG_ALBUM, track->album->title, GST_TAG_DURATION, track->duration *GST_SECOND, GST_TAG_MUSICBRAINZ_ALBUMID, track->album->album_id, GST_TAG_MUSICBRAINZ_ALBUMARTISTID, track->album->artist_id, GST_TAG_MUSICBRAINZ_ARTISTID, track->artist_id, GST_TAG_MUSICBRAINZ_TRACKID, track->track_id, GST_TAG_MUSICBRAINZ_SORTNAME, track->artist_sortname, NULL ); if (track->album->disc_number > 0) { gst_tag_setter_add_tags( tagger, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM_VOLUME_NUMBER, track->album->disc_number, NULL ); } if (track->album->release_date) { gst_tag_setter_add_tags( tagger, GST_TAG_MERGE_APPEND, GST_TAG_DATE, track->album->release_date, NULL ); } break; case GST_ITERATOR_RESYNC: fprintf(stderr, "got iterator resync. wtf\n"); gst_iterator_resync(iter); break; case GST_ITERATOR_ERROR: fprintf(stderr, "iterator error. wtf\n"); /* falling */ case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free(iter); }
static GstPad * get_pad_by_direction (GstElement * element, GstPadDirection direction) { GstIterator *iter = gst_element_iterate_pads (element); GstPad *selected_pad = NULL; gboolean done; GValue item = { 0, }; if (!iter) return NULL; done = FALSE; while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&item); if (gst_pad_get_direction (pad) == direction) { /* We check if there is more than one pad in this direction, * if there is, we return NULL so that the element is refused */ if (selected_pad) { done = TRUE; gst_object_unref (selected_pad); selected_pad = NULL; } else { selected_pad = g_object_ref (pad); } } g_value_unset (&item); } break; case GST_ITERATOR_RESYNC: if (selected_pad) { gst_object_unref (selected_pad); selected_pad = NULL; } gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: GST_ERROR ("Error iterating pads of element %s", GST_OBJECT_NAME (element)); gst_object_unref (selected_pad); selected_pad = NULL; done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } g_value_unset (&item); gst_iterator_free (iter); if (!selected_pad) GST_ERROR ("Did not find pad of direction %d in %s", direction, GST_OBJECT_NAME (element)); return selected_pad; }
/** * 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; }
/** * 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; }
void sj_extractor_extract_track (SjExtractor *extractor, const TrackDetails *track, GFile *file, GError **error) { GParamSpec *spec; GstStateChangeReturn state_ret; SjExtractorPrivate *priv; GstIterator *iter; GValue item = {0, }; GstTagSetter *tagger; gboolean done; char *uri; g_return_if_fail (SJ_IS_EXTRACTOR (extractor)); g_return_if_fail (file != NULL); g_return_if_fail (track != NULL); priv = extractor->priv; /* See if we need to rebuild the pipeline */ if (priv->rebuild_pipeline != FALSE) { build_pipeline (extractor); if (priv->construct_error != NULL) { g_propagate_error (error, priv->construct_error); priv->construct_error = NULL; return; } } /* Need to do this, as playback will have locked the read speed to 2x previously */ spec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->cdsrc), "read-speed"); if (spec && spec->value_type == G_TYPE_INT) { g_object_set (G_OBJECT (priv->cdsrc), "read-speed", ((GParamSpecInt*)spec)->maximum, NULL); } /* Set the output filename */ gst_element_set_state (priv->filesink, GST_STATE_NULL); uri = g_file_get_uri (file); g_object_set (G_OBJECT (priv->filesink), "location", uri, NULL); g_free (uri); /* Set the metadata */ iter = gst_bin_iterate_all_by_interface (GST_BIN (priv->pipeline), GST_TYPE_TAG_SETTER); done = FALSE; while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: /* TODO: generate this as a taglist once, and apply it to all elements */ tagger = g_value_get_object (&item); gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_REPLACE_ALL, GST_TAG_TITLE, track->title, GST_TAG_ARTIST, track->artist, GST_TAG_TRACK_NUMBER, track->number, GST_TAG_TRACK_COUNT, track->album->number, GST_TAG_ALBUM, track->album->title, GST_TAG_DURATION, track->duration * GST_SECOND, NULL); if (track->composer != NULL && strcmp (track->composer, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_COMPOSER, track->composer, NULL); } if (track->composer_sortname != NULL && strcmp (track->composer_sortname, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_COMPOSER_SORTNAME, track->composer_sortname, NULL); } if (track->album->album_id != NULL && strcmp (track->album->album_id, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_MUSICBRAINZ_ALBUMID, track->album->album_id, NULL); } if (track->album->artist_id != NULL && strcmp (track->album->artist_id, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_MUSICBRAINZ_ALBUMARTISTID, track->album->artist_id, NULL); } if (track->album->artist != NULL && strcmp (track->album->artist, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM_ARTIST, track->album->artist, NULL); } if (track->album->artist_sortname != NULL && strcmp (track->album->artist_sortname, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM_ARTIST_SORTNAME, track->album->artist_sortname, NULL); } if (track->artist_id != NULL && strcmp (track->artist_id, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_MUSICBRAINZ_ARTISTID, track->artist_id, NULL); } if (track->track_id != NULL && strcmp (track->track_id, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_MUSICBRAINZ_TRACKID, track->track_id, NULL); } if (track->artist_sortname != NULL && strcmp (track->artist_sortname, "") != 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST_SORTNAME, track->artist_sortname, NULL); } if (track->album->genre != NULL && strcmp (track->album->genre, "") != 0) { char **values, **l; values = g_strsplit (track->album->genre, ",", 0); for (l = values; *l; l++) { g_strstrip (*l); gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_GENRE, *l, NULL); } g_strfreev (values); } if (track->album->release_date) { GDate *date; guint year = 1; guint month = 1; guint day = 1; if (gst_date_time_has_year (track->album->release_date)) { year = gst_date_time_get_year (track->album->release_date); } if (gst_date_time_has_month (track->album->release_date)) { month = gst_date_time_get_month (track->album->release_date); } if (gst_date_time_has_day (track->album->release_date)) { day = gst_date_time_get_day (track->album->release_date); } date = g_date_new_dmy (day, month, year); /* We set both GST_TAG_DATE_TIME and GST_TAG_DATE as most taggers * use GST_TAG__DATE_TIME, but a few (id3v2mux/apemux) are still using * GST_TAG_DATE */ gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_DATE_TIME, track->album->release_date, GST_TAG_DATE, date, NULL); g_date_free (date); } if (track->album->disc_number > 0) { gst_tag_setter_add_tags (tagger, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM_VOLUME_NUMBER, track->album->disc_number, NULL); } g_value_unset (&item); break; case GST_ITERATOR_RESYNC: /* TODO? */ g_warning ("Got GST_ITERATOR_RESYNC, not sure what to do"); gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } g_value_unset (&item); gst_iterator_free (iter); /* Seek to the right track */ g_object_set (G_OBJECT (priv->cdsrc), "track", track->number, NULL); /* Let's get ready to rumble! */ state_ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); if (state_ret == GST_STATE_CHANGE_ASYNC) { /* Wait for state change to either complete or fail, but not for too long, * just to catch immediate errors. The rest we'll handle asynchronously */ state_ret = gst_element_get_state (priv->pipeline, NULL, NULL, GST_SECOND / 2); } if (state_ret == GST_STATE_CHANGE_FAILURE) { GstMessage *msg; msg = gst_bus_poll (GST_ELEMENT_BUS (priv->pipeline), GST_MESSAGE_ERROR, 0); if (msg) { gst_message_parse_error (msg, error, NULL); gst_message_unref (msg); } else if (error) { /* this should never happen, create generic error just in case */ *error = g_error_new (SJ_ERROR, SJ_ERROR_INTERNAL_ERROR, "Error starting ripping pipeline"); } gst_element_set_state (priv->pipeline, GST_STATE_NULL); priv->rebuild_pipeline = TRUE; return; } priv->tick_id = g_timeout_add (250, (GSourceFunc)tick_timeout_cb, extractor); g_source_set_name_by_id (priv->tick_id, "[sound-juicer] tick_timeout_cb"); }
/* 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; }
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; }
/*! * \brief OpenIMAJCapGStreamer::open Open the given file with gstreamer * \param type CvCapture type. One of CAP_GSTREAMER_* * \param filename Filename to open in case of CAP_GSTREAMER_FILE * \return boolean. Specifies if opening was succesful. * * In case of CAP_GSTREAMER_V4L(2), a pipelin is constructed as follows: * v4l2src ! autoconvert ! appsink * * * The 'filename' parameter is not limited to filesystem paths, and may be one of the following: * * - a normal filesystem path: * e.g. video.avi or /path/to/video.avi or C:\\video.avi * - an uri: * e.g. file:///path/to/video.avi or rtsp:///path/to/stream.asf * - a gstreamer pipeline description: * e.g. videotestsrc ! videoconvert ! appsink * the appsink name should be either 'appsink0' (the default) or 'opencvsink' * * When dealing with a file, OpenIMAJCapGStreamer will not drop frames if the grabbing interval * larger than the framerate period. (Unlike the uri or manual pipeline description, which assume * a live source) * * The pipeline will only be started whenever the first frame is grabbed. Setting pipeline properties * is really slow if we need to restart the pipeline over and over again. * */ bool OpenIMAJCapGStreamer::open(const char* filename ) { if(!isInited) { //FIXME: threadsafety gst_init (NULL, NULL); isInited = true; } bool stream = false; bool manualpipeline = false; char *uri = NULL; uridecodebin = NULL; // test if we have a valid uri. If so, open it with an uridecodebin // else, we might have a file or a manual pipeline. // if gstreamer cannot parse the manual pipeline, we assume we were given and // ordinary file path. if(!gst_uri_is_valid(filename)) { uri = realpath(filename, NULL); stream = false; if(uri) { uri = g_filename_to_uri(uri, NULL, NULL); if(!uri) { WARN("GStreamer: Error opening file\n"); close(); return false; } } else { GError *err = NULL; uridecodebin = gst_parse_launch(filename, &err); if(!uridecodebin) { //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message); //close(); return false; } stream = true; manualpipeline = true; } } else { stream = true; uri = g_strdup(filename); } bool element_from_uri = false; if(!uridecodebin) { // At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation. // This means that we cannot use an uridecodebin when dealing with v4l2, since setting // capture properties will not work. // The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2. gchar * protocol = gst_uri_get_protocol(uri); if (!strcasecmp(protocol , "v4l2")) { uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src", NULL); element_from_uri = true; }else{ uridecodebin = gst_element_factory_make ("uridecodebin", NULL); g_object_set(G_OBJECT(uridecodebin),"uri",uri, NULL); } g_free(protocol); if(!uridecodebin) { //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message); close(); return false; } } if(manualpipeline) { GstIterator *it = NULL; it = gst_bin_iterate_sinks (GST_BIN(uridecodebin)); gboolean done = FALSE; GstElement *element = NULL; gchar* name = NULL; GValue value = G_VALUE_INIT; while (!done) { switch (gst_iterator_next (it, &value)) { case GST_ITERATOR_OK: element = GST_ELEMENT (g_value_get_object (&value)); name = gst_element_get_name(element); if (name){ if(strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) { sink = GST_ELEMENT ( gst_object_ref (element) ); done = TRUE; } g_free(name); } g_value_unset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); if (!sink){ //ERROR(1, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } pipeline = uridecodebin; } else { pipeline = gst_pipeline_new (NULL); // videoconvert (in 0.10: ffmpegcolorspace) automatically selects the correct colorspace // conversion based on caps. color = gst_element_factory_make(COLOR_ELEM, NULL); sink = gst_element_factory_make("appsink", NULL); gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL); if(element_from_uri) { if(!gst_element_link(uridecodebin, color)) { //ERROR(1, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); return false; } }else{ g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color); } if(!gst_element_link(color, sink)) { //ERROR(1, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); return false; } } //TODO: is 1 single buffer really high enough? gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1); gst_app_sink_set_drop (GST_APP_SINK(sink), stream); //do not emit signals: all calls will be synchronous and blocking gst_app_sink_set_emit_signals (GST_APP_SINK(sink), 0); // support 1 and 3 channel 8 bit data, as well as bayer (also 1 channel, 8bit) caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}"); gst_app_sink_set_caps(GST_APP_SINK(sink), caps); gst_caps_unref(caps); //we do not start recording here just yet. // the user probably wants to set capture properties first, so start recording whenever the first frame is requested return true; }
MbEvent * handle_application_message (GstMessage *message) { MbEvent *mb_event = NULL; const GstStructure *msg_struct = NULL; int evt_type; msg_struct = gst_message_get_structure(message); gst_structure_get_int (msg_struct, "event_type", &evt_type); switch (evt_type) { case APP_EVT_MEDIA_END: { if (gst_structure_has_field(msg_struct, "data")) { MbMedia *media = NULL; GstElement *bin = NULL, *element = NULL; GstIterator *bin_it = NULL; GValue data = G_VALUE_INIT; gboolean done = FALSE; gst_structure_get (msg_struct, "data", G_TYPE_POINTER, &media, NULL); g_assert (media); bin = gst_bin_get_by_name(GST_BIN(_mb_global_data.pipeline), media->name); g_assert (bin); gst_element_set_state(bin, GST_STATE_NULL); gst_bin_remove (GST_BIN (_mb_global_data.pipeline), bin); bin_it = gst_bin_iterate_elements(GST_BIN(bin)); while (!done) { switch (gst_iterator_next (bin_it, &data)) { case GST_ITERATOR_OK: { element = GST_ELEMENT(g_value_get_object (&data)); g_assert (element); /* we increment the ref_count to destroy this element * only when calling the function mb_media_free () */ g_debug ("Removing %s from pipeline.\n", media->name); gst_object_ref(element); gst_bin_remove(GST_BIN(bin), element); gst_element_set_state(element, GST_STATE_NULL); break; } case GST_ITERATOR_RESYNC: { gst_iterator_resync (bin_it); break; } case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: { done = TRUE; break; } default: break; } } gst_iterator_free(bin_it); gst_object_unref(bin); mb_event = create_state_change_event (MB_REMOVED, media->name); } break; } } return mb_event; }