예제 #1
0
//FIXME this should be part of the library
void
shmdata_base_reader_clean_element (GstElement *element)
{
    if (element != NULL && GST_IS_ELEMENT(element)
            && GST_STATE_CHANGE_FAILURE != GST_STATE_RETURN(element)) {
        {   // unlinking pads
            GstIterator *pad_iter = gst_element_iterate_pads(element);
            gst_iterator_foreach(pad_iter, (GFunc) shmdata_base_reader_unlink_pad, NULL);
            gst_iterator_free(pad_iter);
        }
        {   // releasing request pads
            GstIterator *pad_iter = gst_element_iterate_pads(element);
            gst_iterator_foreach(pad_iter,
                                 (GFunc) shmdata_base_reader_release_request_pad,
                                 element);
            gst_iterator_free(pad_iter);
        }

        GstState state = GST_STATE_TARGET(element);
        if (state != GST_STATE_NULL) {
            if (GST_STATE_CHANGE_ASYNC ==
                    gst_element_set_state(element, GST_STATE_NULL)) {
                while (GST_STATE(element) != GST_STATE_NULL) {
                    // warning this may be blocking
                    gst_element_get_state(element, NULL, NULL,
                                          GST_CLOCK_TIME_NONE);
                }
            }
        }
        if (GST_IS_BIN(gst_element_get_parent(element)))
            gst_bin_remove(GST_BIN(gst_element_get_parent(element)), element);
        else
            gst_object_unref(element);
    }
}
static void
setup_input_selector_counters (GstElement * element)
{
  GstIterator *iterator;
  gboolean done = FALSE;
  GValue value = { 0, };
  GstPad *pad;
  BufferCountData *bcd;

  iterator = gst_element_iterate_pads (element);
  while (!done) {
    switch (gst_iterator_next (iterator, &value)) {
      case GST_ITERATOR_OK:
        pad = g_value_dup_object (&value);
        bcd = g_slice_new0 (BufferCountData);
        g_object_set_data (G_OBJECT (pad), "buffer-count-data", bcd);
        bcd->probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
            (GstPadProbeCallback) input_selector_pad_probe, NULL, NULL);
        bcd->pad = pad;
        g_value_reset (&value);
        break;
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (iterator);
        break;
      case GST_ITERATOR_ERROR:
        done = TRUE;
        break;
      case GST_ITERATOR_DONE:
        done = TRUE;
        break;
    }
  }
  gst_iterator_free (iterator);
}
예제 #3
0
static GstPad *
get_pad_by_direction (GstElement * element, GstPadDirection direction)
{
  GstIterator *iter = gst_element_iterate_pads (element);
  GstPad *pad = NULL;
  GstPad *selected_pad = NULL;
  gboolean done;

  if (!iter)
    return NULL;

  done = FALSE;
  while (!done) {
    switch (gst_iterator_next (iter, (gpointer) & pad)) {
      case GST_ITERATOR_OK:
        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 = pad;
          }
        } else {
          gst_object_unref (pad);
        }
        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;
    }
  }
  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;
}
예제 #4
0
static gboolean
element_is_valid_filter (GstElement * element, gboolean * isdynamic)
{
  gboolean havesink = FALSE;
  gboolean havesrc = FALSE;
  gboolean done = FALSE;
  GstIterator *pads;
  GValue item = { 0, };

  if (isdynamic)
    *isdynamic = FALSE;

  pads = gst_element_iterate_pads (element);

  while (!done) {
    switch (gst_iterator_next (pads, &item)) {
      case GST_ITERATOR_OK:
      {
        GstPad *pad = g_value_get_object (&item);

        if (gst_pad_get_direction (pad) == GST_PAD_SRC)
          havesrc = TRUE;
        else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
          havesink = TRUE;

        g_value_reset (&item);
        break;
      }
      case GST_ITERATOR_RESYNC:
        gst_iterator_resync (pads);
        havesrc = FALSE;
        havesink = FALSE;
        break;
      default:
        /* ERROR and DONE */
        done = TRUE;
        break;
    }
  }

  g_value_unset (&item);
  gst_iterator_free (pads);

  /* just look at the element's class, not the factory, since there might
   * not be a factory (in case of python elements) or the factory is the
   * wrong one (in case of a GstBin sub-class) and doesn't have complete
   * information. */
  {
    GList *tmp =
        gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS
        (element));

    while (tmp) {
      GstPadTemplate *template = (GstPadTemplate *) tmp->data;

      if (template->direction == GST_PAD_SRC)
예제 #5
0
GstPad * GetExistingPadByName(GstElement * inElement, const std::string & inPadName)
{
    GstPad * result(0);

    GstIterator * it = gst_element_iterate_pads(inElement);
    if (!it)
    {
        throw std::runtime_error("Failed to create an iterator for the given element.");
    }

    bool done = false;
    while (!done)
    {
        gpointer pad = 0;
        switch (gst_iterator_next(it, &pad))
        {
        case GST_ITERATOR_OK:
        {
            if (inPadName == GST_PAD_NAME(pad))
            {
                result = GST_PAD(pad);
                done = true;
            }
            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 (!result)
    {
        std::string msg = MakeString() << "Element does not contain a pad with name " << inPadName << ". ";
        throw std::runtime_error(msg);
    }
    return result;
}
예제 #6
0
static VALUE
rb_gst_element_each_pad_with_callback(VALUE self,
                                      EachPadCallback callback,
                                      VALUE user_data)
{
    EachPadData data;

    data.self = self;
    data.callback = callback;
    data.user_data = user_data;
    data.iterator = gst_element_iterate_pads(SELF(self));
    return rb_ensure(rb_gst_element_each_pad_body, (VALUE)(&data),
             rb_gst_element_each_pad_ensure, (VALUE)(&data));
}
예제 #7
0
static void hook_element (GstElement *elem, PipelineChangeListenerContext *ctx)
{
	GstIterator *itr;
	gpointer     item;

	/* check if we've already examined this element, to prevent loops: */
	if (!already_visited (ctx->visited_nodes, elem))
	{
		GST_INFO_OBJECT (elem, "");

		g_signal_connect (elem, "pad-added", (GCallback)pad_added, ctx);

		/* Since it is likely that some pads are already hooked, let's iterate them
		 * (since there will be no pad-added signal for them) and simulate the
		 * the missed signal
		 *
		 * XXX here we probably should do something sane if the underlying data
		 * structure changes as we iterate.. hmm
		 */
		for( itr = gst_element_iterate_pads (elem);
		     gst_iterator_next (itr, &item) == GST_ITERATOR_OK;
		     gst_object_unref (item) )
		{
			pad_added (elem, GST_PAD(item), ctx);
		}
		gst_iterator_free (itr);

		/* in case this elem is a bin, we need to hook all the elements within
		 * the bin too:
		 */
		if( GST_IS_BIN (elem) )
		{
			for( itr = gst_bin_iterate_elements (GST_BIN (elem));
			     gst_iterator_next (itr, &item) == GST_ITERATOR_OK;
			     gst_object_unref (item) )
			{
				hook_element (GST_ELEMENT (item), ctx);
			}
			gst_iterator_free (itr);
		}

		ctx->needs_cb = TRUE;
	}
}
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);
}
예제 #9
0
/**
 * recursively iterate all our pads and search adjacent elements
 */
static GooComponent *
find_goo_component_in_elem (GstElement *elem, SearchContext *ctx)
{
	GstIterator  *itr;
	gpointer      item;
	GooComponent *component = NULL;


	/* check if we've already examined this element, to prevent loops: */
	if (already_visited (ctx->visited_nodes, elem))
	{
		GST_INFO ("already visited elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem));
		return NULL;
	}

	GST_INFO ("elem=%s (%s)", gst_element_get_name (elem), G_OBJECT_TYPE_NAME (elem));

	/* note: we don't handle the case of the underlying data structure changing
	 * while iterating.. we just bail out and the user needs to restart.
	 */
	for( itr = gst_element_iterate_pads (elem);
	     gst_iterator_next (itr, &item) == GST_ITERATOR_OK && !component;
	     gst_object_unref (item) )
	{
		GstElement   *adjacent_elem = NULL;
		GstPad *pad = GST_PAD (item);
		GstPad *peer = gst_pad_get_peer (pad);

		GST_INFO ("found pad: %s (%s)", gst_pad_get_name (pad), G_OBJECT_TYPE_NAME (pad));

		if (G_UNLIKELY (peer == NULL))
		{
			GST_INFO ("NULL peer.. not connected yet?");
			continue;
		}

		/* in the case of GstGhostPad (and probably other proxy pads)
		 * the parent is actually the pad we are a proxy for, so
		 * keep looping until we find the GstElement
		 */
		while(TRUE)
		{
			GstObject *obj = gst_pad_get_parent (peer);
			if( GST_IS_PAD(obj) )
			{
				gst_object_unref (peer);
				peer = GST_PAD (obj);
			}
			else
			{
				adjacent_elem = GST_ELEMENT (obj);
				break;
			}
		}

		if (G_UNLIKELY (adjacent_elem == NULL))
		{
			gst_object_unref (peer);
			GST_INFO ("Cannot find a adjacent element");
			continue;
		}

		GST_INFO ("found adjacent_elem: %s", gst_element_get_name (adjacent_elem));

		component = find_goo_component (adjacent_elem, ctx);

		/* cleanup: */
		gst_object_unref (adjacent_elem);
		gst_object_unref (peer);
	}
	gst_iterator_free (itr);

	return component;
}
/*
 * 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;
}
예제 #13
0
/*
 * 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);
}