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_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; }
/** * 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; }
bool CvCapture_GStreamer::open( int type, const char* filename ) { close(); CV_FUNCNAME("cvCaptureFromCAM_GStreamer"); __BEGIN__; gst_initializer::init(); // if(!isInited) { // printf("gst_init\n"); // gst_init (NULL, NULL); // gst_debug_set_active(TRUE); // gst_debug_set_colored(TRUE); // gst_debug_set_default_threshold(GST_LEVEL_WARNING); // isInited = true; // } bool stream = false; bool manualpipeline = false; char *uri = NULL; uridecodebin = NULL; if(type != CV_CAP_GSTREAMER_FILE) { close(); return false; } if(!gst_uri_is_valid(filename)) { uri = realpath(filename, NULL); stream=false; if(uri) { uri = g_filename_to_uri(uri, NULL, NULL); if(!uri) { CV_WARN("GStreamer: Error opening file\n"); close(); return false; } } else { GError *err = NULL; //uridecodebin = gst_parse_bin_from_description(filename, FALSE, &err); uridecodebin = gst_parse_launch(filename, &err); if(!uridecodebin) { CV_WARN("GStreamer: Error opening bin\n"); close(); return false; } stream = true; manualpipeline = true; } } else { stream = true; uri = g_strdup(filename); } if(!uridecodebin) { uridecodebin = gst_element_factory_make ("uridecodebin", NULL); g_object_set(G_OBJECT(uridecodebin),"uri",uri, NULL); if(!uridecodebin) { CV_WARN("GStreamer: Failed to create uridecodebin\n"); close(); return false; } } if(manualpipeline) { GstIterator *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; } pipeline = uridecodebin; } else { pipeline = gst_pipeline_new (NULL); color = gst_element_factory_make("ffmpegcolorspace", NULL); sink = gst_element_factory_make("appsink", NULL); gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL); 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); return false; } } gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1); gst_app_sink_set_drop (GST_APP_SINK(sink), stream); caps = gst_caps_new_simple("video/x-raw-rgb", "red_mask", G_TYPE_INT, 0x0000FF, "green_mask", G_TYPE_INT, 0x00FF00, "blue_mask", G_TYPE_INT, 0xFF0000, NULL); gst_app_sink_set_caps(GST_APP_SINK(sink), caps); gst_caps_unref(caps); if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { CV_WARN("GStreamer: unable to set pipeline to ready\n"); gst_object_unref(pipeline); return false; } if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL); CV_WARN("GStreamer: unable to set pipeline to playing\n"); gst_object_unref(pipeline); return false; } handleMessage(); __END__; return true; }
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 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; }
/* * 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 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; }
/* 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_audio_aggregator_query_duration (GstAudioAggregator * aagg, GstQuery * query) { gint64 max; gboolean res; GstFormat format; GstIterator *it; gboolean done; GValue item = { 0, }; /* parse format */ gst_query_parse_duration (query, &format, NULL); max = -1; res = TRUE; done = FALSE; it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (aagg)); while (!done) { GstIteratorResult ires; 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 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; } g_value_reset (&item); break; } case GST_ITERATOR_RESYNC: max = -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 max */ GST_DEBUG_OBJECT (aagg, "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_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; }
/*! * \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 stream = false; bool manualpipeline = false; char *uri = NULL; uridecodebin = NULL; GstElementFactory * testfac; 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) { 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); //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")) { #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) 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); 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); 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", "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); //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 __END__; return true; }
/*! * \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; // 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); if(!encodebin) { manualpipeline = false; } 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)); 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, "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); g_object_set(G_OBJECT(source), "emit-signals", 1, 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"); } } stateret = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING); if(stateret == GST_STATE_CHANGE_FAILURE) { CV_ERROR(CV_StsError, "GStreamer: cannot put pipeline to play\n"); } handleMessage(pipeline); framerate = fps; num_frames = 0; __END__; return true; }
/* * 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 *src_pad_name = NULL, *sink_pad_name = NULL; gchar *element_name; gchar *state_name = NULL; gchar *param_name = NULL; const gchar *spc = MAKE_INDENT (indent); 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_object_params (G_OBJECT (element), details, NULL); } /* 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,rounded\";\n", spc); g_string_append_printf (str, "%s color=black;\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; } src_pads = sink_pads = 0; if ((pad_iter = gst_element_iterate_sink_pads (element))) { gchar *cluster_name = g_strdup_printf ("%s_sink", element_name); debug_dump_element_pads (pad_iter, pad, element, details, str, indent + 1, &sink_pads, cluster_name, &sink_pad_name); g_free (cluster_name); gst_iterator_free (pad_iter); } if ((pad_iter = gst_element_iterate_src_pads (element))) { gchar *cluster_name = g_strdup_printf ("%s_src", element_name); debug_dump_element_pads (pad_iter, pad, element, details, str, indent + 1, &src_pads, cluster_name, &src_pad_name); g_free (cluster_name); gst_iterator_free (pad_iter); } if (sink_pads && src_pads) { /* add invisible link from first sink to first src pad */ g_string_append_printf (str, "%s %s_%s -> %s_%s [style=\"invis\"];\n", spc, element_name, sink_pad_name, element_name, src_pad_name); } g_free (sink_pad_name); g_free (src_pad_name); g_free (element_name); sink_pad_name = src_pad_name = NULL; 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); }
/* * 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; 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)); } /* 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_sink_pads (element))) { debug_dump_element_pads (pad_iter, pad, element, details, out, 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, out, indent, &src_pads, &sink_pads); 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, &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, out, 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, out, 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); }
GstElement *create_video_sink() { GstElement *bin, *decoder = NULL; GstIterator *iter; GstIteratorResult res; GError *error = NULL; GstPad *pad; gpointer element = NULL; const char* decoder_name; #ifndef DESKTOP /* create pipeline */ decoder_name = "tividdec20"; bin = gst_parse_launch_full("TIViddec2 genTimeStamps=FALSE \ engineName=decode \ codecName=h264dec numFrames=-1 \ ! videoscale method=0 \ ! video/x-raw-yuv, format=(fourcc)I420, width=320, height=240 \ ! ffmpegcolorspace \ ! video/x-raw-rgb, bpp=16 \ ! TIDmaiVideoSink displayStd=fbdev displayDevice=/dev/fb0 videoStd=QVGA \ videoOutput=LCD resizer=FALSE accelFrameCopy=TRUE", NULL, 0, &error); #else decoder_name = "decodebin"; bin = gst_parse_launch_full("decodebin \ ! videoscale method=0 \ ! video/x-raw-yuv, format=(fourcc)I420, width=320, height=240 \ ! xvimagesink", NULL, 0, &error); #endif if (!bin) { g_error("GStreamer: failed to parse video sink pipeline\n"); return NULL; } gst_object_set_name(GST_OBJECT(bin), "video-sink"); iter = gst_bin_iterate_elements(GST_BIN(bin)); res = gst_iterator_next (iter, &element); while (res == GST_ITERATOR_OK) { gchar *name; name = gst_object_get_name(GST_OBJECT (element)); if (name) { if (!strncmp(name, decoder_name, strlen(decoder_name))) { decoder = GST_ELEMENT(element); } g_printf("GS: video sink element: %s \n", name); g_free (name); } gst_object_unref (element); element = NULL; res = gst_iterator_next (iter, &element); } gst_iterator_free (iter); if (!decoder) { /* mem leak */ g_printf("decoder element not found\n"); return NULL; } /* add ghostpad */ pad = gst_element_get_static_pad (decoder, "sink"); gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad)); gst_object_unref(GST_OBJECT(pad)); return bin; }
/** * recursively iterate all our pads and search adjacent elements */ static GooComponent * find_goo_component (GstElement *elem, SearchContext *ctx) { GstIterator *itr; gpointer item; GooComponent *component = NULL; /* check if we've already examined this element, to prevent loops: */ if (already_visited (ctx->visited_nodes, elem)) { GST_INFO ("already visited elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem)); return NULL; } GST_INFO ("elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem)); /* note: we don't handle the case of the underlying data structure changing * while iterating.. we just bail out and the user needs to restart. */ for( itr = gst_element_iterate_pads (elem); gst_iterator_next (itr, &item) == GST_ITERATOR_OK && !component; gst_object_unref (item) ) { GstElement *adjacent_elem = NULL; GstPad *pad = GST_PAD (item); GstPad *peer = gst_pad_get_peer (pad); GST_INFO ("found pad: %s (%s)", gst_pad_get_name (pad), G_OBJECT_TYPE_NAME (pad)); if (G_UNLIKELY (peer == NULL)) { GST_INFO ("NULL peer.. not connected yet?"); continue; } /* in the case of GstGhostPad (and probably other proxy pads) * the parent is actually the pad we are a proxy for, so * keep looping until we find the GstElement */ while(TRUE) { GstObject *obj = gst_pad_get_parent (peer); if( GST_IS_PAD(obj) ) { gst_object_unref (peer); peer = GST_PAD (obj); } else { adjacent_elem = GST_ELEMENT (obj); break; } } if (G_UNLIKELY (adjacent_elem == NULL)) { gst_object_unref (peer); GST_INFO ("Cannot find a adjacent element"); continue; } GST_INFO ("found adjacent_elem: %s", gst_element_get_name (adjacent_elem)); component = check_for_goo_component (adjacent_elem, ctx); if (component == NULL) { /* if adjacent_elem is itself a bin, we need to search the * contents of that bin: */ if( GST_IS_BIN (adjacent_elem) ) { component = find_goo_component_in_bin (GST_BIN (adjacent_elem), ctx); } } if (component == NULL) { /* if we didn't find our component, recursively search * the contents of adjacent_elem's pads: */ component = find_goo_component (adjacent_elem, ctx); } /* cleanup: */ gst_object_unref (adjacent_elem); gst_object_unref (peer); } gst_iterator_free (itr); return component; }
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; }