tools: minor clean-up
[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 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
25  * with newer GLib versions (>= 2.31.0) */
26 #define GLIB_DISABLE_DEPRECATION_WARNINGS
27
28 #ifdef HAVE_CONFIG_H
29 #  include "config.h"
30 #endif
31
32 #include "tools.h"
33
34 #include <string.h>
35 #include <locale.h>
36 #include <glib/gprintf.h>
37
38 static char *_name = NULL;
39
40 static int print_element_info (GstElementFactory * factory,
41     gboolean print_names);
42
43 static void
44 n_print (const char *format, ...)
45 {
46   va_list args;
47
48   if (_name)
49     g_print ("%s", _name);
50
51   va_start (args, format);
52   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
108 static void
109 print_event_masks (const GstEventMask * masks)
110 {
111   GType event_type;
112   GEnumClass *klass;
113   GType event_flags;
114   GFlagsClass *flags_class = NULL;
115
116   event_type = gst_event_type_get_type ();
117   klass = (GEnumClass *) g_type_class_ref (event_type);
118
119   while (masks && masks->type) {
120     GEnumValue *value;
121     gint flags = 0, index = 0;
122
123     switch (masks->type) {
124       case GST_EVENT_SEEK:
125         flags = masks->flags;
126         event_flags = gst_seek_type_get_type ();
127         flags_class = (GFlagsClass *) g_type_class_ref (event_flags);
128         break;
129       default:
130         break;
131     }
132
133     value = g_enum_get_value (klass, masks->type);
134     g_print ("\t\t%s ", value->value_nick);
135
136     while (flags) {
137       GFlagsValue *value;
138
139       if (flags & 1) {
140         value = g_flags_get_first_value (flags_class, 1 << index);
141
142         if (value)
143           g_print ("| %s ", value->value_nick);
144         else
145           g_print ("| ? ");
146       }
147       flags >>= 1;
148       index++;
149     }
150     g_print ("\n");
151
152     masks++;
153   }
154 }
155 #endif
156
157 static const char *
158 get_rank_name (char *s, gint rank)
159 {
160   static const int ranks[4] = {
161     GST_RANK_NONE, GST_RANK_MARGINAL, GST_RANK_SECONDARY, GST_RANK_PRIMARY
162   };
163   static const char *rank_names[4] = { "none", "marginal", "secondary",
164     "primary"
165   };
166   int i;
167   int best_i;
168
169   best_i = 0;
170   for (i = 0; i < 4; i++) {
171     if (rank == ranks[i])
172       return rank_names[i];
173     if (abs (rank - ranks[i]) < abs (rank - ranks[best_i])) {
174       best_i = i;
175     }
176   }
177
178   sprintf (s, "%s %c %d", rank_names[best_i],
179       (rank - ranks[best_i] > 0) ? '+' : '-', abs (ranks[best_i] - rank));
180
181   return s;
182 }
183
184 static void
185 print_factory_details_info (GstElementFactory * factory)
186 {
187   gchar **keys, **k;
188   GstRank rank;
189   char s[20];
190
191   rank = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory));
192   n_print ("Factory Details:\n");
193   n_print ("  Rank:\t\t%s (%d)\n", get_rank_name (s, rank), rank);
194
195   keys = gst_element_factory_get_metadata_keys (factory);
196   if (keys != NULL) {
197     for (k = keys; *k != NULL; ++k) {
198       const gchar *val;
199       gchar *key = *k;
200
201       val = gst_element_factory_get_metadata (factory, key);
202       key[0] = g_ascii_toupper (key[0]);
203       n_print ("  %s:\t\t%s\n", key, val);
204     }
205     g_strfreev (keys);
206   }
207   n_print ("\n");
208 }
209
210 static void
211 print_hierarchy (GType type, gint level, gint * maxlevel)
212 {
213   GType parent;
214   gint i;
215
216   parent = g_type_parent (type);
217
218   *maxlevel = *maxlevel + 1;
219   level++;
220
221   if (parent)
222     print_hierarchy (parent, level, maxlevel);
223
224   if (_name)
225     g_print ("%s", _name);
226
227   for (i = 1; i < *maxlevel - level; i++)
228     g_print ("      ");
229   if (*maxlevel - level)
230     g_print (" +----");
231
232   g_print ("%s\n", g_type_name (type));
233
234   if (level == 1)
235     n_print ("\n");
236 }
237
238 static void
239 print_interfaces (GType type)
240 {
241   guint n_ifaces;
242   GType *iface, *ifaces = g_type_interfaces (type, &n_ifaces);
243
244   if (ifaces) {
245     if (n_ifaces) {
246       if (_name)
247         g_print ("%s", _name);
248       g_print (_("Implemented Interfaces:\n"));
249       iface = ifaces;
250       while (*iface) {
251         if (_name)
252           g_print ("%s", _name);
253         g_print ("  %s\n", g_type_name (*iface));
254         iface++;
255       }
256       if (_name)
257         g_print ("%s", _name);
258       g_print ("\n");
259     }
260     g_free (ifaces);
261   }
262 }
263
264 static gchar *
265 flags_to_string (GFlagsValue * vals, guint flags)
266 {
267   GString *s = NULL;
268   guint flags_left, i;
269
270   /* first look for an exact match and count the number of values */
271   for (i = 0; vals[i].value_name != NULL; ++i) {
272     if (vals[i].value == flags)
273       return g_strdup (vals[i].value_nick);
274   }
275
276   s = g_string_new (NULL);
277
278   /* we assume the values are sorted from lowest to highest value */
279   flags_left = flags;
280   while (i > 0) {
281     --i;
282     if (vals[i].value != 0 && (flags_left & vals[i].value) == vals[i].value) {
283       if (s->len > 0)
284         g_string_append_c (s, '+');
285       g_string_append (s, vals[i].value_nick);
286       flags_left -= vals[i].value;
287       if (flags_left == 0)
288         break;
289     }
290   }
291
292   if (s->len == 0)
293     g_string_assign (s, "(none)");
294
295   return g_string_free (s, FALSE);
296 }
297
298 #define KNOWN_PARAM_FLAGS \
299   (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY | \
300   G_PARAM_LAX_VALIDATION |  G_PARAM_STATIC_STRINGS | \
301   G_PARAM_READABLE | G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE | \
302   GST_PARAM_MUTABLE_PLAYING | GST_PARAM_MUTABLE_PAUSED | \
303   GST_PARAM_MUTABLE_READY)
304
305 static void
306 print_element_properties_info (GstElement * element)
307 {
308   GParamSpec **property_specs;
309   guint num_properties, i;
310   gboolean readable;
311   gboolean first_flag;
312
313   property_specs = g_object_class_list_properties
314       (G_OBJECT_GET_CLASS (element), &num_properties);
315   n_print ("\n");
316   n_print ("Element Properties:\n");
317
318   for (i = 0; i < num_properties; i++) {
319     GValue value = { 0, };
320     GParamSpec *param = property_specs[i];
321
322     readable = FALSE;
323
324     g_value_init (&value, param->value_type);
325
326     n_print ("  %-20s: %s\n", g_param_spec_get_name (param),
327         g_param_spec_get_blurb (param));
328
329     first_flag = TRUE;
330     n_print ("%-23.23s flags: ", "");
331     if (param->flags & G_PARAM_READABLE) {
332       g_object_get_property (G_OBJECT (element), param->name, &value);
333       readable = TRUE;
334       g_print ("%s%s", (first_flag) ? "" : ", ", _("readable"));
335       first_flag = FALSE;
336     } else {
337       /* if we can't read the property value, assume it's set to the default
338        * (which might not be entirely true for sub-classes, but that's an
339        * unlikely corner-case anyway) */
340       g_param_value_set_default (param, &value);
341     }
342     if (param->flags & G_PARAM_WRITABLE) {
343       g_print ("%s%s", (first_flag) ? "" : ", ", _("writable"));
344       first_flag = FALSE;
345     }
346     if (param->flags & GST_PARAM_CONTROLLABLE) {
347       g_print (", %s", _("controllable"));
348       first_flag = FALSE;
349     }
350     if (param->flags & GST_PARAM_MUTABLE_PLAYING) {
351       g_print (", %s", _("changeable in NULL, READY, PAUSED or PLAYING state"));
352     } else if (param->flags & GST_PARAM_MUTABLE_PAUSED) {
353       g_print (", %s", _("changeable only in NULL, READY or PAUSED state"));
354     } else if (param->flags & GST_PARAM_MUTABLE_READY) {
355       g_print (", %s", _("changeable only in NULL or READY state"));
356     }
357     if (param->flags & ~KNOWN_PARAM_FLAGS) {
358       g_print ("%s0x%0x", (first_flag) ? "" : ", ",
359           param->flags & ~KNOWN_PARAM_FLAGS);
360     }
361     n_print ("\n");
362
363     switch (G_VALUE_TYPE (&value)) {
364       case G_TYPE_STRING:
365       {
366         const char *string_val = g_value_get_string (&value);
367
368         n_print ("%-23.23s String. ", "");
369
370         if (string_val == NULL)
371           g_print ("Default: null");
372         else
373           g_print ("Default: \"%s\"", string_val);
374         break;
375       }
376       case G_TYPE_BOOLEAN:
377       {
378         gboolean bool_val = g_value_get_boolean (&value);
379
380         n_print ("%-23.23s Boolean. ", "");
381
382         g_print ("Default: %s", bool_val ? "true" : "false");
383         break;
384       }
385       case G_TYPE_ULONG:
386       {
387         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
388
389         n_print ("%-23.23s Unsigned Long. ", "");
390         g_print ("Range: %lu - %lu Default: %lu ",
391             pulong->minimum, pulong->maximum, g_value_get_ulong (&value));
392
393         GST_ERROR ("%s: property '%s' of type ulong: consider changing to "
394             "uint/uint64", GST_OBJECT_NAME (element),
395             g_param_spec_get_name (param));
396         break;
397       }
398       case G_TYPE_LONG:
399       {
400         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
401
402         n_print ("%-23.23s Long. ", "");
403         g_print ("Range: %ld - %ld Default: %ld ",
404             plong->minimum, plong->maximum, g_value_get_long (&value));
405
406         GST_ERROR ("%s: property '%s' of type long: consider changing to "
407             "int/int64", GST_OBJECT_NAME (element),
408             g_param_spec_get_name (param));
409         break;
410       }
411       case G_TYPE_UINT:
412       {
413         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
414
415         n_print ("%-23.23s Unsigned Integer. ", "");
416         g_print ("Range: %u - %u Default: %u ",
417             puint->minimum, puint->maximum, g_value_get_uint (&value));
418         break;
419       }
420       case G_TYPE_INT:
421       {
422         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
423
424         n_print ("%-23.23s Integer. ", "");
425         g_print ("Range: %d - %d Default: %d ",
426             pint->minimum, pint->maximum, g_value_get_int (&value));
427         break;
428       }
429       case G_TYPE_UINT64:
430       {
431         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
432
433         n_print ("%-23.23s Unsigned Integer64. ", "");
434         g_print ("Range: %" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT
435             " Default: %" G_GUINT64_FORMAT " ",
436             puint64->minimum, puint64->maximum, g_value_get_uint64 (&value));
437         break;
438       }
439       case G_TYPE_INT64:
440       {
441         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
442
443         n_print ("%-23.23s Integer64. ", "");
444         g_print ("Range: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT
445             " Default: %" G_GINT64_FORMAT " ",
446             pint64->minimum, pint64->maximum, g_value_get_int64 (&value));
447         break;
448       }
449       case G_TYPE_FLOAT:
450       {
451         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
452
453         n_print ("%-23.23s Float. ", "");
454         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
455             pfloat->minimum, pfloat->maximum, g_value_get_float (&value));
456         break;
457       }
458       case G_TYPE_DOUBLE:
459       {
460         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
461
462         n_print ("%-23.23s Double. ", "");
463         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
464             pdouble->minimum, pdouble->maximum, g_value_get_double (&value));
465         break;
466       }
467       case G_TYPE_CHAR:
468       case G_TYPE_UCHAR:
469         GST_ERROR ("%s: property '%s' of type char: consider changing to "
470             "int/string", GST_OBJECT_NAME (element),
471             g_param_spec_get_name (param));
472         /* fall through */
473       default:
474         if (param->value_type == GST_TYPE_CAPS) {
475           const GstCaps *caps = gst_value_get_caps (&value);
476
477           if (!caps)
478             n_print ("%-23.23s Caps (NULL)", "");
479           else {
480             print_caps (caps, "                           ");
481           }
482         } else if (G_IS_PARAM_SPEC_ENUM (param)) {
483           GEnumValue *values;
484           guint j = 0;
485           gint enum_value;
486           const gchar *value_nick = "";
487
488           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
489           enum_value = g_value_get_enum (&value);
490
491           while (values[j].value_name) {
492             if (values[j].value == enum_value)
493               value_nick = values[j].value_nick;
494             j++;
495           }
496
497           n_print ("%-23.23s Enum \"%s\" Default: %d, \"%s\"", "",
498               g_type_name (G_VALUE_TYPE (&value)), enum_value, value_nick);
499
500           j = 0;
501           while (values[j].value_name) {
502             g_print ("\n");
503             if (_name)
504               g_print ("%s", _name);
505             g_print ("%-23.23s    (%d): %-16s - %s", "",
506                 values[j].value, values[j].value_nick, values[j].value_name);
507             j++;
508           }
509           /* g_type_class_unref (ec); */
510         } else if (G_IS_PARAM_SPEC_FLAGS (param)) {
511           GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (param);
512           GFlagsValue *vals;
513           gchar *cur;
514
515           vals = pflags->flags_class->values;
516
517           cur = flags_to_string (vals, g_value_get_flags (&value));
518
519           n_print ("%-23.23s Flags \"%s\" Default: 0x%08x, \"%s\"", "",
520               g_type_name (G_VALUE_TYPE (&value)),
521               g_value_get_flags (&value), cur);
522
523           while (vals[0].value_name) {
524             g_print ("\n");
525             if (_name)
526               g_print ("%s", _name);
527             g_print ("%-23.23s    (0x%08x): %-16s - %s", "",
528                 vals[0].value, vals[0].value_nick, vals[0].value_name);
529             ++vals;
530           }
531
532           g_free (cur);
533         } else if (G_IS_PARAM_SPEC_OBJECT (param)) {
534           n_print ("%-23.23s Object of type \"%s\"", "",
535               g_type_name (param->value_type));
536         } else if (G_IS_PARAM_SPEC_BOXED (param)) {
537           n_print ("%-23.23s Boxed pointer of type \"%s\"", "",
538               g_type_name (param->value_type));
539         } else if (G_IS_PARAM_SPEC_POINTER (param)) {
540           if (param->value_type != G_TYPE_POINTER) {
541             n_print ("%-23.23s Pointer of type \"%s\".", "",
542                 g_type_name (param->value_type));
543           } else {
544             n_print ("%-23.23s Pointer.", "");
545           }
546         } else if (param->value_type == G_TYPE_VALUE_ARRAY) {
547           GParamSpecValueArray *pvarray = G_PARAM_SPEC_VALUE_ARRAY (param);
548
549           if (pvarray->element_spec) {
550             n_print ("%-23.23s Array of GValues of type \"%s\"", "",
551                 g_type_name (pvarray->element_spec->value_type));
552           } else {
553             n_print ("%-23.23s Array of GValues", "");
554           }
555         } else if (GST_IS_PARAM_SPEC_FRACTION (param)) {
556           GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (param);
557
558           n_print ("%-23.23s Fraction. ", "");
559
560           g_print ("Range: %d/%d - %d/%d Default: %d/%d ",
561               pfraction->min_num, pfraction->min_den,
562               pfraction->max_num, pfraction->max_den,
563               gst_value_get_fraction_numerator (&value),
564               gst_value_get_fraction_denominator (&value));
565         } else {
566           n_print ("%-23.23s Unknown type %ld \"%s\"", "", param->value_type,
567               g_type_name (param->value_type));
568         }
569         break;
570     }
571     if (!readable)
572       g_print (" Write only\n");
573     else
574       g_print ("\n");
575
576     g_value_reset (&value);
577   }
578   if (num_properties == 0)
579     n_print ("  none\n");
580
581   g_free (property_specs);
582 }
583
584 static void
585 print_pad_templates_info (GstElement * element, GstElementFactory * factory)
586 {
587   GstElementClass *gstelement_class;
588   const GList *pads;
589   GstStaticPadTemplate *padtemplate;
590
591   n_print ("Pad Templates:\n");
592   if (gst_element_factory_get_num_pad_templates (factory) == 0) {
593     n_print ("  none\n");
594     return;
595   }
596
597   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
598
599   pads = gst_element_factory_get_static_pad_templates (factory);
600   while (pads) {
601     padtemplate = (GstStaticPadTemplate *) (pads->data);
602     pads = g_list_next (pads);
603
604     if (padtemplate->direction == GST_PAD_SRC)
605       n_print ("  SRC template: '%s'\n", padtemplate->name_template);
606     else if (padtemplate->direction == GST_PAD_SINK)
607       n_print ("  SINK template: '%s'\n", padtemplate->name_template);
608     else
609       n_print ("  UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
610
611     if (padtemplate->presence == GST_PAD_ALWAYS)
612       n_print ("    Availability: Always\n");
613     else if (padtemplate->presence == GST_PAD_SOMETIMES)
614       n_print ("    Availability: Sometimes\n");
615     else if (padtemplate->presence == GST_PAD_REQUEST) {
616       n_print ("    Availability: On request\n");
617       n_print ("      Has request_new_pad() function: %s\n",
618           GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad));
619     } else
620       n_print ("    Availability: UNKNOWN!!!\n");
621
622     if (padtemplate->static_caps.string) {
623       n_print ("    Capabilities:\n");
624       print_caps (gst_static_caps_get (&padtemplate->static_caps), "      ");
625     }
626
627     n_print ("\n");
628   }
629 }
630
631 static void
632 print_element_flag_info (GstElement * element)
633 {
634   gboolean have_flags = FALSE;
635
636   n_print ("\n");
637   n_print ("Element Flags:\n");
638
639   if (!have_flags)
640     n_print ("  no flags set\n");
641
642   if (GST_IS_BIN (element)) {
643     n_print ("\n");
644     n_print ("Bin Flags:\n");
645     if (!have_flags)
646       n_print ("  no flags set\n");
647   }
648 }
649
650 static void
651 print_implementation_info (GstElement * element)
652 {
653   GstElementClass *gstelement_class;
654
655   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
656
657   n_print ("\n");
658   n_print ("Element Implementation:\n");
659
660   n_print ("  Has change_state() function: %s\n",
661       GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
662 }
663
664 static void
665 print_clocking_info (GstElement * element)
666 {
667   gboolean requires_clock, provides_clock;
668
669   requires_clock =
670       GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
671   provides_clock =
672       GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
673
674   if (!requires_clock && !provides_clock) {
675     n_print ("\n");
676     n_print ("Element has no clocking capabilities.");
677     return;
678   }
679
680   n_print ("\n");
681   n_print ("Clocking Interaction:\n");
682   if (requires_clock) {
683     n_print ("  element requires a clock\n");
684   }
685
686   if (provides_clock) {
687     GstClock *clock;
688
689     clock = gst_element_get_clock (element);
690     if (clock) {
691       n_print ("  element provides a clock: %s\n", GST_OBJECT_NAME (clock));
692       gst_object_unref (clock);
693     } else
694       n_print ("  element is supposed to provide a clock but returned NULL\n");
695   }
696 }
697
698 static void
699 print_index_info (GstElement * element)
700 {
701   if (GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_INDEXABLE)) {
702     n_print ("\n");
703     n_print ("Indexing capabilities:\n");
704     n_print ("  element can do indexing\n");
705   } else {
706     n_print ("\n");
707     n_print ("Element has no indexing capabilities.\n");
708   }
709 }
710
711 static void
712 print_uri_handler_info (GstElement * element)
713 {
714   if (GST_IS_URI_HANDLER (element)) {
715     const gchar *const *uri_protocols;
716     const gchar *uri_type;
717
718     if (gst_uri_handler_get_uri_type (GST_URI_HANDLER (element)) == GST_URI_SRC)
719       uri_type = "source";
720     else if (gst_uri_handler_get_uri_type (GST_URI_HANDLER (element)) ==
721         GST_URI_SINK)
722       uri_type = "sink";
723     else
724       uri_type = "unknown";
725
726     uri_protocols = gst_uri_handler_get_protocols (GST_URI_HANDLER (element));
727
728     n_print ("\n");
729     n_print ("URI handling capabilities:\n");
730     n_print ("  Element can act as %s.\n", uri_type);
731
732     if (uri_protocols && *uri_protocols) {
733       n_print ("  Supported URI protocols:\n");
734       for (; *uri_protocols != NULL; uri_protocols++)
735         n_print ("    %s\n", *uri_protocols);
736     } else {
737       n_print ("  No supported URI protocols\n");
738     }
739   } else {
740     n_print ("Element has no URI handling capabilities.\n");
741   }
742 }
743
744 static void
745 print_pad_info (GstElement * element)
746 {
747   const GList *pads;
748   GstPad *pad;
749
750   n_print ("\n");
751   n_print ("Pads:\n");
752
753   if (!element->numpads) {
754     n_print ("  none\n");
755     return;
756   }
757
758   pads = element->pads;
759   while (pads) {
760     gchar *name;
761     GstCaps *caps;
762
763     pad = GST_PAD (pads->data);
764     pads = g_list_next (pads);
765
766     n_print ("");
767
768     name = gst_pad_get_name (pad);
769     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
770       g_print ("  SRC: '%s'", name);
771     else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
772       g_print ("  SINK: '%s'", name);
773     else
774       g_print ("  UNKNOWN!!!: '%s'", name);
775
776     g_free (name);
777
778     g_print ("\n");
779
780     n_print ("    Implementation:\n");
781     if (pad->chainfunc)
782       n_print ("      Has chainfunc(): %s\n",
783           GST_DEBUG_FUNCPTR_NAME (pad->chainfunc));
784     if (pad->getrangefunc)
785       n_print ("      Has getrangefunc(): %s\n",
786           GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc));
787     if (pad->eventfunc != gst_pad_event_default)
788       n_print ("      Has custom eventfunc(): %s\n",
789           GST_DEBUG_FUNCPTR_NAME (pad->eventfunc));
790     if (pad->queryfunc != gst_pad_query_default)
791       n_print ("      Has custom queryfunc(): %s\n",
792           GST_DEBUG_FUNCPTR_NAME (pad->queryfunc));
793
794     if (pad->iterintlinkfunc != gst_pad_iterate_internal_links_default)
795       n_print ("      Has custom iterintlinkfunc(): %s\n",
796           GST_DEBUG_FUNCPTR_NAME (pad->iterintlinkfunc));
797
798     if (pad->padtemplate)
799       n_print ("    Pad Template: '%s'\n", pad->padtemplate->name_template);
800
801     caps = gst_pad_get_current_caps (pad);
802     if (caps) {
803       n_print ("    Capabilities:\n");
804       print_caps (caps, "      ");
805       gst_caps_unref (caps);
806     }
807   }
808 }
809
810 static gboolean
811 has_sometimes_template (GstElement * element)
812 {
813   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
814   GList *l;
815
816   for (l = klass->padtemplates; l != NULL; l = l->next) {
817     if (GST_PAD_TEMPLATE (l->data)->presence == GST_PAD_SOMETIMES)
818       return TRUE;
819   }
820
821   return FALSE;
822 }
823
824 static void
825 print_signal_info (GstElement * element)
826 {
827   /* Signals/Actions Block */
828   guint *signals;
829   guint nsignals;
830   gint i = 0, j, k;
831   GSignalQuery *query = NULL;
832   GType type;
833   GSList *found_signals, *l;
834
835   for (k = 0; k < 2; k++) {
836     found_signals = NULL;
837
838     /* For elements that have sometimes pads, also list a few useful GstElement
839      * signals. Put these first, so element-specific ones come later. */
840     if (k == 0 && has_sometimes_template (element)) {
841       query = g_new0 (GSignalQuery, 1);
842       g_signal_query (g_signal_lookup ("pad-added", GST_TYPE_ELEMENT), query);
843       found_signals = g_slist_append (found_signals, query);
844       query = g_new0 (GSignalQuery, 1);
845       g_signal_query (g_signal_lookup ("pad-removed", GST_TYPE_ELEMENT), query);
846       found_signals = g_slist_append (found_signals, query);
847       query = g_new0 (GSignalQuery, 1);
848       g_signal_query (g_signal_lookup ("no-more-pads", GST_TYPE_ELEMENT),
849           query);
850       found_signals = g_slist_append (found_signals, query);
851     }
852
853     for (type = G_OBJECT_TYPE (element); type; type = g_type_parent (type)) {
854       if (type == GST_TYPE_ELEMENT || type == GST_TYPE_OBJECT)
855         break;
856
857       if (type == GST_TYPE_BIN && G_OBJECT_TYPE (element) != GST_TYPE_BIN)
858         continue;
859
860       signals = g_signal_list_ids (type, &nsignals);
861       for (i = 0; i < nsignals; i++) {
862         query = g_new0 (GSignalQuery, 1);
863         g_signal_query (signals[i], query);
864
865         if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
866             (k == 1 && (query->signal_flags & G_SIGNAL_ACTION)))
867           found_signals = g_slist_append (found_signals, query);
868         else
869           g_free (query);
870       }
871       g_free (signals);
872       signals = NULL;
873     }
874
875     if (found_signals) {
876       n_print ("\n");
877       if (k == 0)
878         n_print ("Element Signals:\n");
879       else
880         n_print ("Element Actions:\n");
881     } else {
882       continue;
883     }
884
885     for (l = found_signals; l; l = l->next) {
886       gchar *indent;
887       int indent_len;
888
889       query = (GSignalQuery *) l->data;
890       indent_len = strlen (query->signal_name) +
891           strlen (g_type_name (query->return_type)) + 24;
892
893       indent = g_new0 (gchar, indent_len + 1);
894       memset (indent, ' ', indent_len);
895
896       n_print ("  \"%s\" :  %s user_function (%s* object",
897           query->signal_name,
898           g_type_name (query->return_type), g_type_name (type));
899
900       for (j = 0; j < query->n_params; j++) {
901         g_print (",\n");
902         if (G_TYPE_IS_FUNDAMENTAL (query->param_types[j])) {
903           n_print ("%s%s arg%d", indent,
904               g_type_name (query->param_types[j]), j);
905         } else if (G_TYPE_IS_ENUM (query->param_types[j])) {
906           n_print ("%s%s arg%d", indent,
907               g_type_name (query->param_types[j]), j);
908         } else {
909           n_print ("%s%s* arg%d", indent,
910               g_type_name (query->param_types[j]), j);
911         }
912       }
913
914       if (k == 0) {
915         g_print (",\n");
916         n_print ("%sgpointer user_data);\n", indent);
917       } else
918         g_print (");\n");
919
920       g_free (indent);
921     }
922
923     if (found_signals) {
924       g_slist_foreach (found_signals, (GFunc) g_free, NULL);
925       g_slist_free (found_signals);
926     }
927   }
928 }
929
930 static void
931 print_children_info (GstElement * element)
932 {
933   GList *children;
934
935   if (!GST_IS_BIN (element))
936     return;
937
938   children = (GList *) GST_BIN (element)->children;
939   if (children) {
940     n_print ("\n");
941     n_print ("Children:\n");
942   }
943
944   while (children) {
945     n_print ("  %s\n", GST_ELEMENT_NAME (GST_ELEMENT (children->data)));
946     children = g_list_next (children);
947   }
948 }
949
950 static void
951 print_blacklist (void)
952 {
953   GList *plugins, *cur;
954   gint count = 0;
955
956   g_print ("%s\n", _("Blacklisted files:"));
957
958   plugins = gst_registry_get_plugin_list (gst_registry_get ());
959   for (cur = plugins; cur != NULL; cur = g_list_next (cur)) {
960     GstPlugin *plugin = (GstPlugin *) (cur->data);
961     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED)) {
962       g_print ("  %s\n", gst_plugin_get_name (plugin));
963       count++;
964     }
965   }
966
967   g_print ("\n");
968   g_print (_("Total count: "));
969   g_print (ngettext ("%d blacklisted file", "%d blacklisted files", count),
970       count);
971   g_print ("\n");
972   gst_plugin_list_free (plugins);
973 }
974
975 static void
976 print_element_list (gboolean print_all)
977 {
978   int plugincount = 0, featurecount = 0, blacklistcount = 0;
979   GList *plugins, *orig_plugins;
980
981   orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ());
982   while (plugins) {
983     GList *features, *orig_features;
984     GstPlugin *plugin;
985
986     plugin = (GstPlugin *) (plugins->data);
987     plugins = g_list_next (plugins);
988     plugincount++;
989
990     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED)) {
991       blacklistcount++;
992       continue;
993     }
994
995     orig_features = features =
996         gst_registry_get_feature_list_by_plugin (gst_registry_get (),
997         gst_plugin_get_name (plugin));
998     while (features) {
999       GstPluginFeature *feature;
1000
1001       if (G_UNLIKELY (features->data == NULL))
1002         goto next;
1003       feature = GST_PLUGIN_FEATURE (features->data);
1004       featurecount++;
1005
1006       if (GST_IS_ELEMENT_FACTORY (feature)) {
1007         GstElementFactory *factory;
1008
1009         factory = GST_ELEMENT_FACTORY (feature);
1010         if (print_all)
1011           print_element_info (factory, TRUE);
1012         else
1013           g_print ("%s:  %s: %s\n", gst_plugin_get_name (plugin),
1014               GST_OBJECT_NAME (factory),
1015               gst_element_factory_get_longname (factory));
1016 #if 0
1017       } else if (GST_IS_INDEX_FACTORY (feature)) {
1018         GstIndexFactory *factory;
1019
1020         factory = GST_INDEX_FACTORY (feature);
1021         if (!print_all)
1022           g_print ("%s:  %s: %s\n", plugin->desc.name,
1023               GST_OBJECT_NAME (factory), factory->longdesc);
1024 #endif
1025       } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
1026         GstTypeFindFactory *factory;
1027         const gchar *const *extensions;
1028
1029         factory = GST_TYPE_FIND_FACTORY (feature);
1030         if (!print_all)
1031           g_print ("%s: %s: ", gst_plugin_get_name (plugin),
1032               gst_plugin_feature_get_name (feature));
1033
1034         extensions = gst_type_find_factory_get_extensions (factory);
1035         if (extensions != NULL) {
1036           guint i = 0;
1037
1038           while (extensions[i]) {
1039             if (!print_all)
1040               g_print ("%s%s", i > 0 ? ", " : "", extensions[i]);
1041             i++;
1042           }
1043           if (!print_all)
1044             g_print ("\n");
1045         } else {
1046           if (!print_all)
1047             g_print ("no extensions\n");
1048         }
1049       } else {
1050         if (!print_all)
1051           n_print ("%s:  %s (%s)\n", gst_plugin_get_name (plugin),
1052               GST_OBJECT_NAME (feature), g_type_name (G_OBJECT_TYPE (feature)));
1053       }
1054
1055     next:
1056       features = g_list_next (features);
1057     }
1058
1059     gst_plugin_feature_list_free (orig_features);
1060   }
1061
1062   gst_plugin_list_free (orig_plugins);
1063
1064   g_print ("\n");
1065   g_print (_("Total count: "));
1066   g_print (ngettext ("%d plugin", "%d plugins", plugincount), plugincount);
1067   if (blacklistcount) {
1068     g_print (" (");
1069     g_print (ngettext ("%d blacklist entry", "%d blacklist entries",
1070             blacklistcount), blacklistcount);
1071     g_print (" not shown)");
1072   }
1073   g_print (", ");
1074   g_print (ngettext ("%d feature", "%d features", featurecount), featurecount);
1075   g_print ("\n");
1076 }
1077
1078 static void
1079 print_all_uri_handlers (void)
1080 {
1081   GList *plugins, *p, *features, *f;
1082
1083   plugins = gst_registry_get_plugin_list (gst_registry_get ());
1084
1085   for (p = plugins; p; p = p->next) {
1086     GstPlugin *plugin = (GstPlugin *) (p->data);
1087
1088     features =
1089         gst_registry_get_feature_list_by_plugin (gst_registry_get (),
1090         gst_plugin_get_name (plugin));
1091
1092     for (f = features; f; f = f->next) {
1093       GstPluginFeature *feature = GST_PLUGIN_FEATURE (f->data);
1094
1095       if (GST_IS_ELEMENT_FACTORY (feature)) {
1096         GstElementFactory *factory;
1097         GstElement *element;
1098
1099         factory = GST_ELEMENT_FACTORY (gst_plugin_feature_load (feature));
1100         if (!factory) {
1101           g_print ("element plugin %s couldn't be loaded\n",
1102               gst_plugin_get_name (plugin));
1103           continue;
1104         }
1105
1106         element = gst_element_factory_create (factory, NULL);
1107         if (!element) {
1108           g_print ("couldn't construct element for %s for some reason\n",
1109               GST_OBJECT_NAME (factory));
1110           gst_object_unref (factory);
1111           continue;
1112         }
1113
1114         if (GST_IS_URI_HANDLER (element)) {
1115           const gchar *const *uri_protocols;
1116           const gchar *dir;
1117           gchar *joined;
1118
1119           switch (gst_uri_handler_get_uri_type (GST_URI_HANDLER (element))) {
1120             case GST_URI_SRC:
1121               dir = "read";
1122               break;
1123             case GST_URI_SINK:
1124               dir = "write";
1125               break;
1126             default:
1127               dir = "unknown";
1128               break;
1129           }
1130
1131           uri_protocols =
1132               gst_uri_handler_get_protocols (GST_URI_HANDLER (element));
1133           joined = g_strjoinv (", ", (gchar **) uri_protocols);
1134
1135           g_print ("%s (%s, rank %u): %s\n",
1136               gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), dir,
1137               gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)),
1138               joined);
1139
1140           g_free (joined);
1141         }
1142
1143         gst_object_unref (element);
1144         gst_object_unref (factory);
1145       }
1146     }
1147
1148     gst_plugin_feature_list_free (features);
1149   }
1150
1151   gst_plugin_list_free (plugins);
1152 }
1153
1154 static void
1155 print_plugin_info (GstPlugin * plugin)
1156 {
1157   const gchar *release_date = gst_plugin_get_release_date_string (plugin);
1158   const gchar *filename = gst_plugin_get_filename (plugin);
1159
1160   n_print ("Plugin Details:\n");
1161   n_print ("  Name:\t\t\t%s\n", gst_plugin_get_name (plugin));
1162   n_print ("  Description:\t\t%s\n", gst_plugin_get_description (plugin));
1163   n_print ("  Filename:\t\t%s\n", (filename != NULL) ? filename : "(null)");
1164   n_print ("  Version:\t\t%s\n", gst_plugin_get_version (plugin));
1165   n_print ("  License:\t\t%s\n", gst_plugin_get_license (plugin));
1166   n_print ("  Source module:\t%s\n", gst_plugin_get_source (plugin));
1167
1168   if (release_date != NULL) {
1169     const gchar *tz = "(UTC)";
1170     gchar *str, *sep;
1171
1172     /* may be: YYYY-MM-DD or YYYY-MM-DDTHH:MMZ */
1173     /* YYYY-MM-DDTHH:MMZ => YYYY-MM-DD HH:MM (UTC) */
1174     str = g_strdup (release_date);
1175     sep = strstr (str, "T");
1176     if (sep != NULL) {
1177       *sep = ' ';
1178       sep = strstr (sep + 1, "Z");
1179       if (sep != NULL)
1180         *sep = ' ';
1181     } else {
1182       tz = "";
1183     }
1184     n_print ("  Source release date:\t%s%s\n", str, tz);
1185     g_free (str);
1186   }
1187   n_print ("  Binary package:\t%s\n", gst_plugin_get_package (plugin));
1188   n_print ("  Origin URL:\t\t%s\n", gst_plugin_get_origin (plugin));
1189   n_print ("\n");
1190 }
1191
1192 static void
1193 print_plugin_features (GstPlugin * plugin)
1194 {
1195   GList *features, *origlist;
1196   gint num_features = 0;
1197   gint num_elements = 0;
1198   gint num_typefinders = 0;
1199   gint num_indexes = 0;
1200   gint num_other = 0;
1201
1202   origlist = features =
1203       gst_registry_get_feature_list_by_plugin (gst_registry_get (),
1204       gst_plugin_get_name (plugin));
1205
1206   while (features) {
1207     GstPluginFeature *feature;
1208
1209     feature = GST_PLUGIN_FEATURE (features->data);
1210
1211     if (GST_IS_ELEMENT_FACTORY (feature)) {
1212       GstElementFactory *factory;
1213
1214       factory = GST_ELEMENT_FACTORY (feature);
1215       n_print ("  %s: %s\n", GST_OBJECT_NAME (factory),
1216           gst_element_factory_get_longname (factory));
1217       num_elements++;
1218 #if 0
1219     } else if (GST_IS_INDEX_FACTORY (feature)) {
1220       GstIndexFactory *factory;
1221
1222       factory = GST_INDEX_FACTORY (feature);
1223       n_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
1224       num_indexes++;
1225 #endif
1226     } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
1227       GstTypeFindFactory *factory;
1228       const gchar *const *extensions;
1229
1230       factory = GST_TYPE_FIND_FACTORY (feature);
1231       extensions = gst_type_find_factory_get_extensions (factory);
1232       if (extensions) {
1233         guint i = 0;
1234
1235         g_print ("%s: %s: ", gst_plugin_get_name (plugin),
1236             gst_plugin_feature_get_name (feature));
1237         while (extensions[i]) {
1238           g_print ("%s%s", i > 0 ? ", " : "", extensions[i]);
1239           i++;
1240         }
1241         g_print ("\n");
1242       } else
1243         g_print ("%s: %s: no extensions\n", gst_plugin_get_name (plugin),
1244             gst_plugin_feature_get_name (feature));
1245
1246       num_typefinders++;
1247     } else if (feature) {
1248       n_print ("  %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)),
1249           g_type_name (G_OBJECT_TYPE (feature)));
1250       num_other++;
1251     }
1252     num_features++;
1253     features = g_list_next (features);
1254   }
1255
1256   gst_plugin_feature_list_free (origlist);
1257
1258   n_print ("\n");
1259   n_print ("  %d features:\n", num_features);
1260   if (num_elements > 0)
1261     n_print ("  +-- %d elements\n", num_elements);
1262   if (num_typefinders > 0)
1263     n_print ("  +-- %d typefinders\n", num_typefinders);
1264   if (num_indexes > 0)
1265     n_print ("  +-- %d indexes\n", num_indexes);
1266   if (num_other > 0)
1267     n_print ("  +-- %d other objects\n", num_other);
1268
1269   n_print ("\n");
1270 }
1271
1272 static int
1273 print_element_features (const gchar * element_name)
1274 {
1275   GstPluginFeature *feature;
1276
1277   /* FIXME implement other pretty print function for these */
1278 #if 0
1279   feature = gst_default_registry_find_feature (element_name,
1280       GST_TYPE_INDEX_FACTORY);
1281   if (feature) {
1282     n_print ("%s: an index\n", element_name);
1283     return 0;
1284   }
1285 #endif
1286   feature = gst_registry_find_feature (gst_registry_get (), element_name,
1287       GST_TYPE_TYPE_FIND_FACTORY);
1288   if (feature) {
1289     n_print ("%s: a typefind function\n", element_name);
1290     return 0;
1291   }
1292
1293   return -1;
1294 }
1295
1296 static int
1297 print_element_info (GstElementFactory * factory, gboolean print_names)
1298 {
1299   GstElement *element;
1300   GstPlugin *plugin;
1301   gint maxlevel = 0;
1302
1303   factory =
1304       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
1305           (factory)));
1306
1307   if (!factory) {
1308     g_print ("element plugin couldn't be loaded\n");
1309     return -1;
1310   }
1311
1312   element = gst_element_factory_create (factory, NULL);
1313   if (!element) {
1314     gst_object_unref (factory);
1315     g_print ("couldn't construct element for some reason\n");
1316     return -1;
1317   }
1318
1319   if (print_names)
1320     _name = g_strdup_printf ("%s: ", GST_OBJECT_NAME (factory));
1321   else
1322     _name = NULL;
1323
1324   print_factory_details_info (factory);
1325
1326   plugin = gst_plugin_feature_get_plugin (GST_PLUGIN_FEATURE (factory));
1327   if (plugin) {
1328     print_plugin_info (plugin);
1329     gst_object_unref (plugin);
1330   }
1331
1332   print_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel);
1333   print_interfaces (G_OBJECT_TYPE (element));
1334
1335   print_pad_templates_info (element, factory);
1336   print_element_flag_info (element);
1337   print_implementation_info (element);
1338   print_clocking_info (element);
1339   print_index_info (element);
1340   print_uri_handler_info (element);
1341   print_pad_info (element);
1342   print_element_properties_info (element);
1343   print_signal_info (element);
1344   print_children_info (element);
1345
1346   gst_object_unref (element);
1347   gst_object_unref (factory);
1348   g_free (_name);
1349
1350   return 0;
1351 }
1352
1353
1354 static void
1355 print_plugin_automatic_install_info_codecs (GstElementFactory * factory)
1356 {
1357   GstPadDirection direction;
1358   const gchar *type_name;
1359   const gchar *klass;
1360   const GList *static_templates, *l;
1361   GstCaps *caps = NULL;
1362   guint i, num;
1363
1364   klass = gst_element_factory_get_klass (factory);
1365   g_return_if_fail (klass != NULL);
1366
1367   if (strstr (klass, "Demuxer") ||
1368       strstr (klass, "Decoder") ||
1369       strstr (klass, "Depay") || strstr (klass, "Parser")) {
1370     type_name = "decoder";
1371     direction = GST_PAD_SINK;
1372   } else if (strstr (klass, "Muxer") ||
1373       strstr (klass, "Encoder") || strstr (klass, "Pay")) {
1374     type_name = "encoder";
1375     direction = GST_PAD_SRC;
1376   } else {
1377     return;
1378   }
1379
1380   /* decoder/demuxer sink pads should always be static and there should only
1381    * be one, the same applies to encoders/muxers and source pads */
1382   static_templates = gst_element_factory_get_static_pad_templates (factory);
1383   for (l = static_templates; l != NULL; l = l->next) {
1384     GstStaticPadTemplate *tmpl = NULL;
1385
1386     tmpl = (GstStaticPadTemplate *) l->data;
1387     if (tmpl->direction == direction) {
1388       caps = gst_static_pad_template_get_caps (tmpl);
1389       break;
1390     }
1391   }
1392
1393   if (caps == NULL) {
1394     g_printerr ("Couldn't find static pad template for %s '%s'\n",
1395         type_name, GST_OBJECT_NAME (factory));
1396     return;
1397   }
1398
1399   caps = gst_caps_make_writable (caps);
1400   num = gst_caps_get_size (caps);
1401   for (i = 0; i < num; ++i) {
1402     GstStructure *s;
1403     gchar *s_str;
1404
1405     s = gst_caps_get_structure (caps, i);
1406     /* remove fields that are almost always just MIN-MAX of some sort
1407      * in order to make the caps look less messy */
1408     gst_structure_remove_field (s, "pixel-aspect-ratio");
1409     gst_structure_remove_field (s, "framerate");
1410     gst_structure_remove_field (s, "channels");
1411     gst_structure_remove_field (s, "width");
1412     gst_structure_remove_field (s, "height");
1413     gst_structure_remove_field (s, "rate");
1414     gst_structure_remove_field (s, "depth");
1415     gst_structure_remove_field (s, "clock-rate");
1416     s_str = gst_structure_to_string (s);
1417     g_print ("%s-%s\n", type_name, s_str);
1418     g_free (s_str);
1419   }
1420   gst_caps_unref (caps);
1421 }
1422
1423 static void
1424 print_plugin_automatic_install_info_protocols (GstElementFactory * factory)
1425 {
1426   const gchar *const *protocols;
1427
1428   protocols = gst_element_factory_get_uri_protocols (factory);
1429   if (protocols != NULL && *protocols != NULL) {
1430     switch (gst_element_factory_get_uri_type (factory)) {
1431       case GST_URI_SINK:
1432         while (*protocols != NULL) {
1433           g_print ("urisink-%s\n", *protocols);
1434           ++protocols;
1435         }
1436         break;
1437       case GST_URI_SRC:
1438         while (*protocols != NULL) {
1439           g_print ("urisource-%s\n", *protocols);
1440           ++protocols;
1441         }
1442         break;
1443       default:
1444         break;
1445     }
1446   }
1447 }
1448
1449 static void
1450 print_plugin_automatic_install_info (GstPlugin * plugin)
1451 {
1452   GList *features, *l;
1453
1454   /* not interested in typefind factories, only element factories */
1455   features = gst_registry_get_feature_list (gst_registry_get (),
1456       GST_TYPE_ELEMENT_FACTORY);
1457
1458   for (l = features; l != NULL; l = l->next) {
1459     GstPluginFeature *feature;
1460     GstPlugin *feature_plugin;
1461
1462     feature = GST_PLUGIN_FEATURE (l->data);
1463
1464     /* only interested in the ones that are in the plugin we just loaded */
1465     feature_plugin = gst_plugin_feature_get_plugin (feature);
1466     if (feature_plugin == plugin) {
1467       GstElementFactory *factory;
1468
1469       g_print ("element-%s\n", gst_plugin_feature_get_name (feature));
1470
1471       factory = GST_ELEMENT_FACTORY (feature);
1472       print_plugin_automatic_install_info_protocols (factory);
1473       print_plugin_automatic_install_info_codecs (factory);
1474     }
1475     if (feature_plugin)
1476       gst_object_unref (feature_plugin);
1477   }
1478
1479   g_list_foreach (features, (GFunc) gst_object_unref, NULL);
1480   g_list_free (features);
1481 }
1482
1483 static void
1484 print_all_plugin_automatic_install_info (void)
1485 {
1486   GList *plugins, *orig_plugins;
1487
1488   orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ());
1489   while (plugins) {
1490     GstPlugin *plugin;
1491
1492     plugin = (GstPlugin *) (plugins->data);
1493     plugins = g_list_next (plugins);
1494
1495     print_plugin_automatic_install_info (plugin);
1496   }
1497   gst_plugin_list_free (orig_plugins);
1498 }
1499
1500 int
1501 main (int argc, char *argv[])
1502 {
1503   gboolean print_all = FALSE;
1504   gboolean do_print_blacklist = FALSE;
1505   gboolean plugin_name = FALSE;
1506   gboolean print_aii = FALSE;
1507   gboolean uri_handlers = FALSE;
1508 #ifndef GST_DISABLE_OPTION_PARSING
1509   GOptionEntry options[] = {
1510     {"print-all", 'a', 0, G_OPTION_ARG_NONE, &print_all,
1511         N_("Print all elements"), NULL},
1512     {"print-blacklist", 'b', 0, G_OPTION_ARG_NONE, &do_print_blacklist,
1513         N_("Print list of blacklisted files"), NULL},
1514     {"print-plugin-auto-install-info", '\0', 0, G_OPTION_ARG_NONE, &print_aii,
1515         N_("Print a machine-parsable list of features the specified plugin "
1516               "or all plugins provide.\n                                       "
1517               "Useful in connection with external automatic plugin "
1518               "installation mechanisms"), NULL},
1519     {"plugin", '\0', 0, G_OPTION_ARG_NONE, &plugin_name,
1520         N_("List the plugin contents"), NULL},
1521     {"uri-handlers", 'u', 0, G_OPTION_ARG_NONE, &uri_handlers,
1522           N_
1523           ("Print supported URI schemes, with the elements that implement them"),
1524         NULL},
1525     GST_TOOLS_GOPTION_VERSION,
1526     {NULL}
1527   };
1528   GOptionContext *ctx;
1529   GError *err = NULL;
1530 #endif
1531
1532 #ifdef ENABLE_NLS
1533   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1534   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1535   textdomain (GETTEXT_PACKAGE);
1536 #endif
1537
1538   g_set_prgname ("gst-inspect-" GST_API_VERSION);
1539
1540 #ifndef GST_DISABLE_OPTION_PARSING
1541   ctx = g_option_context_new ("[ELEMENT-NAME | PLUGIN-NAME]");
1542   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
1543   g_option_context_add_group (ctx, gst_init_get_option_group ());
1544   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1545     g_print ("Error initializing: %s\n", err->message);
1546     exit (1);
1547   }
1548   g_option_context_free (ctx);
1549 #else
1550   gst_init (&argc, &argv);
1551 #endif
1552
1553   gst_tools_print_version ();
1554
1555   if (print_all && argc > 1) {
1556     g_print ("-a requires no extra arguments\n");
1557     return 1;
1558   }
1559
1560   if (uri_handlers && argc > 1) {
1561     g_print ("-u requires no extra arguments\n");
1562     exit (1);
1563   }
1564
1565   /* if no arguments, print out list of elements */
1566   if (uri_handlers) {
1567     print_all_uri_handlers ();
1568   } else if (argc == 1 || print_all) {
1569     if (do_print_blacklist)
1570       print_blacklist ();
1571     else {
1572       if (print_aii)
1573         print_all_plugin_automatic_install_info ();
1574       else
1575         print_element_list (print_all);
1576     }
1577   } else {
1578     /* else we try to get a factory */
1579     GstElementFactory *factory;
1580     GstPlugin *plugin;
1581     const char *arg = argv[argc - 1];
1582     int retval;
1583
1584     if (!plugin_name) {
1585       factory = gst_element_factory_find (arg);
1586
1587       /* if there's a factory, print out the info */
1588       if (factory) {
1589         retval = print_element_info (factory, print_all);
1590         gst_object_unref (factory);
1591       } else {
1592         retval = print_element_features (arg);
1593       }
1594     } else {
1595       retval = -1;
1596     }
1597
1598     /* otherwise check if it's a plugin */
1599     if (retval) {
1600       plugin = gst_registry_find_plugin (gst_registry_get (), arg);
1601
1602       /* if there is such a plugin, print out info */
1603       if (plugin) {
1604         if (print_aii) {
1605           print_plugin_automatic_install_info (plugin);
1606         } else {
1607           print_plugin_info (plugin);
1608           print_plugin_features (plugin);
1609         }
1610       } else {
1611         GError *error = NULL;
1612
1613         if (g_file_test (arg, G_FILE_TEST_EXISTS)) {
1614           plugin = gst_plugin_load_file (arg, &error);
1615
1616           if (plugin) {
1617             if (print_aii) {
1618               print_plugin_automatic_install_info (plugin);
1619             } else {
1620               print_plugin_info (plugin);
1621               print_plugin_features (plugin);
1622             }
1623           } else {
1624             g_print (_("Could not load plugin file: %s\n"), error->message);
1625             g_error_free (error);
1626             return -1;
1627           }
1628         } else {
1629           g_print (_("No such element or plugin '%s'\n"), arg);
1630           return -1;
1631         }
1632       }
1633     }
1634   }
1635
1636   return 0;
1637 }