API: Add GST_IS_PARAM_SPEC_MINI_OBJECT, GST_PARAM_SPEC_MINI_OBJECT
[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/controller/gstcontroller.h>
29
30 #include "tools.h"
31
32 #include <string.h>
33 #include <locale.h>
34 #include <glib/gprintf.h>
35
36 static char *_name = NULL;
37
38 static int print_element_info (GstElementFactory * factory,
39     gboolean print_names);
40
41 static void
42 n_print (const char *format, ...)
43 {
44   va_list args;
45   gint retval;
46
47   if (_name)
48     g_print (_name);
49
50   va_start (args, format);
51   retval = g_vprintf (format, args);
52   va_end (args);
53 }
54
55 static gboolean
56 print_field (GQuark field, const GValue * value, gpointer pfx)
57 {
58   gchar *str = gst_value_serialize (value);
59
60   n_print ("%s  %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
61   g_free (str);
62   return TRUE;
63 }
64
65 static void
66 print_caps (const GstCaps * caps, const gchar * pfx)
67 {
68   guint i;
69
70   g_return_if_fail (caps != NULL);
71
72   if (gst_caps_is_any (caps)) {
73     n_print ("%sANY\n", pfx);
74     return;
75   }
76   if (gst_caps_is_empty (caps)) {
77     n_print ("%sEMPTY\n", pfx);
78     return;
79   }
80
81   for (i = 0; i < gst_caps_get_size (caps); i++) {
82     GstStructure *structure = gst_caps_get_structure (caps, i);
83
84     n_print ("%s%s\n", pfx, gst_structure_get_name (structure));
85     gst_structure_foreach (structure, print_field, (gpointer) pfx);
86   }
87 }
88
89 #if 0
90 static void
91 print_formats (const GstFormat * formats)
92 {
93   while (formats && *formats) {
94     const GstFormatDefinition *definition;
95
96     definition = gst_format_get_details (*formats);
97     if (definition)
98       n_print ("\t\t(%d):\t%s (%s)\n", *formats,
99           definition->nick, definition->description);
100     else
101       n_print ("\t\t(%d):\tUnknown format\n", *formats);
102
103     formats++;
104   }
105 }
106 #endif
107
108 static void
109 print_query_types (const GstQueryType * types)
110 {
111   while (types && *types) {
112     const GstQueryTypeDefinition *definition;
113
114     definition = gst_query_type_get_details (*types);
115     if (definition)
116       n_print ("\t\t(%d):\t%s (%s)\n", *types,
117           definition->nick, definition->description);
118     else
119       n_print ("\t\t(%d):\tUnknown query format\n", *types);
120
121     types++;
122   }
123 }
124
125 #ifndef GST_DISABLE_ENUMTYPES
126 #if 0
127 static void
128 print_event_masks (const GstEventMask * masks)
129 {
130   GType event_type;
131   GEnumClass *klass;
132   GType event_flags;
133   GFlagsClass *flags_class = NULL;
134
135   event_type = gst_event_type_get_type ();
136   klass = (GEnumClass *) g_type_class_ref (event_type);
137
138   while (masks && masks->type) {
139     GEnumValue *value;
140     gint flags = 0, index = 0;
141
142     switch (masks->type) {
143       case GST_EVENT_SEEK:
144         flags = masks->flags;
145         event_flags = gst_seek_type_get_type ();
146         flags_class = (GFlagsClass *) g_type_class_ref (event_flags);
147         break;
148       default:
149         break;
150     }
151
152     value = g_enum_get_value (klass, masks->type);
153     g_print ("\t\t%s ", value->value_nick);
154
155     while (flags) {
156       GFlagsValue *value;
157
158       if (flags & 1) {
159         value = g_flags_get_first_value (flags_class, 1 << index);
160
161         if (value)
162           g_print ("| %s ", value->value_nick);
163         else
164           g_print ("| ? ");
165       }
166       flags >>= 1;
167       index++;
168     }
169     g_print ("\n");
170
171     masks++;
172   }
173 }
174 #endif
175 #else
176 static void
177 print_event_masks (const GstEventMask * masks)
178 {
179 }
180 #endif
181
182 static char *
183 get_rank_name (gint rank)
184 {
185   switch (rank) {
186     case GST_RANK_NONE:
187       return "none";
188     case GST_RANK_MARGINAL:
189       return "marginal";
190     case GST_RANK_SECONDARY:
191       return "secondary";
192     case GST_RANK_PRIMARY:
193       return "primary";
194     default:
195       return "unknown";
196   }
197 }
198
199 static void
200 print_factory_details_info (GstElementFactory * factory)
201 {
202   n_print ("Factory Details:\n");
203   n_print ("  Long name:\t%s\n", factory->details.longname);
204   n_print ("  Class:\t%s\n", factory->details.klass);
205   n_print ("  Description:\t%s\n", factory->details.description);
206   n_print ("  Author(s):\t%s\n", factory->details.author);
207   n_print ("  Rank:\t\t%s (%d)\n",
208       get_rank_name (GST_PLUGIN_FEATURE (factory)->rank),
209       GST_PLUGIN_FEATURE (factory)->rank);
210   n_print ("\n");
211 }
212
213 static void
214 print_hierarchy (GType type, gint level, gint * maxlevel)
215 {
216   GType parent;
217   gint i;
218
219   parent = g_type_parent (type);
220
221   *maxlevel = *maxlevel + 1;
222   level++;
223
224   if (parent)
225     print_hierarchy (parent, level, maxlevel);
226
227   if (_name)
228     g_print (_name);
229
230   for (i = 1; i < *maxlevel - level; i++)
231     g_print ("      ");
232   if (*maxlevel - level)
233     g_print (" +----");
234
235   g_print ("%s\n", g_type_name (type));
236
237   if (level == 1)
238     n_print ("\n");
239 }
240
241 static void
242 print_interfaces (GType type)
243 {
244   guint n_ifaces;
245   GType *iface, *ifaces = g_type_interfaces (type, &n_ifaces);
246
247   if (ifaces) {
248     if (n_ifaces) {
249       if (_name)
250         g_print (_name);
251       g_print (_("Implemented Interfaces:\n"));
252       iface = ifaces;
253       while (*iface) {
254         if (_name)
255           g_print (_name);
256         g_print ("  %s\n", g_type_name (*iface));
257         iface++;
258       }
259       if (_name)
260         g_print (_name);
261       g_print ("\n");
262     }
263     g_free (ifaces);
264   }
265 }
266
267 static void
268 print_element_properties_info (GstElement * element)
269 {
270   GParamSpec **property_specs;
271   guint num_properties, i;
272   gboolean readable;
273   gboolean first_flag;
274
275   property_specs = g_object_class_list_properties
276       (G_OBJECT_GET_CLASS (element), &num_properties);
277   n_print ("\n");
278   n_print ("Element Properties:\n");
279
280   for (i = 0; i < num_properties; i++) {
281     GValue value = { 0, };
282     GParamSpec *param = property_specs[i];
283
284     readable = FALSE;
285
286     g_value_init (&value, param->value_type);
287
288     n_print ("  %-20s: %s\n", g_param_spec_get_name (param),
289         g_param_spec_get_blurb (param));
290
291     first_flag = TRUE;
292     n_print ("%-23.23s flags: ", "");
293     if (param->flags & G_PARAM_READABLE) {
294       g_object_get_property (G_OBJECT (element), param->name, &value);
295       readable = TRUE;
296       if (!first_flag)
297         g_print (", ");
298       else
299         first_flag = FALSE;
300       g_print (_("readable"));
301     }
302     if (param->flags & G_PARAM_WRITABLE) {
303       if (!first_flag)
304         g_print (", ");
305       else
306         first_flag = FALSE;
307       g_print (_("writable"));
308     }
309     if (param->flags & GST_PARAM_CONTROLLABLE) {
310       if (!first_flag)
311         g_print (", ");
312       else
313         first_flag = FALSE;
314       g_print (_("controllable"));
315     }
316     n_print ("\n");
317
318     switch (G_VALUE_TYPE (&value)) {
319       case G_TYPE_STRING:
320       {
321         GParamSpecString *pstring = G_PARAM_SPEC_STRING (param);
322
323         n_print ("%-23.23s String. ", "");
324
325         if (pstring->default_value == NULL)
326           g_print ("Default: null ");
327         else
328           g_print ("Default: \"%s\" ", pstring->default_value);
329
330         if (readable) {
331           const char *string_val = g_value_get_string (&value);
332
333           if (string_val == NULL)
334             g_print ("Current: null");
335           else
336             g_print ("Current: \"%s\"", string_val);
337         }
338         break;
339       }
340       case G_TYPE_BOOLEAN:
341       {
342         GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (param);
343
344         n_print ("%-23.23s Boolean. ", "");
345         g_print ("Default: %s ", (pboolean->default_value ? "true" : "false"));
346         if (readable)
347           g_print ("Current: %s",
348               (g_value_get_boolean (&value) ? "true" : "false"));
349         break;
350       }
351       case G_TYPE_ULONG:
352       {
353         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
354
355         n_print ("%-23.23s Unsigned Long. ", "");
356         g_print ("Range: %lu - %lu Default: %lu ",
357             pulong->minimum, pulong->maximum, pulong->default_value);
358         if (readable)
359           g_print ("Current: %lu", g_value_get_ulong (&value));
360         break;
361       }
362       case G_TYPE_LONG:
363       {
364         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
365
366         n_print ("%-23.23s Long. ", "");
367         g_print ("Range: %ld - %ld Default: %ld ",
368             plong->minimum, plong->maximum, plong->default_value);
369         if (readable)
370           g_print ("Current: %ld", g_value_get_long (&value));
371         break;
372       }
373       case G_TYPE_UINT:
374       {
375         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
376
377         n_print ("%-23.23s Unsigned Integer. ", "");
378         g_print ("Range: %u - %u Default: %u ",
379             puint->minimum, puint->maximum, puint->default_value);
380         if (readable)
381           g_print ("Current: %u", g_value_get_uint (&value));
382         break;
383       }
384       case G_TYPE_INT:
385       {
386         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
387
388         n_print ("%-23.23s Integer. ", "");
389         g_print ("Range: %d - %d Default: %d ",
390             pint->minimum, pint->maximum, pint->default_value);
391         if (readable)
392           g_print ("Current: %d", g_value_get_int (&value));
393         break;
394       }
395       case G_TYPE_UINT64:
396       {
397         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
398
399         n_print ("%-23.23s Unsigned Integer64. ", "");
400         g_print ("Range: %" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT
401             " Default: %" G_GUINT64_FORMAT " ",
402             puint64->minimum, puint64->maximum, puint64->default_value);
403         if (readable)
404           g_print ("Current: %" G_GUINT64_FORMAT, g_value_get_uint64 (&value));
405         break;
406       }
407       case G_TYPE_INT64:
408       {
409         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
410
411         n_print ("%-23.23s Integer64. ", "");
412         g_print ("Range: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT
413             " Default: %" G_GINT64_FORMAT " ",
414             pint64->minimum, pint64->maximum, pint64->default_value);
415         if (readable)
416           g_print ("Current: %" G_GINT64_FORMAT, g_value_get_int64 (&value));
417         break;
418       }
419       case G_TYPE_FLOAT:
420       {
421         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
422
423         n_print ("%-23.23s Float. ", "");
424         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
425             pfloat->minimum, pfloat->maximum, pfloat->default_value);
426         if (readable)
427           g_print ("Current: %15.7g", g_value_get_float (&value));
428         break;
429       }
430       case G_TYPE_DOUBLE:
431       {
432         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
433
434         n_print ("%-23.23s Double. ", "");
435         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
436             pdouble->minimum, pdouble->maximum, pdouble->default_value);
437         if (readable)
438           g_print ("Current: %15.7g", g_value_get_double (&value));
439         break;
440       }
441       default:
442         if (param->value_type == GST_TYPE_CAPS) {
443           const GstCaps *caps = gst_value_get_caps (&value);
444
445           if (!caps)
446             n_print ("%-23.23s Caps (NULL)", "");
447           else {
448             print_caps (caps, "                           ");
449           }
450         } else if (G_IS_PARAM_SPEC_ENUM (param)) {
451           GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (param);
452           GEnumValue *values;
453           guint j = 0;
454           gint enum_value;
455           const gchar *def_val_nick = "", *cur_val_nick = "";
456
457           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
458           enum_value = g_value_get_enum (&value);
459
460           while (values[j].value_name) {
461             if (values[j].value == enum_value)
462               cur_val_nick = values[j].value_nick;
463             if (values[j].value == penum->default_value)
464               def_val_nick = values[j].value_nick;
465             j++;
466           }
467
468           n_print
469               ("%-23.23s Enum \"%s\" Default: %d, \"%s\" Current: %d, \"%s\"",
470               "", g_type_name (G_VALUE_TYPE (&value)), penum->default_value,
471               def_val_nick, enum_value, cur_val_nick);
472
473           j = 0;
474           while (values[j].value_name) {
475             g_print ("\n");
476             if (_name)
477               g_print (_name);
478             g_print ("%-23.23s    (%d): %-16s - %s", "",
479                 values[j].value, values[j].value_nick, values[j].value_name);
480             j++;
481           }
482           /* g_type_class_unref (ec); */
483         } else if (G_IS_PARAM_SPEC_FLAGS (param)) {
484           GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (param);
485           GFlagsValue *values;
486           guint j = 0;
487           gint flags_value;
488           GString *cur_flags = NULL, *def_flags = NULL;
489
490           values = G_FLAGS_CLASS (g_type_class_ref (param->value_type))->values;
491           flags_value = g_value_get_flags (&value);
492
493           while (values[j].value_name) {
494             if (values[j].value & flags_value) {
495               if (cur_flags) {
496                 g_string_append_printf (cur_flags, " | %s",
497                     values[j].value_nick);
498               } else {
499                 cur_flags = g_string_new (values[j].value_nick);
500               }
501             }
502             if (values[j].value & pflags->default_value) {
503               if (def_flags) {
504                 g_string_append_printf (def_flags, " | %s",
505                     values[j].value_nick);
506               } else {
507                 def_flags = g_string_new (values[j].value_nick);
508               }
509             }
510             j++;
511           }
512
513           n_print
514               ("%-23.23s Flags \"%s\" Default: 0x%08x, \"%s\" Current: 0x%08x, \"%s\"",
515               "", g_type_name (G_VALUE_TYPE (&value)), pflags->default_value,
516               (def_flags ? def_flags->str : "(none)"), flags_value,
517               (cur_flags ? cur_flags->str : "(none)"));
518
519           j = 0;
520           while (values[j].value_name) {
521             g_print ("\n");
522             if (_name)
523               g_print (_name);
524             g_print ("%-23.23s    (0x%08x): %-16s - %s", "",
525                 values[j].value, values[j].value_nick, values[j].value_name);
526             j++;
527           }
528
529           if (cur_flags)
530             g_string_free (cur_flags, TRUE);
531           if (def_flags)
532             g_string_free (def_flags, TRUE);
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           n_print ("%-23.23s Array of GValues", "");
548         } else if (GST_IS_PARAM_SPEC_FRACTION (param)) {
549           GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (param);
550
551           n_print ("%-23.23s Fraction. ", "");
552
553           g_print ("Range: %d/%d - %d/%d Default: %d/%d ",
554               pfraction->min_num, pfraction->min_den,
555               pfraction->max_num, pfraction->max_den,
556               pfraction->def_num, pfraction->def_den);
557           if (readable)
558             g_print ("Current: %d/%d",
559                 gst_value_get_fraction_numerator (&value),
560                 gst_value_get_fraction_denominator (&value));
561
562         } else if (GST_IS_PARAM_SPEC_MINI_OBJECT (param)) {
563           n_print ("%-23.23s MiniObject of type \"%s\"", "",
564               g_type_name (param->value_type));
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 (!factory->numpadtemplates) {
593     n_print ("  none\n");
594     return;
595   }
596
597   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
598
599   pads = factory->staticpadtemplates;
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   GstObjectClass *gstobject_class;
654   GstElementClass *gstelement_class;
655
656   gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element));
657   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
658
659   n_print ("\n");
660   n_print ("Element Implementation:\n");
661
662   n_print ("  Has change_state() function: %s\n",
663       GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
664 #ifndef GST_DISABLE_LOADSAVE
665   n_print ("  Has custom save_thyself() function: %s\n",
666       GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself));
667   n_print ("  Has custom restore_thyself() function: %s\n",
668       GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself));
669 #endif
670 }
671
672 static void
673 print_clocking_info (GstElement * element)
674 {
675   if (!gst_element_requires_clock (element) &&
676       !(gst_element_provides_clock (element) &&
677           gst_element_get_clock (element))) {
678     n_print ("\n");
679     n_print ("Element has no clocking capabilities.");
680     return;
681   }
682
683   n_print ("\n");
684   n_print ("Clocking Interaction:\n");
685   if (gst_element_requires_clock (element)) {
686     n_print ("  element requires a clock\n");
687   }
688
689   if (gst_element_provides_clock (element)) {
690     GstClock *clock;
691
692     clock = gst_element_get_clock (element);
693     if (clock)
694       n_print ("  element provides a clock: %s\n", GST_OBJECT_NAME (clock));
695     else
696       n_print ("  element is supposed to provide a clock but returned NULL\n");
697   }
698 }
699
700 #ifndef GST_DISABLE_INDEX
701 static void
702 print_index_info (GstElement * element)
703 {
704   if (gst_element_is_indexable (element)) {
705     n_print ("\n");
706     n_print ("Indexing capabilities:\n");
707     n_print ("  element can do indexing\n");
708   } else {
709     n_print ("\n");
710     n_print ("Element has no indexing capabilities.\n");
711   }
712 }
713 #else
714 static void
715 print_index_info (GstElement * element)
716 {
717 }
718 #endif
719
720 static void
721 print_pad_info (GstElement * element)
722 {
723   const GList *pads;
724   GstPad *pad;
725
726   n_print ("\n");
727   n_print ("Pads:\n");
728
729   if (!element->numpads) {
730     n_print ("  none\n");
731     return;
732   }
733
734   pads = element->pads;
735   while (pads) {
736     gchar *name;
737
738     pad = GST_PAD (pads->data);
739     pads = g_list_next (pads);
740
741     n_print ("");
742
743     name = gst_pad_get_name (pad);
744     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
745       g_print ("  SRC: '%s'", name);
746     else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
747       g_print ("  SINK: '%s'", name);
748     else
749       g_print ("  UNKNOWN!!!: '%s'", name);
750
751     g_free (name);
752
753     g_print ("\n");
754
755     n_print ("    Implementation:\n");
756     if (pad->chainfunc)
757       n_print ("      Has chainfunc(): %s\n",
758           GST_DEBUG_FUNCPTR_NAME (pad->chainfunc));
759     if (pad->getrangefunc)
760       n_print ("      Has getrangefunc(): %s\n",
761           GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc));
762     if (pad->eventfunc != gst_pad_event_default)
763       n_print ("      Has custom eventfunc(): %s\n",
764           GST_DEBUG_FUNCPTR_NAME (pad->eventfunc));
765     if (pad->queryfunc != gst_pad_query_default)
766       n_print ("      Has custom queryfunc(): %s\n",
767           GST_DEBUG_FUNCPTR_NAME (pad->queryfunc));
768     if (pad->querytypefunc != gst_pad_get_query_types_default) {
769       n_print ("        Provides query types:\n");
770       print_query_types (gst_pad_get_query_types (pad));
771     }
772
773     if (pad->intlinkfunc != gst_pad_get_internal_links_default)
774       n_print ("      Has custom intconnfunc(): %s\n",
775           GST_DEBUG_FUNCPTR_NAME (pad->intlinkfunc));
776
777     if (pad->bufferallocfunc)
778       n_print ("      Has bufferallocfunc(): %s\n",
779           GST_DEBUG_FUNCPTR_NAME (pad->bufferallocfunc));
780
781     if (pad->padtemplate)
782       n_print ("    Pad Template: '%s'\n", pad->padtemplate->name_template);
783
784     if (pad->caps) {
785       n_print ("    Capabilities:\n");
786       print_caps (pad->caps, "      ");
787     }
788   }
789 }
790
791 #if 0
792 static gint
793 compare_signal_names (GSignalQuery * a, GSignalQuery * b)
794 {
795   return strcmp (a->signal_name, b->signal_name);
796 }
797 #endif
798
799 static void
800 print_signal_info (GstElement * element)
801 {
802   /* Signals/Actions Block */
803   guint *signals;
804   guint nsignals;
805   gint i = 0, j, k;
806   GSignalQuery *query = NULL;
807   GType type;
808   GSList *found_signals, *l;
809
810   for (k = 0; k < 2; k++) {
811     found_signals = NULL;
812     for (type = G_OBJECT_TYPE (element); type; type = g_type_parent (type)) {
813       if (type == GST_TYPE_ELEMENT || type == GST_TYPE_OBJECT)
814         break;
815
816       if (type == GST_TYPE_BIN && G_OBJECT_TYPE (element) != GST_TYPE_BIN)
817         continue;
818
819       signals = g_signal_list_ids (type, &nsignals);
820       for (i = 0; i < nsignals; i++) {
821         query = g_new0 (GSignalQuery, 1);
822         g_signal_query (signals[i], query);
823
824         if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
825             (k == 1 && (query->signal_flags & G_SIGNAL_ACTION)))
826           found_signals = g_slist_append (found_signals, query);
827         else
828           g_free (query);
829       }
830       g_free (signals);
831       signals = NULL;
832     }
833
834     if (found_signals) {
835       n_print ("\n");
836       if (k == 0)
837         n_print ("Element Signals:\n");
838       else
839         n_print ("Element Actions:\n");
840     } else {
841       continue;
842     }
843
844     for (l = found_signals; l; l = l->next) {
845       gchar *indent;
846       int indent_len;
847
848       query = (GSignalQuery *) l->data;
849       indent_len = strlen (query->signal_name) +
850           strlen (g_type_name (query->return_type)) + 24;
851
852       indent = g_new0 (gchar, indent_len + 1);
853       memset (indent, ' ', indent_len);
854
855       n_print ("  \"%s\" :  %s user_function (%s* object",
856           query->signal_name,
857           g_type_name (query->return_type), g_type_name (type));
858
859       for (j = 0; j < query->n_params; j++) {
860         if (_name)
861           g_print (_name);
862         if (G_TYPE_IS_FUNDAMENTAL (query->param_types[j])) {
863           g_print (",\n%s%s arg%d", indent,
864               g_type_name (query->param_types[j]), j);
865         } else if (G_TYPE_IS_ENUM (query->param_types[j])) {
866           g_print (",\n%s%s arg%d", indent,
867               g_type_name (query->param_types[j]), j);
868         } else {
869           g_print (",\n%s%s* arg%d", indent,
870               g_type_name (query->param_types[j]), j);
871         }
872       }
873
874       if (k == 0) {
875         if (_name)
876           g_print (_name);
877         g_print (",\n%sgpointer user_data);\n", indent);
878       } else
879         g_print (");\n");
880
881       g_free (indent);
882     }
883
884     if (found_signals) {
885       g_slist_foreach (found_signals, (GFunc) g_free, NULL);
886       g_slist_free (found_signals);
887     }
888   }
889 }
890
891 static void
892 print_children_info (GstElement * element)
893 {
894   GList *children;
895
896   if (!GST_IS_BIN (element))
897     return;
898
899   children = (GList *) GST_BIN (element)->children;
900   if (children) {
901     n_print ("\n");
902     g_print ("Children:\n");
903   }
904
905   while (children) {
906     n_print ("  %s\n", GST_ELEMENT_NAME (GST_ELEMENT (children->data)));
907     children = g_list_next (children);
908   }
909 }
910
911 static void
912 print_element_list (gboolean print_all)
913 {
914   int plugincount = 0, featurecount = 0;
915   GList *plugins, *orig_plugins;
916
917   orig_plugins = plugins = gst_default_registry_get_plugin_list ();
918   while (plugins) {
919     GList *features, *orig_features;
920     GstPlugin *plugin;
921
922     plugin = (GstPlugin *) (plugins->data);
923     plugins = g_list_next (plugins);
924     plugincount++;
925
926     orig_features = features =
927         gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
928         plugin->desc.name);
929     while (features) {
930       GstPluginFeature *feature;
931
932       feature = GST_PLUGIN_FEATURE (features->data);
933       featurecount++;
934
935       if (GST_IS_ELEMENT_FACTORY (feature)) {
936         GstElementFactory *factory;
937
938         factory = GST_ELEMENT_FACTORY (feature);
939         if (print_all)
940           print_element_info (factory, TRUE);
941         else
942           g_print ("%s:  %s: %s\n", plugin->desc.name,
943               GST_PLUGIN_FEATURE_NAME (factory),
944               gst_element_factory_get_longname (factory));
945       }
946 #ifndef GST_DISABLE_INDEX
947       else if (GST_IS_INDEX_FACTORY (feature)) {
948         GstIndexFactory *factory;
949
950         factory = GST_INDEX_FACTORY (feature);
951         if (!print_all)
952           g_print ("%s:  %s: %s\n", plugin->desc.name,
953               GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
954       }
955 #endif
956       else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
957         GstTypeFindFactory *factory;
958
959         factory = GST_TYPE_FIND_FACTORY (feature);
960         if (!print_all)
961           g_print ("%s: %s: ", plugin->desc.name,
962               gst_plugin_feature_get_name (feature));
963         if (factory->extensions) {
964           guint i = 0;
965
966           while (factory->extensions[i]) {
967             if (!print_all)
968               g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
969             i++;
970           }
971           if (!print_all)
972             g_print ("\n");
973         } else {
974           if (!print_all)
975             g_print ("no extensions\n");
976         }
977       } else {
978         if (!print_all)
979           n_print ("%s:  %s (%s)\n", plugin->desc.name,
980               GST_PLUGIN_FEATURE_NAME (feature),
981               g_type_name (G_OBJECT_TYPE (feature)));
982       }
983
984       features = g_list_next (features);
985     }
986
987     gst_plugin_feature_list_free (orig_features);
988   }
989
990   gst_plugin_list_free (orig_plugins);
991
992   g_print ("\n");
993   g_print (_("Total count: "));
994   g_print (ngettext ("%d plugin", "%d plugins", plugincount), plugincount);
995   g_print (", ");
996   g_print (ngettext ("%d feature", "%d features", featurecount), featurecount);
997   g_print ("\n");
998 }
999
1000 static void
1001 print_plugin_info (GstPlugin * plugin)
1002 {
1003   n_print ("Plugin Details:\n");
1004   n_print ("  Name:\t\t\t%s\n", plugin->desc.name);
1005   n_print ("  Description:\t\t%s\n", plugin->desc.description);
1006   n_print ("  Filename:\t\t%s\n",
1007       plugin->filename ? plugin->filename : "(null)");
1008   n_print ("  Version:\t\t%s\n", plugin->desc.version);
1009   n_print ("  License:\t\t%s\n", plugin->desc.license);
1010   n_print ("  Source module:\t%s\n", plugin->desc.source);
1011   n_print ("  Binary package:\t%s\n", plugin->desc.package);
1012   n_print ("  Origin URL:\t\t%s\n", plugin->desc.origin);
1013   n_print ("\n");
1014 }
1015
1016 static void
1017 print_plugin_features (GstPlugin * plugin)
1018 {
1019   GList *features;
1020   gint num_features = 0;
1021   gint num_elements = 0;
1022   gint num_types = 0;
1023   gint num_indexes = 0;
1024   gint num_other = 0;
1025
1026   features =
1027       gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
1028       plugin->desc.name);
1029
1030   while (features) {
1031     GstPluginFeature *feature;
1032
1033     feature = GST_PLUGIN_FEATURE (features->data);
1034
1035     if (GST_IS_ELEMENT_FACTORY (feature)) {
1036       GstElementFactory *factory;
1037
1038       factory = GST_ELEMENT_FACTORY (feature);
1039       n_print ("  %s: %s\n", GST_PLUGIN_FEATURE_NAME (factory),
1040           gst_element_factory_get_longname (factory));
1041       num_elements++;
1042     }
1043 #ifndef GST_DISABLE_INDEX
1044     else if (GST_IS_INDEX_FACTORY (feature)) {
1045       GstIndexFactory *factory;
1046
1047       factory = GST_INDEX_FACTORY (feature);
1048       n_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
1049       num_indexes++;
1050     }
1051 #endif
1052     else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
1053       GstTypeFindFactory *factory;
1054
1055       factory = GST_TYPE_FIND_FACTORY (feature);
1056       if (factory->extensions) {
1057         guint i = 0;
1058
1059         g_print ("%s: %s: ", plugin->desc.name,
1060             gst_plugin_feature_get_name (feature));
1061         while (factory->extensions[i]) {
1062           g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
1063           i++;
1064         }
1065         g_print ("\n");
1066       } else
1067         g_print ("%s: %s: no extensions\n", plugin->desc.name,
1068             gst_plugin_feature_get_name (feature));
1069
1070       num_types++;
1071     } else {
1072       n_print ("  %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)),
1073           g_type_name (G_OBJECT_TYPE (feature)));
1074       num_other++;
1075     }
1076     num_features++;
1077     features = g_list_next (features);
1078   }
1079   n_print ("\n");
1080   n_print ("  %d features:\n", num_features);
1081   if (num_elements > 0)
1082     n_print ("  +-- %d elements\n", num_elements);
1083   if (num_types > 0)
1084     n_print ("  +-- %d types\n", num_types);
1085   if (num_indexes > 0)
1086     n_print ("  +-- %d indexes\n", num_indexes);
1087   if (num_other > 0)
1088     n_print ("  +-- %d other objects\n", num_other);
1089
1090   n_print ("\n");
1091 }
1092
1093 static int
1094 print_element_features (const gchar * element_name)
1095 {
1096   GstPluginFeature *feature;
1097
1098   /* FIXME implement other pretty print function for these */
1099 #ifndef GST_DISABLE_INDEX
1100   feature = gst_default_registry_find_feature (element_name,
1101       GST_TYPE_INDEX_FACTORY);
1102   if (feature) {
1103     n_print ("%s: an index\n", element_name);
1104     return 0;
1105   }
1106 #endif
1107   feature = gst_default_registry_find_feature (element_name,
1108       GST_TYPE_TYPE_FIND_FACTORY);
1109   if (feature) {
1110     n_print ("%s: a typefind function\n", element_name);
1111     return 0;
1112   }
1113
1114   return -1;
1115 }
1116
1117 static int
1118 print_element_info (GstElementFactory * factory, gboolean print_names)
1119 {
1120   GstElement *element;
1121   gint maxlevel = 0;
1122
1123   factory =
1124       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
1125           (factory)));
1126
1127   if (!factory) {
1128     g_print ("element plugin couldn't be loaded\n");
1129     return -1;
1130   }
1131
1132   element = gst_element_factory_create (factory, NULL);
1133   if (!element) {
1134     g_print ("couldn't construct element for some reason\n");
1135     return -1;
1136   }
1137
1138   if (print_names)
1139     _name = g_strdup_printf ("%s: ", GST_PLUGIN_FEATURE (factory)->name);
1140   else
1141     _name = NULL;
1142
1143   print_factory_details_info (factory);
1144   if (GST_PLUGIN_FEATURE (factory)->plugin_name) {
1145     GstPlugin *plugin;
1146
1147     plugin = gst_registry_find_plugin (gst_registry_get_default (),
1148         GST_PLUGIN_FEATURE (factory)->plugin_name);
1149     if (plugin) {
1150       print_plugin_info (plugin);
1151     }
1152   }
1153
1154   print_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel);
1155   print_interfaces (G_OBJECT_TYPE (element));
1156
1157   print_pad_templates_info (element, factory);
1158   print_element_flag_info (element);
1159   print_implementation_info (element);
1160   print_clocking_info (element);
1161   print_index_info (element);
1162   print_pad_info (element);
1163   print_element_properties_info (element);
1164   print_signal_info (element);
1165   print_children_info (element);
1166
1167   gst_object_unref (element);
1168   gst_object_unref (factory);
1169   g_free (_name);
1170
1171   return 0;
1172 }
1173
1174
1175 static void
1176 print_plugin_automatic_install_info_codecs (GstElementFactory * factory)
1177 {
1178   GstPadDirection direction;
1179   const gchar *type_name;
1180   const gchar *klass;
1181   const GList *static_templates, *l;
1182   GstCaps *caps = NULL;
1183   guint i, num;
1184
1185   klass = gst_element_factory_get_klass (factory);
1186   g_return_if_fail (klass != NULL);
1187
1188   if (strstr (klass, "Demuxer") ||
1189       strstr (klass, "Decoder") ||
1190       strstr (klass, "Depay") || strstr (klass, "Parser")) {
1191     type_name = "decoder";
1192     direction = GST_PAD_SINK;
1193   } else if (strstr (klass, "Muxer") ||
1194       strstr (klass, "Encoder") || strstr (klass, "Pay")) {
1195     type_name = "encoder";
1196     direction = GST_PAD_SRC;
1197   } else {
1198     return;
1199   }
1200
1201   /* decoder/demuxer sink pads should always be static and there should only
1202    * be one, the same applies to encoders/muxers and source pads */
1203   static_templates = gst_element_factory_get_static_pad_templates (factory);
1204   for (l = static_templates; l != NULL; l = l->next) {
1205     GstStaticPadTemplate *tmpl = NULL;
1206
1207     tmpl = (GstStaticPadTemplate *) l->data;
1208     if (tmpl->direction == direction) {
1209       caps = gst_static_pad_template_get_caps (tmpl);
1210       break;
1211     }
1212   }
1213
1214   if (caps == NULL) {
1215     g_printerr ("Couldn't find static pad template for %s '%s'\n",
1216         type_name, GST_PLUGIN_FEATURE_NAME (factory));
1217     return;
1218   }
1219
1220   caps = gst_caps_make_writable (caps);
1221   num = gst_caps_get_size (caps);
1222   for (i = 0; i < num; ++i) {
1223     GstStructure *s;
1224     gchar *s_str;
1225
1226     s = gst_caps_get_structure (caps, i);
1227     /* remove fields that are almost always just MIN-MAX of some sort
1228      * in order to make the caps look less messy */
1229     gst_structure_remove_field (s, "pixel-aspect-ratio");
1230     gst_structure_remove_field (s, "framerate");
1231     gst_structure_remove_field (s, "channels");
1232     gst_structure_remove_field (s, "width");
1233     gst_structure_remove_field (s, "height");
1234     gst_structure_remove_field (s, "rate");
1235     gst_structure_remove_field (s, "depth");
1236     gst_structure_remove_field (s, "clock-rate");
1237     s_str = gst_structure_to_string (s);
1238     g_print ("%s-%s\n", type_name, s_str);
1239     g_free (s_str);
1240   }
1241   gst_caps_unref (caps);
1242 }
1243
1244 static void
1245 print_plugin_automatic_install_info_protocols (GstElementFactory * factory)
1246 {
1247   gchar **protocols, **p;
1248
1249   protocols = gst_element_factory_get_uri_protocols (factory);
1250   if (protocols != NULL && *protocols != NULL) {
1251     switch (gst_element_factory_get_uri_type (factory)) {
1252       case GST_URI_SINK:
1253         for (p = protocols; *p != NULL; ++p)
1254           g_print ("urisink-%s\n", *p);
1255         break;
1256       case GST_URI_SRC:
1257         for (p = protocols; *p != NULL; ++p)
1258           g_print ("urisource-%s\n", *p);
1259         break;
1260       default:
1261         break;
1262     }
1263     g_strfreev (protocols);
1264   }
1265 }
1266
1267 static void
1268 print_plugin_automatic_install_info (GstPlugin * plugin)
1269 {
1270   const gchar *plugin_name;
1271   GList *features, *l;
1272
1273   plugin_name = gst_plugin_get_name (plugin);
1274
1275   /* not interested in typefind factories, only element factories */
1276   features = gst_registry_get_feature_list (gst_registry_get_default (),
1277       GST_TYPE_ELEMENT_FACTORY);
1278
1279   for (l = features; l != NULL; l = l->next) {
1280     GstPluginFeature *feature;
1281
1282     feature = GST_PLUGIN_FEATURE (l->data);
1283
1284     /* only interested in the ones that are in the plugin we just loaded */
1285     if (g_str_equal (plugin_name, feature->plugin_name)) {
1286       GstElementFactory *factory;
1287
1288       g_print ("element-%s\n", gst_plugin_feature_get_name (feature));
1289
1290       factory = GST_ELEMENT_FACTORY (feature);
1291       print_plugin_automatic_install_info_protocols (factory);
1292       print_plugin_automatic_install_info_codecs (factory);
1293     }
1294   }
1295
1296   g_list_foreach (features, (GFunc) gst_object_unref, NULL);
1297   g_list_free (features);
1298 }
1299
1300 int
1301 main (int argc, char *argv[])
1302 {
1303   gboolean print_all = FALSE;
1304   gboolean print_aii = FALSE;
1305   GOptionEntry options[] = {
1306     {"print-all", 'a', 0, G_OPTION_ARG_NONE, &print_all,
1307         N_("Print all elements"), NULL},
1308     {"print-plugin-auto-install-info", '\0', 0, G_OPTION_ARG_NONE, &print_aii,
1309         N_("Print a machine-parsable list of features the specified plugin "
1310               "provides.\n                                       "
1311               "Useful in connection with external automatic plugin "
1312               "installation mechanisms"), NULL},
1313     GST_TOOLS_GOPTION_VERSION,
1314     {NULL}
1315   };
1316   GOptionContext *ctx;
1317   GError *err = NULL;
1318
1319 #ifdef ENABLE_NLS
1320   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1321   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1322   textdomain (GETTEXT_PACKAGE);
1323 #endif
1324
1325   if (!g_thread_supported ())
1326     g_thread_init (NULL);
1327
1328   ctx = g_option_context_new ("[ELEMENT-NAME | PLUGIN-NAME]");
1329   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
1330   g_option_context_add_group (ctx, gst_init_get_option_group ());
1331   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1332     g_print ("Error initializing: %s\n", err->message);
1333     exit (1);
1334   }
1335   g_option_context_free (ctx);
1336
1337   gst_tools_print_version ("gst-inspect");
1338
1339   if (print_all && argc > 2) {
1340     g_print ("-a requires no extra arguments\n");
1341     return 1;
1342   }
1343
1344   /* if no arguments, print out list of elements */
1345   if (argc == 1 || print_all) {
1346     print_element_list (print_all);
1347     /* else we try to get a factory */
1348   } else {
1349     GstElementFactory *factory;
1350     GstPlugin *plugin;
1351     const char *arg = argv[argc - 1];
1352     int retval;
1353
1354     factory = gst_element_factory_find (arg);
1355     /* if there's a factory, print out the info */
1356     if (factory) {
1357       retval = print_element_info (factory, print_all);
1358       gst_object_unref (factory);
1359     } else {
1360       retval = print_element_features (arg);
1361     }
1362
1363     /* otherwise check if it's a plugin */
1364     if (retval) {
1365       plugin = gst_default_registry_find_plugin (arg);
1366
1367       /* if there is such a plugin, print out info */
1368       if (plugin) {
1369         if (print_aii) {
1370           print_plugin_automatic_install_info (plugin);
1371         } else {
1372           print_plugin_info (plugin);
1373           print_plugin_features (plugin);
1374         }
1375       } else {
1376         GError *error = NULL;
1377
1378         if (g_file_test (arg, G_FILE_TEST_EXISTS)) {
1379           plugin = gst_plugin_load_file (arg, &error);
1380
1381           if (plugin) {
1382             if (print_aii) {
1383               print_plugin_automatic_install_info (plugin);
1384             } else {
1385               print_plugin_info (plugin);
1386               print_plugin_features (plugin);
1387             }
1388           } else {
1389             g_print (_("Could not load plugin file: %s\n"), error->message);
1390             g_error_free (error);
1391             return -1;
1392           }
1393         } else {
1394           g_print (_("No such element or plugin '%s'\n"), arg);
1395           return -1;
1396         }
1397       }
1398     }
1399   }
1400
1401   return 0;
1402 }