tools/gst-inspect.c: Can't pass NULL strings to g_print() on windows.
[platform/upstream/gstreamer.git] / tools / gst-inspect.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2000 Wim Taymans <wtay@chello.be>
4  *               2004 Thomas Vander Stichele <thomas@apestaart.org>
5  *
6  * gst-inspect.c: tool to inspect the GStreamer registry
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include <gst/gst.h>
29 #include <gst/controller/gstcontroller.h>
30
31 #include "gst/gst-i18n-app.h"
32
33 #include <string.h>
34 #include <locale.h>
35 #include <glib/gprintf.h>
36
37 static char *_name;
38
39 static int print_element_info (GstElementFactory * factory,
40     gboolean print_names);
41
42 void
43 n_print (const char *format, ...)
44 {
45   va_list args;
46   gint retval;
47
48   if (_name)
49     g_print (_name);
50
51   va_start (args, format);
52   retval = g_vprintf (format, args);
53   va_end (args);
54 }
55
56 static gboolean
57 print_field (GQuark field, const GValue * value, gpointer pfx)
58 {
59   gchar *str = gst_value_serialize (value);
60
61   n_print ("%s  %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
62   g_free (str);
63   return TRUE;
64 }
65
66 static void
67 print_caps (const GstCaps * caps, const gchar * pfx)
68 {
69   guint i;
70
71   g_return_if_fail (caps != NULL);
72
73   if (gst_caps_is_any (caps)) {
74     n_print ("%sANY\n", pfx);
75     return;
76   }
77   if (gst_caps_is_empty (caps)) {
78     n_print ("%sEMPTY\n", pfx);
79     return;
80   }
81
82   for (i = 0; i < gst_caps_get_size (caps); i++) {
83     GstStructure *structure = gst_caps_get_structure (caps, i);
84
85     n_print ("%s%s\n", pfx, gst_structure_get_name (structure));
86     gst_structure_foreach (structure, print_field, (gpointer) pfx);
87   }
88 }
89
90 #if 0
91 static void
92 print_formats (const GstFormat * formats)
93 {
94   while (formats && *formats) {
95     const GstFormatDefinition *definition;
96
97     definition = gst_format_get_details (*formats);
98     if (definition)
99       n_print ("\t\t(%d):\t%s (%s)\n", *formats,
100           definition->nick, definition->description);
101     else
102       n_print ("\t\t(%d):\tUnknown format\n", *formats);
103
104     formats++;
105   }
106 }
107 #endif
108
109 static void
110 print_query_types (const GstQueryType * types)
111 {
112   while (types && *types) {
113     const GstQueryTypeDefinition *definition;
114
115     definition = gst_query_type_get_details (*types);
116     if (definition)
117       n_print ("\t\t(%d):\t%s (%s)\n", *types,
118           definition->nick, definition->description);
119     else
120       n_print ("\t\t(%d):\tUnknown query format\n", *types);
121
122     types++;
123   }
124 }
125
126 #ifndef GST_DISABLE_ENUMTYPES
127 #if 0
128 static void
129 print_event_masks (const GstEventMask * masks)
130 {
131   GType event_type;
132   GEnumClass *klass;
133   GType event_flags;
134   GFlagsClass *flags_class = NULL;
135
136   event_type = gst_event_type_get_type ();
137   klass = (GEnumClass *) g_type_class_ref (event_type);
138
139   while (masks && masks->type) {
140     GEnumValue *value;
141     gint flags = 0, index = 0;
142
143     switch (masks->type) {
144       case GST_EVENT_SEEK:
145         flags = masks->flags;
146         event_flags = gst_seek_type_get_type ();
147         flags_class = (GFlagsClass *) g_type_class_ref (event_flags);
148         break;
149       default:
150         break;
151     }
152
153     value = g_enum_get_value (klass, masks->type);
154     g_print ("\t\t%s ", value->value_nick);
155
156     while (flags) {
157       GFlagsValue *value;
158
159       if (flags & 1) {
160         value = g_flags_get_first_value (flags_class, 1 << index);
161
162         if (value)
163           g_print ("| %s ", value->value_nick);
164         else
165           g_print ("| ? ");
166       }
167       flags >>= 1;
168       index++;
169     }
170     g_print ("\n");
171
172     masks++;
173   }
174 }
175 #endif
176 #else
177 static void
178 print_event_masks (const GstEventMask * masks)
179 {
180 }
181 #endif
182
183 static char *
184 get_rank_name (gint rank)
185 {
186   switch (rank) {
187     case GST_RANK_NONE:
188       return "none";
189     case GST_RANK_MARGINAL:
190       return "marginal";
191     case GST_RANK_SECONDARY:
192       return "secondary";
193     case GST_RANK_PRIMARY:
194       return "primary";
195     default:
196       return "unknown";
197   }
198 }
199
200 static void
201 print_factory_details_info (GstElementFactory * factory)
202 {
203   n_print ("Factory Details:\n");
204   n_print ("  Long name:\t%s\n", factory->details.longname);
205   n_print ("  Class:\t%s\n", factory->details.klass);
206   n_print ("  Description:\t%s\n", factory->details.description);
207   n_print ("  Author(s):\t%s\n", factory->details.author);
208   n_print ("  Rank:\t\t%s (%d)\n",
209       get_rank_name (GST_PLUGIN_FEATURE (factory)->rank),
210       GST_PLUGIN_FEATURE (factory)->rank);
211   n_print ("\n");
212 }
213
214 static void
215 print_hierarchy (GType type, gint level, gint * maxlevel)
216 {
217   GType parent;
218   gint i;
219
220   parent = g_type_parent (type);
221
222   *maxlevel = *maxlevel + 1;
223   level++;
224
225   if (parent)
226     print_hierarchy (parent, level, maxlevel);
227
228   if (_name)
229     g_print (_name);
230
231   for (i = 1; i < *maxlevel - level; i++)
232     g_print ("      ");
233   if (*maxlevel - level)
234     g_print (" +----");
235
236   g_print ("%s\n", g_type_name (type));
237
238   if (level == 1)
239     n_print ("\n");
240 }
241
242 static void
243 print_interfaces (GType type)
244 {
245   guint n_ifaces;
246   GType *iface, *ifaces = g_type_interfaces (type, &n_ifaces);
247
248   if (ifaces) {
249     if (n_ifaces) {
250       g_print ("Implemented Interfaces:\n");
251       iface = ifaces;
252       while (*iface) {
253         g_print ("  %s\n", g_type_name (*iface));
254         iface++;
255       }
256       g_print ("\n");
257       g_free (ifaces);
258     }
259   }
260 }
261
262 static void
263 print_element_properties_info (GstElement * element)
264 {
265   GParamSpec **property_specs;
266   guint num_properties, i;
267   gboolean readable;
268   gboolean first_flag;
269
270   property_specs = g_object_class_list_properties
271       (G_OBJECT_GET_CLASS (element), &num_properties);
272   n_print ("\n");
273   n_print ("Element Properties:\n");
274
275   for (i = 0; i < num_properties; i++) {
276     GValue value = { 0, };
277     GParamSpec *param = property_specs[i];
278
279     readable = FALSE;
280
281     g_value_init (&value, param->value_type);
282
283     n_print ("  %-20s: %s\n", g_param_spec_get_name (param),
284         g_param_spec_get_blurb (param));
285
286     first_flag = TRUE;
287     n_print ("%-23.23s flags: ", "");
288     if (param->flags & G_PARAM_READABLE) {
289       g_object_get_property (G_OBJECT (element), param->name, &value);
290       readable = TRUE;
291       g_print ((first_flag ? "readable" : ", readable"));
292       first_flag = FALSE;
293     }
294     if (param->flags & G_PARAM_WRITABLE) {
295       g_print ((first_flag ? "writable" : ", writable"));
296       first_flag = FALSE;
297     }
298     if (param->flags & GST_PARAM_CONTROLLABLE) {
299       g_print ((first_flag ? "controllable" : ", controllable"));
300       first_flag = FALSE;
301     }
302     n_print ("\n");
303
304     switch (G_VALUE_TYPE (&value)) {
305       case G_TYPE_STRING:
306       {
307         GParamSpecString *pstring = G_PARAM_SPEC_STRING (param);
308
309         n_print ("%-23.23s String. ", "");
310
311         if (pstring->default_value == NULL)
312           g_print ("Default: null ");
313         else
314           g_print ("Default: \"%s\" ", pstring->default_value);
315
316         if (readable) {
317           const char *string_val = g_value_get_string (&value);
318
319           if (string_val == NULL)
320             g_print ("Current: null");
321           else
322             g_print ("Current: \"%s\"", string_val);
323         }
324         break;
325       }
326       case G_TYPE_BOOLEAN:
327       {
328         GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (param);
329
330         n_print ("%-23.23s Boolean. ", "");
331         g_print ("Default: %s ", (pboolean->default_value ? "true" : "false"));
332         if (readable)
333           g_print ("Current: %s",
334               (g_value_get_boolean (&value) ? "true" : "false"));
335         break;
336       }
337       case G_TYPE_ULONG:
338       {
339         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
340
341         n_print ("%-23.23s Unsigned Long. ", "");
342         g_print ("Range: %lu - %lu Default: %lu ",
343             pulong->minimum, pulong->maximum, pulong->default_value);
344         if (readable)
345           g_print ("Current: %lu", g_value_get_ulong (&value));
346         break;
347       }
348       case G_TYPE_LONG:
349       {
350         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
351
352         n_print ("%-23.23s Long. ", "");
353         g_print ("Range: %ld - %ld Default: %ld ",
354             plong->minimum, plong->maximum, plong->default_value);
355         if (readable)
356           g_print ("Current: %ld", g_value_get_long (&value));
357         break;
358       }
359       case G_TYPE_UINT:
360       {
361         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
362
363         n_print ("%-23.23s Unsigned Integer. ", "");
364         g_print ("Range: %u - %u Default: %u ",
365             puint->minimum, puint->maximum, puint->default_value);
366         if (readable)
367           g_print ("Current: %u", g_value_get_uint (&value));
368         break;
369       }
370       case G_TYPE_INT:
371       {
372         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
373
374         n_print ("%-23.23s Integer. ", "");
375         g_print ("Range: %d - %d Default: %d ",
376             pint->minimum, pint->maximum, pint->default_value);
377         if (readable)
378           g_print ("Current: %d", g_value_get_int (&value));
379         break;
380       }
381       case G_TYPE_UINT64:
382       {
383         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
384
385         n_print ("%-23.23s Unsigned Integer64. ", "");
386         g_print ("Range: %" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT
387             " Default: %" G_GUINT64_FORMAT " ",
388             puint64->minimum, puint64->maximum, puint64->default_value);
389         if (readable)
390           g_print ("Current: %" G_GUINT64_FORMAT, g_value_get_uint64 (&value));
391         break;
392       }
393       case G_TYPE_INT64:
394       {
395         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
396
397         n_print ("%-23.23s Integer64. ", "");
398         g_print ("Range: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT
399             " Default: %" G_GINT64_FORMAT " ",
400             pint64->minimum, pint64->maximum, pint64->default_value);
401         if (readable)
402           g_print ("Current: %" G_GINT64_FORMAT, g_value_get_int64 (&value));
403         break;
404       }
405       case G_TYPE_FLOAT:
406       {
407         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
408
409         n_print ("%-23.23s Float. ", "");
410         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
411             pfloat->minimum, pfloat->maximum, pfloat->default_value);
412         if (readable)
413           g_print ("Current: %15.7g\n", g_value_get_float (&value));
414         break;
415       }
416       case G_TYPE_DOUBLE:
417       {
418         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
419
420         n_print ("%-23.23s Double. ", "");
421         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
422             pdouble->minimum, pdouble->maximum, pdouble->default_value);
423         if (readable)
424           g_print ("Current: %15.7g\n", g_value_get_double (&value));
425         break;
426       }
427       default:
428         if (param->value_type == GST_TYPE_URI) {
429           n_print ("%-23.23s URI", "");
430         }
431         if (param->value_type == GST_TYPE_CAPS) {
432           const GstCaps *caps = gst_value_get_caps (&value);
433
434           if (!caps)
435             n_print ("%-23.23s Caps (NULL)", "");
436           else {
437             print_caps (caps, "                           ");
438           }
439         } else if (G_IS_PARAM_SPEC_ENUM (param)) {
440           GEnumValue *values;
441           guint j = 0;
442           gint enum_value;
443
444           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
445           enum_value = g_value_get_enum (&value);
446
447           while (values[j].value_name) {
448             if (values[j].value == enum_value)
449               break;
450             j++;
451           }
452
453           n_print ("%-23.23s Enum \"%s\" Current: %d, \"%s\"", "",
454               g_type_name (G_VALUE_TYPE (&value)),
455               enum_value, values[j].value_nick);
456
457           j = 0;
458           while (values[j].value_name) {
459             g_print ("\n%s%-23.23s    (%d): \t%s", "",
460                 _name, values[j].value, values[j].value_nick);
461             j++;
462           }
463           /* g_type_class_unref (ec); */
464         } else if (G_IS_PARAM_SPEC_FLAGS (param)) {
465           GFlagsValue *values;
466           guint j = 0;
467           gint flags_value;
468           GString *flags = NULL;
469
470           values = G_FLAGS_CLASS (g_type_class_ref (param->value_type))->values;
471           flags_value = g_value_get_flags (&value);
472
473           while (values[j].value_name) {
474             if (values[j].value & flags_value) {
475               if (flags) {
476                 g_string_append_printf (flags, " | %s", values[j].value_nick);
477               } else {
478                 flags = g_string_new (values[j].value_nick);
479               }
480             }
481             j++;
482           }
483
484           n_print ("%-23.23s Flags \"%s\" Current: %d, \"%s\"", "",
485               g_type_name (G_VALUE_TYPE (&value)),
486               flags_value, (flags ? flags->str : "(none)"));
487
488           j = 0;
489           while (values[j].value_name) {
490             g_print ("\n%s%-23.23s    (%d): \t%s", "",
491                 _name, values[j].value, values[j].value_nick);
492             j++;
493           }
494
495           if (flags)
496             g_string_free (flags, TRUE);
497         } else if (G_IS_PARAM_SPEC_OBJECT (param)) {
498           n_print ("%-23.23s Object of type \"%s\"", "",
499               g_type_name (param->value_type));
500         } else {
501           n_print ("%-23.23s Unknown type %ld \"%s\"", "", param->value_type,
502               g_type_name (param->value_type));
503         }
504         break;
505     }
506     if (!readable)
507       g_print (" Write only\n");
508     else
509       g_print ("\n");
510   }
511   if (num_properties == 0)
512     n_print ("  none\n");
513
514   g_free (property_specs);
515 }
516
517 static void
518 print_pad_templates_info (GstElement * element, GstElementFactory * factory)
519 {
520   GstElementClass *gstelement_class;
521   const GList *pads;
522   GstStaticPadTemplate *padtemplate;
523
524   n_print ("Pad Templates:\n");
525   if (!factory->numpadtemplates) {
526     n_print ("  none\n");
527     return;
528   }
529
530   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
531
532   pads = factory->staticpadtemplates;
533   while (pads) {
534     padtemplate = (GstStaticPadTemplate *) (pads->data);
535     pads = g_list_next (pads);
536
537     if (padtemplate->direction == GST_PAD_SRC)
538       n_print ("  SRC template: '%s'\n", padtemplate->name_template);
539     else if (padtemplate->direction == GST_PAD_SINK)
540       n_print ("  SINK template: '%s'\n", padtemplate->name_template);
541     else
542       n_print ("  UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
543
544     if (padtemplate->presence == GST_PAD_ALWAYS)
545       n_print ("    Availability: Always\n");
546     else if (padtemplate->presence == GST_PAD_SOMETIMES)
547       n_print ("    Availability: Sometimes\n");
548     else if (padtemplate->presence == GST_PAD_REQUEST) {
549       n_print ("    Availability: On request\n");
550       n_print ("      Has request_new_pad() function: %s\n",
551           GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad));
552     } else
553       n_print ("    Availability: UNKNOWN!!!\n");
554
555     if (padtemplate->static_caps.string) {
556       n_print ("    Capabilities:\n");
557       print_caps (gst_static_caps_get (&padtemplate->static_caps), "      ");
558     }
559
560     n_print ("\n");
561   }
562 }
563
564 static void
565 print_element_flag_info (GstElement * element)
566 {
567   gboolean have_flags = FALSE;
568
569   n_print ("\n");
570   n_print ("Element Flags:\n");
571
572   if (!have_flags)
573     n_print ("  no flags set\n");
574
575   if (GST_IS_BIN (element)) {
576     n_print ("\n");
577     n_print ("Bin Flags:\n");
578     if (!have_flags)
579       n_print ("  no flags set\n");
580   }
581 }
582
583 static void
584 print_implementation_info (GstElement * element)
585 {
586   GstObjectClass *gstobject_class;
587   GstElementClass *gstelement_class;
588
589   gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element));
590   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
591
592   n_print ("\n");
593   n_print ("Element Implementation:\n");
594
595   n_print ("  No loopfunc(), must be chain-based or not configured yet\n");
596
597   n_print ("  Has change_state() function: %s\n",
598       GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
599 #ifndef GST_DISABLE_LOADSAVE
600   n_print ("  Has custom save_thyself() function: %s\n",
601       GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself));
602   n_print ("  Has custom restore_thyself() function: %s\n",
603       GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself));
604 #endif
605 }
606
607 static void
608 print_clocking_info (GstElement * element)
609 {
610   if (!gst_element_requires_clock (element) &&
611       !(gst_element_provides_clock (element) &&
612           gst_element_get_clock (element))) {
613     n_print ("\n");
614     n_print ("Element has no clocking capabilities.");
615     return;
616   }
617
618   n_print ("\n");
619   n_print ("Clocking Interaction:\n");
620   if (gst_element_requires_clock (element)) {
621     n_print ("  element requires a clock\n");
622   }
623
624   if (gst_element_provides_clock (element)) {
625     GstClock *clock;
626
627     clock = gst_element_get_clock (element);
628     if (clock)
629       n_print ("  element provides a clock: %s\n", GST_OBJECT_NAME (clock));
630     else
631       n_print ("  element is supposed to provide a clock but returned NULL\n");
632   }
633 }
634
635 #ifndef GST_DISABLE_INDEX
636 static void
637 print_index_info (GstElement * element)
638 {
639   if (gst_element_is_indexable (element)) {
640     n_print ("\n");
641     n_print ("Indexing capabilities:\n");
642     n_print ("  element can do indexing\n");
643   } else {
644     n_print ("\n");
645     n_print ("Element has no indexing capabilities.\n");
646   }
647 }
648 #else
649 static void
650 print_index_info (GstElement * element)
651 {
652 }
653 #endif
654
655 static void
656 print_pad_info (GstElement * element)
657 {
658   const GList *pads;
659   GstPad *pad;
660
661   n_print ("\n");
662   n_print ("Pads:\n");
663
664   if (!element->numpads) {
665     n_print ("  none\n");
666     return;
667   }
668
669   pads = element->pads;
670   while (pads) {
671     pad = GST_PAD (pads->data);
672     pads = g_list_next (pads);
673
674     n_print ("");
675
676     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
677       g_print ("  SRC: '%s'", gst_pad_get_name (pad));
678     else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
679       g_print ("  SINK: '%s'", gst_pad_get_name (pad));
680     else
681       g_print ("  UNKNOWN!!!: '%s'", gst_pad_get_name (pad));
682
683     g_print ("\n");
684
685     n_print ("    Implementation:\n");
686     if (pad->chainfunc)
687       n_print ("      Has chainfunc(): %s\n",
688           GST_DEBUG_FUNCPTR_NAME (pad->chainfunc));
689     if (pad->getrangefunc)
690       n_print ("      Has getrangefunc(): %s\n",
691           GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc));
692     if (pad->eventfunc != gst_pad_event_default)
693       n_print ("      Has custom eventfunc(): %s\n",
694           GST_DEBUG_FUNCPTR_NAME (pad->eventfunc));
695     if (pad->queryfunc != gst_pad_query_default)
696       n_print ("      Has custom queryfunc(): %s\n",
697           GST_DEBUG_FUNCPTR_NAME (pad->queryfunc));
698     if (pad->querytypefunc != gst_pad_get_query_types_default) {
699       n_print ("        Provides query types:\n");
700       print_query_types (gst_pad_get_query_types (pad));
701     }
702
703     if (pad->intlinkfunc != gst_pad_get_internal_links_default)
704       n_print ("      Has custom intconnfunc(): %s\n",
705           GST_DEBUG_FUNCPTR_NAME (pad->intlinkfunc));
706
707     if (pad->bufferallocfunc)
708       n_print ("      Has bufferallocfunc(): %s\n",
709           GST_DEBUG_FUNCPTR_NAME (pad->bufferallocfunc));
710
711     if (pad->padtemplate)
712       n_print ("    Pad Template: '%s'\n", pad->padtemplate->name_template);
713
714     if (pad->caps) {
715       n_print ("    Capabilities:\n");
716       print_caps (pad->caps, "      ");
717     }
718   }
719 }
720
721 #if 0
722 static gint
723 compare_signal_names (GSignalQuery * a, GSignalQuery * b)
724 {
725   return strcmp (a->signal_name, b->signal_name);
726 }
727 #endif
728
729 static void
730 print_signal_info (GstElement * element)
731 {
732   /* Signals/Actions Block */
733   guint *signals;
734   guint nsignals;
735   gint i = 0, j, k;
736   GSignalQuery *query = NULL;
737   GType type;
738   GSList *found_signals, *l;
739
740   for (k = 0; k < 2; k++) {
741     found_signals = NULL;
742     for (type = G_OBJECT_TYPE (element); type; type = g_type_parent (type)) {
743       if (type == GST_TYPE_ELEMENT || type == GST_TYPE_OBJECT)
744         break;
745
746       if (type == GST_TYPE_BIN && G_OBJECT_TYPE (element) != GST_TYPE_BIN)
747         continue;
748
749       signals = g_signal_list_ids (type, &nsignals);
750       for (i = 0; i < nsignals; i++) {
751         query = g_new0 (GSignalQuery, 1);
752         g_signal_query (signals[i], query);
753
754         if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
755             (k == 1 && (query->signal_flags & G_SIGNAL_ACTION)))
756           found_signals = g_slist_append (found_signals, query);
757       }
758     }
759
760     if (found_signals) {
761       n_print ("\n");
762       if (k == 0)
763         n_print ("Element Signals:\n");
764       else
765         n_print ("Element Actions:\n");
766     } else {
767       continue;
768     }
769
770     for (l = found_signals; l; l = l->next) {
771       gchar *indent;
772       int indent_len;
773
774       query = (GSignalQuery *) l->data;
775       indent_len = strlen (query->signal_name) +
776           strlen (g_type_name (query->return_type)) + 24;
777
778       indent = g_new0 (gchar, indent_len + 1);
779       memset (indent, ' ', indent_len);
780
781       n_print ("  \"%s\" :  %s user_function (%s* object",
782           query->signal_name,
783           g_type_name (query->return_type), g_type_name (type));
784
785       for (j = 0; j < query->n_params; j++) {
786         if (G_TYPE_IS_FUNDAMENTAL (query->param_types[j])) {
787           g_print (",\n%s%s%s arg%d", _name, indent,
788               g_type_name (query->param_types[j]), j);
789         } else {
790           g_print (",\n%s%s%s* arg%d", _name, indent,
791               g_type_name (query->param_types[j]), j);
792         }
793       }
794
795       if (k == 0)
796         g_print (",\n%s%sgpointer user_data);\n", _name, indent);
797       else
798         g_print (");\n");
799
800       g_free (indent);
801     }
802
803     if (found_signals) {
804       g_slist_foreach (found_signals, (GFunc) g_free, NULL);
805       g_slist_free (found_signals);
806     }
807   }
808 }
809
810 static void
811 print_children_info (GstElement * element)
812 {
813   GList *children;
814
815   if (!GST_IS_BIN (element))
816     return;
817
818   children = (GList *) GST_BIN (element)->children;
819   if (children) {
820     n_print ("\n");
821     g_print ("Children:\n");
822   }
823
824   while (children) {
825     n_print ("  %s\n", GST_ELEMENT_NAME (GST_ELEMENT (children->data)));
826     children = g_list_next (children);
827   }
828 }
829
830 static void
831 print_element_list (gboolean print_all)
832 {
833   int plugincount = 0, featurecount = 0;
834   GList *plugins, *orig_plugins;
835
836   orig_plugins = plugins = gst_default_registry_get_plugin_list ();
837   while (plugins) {
838     GList *features, *orig_features;
839     GstPlugin *plugin;
840
841     plugin = (GstPlugin *) (plugins->data);
842     plugins = g_list_next (plugins);
843     plugincount++;
844
845     orig_features = features =
846         gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
847         plugin->desc.name);
848     while (features) {
849       GstPluginFeature *feature;
850
851       feature = GST_PLUGIN_FEATURE (features->data);
852       featurecount++;
853
854       if (GST_IS_ELEMENT_FACTORY (feature)) {
855         GstElementFactory *factory;
856
857         factory = GST_ELEMENT_FACTORY (feature);
858         if (print_all)
859           print_element_info (factory, TRUE);
860         else
861           g_print ("%s:  %s: %s\n", plugin->desc.name,
862               GST_PLUGIN_FEATURE_NAME (factory), factory->details.longname);
863       }
864 #ifndef GST_DISABLE_INDEX
865       else if (GST_IS_INDEX_FACTORY (feature)) {
866         GstIndexFactory *factory;
867
868         factory = GST_INDEX_FACTORY (feature);
869         if (!print_all)
870           g_print ("%s:  %s: %s\n", plugin->desc.name,
871               GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
872       }
873 #endif
874       else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
875         GstTypeFindFactory *factory;
876
877         factory = GST_TYPE_FIND_FACTORY (feature);
878         if (!print_all)
879           g_print ("%s: %s: ", plugin->desc.name,
880               gst_plugin_feature_get_name (feature));
881         if (factory->extensions) {
882           guint i = 0;
883
884           while (factory->extensions[i]) {
885             if (!print_all)
886               g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
887             i++;
888           }
889           if (!print_all)
890             g_print ("\n");
891         } else {
892           if (!print_all)
893             g_print ("no extensions\n");
894         }
895       } else {
896         if (!print_all)
897           n_print ("%s:  %s (%s)\n", plugin->desc.name,
898               GST_PLUGIN_FEATURE_NAME (feature),
899               g_type_name (G_OBJECT_TYPE (feature)));
900       }
901
902       features = g_list_next (features);
903     }
904
905     gst_plugin_feature_list_free (orig_features);
906   }
907
908   gst_plugin_list_free (plugins);
909
910   g_print ("\nTotal plugins: %d\nTotal features: %d\n",
911       plugincount, featurecount);
912 }
913
914 static void
915 print_plugin_info (GstPlugin * plugin)
916 {
917   n_print ("Plugin Details:\n");
918   n_print ("  Name:\t\t\t%s\n", plugin->desc.name);
919   n_print ("  Description:\t\t%s\n", plugin->desc.description);
920   n_print ("  Filename:\t\t%s\n",
921       plugin->filename ? plugin->filename : "(null)");
922   n_print ("  Version:\t\t%s\n", plugin->desc.version);
923   n_print ("  License:\t\t%s\n", plugin->desc.license);
924   n_print ("  Source module:\t%s\n", plugin->desc.source);
925   n_print ("  Binary package:\t%s\n", plugin->desc.package);
926   n_print ("  Origin URL:\t\t%s\n", plugin->desc.origin);
927   n_print ("\n");
928 }
929
930 static void
931 print_plugin_features (GstPlugin * plugin)
932 {
933   GList *features;
934   gint num_features = 0;
935   gint num_elements = 0;
936   gint num_types = 0;
937   gint num_indexes = 0;
938   gint num_other = 0;
939
940   features =
941       gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
942       plugin->desc.name);
943
944   while (features) {
945     GstPluginFeature *feature;
946
947     feature = GST_PLUGIN_FEATURE (features->data);
948
949     if (GST_IS_ELEMENT_FACTORY (feature)) {
950       GstElementFactory *factory;
951
952       factory = GST_ELEMENT_FACTORY (feature);
953       n_print ("  %s: %s\n", GST_PLUGIN_FEATURE_NAME (factory),
954           factory->details.longname);
955       num_elements++;
956     }
957 #ifndef GST_DISABLE_INDEX
958     else if (GST_IS_INDEX_FACTORY (feature)) {
959       GstIndexFactory *factory;
960
961       factory = GST_INDEX_FACTORY (feature);
962       n_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
963       num_indexes++;
964     }
965 #endif
966     else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
967       GstTypeFindFactory *factory;
968
969       factory = GST_TYPE_FIND_FACTORY (feature);
970       if (factory->extensions) {
971         guint i = 0;
972
973         g_print ("%s type: ", plugin->desc.name);
974         while (factory->extensions[i]) {
975           g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
976           i++;
977         }
978         g_print ("\n");
979       } else
980         g_print ("%s type: N/A\n", plugin->desc.name);
981
982       num_types++;
983     } else {
984       n_print ("  %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)),
985           g_type_name (G_OBJECT_TYPE (feature)));
986       num_other++;
987     }
988     num_features++;
989     features = g_list_next (features);
990   }
991   n_print ("\n");
992   n_print ("  %d features:\n", num_features);
993   if (num_elements > 0)
994     n_print ("  +-- %d elements\n", num_elements);
995   if (num_types > 0)
996     n_print ("  +-- %d types\n", num_types);
997   if (num_indexes > 0)
998     n_print ("  +-- %d indexes\n", num_indexes);
999   if (num_other > 0)
1000     n_print ("  +-- %d other objects\n", num_other);
1001
1002   n_print ("\n");
1003 }
1004
1005 static int
1006 print_element_features (const gchar * element_name)
1007 {
1008   GstPluginFeature *feature;
1009
1010   /* FIXME implement other pretty print function for these */
1011 #ifndef GST_DISABLE_INDEX
1012   feature = gst_default_registry_find_feature (element_name,
1013       GST_TYPE_INDEX_FACTORY);
1014   if (feature) {
1015     n_print ("%s: an index\n", element_name);
1016     return 0;
1017   }
1018 #endif
1019   feature = gst_default_registry_find_feature (element_name,
1020       GST_TYPE_TYPE_FIND_FACTORY);
1021   if (feature) {
1022     n_print ("%s: a typefind function\n", element_name);
1023     return 0;
1024   }
1025 #ifndef GST_DISABLE_URI
1026   feature = gst_default_registry_find_feature (element_name,
1027       GST_TYPE_URI_HANDLER);
1028   if (feature) {
1029     n_print ("%s: an uri handler\n", element_name);
1030     return 0;
1031   }
1032 #endif
1033
1034   return -1;
1035 }
1036
1037 static int
1038 print_element_info (GstElementFactory * factory, gboolean print_names)
1039 {
1040   GstElement *element;
1041   gint maxlevel = 0;
1042
1043   factory =
1044       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
1045           (factory)));
1046
1047   if (!factory) {
1048     g_print ("element plugin couldn't be loaded\n");
1049     return -1;
1050   }
1051
1052   element = gst_element_factory_create (factory, NULL);
1053   if (!element) {
1054     g_print ("couldn't construct element for some reason\n");
1055     return -1;
1056   }
1057
1058   if (print_names)
1059     _name = g_strdup_printf ("%s: ", GST_PLUGIN_FEATURE (factory)->name);
1060   else
1061     _name = "";
1062
1063   print_factory_details_info (factory);
1064   if (GST_PLUGIN_FEATURE (factory)->plugin_name) {
1065     GstPlugin *plugin;
1066
1067     plugin = gst_registry_find_plugin (gst_registry_get_default (),
1068         GST_PLUGIN_FEATURE (factory)->plugin_name);
1069     if (plugin) {
1070       print_plugin_info (plugin);
1071     }
1072   }
1073
1074   print_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel);
1075   print_interfaces (G_OBJECT_TYPE (element));
1076
1077   print_pad_templates_info (element, factory);
1078   print_element_flag_info (element);
1079   print_implementation_info (element);
1080   print_clocking_info (element);
1081   print_index_info (element);
1082   print_pad_info (element);
1083   print_element_properties_info (element);
1084   print_signal_info (element);
1085   print_children_info (element);
1086
1087   gst_object_unref (factory);
1088
1089   if (_name != "")
1090     g_free (_name);
1091
1092   return 0;
1093 }
1094
1095 int
1096 main (int argc, char *argv[])
1097 {
1098   gboolean print_all = FALSE;
1099   struct poptOption options[] = {
1100     {"print-all", 'a', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &print_all, 0,
1101         N_("Print all elements"), NULL},
1102     POPT_TABLEEND
1103   };
1104
1105 #ifdef GETTEXT_PACKAGE
1106   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1107   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1108   textdomain (GETTEXT_PACKAGE);
1109 #endif
1110
1111   gst_init_with_popt_table (&argc, &argv, options);
1112
1113   if (print_all && argc > 2) {
1114     g_print ("-a requires no extra arguments\n");
1115     return 1;
1116   }
1117
1118   /* if no arguments, print out list of elements */
1119   if (argc == 1 || print_all) {
1120     print_element_list (print_all);
1121     /* else we try to get a factory */
1122   } else {
1123     GstElementFactory *factory;
1124     GstPlugin *plugin;
1125     const char *arg = argv[argc - 1];
1126     int retval;
1127
1128     factory = gst_element_factory_find (arg);
1129     /* if there's a factory, print out the info */
1130     if (factory) {
1131       retval = print_element_info (factory, print_all);
1132     } else {
1133       retval = print_element_features (arg);
1134     }
1135
1136     /* otherwise check if it's a plugin */
1137     if (retval) {
1138       plugin = gst_default_registry_find_plugin (arg);
1139
1140       /* if there is such a plugin, print out info */
1141       if (plugin) {
1142         print_plugin_info (plugin);
1143         print_plugin_features (plugin);
1144       } else {
1145         GError *error = NULL;
1146
1147         if (g_file_test (arg, G_FILE_TEST_EXISTS)) {
1148           plugin = gst_plugin_load_file (arg, &error);
1149
1150           if (plugin) {
1151             print_plugin_info (plugin);
1152             print_plugin_features (plugin);
1153           } else {
1154             g_print ("Error loading plugin file: %s\n", error->message);
1155             g_error_free (error);
1156             return -1;
1157           }
1158         } else {
1159           g_print ("No such element or plugin '%s'\n", arg);
1160           return -1;
1161         }
1162       }
1163     }
1164   }
1165
1166   return 0;
1167 }