diff -r 9b2c3c7a1a9c -r 567bb019e3e3 gstreamer_core/gst/gstdebugutils.c --- a/gstreamer_core/gst/gstdebugutils.c Wed Mar 31 22:03:18 2010 +0300 +++ b/gstreamer_core/gst/gstdebugutils.c Tue Aug 31 15:30:33 2010 +0300 @@ -20,10 +20,18 @@ */ /* TODO: * edge [ constraint=false ]; - * edge [ minlen=0 ]; - * does not create spacial dependency - * node [ margin="0.02,0.01" ]; - * space surrounding the label + * this creates strange graphs ("minlen=0" is better) + * try puting src/sink ghostpads for each bin into invisible clusters + * + * for more compact nodes, try + * - changing node-shape from box into record + * - use labels like : element [ label="{element | src | sink}"] + * - point to record-connectors : element1:src -> element2:sink + * - we use head/tail labels for pad-caps right now + * - this does not work well, as dot seems to not llok at their sizen when + * doing the layout + * - we could add the caps to the pad itself, then we should use one line per + * caps (simple caps = one line) */ #include "gst_private.h" @@ -42,11 +50,19 @@ #include "gstghostpad.h" #include "gstpad.h" #include "gstutils.h" +#include "gstvalue.h" /*** PIPELINE GRAPHS **********************************************************/ const gchar *priv_gst_dump_dot_dir; /* NULL *//* set from gst.c */ +const gchar spaces[] = { + " " /* 32 */ + " " /* 64 */ + " " /* 96 */ + " " /* 128 */ +}; + extern GstClockTime _priv_gst_info_start_time; static gchar * @@ -67,7 +83,7 @@ if (pending == GST_STATE_VOID_PENDING) { state_name = g_strdup_printf ("\\n[%c]", state_icons[state]); } else { - state_name = g_strdup_printf ("\\n[%c]->[%c]", state_icons[state], + state_name = g_strdup_printf ("\\n[%c] -> [%c]", state_icons[state], state_icons[pending]); } return state_name; @@ -119,6 +135,351 @@ return param_name; } +static void +debug_dump_pad (GstPad * pad, gchar * color_name, gchar * element_name, + FILE * out, const gint indent) +{ + GstPadTemplate *pad_templ; + GstPadPresence presence; + gchar *pad_name, *style_name; + gchar pad_flags[6]; + const gchar *activation_mode = "-><"; + const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)]; + + pad_name = debug_dump_make_object_name (GST_OBJECT (pad)); + + /* pad availability */ + style_name = "filled,solid"; + if ((pad_templ = gst_pad_get_pad_template (pad))) { + presence = GST_PAD_TEMPLATE_PRESENCE (pad_templ); + if (presence == GST_PAD_SOMETIMES) { + style_name = "filled,dotted"; + } else if (presence == GST_PAD_REQUEST) { + style_name = "filled,dashed"; + } + } + /* check if pad flags */ + pad_flags[0] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKED) ? 'B' : 'b'; + pad_flags[1] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING) ? 'F' : 'f'; + pad_flags[2] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_GETCAPS) ? 'G' : 'g'; + pad_flags[3] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_SETCAPS) ? 's' : 's'; + pad_flags[4] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) ? 'B' : 'b'; + pad_flags[5] = '\0'; + + fprintf (out, "%s %s_%s [color=black, fillcolor=\"%s\", label=\"%s\\n[%c][%s]\", height=\"0.2\", style=\"%s\"];\n", spc, element_name, pad_name, color_name, GST_OBJECT_NAME (pad), activation_mode[pad->mode], /* NONE/PUSH/PULL */ + pad_flags, style_name); + + g_free (pad_name); +} + +static void +debug_dump_element_pad (GstPad * pad, GstElement * element, + GstDebugGraphDetails details, FILE * out, const gint indent) +{ + GstElement *target_element; + GstPad *target_pad, *tmp_pad; + GstPadDirection dir; + gchar *pad_name, *element_name; + gchar *target_element_name; + gchar *color_name; + + 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"); + /* output target-pad so that it belongs to this element */ + if ((tmp_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)))) { + if ((target_pad = gst_pad_get_peer (tmp_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 = ""; + } + debug_dump_pad (target_pad, color_name, target_element_name, out, + indent); + if (target_element) { + g_free (target_element_name); + gst_object_unref (target_element); + } + gst_object_unref (target_pad); + } + gst_object_unref (tmp_pad); + } + } else { + color_name = + (dir == GST_PAD_SRC) ? "#ffaaaa" : ((dir == + GST_PAD_SINK) ? "#aaaaff" : "#cccccc"); + } + /* pads */ + debug_dump_pad (pad, color_name, element_name, out, indent); + g_free (element_name); +} + +static gboolean +string_append_field (GQuark field, const GValue * value, gpointer ptr) +{ + GString *str = (GString *) ptr; + gchar *value_str = gst_value_serialize (value); + + /* some enums can become really long */ + if (strlen (value_str) > 25) { + gint pos = 24; + + /* truncate */ + value_str[25] = '\0'; + + /* mirror any brackets */ + if (value_str[0] == '<') + value_str[pos--] = '>'; + if (value_str[0] == '[') + value_str[pos--] = ']'; + if (value_str[0] == '(') + value_str[pos--] = ')'; + if (value_str[0] == '{') + value_str[pos--] = '}'; + if (pos != 24) + value_str[pos--] = ' '; + /* elippsize */ + value_str[pos--] = '.'; + value_str[pos--] = '.'; + value_str[pos--] = '.'; + } + g_string_append_printf (str, " %18s: %s\\l", g_quark_to_string (field), + value_str); + + g_free (value_str); + return TRUE; +} + +static gchar * +debug_dump_describe_caps (GstCaps * caps, GstDebugGraphDetails details, + gboolean * need_free) +{ + gchar *media = NULL; + + if (details & GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS) { + + if (gst_caps_is_any (caps) || gst_caps_is_empty (caps)) { + media = gst_caps_to_string (caps); + *need_free = TRUE; + + } else { + GString *str = NULL; + guint i; + guint slen = 0; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + slen += 25 + + STRUCTURE_ESTIMATED_STRING_LEN (gst_caps_get_structure (caps, i)); + } + + str = g_string_sized_new (slen); + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *structure = gst_caps_get_structure (caps, i); + + g_string_append (str, gst_structure_get_name (structure)); + g_string_append (str, "\\l"); + + gst_structure_foreach (structure, string_append_field, (gpointer) str); + } + + media = g_string_free (str, FALSE); + *need_free = TRUE; + } + + } else { + if (GST_CAPS_IS_SIMPLE (caps)) + media = + (gchar *) gst_structure_get_name (gst_caps_get_structure (caps, 0)); + else + media = "*"; + *need_free = FALSE; + } + return media; +} + +static void +debug_dump_element_pad_link (GstPad * pad, GstElement * element, + GstDebugGraphDetails details, FILE * out, const gint indent) +{ + GstElement *peer_element, *target_element; + GstPad *peer_pad, *target_pad, *tmp_pad; + GstCaps *caps, *peer_caps; + gboolean free_caps, free_peer_caps; + gboolean free_media, free_media_src, free_media_sink; + gchar *media = NULL; + gchar *media_src = NULL, *media_sink = NULL; + gchar *pad_name, *element_name; + gchar *peer_pad_name, *peer_element_name; + gchar *target_pad_name, *target_element_name; + const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)]; + + if ((peer_pad = gst_pad_get_peer (pad))) { + free_media = free_media_src = free_media_sink = 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 ((peer_caps = gst_pad_get_negotiated_caps (peer_pad))) { + free_peer_caps = TRUE; + } else { + free_peer_caps = FALSE; + peer_caps = (GstCaps *) gst_pad_get_pad_template_caps (peer_pad); + } + if (caps) { + media = debug_dump_describe_caps (caps, details, &free_media); + /* check if peer caps are different */ + if (peer_caps && !gst_caps_is_equal (caps, peer_caps)) { + gchar *tmp; + gboolean free_tmp; + + tmp = debug_dump_describe_caps (peer_caps, details, &free_tmp); + if (gst_pad_get_direction (pad) == GST_PAD_SRC) { + media_src = media; + free_media_src = free_media; + media_sink = tmp; + free_media_sink = free_tmp; + } else { + media_src = tmp; + free_media_src = free_tmp; + media_sink = media; + free_media_sink = free_media; + } + media = NULL; + free_media = FALSE; + } + if (free_caps) { + gst_caps_unref (caps); + } + } + if (free_peer_caps && peer_caps) { + gst_caps_unref (peer_caps); + } + } + + pad_name = debug_dump_make_object_name (GST_OBJECT (pad)); + if (element) { + element_name = debug_dump_make_object_name (GST_OBJECT (element)); + } else { + element_name = ""; + } + 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 = ""; + } + + if (GST_IS_GHOST_PAD (pad)) { + if ((tmp_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)))) { + if ((target_pad = gst_pad_get_peer (tmp_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, minlen=0]\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); + } + gst_object_unref (tmp_pad); + } + } + if (GST_IS_GHOST_PAD (peer_pad)) { + if ((tmp_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer_pad)))) { + if ((target_pad = gst_pad_get_peer (tmp_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, minlen=0]\n", spc, + peer_element_name, peer_pad_name, + target_element_name, target_pad_name); + /* FIXME: we are missing links from the proxy pad + * theoretically we need to: + * pad=gst_object_ref(target_pad); + * goto line 280: if ((peer_pad = gst_pad_get_peer (pad))) + * as this would be ugly we need to refactor ... + */ + debug_dump_element_pad_link (target_pad, target_element, details, out, + indent); + g_free (target_pad_name); + if (target_element) { + g_free (target_element_name); + gst_object_unref (target_element); + } + gst_object_unref (target_pad); + } + gst_object_unref (tmp_pad); + } + } + + /* 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 if (media_src && media_sink) { + /* dot has some issues with placement of head and taillabels, + * we need an empty label to make space */ + fprintf (out, "%s%s_%s -> %s_%s [labeldistance=\"10\", labelangle=\"0\", " + "label=\" \", " + "headlabel=\"%s\", taillabel=\"%s\"]\n", + spc, element_name, pad_name, peer_element_name, peer_pad_name, + media_src, media_sink); + if (free_media_src) + g_free (media_src); + if (free_media_sink) + g_free (media_sink); + } else { + fprintf (out, "%s%s_%s -> %s_%s\n", spc, + element_name, pad_name, peer_element_name, peer_pad_name); + } + + g_free (pad_name); + if (element) { + 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); + } +} + /* * debug_dump_element: * @bin: the bin that should be analyzed @@ -133,25 +494,14 @@ { GstIterator *element_iter, *pad_iter; gboolean elements_done, pads_done; - GstElement *element, *peer_element, *target_element; - GstPad *pad, *peer_pad, *target_pad; + GstElement *element; + GstPad *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 *element_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'; + const gchar *spc = &spaces[MAX (sizeof (spaces) - (1 + indent * 2), 0)]; element_iter = gst_bin_iterate_elements (bin); elements_done = FALSE; @@ -172,7 +522,7 @@ 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, + 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 : "") ); @@ -192,31 +542,12 @@ while (!pads_done) { switch (gst_iterator_next (pad_iter, (gpointer) & pad)) { case GST_ITERATOR_OK: + debug_dump_element_pad (pad, element, details, out, indent); 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: @@ -252,135 +583,8 @@ 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); - } + debug_dump_element_pad_link (pad, element, details, out, + indent); } gst_object_unref (pad); break; @@ -407,7 +611,6 @@ } } gst_iterator_free (element_iter); - g_free (spc); } /* @@ -462,14 +665,14 @@ fprintf (out, "digraph pipeline {\n" " rankdir=LR;\n" - " fontname=\"Bitstream Vera Sans\";\n" - " fontsize=\"8\";\n" + " fontname=\"sans\";\n" + " fontsize=\"10\";\n" " labelloc=t;\n" " nodesep=.1;\n" " ranksep=.2;\n" " label=\"<%s>\\n%s%s%s\";\n" - " node [style=filled, shape=box, fontsize=\"7\", fontname=\"Bitstream Vera Sans\"];\n" - " edge [labelfontsize=\"7\", fontsize=\"7\", labelfontname=\"Bitstream Vera Sans\", fontname=\"Bitstream Vera Sans\"];\n" + " node [style=filled, shape=box, fontsize=\"9\", fontname=\"sans\", margin=\"0.0,0.0\"];\n" + " edge [labelfontsize=\"6\", fontsize=\"9\", fontname=\"monospace\"];\n" "\n", G_OBJECT_TYPE_NAME (bin), GST_OBJECT_NAME (bin), (state_name ? state_name : ""), (param_name ? param_name : "") ); @@ -521,12 +724,32 @@ /* add timestamp */ elapsed = GST_CLOCK_DIFF (_priv_gst_info_start_time, gst_util_get_timestamp ()); + + /* we don't use GST_TIME_FORMAT as such filenames would fail on some + * filesystems like fat */ ts_file_name = - g_strdup_printf ("%" GST_TIME_FORMAT "-%s", GST_TIME_ARGS (elapsed), + g_strdup_printf ("%u.%02u.%02u.%09u-%s", GST_TIME_ARGS (elapsed), file_name); _gst_debug_bin_to_dot_file (bin, details, ts_file_name); g_free (ts_file_name); } +#else /* !GST_DISABLE_GST_DEBUG */ +#ifndef GST_REMOVE_DISABLED +void +_gst_debug_bin_to_dot_file (GstBin * bin, GstDebugGraphDetails details, + const gchar * file_name) +{ +} +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +void +_gst_debug_bin_to_dot_file_with_ts (GstBin * bin, GstDebugGraphDetails details, + const gchar * file_name) +{ +} +#endif /* GST_REMOVE_DISABLED */ #endif /* GST_DISABLE_GST_DEBUG */