tools/gst-launch.1.in: Give example for network streaming (#351998)
[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;
37
38 static int print_element_info (GstElementFactory * factory,
39     gboolean print_names);
40
41 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       g_print ("%s", _name);
250       g_print (_("Implemented Interfaces:\n"));
251       iface = ifaces;
252       while (*iface) {
253         g_print ("%s  %s\n", _name, g_type_name (*iface));
254         iface++;
255       }
256       g_print ("%s\n", _name);
257       g_free (ifaces);
258     }
259   }
260 }
261
262 static void
263 print_element_properties_info (GstElement * element)
264 {
265   GParamSpec **property_specs;
266   guint num_properties, i;
267   gboolean readable;
268   gboolean first_flag;
269
270   property_specs = g_object_class_list_properties
271       (G_OBJECT_GET_CLASS (element), &num_properties);
272   n_print ("\n");
273   n_print ("Element Properties:\n");
274
275   for (i = 0; i < num_properties; i++) {
276     GValue value = { 0, };
277     GParamSpec *param = property_specs[i];
278
279     readable = FALSE;
280
281     g_value_init (&value, param->value_type);
282
283     n_print ("  %-20s: %s\n", g_param_spec_get_name (param),
284         g_param_spec_get_blurb (param));
285
286     first_flag = TRUE;
287     n_print ("%-23.23s flags: ", "");
288     if (param->flags & G_PARAM_READABLE) {
289       g_object_get_property (G_OBJECT (element), param->name, &value);
290       readable = TRUE;
291       g_print ((first_flag ? "" : ", "));
292       g_print (_("readable"));
293       first_flag = FALSE;
294     }
295     if (param->flags & G_PARAM_WRITABLE) {
296       g_print ((first_flag ? "" : ", "));
297       g_print (_("writable"));
298       first_flag = FALSE;
299     }
300     if (param->flags & GST_PARAM_CONTROLLABLE) {
301       g_print ((first_flag ? "" : ", "));
302       g_print (_("controllable"));
303       first_flag = FALSE;
304     }
305     n_print ("\n");
306
307     switch (G_VALUE_TYPE (&value)) {
308       case G_TYPE_STRING:
309       {
310         GParamSpecString *pstring = G_PARAM_SPEC_STRING (param);
311
312         n_print ("%-23.23s String. ", "");
313
314         if (pstring->default_value == NULL)
315           g_print ("Default: null ");
316         else
317           g_print ("Default: \"%s\" ", pstring->default_value);
318
319         if (readable) {
320           const char *string_val = g_value_get_string (&value);
321
322           if (string_val == NULL)
323             g_print ("Current: null");
324           else
325             g_print ("Current: \"%s\"", string_val);
326         }
327         break;
328       }
329       case G_TYPE_BOOLEAN:
330       {
331         GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (param);
332
333         n_print ("%-23.23s Boolean. ", "");
334         g_print ("Default: %s ", (pboolean->default_value ? "true" : "false"));
335         if (readable)
336           g_print ("Current: %s",
337               (g_value_get_boolean (&value) ? "true" : "false"));
338         break;
339       }
340       case G_TYPE_ULONG:
341       {
342         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
343
344         n_print ("%-23.23s Unsigned Long. ", "");
345         g_print ("Range: %lu - %lu Default: %lu ",
346             pulong->minimum, pulong->maximum, pulong->default_value);
347         if (readable)
348           g_print ("Current: %lu", g_value_get_ulong (&value));
349         break;
350       }
351       case G_TYPE_LONG:
352       {
353         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
354
355         n_print ("%-23.23s Long. ", "");
356         g_print ("Range: %ld - %ld Default: %ld ",
357             plong->minimum, plong->maximum, plong->default_value);
358         if (readable)
359           g_print ("Current: %ld", g_value_get_long (&value));
360         break;
361       }
362       case G_TYPE_UINT:
363       {
364         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
365
366         n_print ("%-23.23s Unsigned Integer. ", "");
367         g_print ("Range: %u - %u Default: %u ",
368             puint->minimum, puint->maximum, puint->default_value);
369         if (readable)
370           g_print ("Current: %u", g_value_get_uint (&value));
371         break;
372       }
373       case G_TYPE_INT:
374       {
375         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
376
377         n_print ("%-23.23s Integer. ", "");
378         g_print ("Range: %d - %d Default: %d ",
379             pint->minimum, pint->maximum, pint->default_value);
380         if (readable)
381           g_print ("Current: %d", g_value_get_int (&value));
382         break;
383       }
384       case G_TYPE_UINT64:
385       {
386         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
387
388         n_print ("%-23.23s Unsigned Integer64. ", "");
389         g_print ("Range: %" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT
390             " Default: %" G_GUINT64_FORMAT " ",
391             puint64->minimum, puint64->maximum, puint64->default_value);
392         if (readable)
393           g_print ("Current: %" G_GUINT64_FORMAT, g_value_get_uint64 (&value));
394         break;
395       }
396       case G_TYPE_INT64:
397       {
398         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
399
400         n_print ("%-23.23s Integer64. ", "");
401         g_print ("Range: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT
402             " Default: %" G_GINT64_FORMAT " ",
403             pint64->minimum, pint64->maximum, pint64->default_value);
404         if (readable)
405           g_print ("Current: %" G_GINT64_FORMAT, g_value_get_int64 (&value));
406         break;
407       }
408       case G_TYPE_FLOAT:
409       {
410         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
411
412         n_print ("%-23.23s Float. ", "");
413         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
414             pfloat->minimum, pfloat->maximum, pfloat->default_value);
415         if (readable)
416           g_print ("Current: %15.7g", g_value_get_float (&value));
417         break;
418       }
419       case G_TYPE_DOUBLE:
420       {
421         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
422
423         n_print ("%-23.23s Double. ", "");
424         g_print ("Range: %15.7g - %15.7g Default: %15.7g ",
425             pdouble->minimum, pdouble->maximum, pdouble->default_value);
426         if (readable)
427           g_print ("Current: %15.7g", g_value_get_double (&value));
428         break;
429       }
430       default:
431         if (param->value_type == GST_TYPE_CAPS) {
432           const GstCaps *caps = gst_value_get_caps (&value);
433
434           if (!caps)
435             n_print ("%-23.23s Caps (NULL)", "");
436           else {
437             print_caps (caps, "                           ");
438           }
439         } else if (G_IS_PARAM_SPEC_ENUM (param)) {
440           GEnumValue *values;
441           guint j = 0;
442           gint enum_value;
443
444           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
445           enum_value = g_value_get_enum (&value);
446
447           while (values[j].value_name) {
448             if (values[j].value == enum_value)
449               break;
450             j++;
451           }
452
453           n_print ("%-23.23s Enum \"%s\" Current: %d, \"%s\"", "",
454               g_type_name (G_VALUE_TYPE (&value)),
455               enum_value, values[j].value_nick);
456
457           j = 0;
458           while (values[j].value_name) {
459             g_print ("\n%s%-23.23s    (%d): %-16s - %s", "",
460                 _name, values[j].value, values[j].value_nick,
461                 values[j].value_name);
462             j++;
463           }
464           /* g_type_class_unref (ec); */
465         } else if (G_IS_PARAM_SPEC_FLAGS (param)) {
466           GFlagsValue *values;
467           guint j = 0;
468           gint flags_value;
469           GString *flags = NULL;
470
471           values = G_FLAGS_CLASS (g_type_class_ref (param->value_type))->values;
472           flags_value = g_value_get_flags (&value);
473
474           while (values[j].value_name) {
475             if (values[j].value & flags_value) {
476               if (flags) {
477                 g_string_append_printf (flags, " | %s", values[j].value_nick);
478               } else {
479                 flags = g_string_new (values[j].value_nick);
480               }
481             }
482             j++;
483           }
484
485           n_print ("%-23.23s Flags \"%s\" Current: %d, \"%s\"", "",
486               g_type_name (G_VALUE_TYPE (&value)),
487               flags_value, (flags ? flags->str : "(none)"));
488
489           j = 0;
490           while (values[j].value_name) {
491             g_print ("\n%s%-23.23s    (0x%08x): %-16s - %s", "",
492                 _name, values[j].value, values[j].value_nick,
493                 values[j].value_name);
494             j++;
495           }
496
497           if (flags)
498             g_string_free (flags, TRUE);
499         } else if (G_IS_PARAM_SPEC_OBJECT (param)) {
500           n_print ("%-23.23s Object of type \"%s\"", "",
501               g_type_name (param->value_type));
502         } else if (G_IS_PARAM_SPEC_BOXED (param)) {
503           n_print ("%-23.23s Boxed pointer of type \"%s\"", "",
504               g_type_name (param->value_type));
505         } else if (G_IS_PARAM_SPEC_POINTER (param)) {
506           if (param->value_type != G_TYPE_POINTER) {
507             n_print ("%-23.23s Pointer of type \"%s\".", "",
508                 g_type_name (param->value_type));
509           } else {
510             n_print ("%-23.23s Pointer.", "");
511           }
512         } else if (param->value_type == G_TYPE_VALUE_ARRAY) {
513           n_print ("%-23.23s Array of GValues", "");
514         } else {
515           n_print ("%-23.23s Unknown type %ld \"%s\"", "", param->value_type,
516               g_type_name (param->value_type));
517         }
518         break;
519     }
520     if (!readable)
521       g_print (" Write only\n");
522     else
523       g_print ("\n");
524   }
525   if (num_properties == 0)
526     n_print ("  none\n");
527
528   g_free (property_specs);
529 }
530
531 static void
532 print_pad_templates_info (GstElement * element, GstElementFactory * factory)
533 {
534   GstElementClass *gstelement_class;
535   const GList *pads;
536   GstStaticPadTemplate *padtemplate;
537
538   n_print ("Pad Templates:\n");
539   if (!factory->numpadtemplates) {
540     n_print ("  none\n");
541     return;
542   }
543
544   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
545
546   pads = factory->staticpadtemplates;
547   while (pads) {
548     padtemplate = (GstStaticPadTemplate *) (pads->data);
549     pads = g_list_next (pads);
550
551     if (padtemplate->direction == GST_PAD_SRC)
552       n_print ("  SRC template: '%s'\n", padtemplate->name_template);
553     else if (padtemplate->direction == GST_PAD_SINK)
554       n_print ("  SINK template: '%s'\n", padtemplate->name_template);
555     else
556       n_print ("  UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
557
558     if (padtemplate->presence == GST_PAD_ALWAYS)
559       n_print ("    Availability: Always\n");
560     else if (padtemplate->presence == GST_PAD_SOMETIMES)
561       n_print ("    Availability: Sometimes\n");
562     else if (padtemplate->presence == GST_PAD_REQUEST) {
563       n_print ("    Availability: On request\n");
564       n_print ("      Has request_new_pad() function: %s\n",
565           GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad));
566     } else
567       n_print ("    Availability: UNKNOWN!!!\n");
568
569     if (padtemplate->static_caps.string) {
570       n_print ("    Capabilities:\n");
571       print_caps (gst_static_caps_get (&padtemplate->static_caps), "      ");
572     }
573
574     n_print ("\n");
575   }
576 }
577
578 static void
579 print_element_flag_info (GstElement * element)
580 {
581   gboolean have_flags = FALSE;
582
583   n_print ("\n");
584   n_print ("Element Flags:\n");
585
586   if (!have_flags)
587     n_print ("  no flags set\n");
588
589   if (GST_IS_BIN (element)) {
590     n_print ("\n");
591     n_print ("Bin Flags:\n");
592     if (!have_flags)
593       n_print ("  no flags set\n");
594   }
595 }
596
597 static void
598 print_implementation_info (GstElement * element)
599 {
600   GstObjectClass *gstobject_class;
601   GstElementClass *gstelement_class;
602
603   gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element));
604   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
605
606   n_print ("\n");
607   n_print ("Element Implementation:\n");
608
609   n_print ("  No loopfunc(), must be chain-based or not configured yet\n");
610
611   n_print ("  Has change_state() function: %s\n",
612       GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
613 #ifndef GST_DISABLE_LOADSAVE
614   n_print ("  Has custom save_thyself() function: %s\n",
615       GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself));
616   n_print ("  Has custom restore_thyself() function: %s\n",
617       GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself));
618 #endif
619 }
620
621 static void
622 print_clocking_info (GstElement * element)
623 {
624   if (!gst_element_requires_clock (element) &&
625       !(gst_element_provides_clock (element) &&
626           gst_element_get_clock (element))) {
627     n_print ("\n");
628     n_print ("Element has no clocking capabilities.");
629     return;
630   }
631
632   n_print ("\n");
633   n_print ("Clocking Interaction:\n");
634   if (gst_element_requires_clock (element)) {
635     n_print ("  element requires a clock\n");
636   }
637
638   if (gst_element_provides_clock (element)) {
639     GstClock *clock;
640
641     clock = gst_element_get_clock (element);
642     if (clock)
643       n_print ("  element provides a clock: %s\n", GST_OBJECT_NAME (clock));
644     else
645       n_print ("  element is supposed to provide a clock but returned NULL\n");
646   }
647 }
648
649 #ifndef GST_DISABLE_INDEX
650 static void
651 print_index_info (GstElement * element)
652 {
653   if (gst_element_is_indexable (element)) {
654     n_print ("\n");
655     n_print ("Indexing capabilities:\n");
656     n_print ("  element can do indexing\n");
657   } else {
658     n_print ("\n");
659     n_print ("Element has no indexing capabilities.\n");
660   }
661 }
662 #else
663 static void
664 print_index_info (GstElement * element)
665 {
666 }
667 #endif
668
669 static void
670 print_pad_info (GstElement * element)
671 {
672   const GList *pads;
673   GstPad *pad;
674
675   n_print ("\n");
676   n_print ("Pads:\n");
677
678   if (!element->numpads) {
679     n_print ("  none\n");
680     return;
681   }
682
683   pads = element->pads;
684   while (pads) {
685     pad = GST_PAD (pads->data);
686     pads = g_list_next (pads);
687
688     n_print ("");
689
690     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
691       g_print ("  SRC: '%s'", gst_pad_get_name (pad));
692     else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
693       g_print ("  SINK: '%s'", gst_pad_get_name (pad));
694     else
695       g_print ("  UNKNOWN!!!: '%s'", gst_pad_get_name (pad));
696
697     g_print ("\n");
698
699     n_print ("    Implementation:\n");
700     if (pad->chainfunc)
701       n_print ("      Has chainfunc(): %s\n",
702           GST_DEBUG_FUNCPTR_NAME (pad->chainfunc));
703     if (pad->getrangefunc)
704       n_print ("      Has getrangefunc(): %s\n",
705           GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc));
706     if (pad->eventfunc != gst_pad_event_default)
707       n_print ("      Has custom eventfunc(): %s\n",
708           GST_DEBUG_FUNCPTR_NAME (pad->eventfunc));
709     if (pad->queryfunc != gst_pad_query_default)
710       n_print ("      Has custom queryfunc(): %s\n",
711           GST_DEBUG_FUNCPTR_NAME (pad->queryfunc));
712     if (pad->querytypefunc != gst_pad_get_query_types_default) {
713       n_print ("        Provides query types:\n");
714       print_query_types (gst_pad_get_query_types (pad));
715     }
716
717     if (pad->intlinkfunc != gst_pad_get_internal_links_default)
718       n_print ("      Has custom intconnfunc(): %s\n",
719           GST_DEBUG_FUNCPTR_NAME (pad->intlinkfunc));
720
721     if (pad->bufferallocfunc)
722       n_print ("      Has bufferallocfunc(): %s\n",
723           GST_DEBUG_FUNCPTR_NAME (pad->bufferallocfunc));
724
725     if (pad->padtemplate)
726       n_print ("    Pad Template: '%s'\n", pad->padtemplate->name_template);
727
728     if (pad->caps) {
729       n_print ("    Capabilities:\n");
730       print_caps (pad->caps, "      ");
731     }
732   }
733 }
734
735 #if 0
736 static gint
737 compare_signal_names (GSignalQuery * a, GSignalQuery * b)
738 {
739   return strcmp (a->signal_name, b->signal_name);
740 }
741 #endif
742
743 static void
744 print_signal_info (GstElement * element)
745 {
746   /* Signals/Actions Block */
747   guint *signals;
748   guint nsignals;
749   gint i = 0, j, k;
750   GSignalQuery *query = NULL;
751   GType type;
752   GSList *found_signals, *l;
753
754   for (k = 0; k < 2; k++) {
755     found_signals = NULL;
756     for (type = G_OBJECT_TYPE (element); type; type = g_type_parent (type)) {
757       if (type == GST_TYPE_ELEMENT || type == GST_TYPE_OBJECT)
758         break;
759
760       if (type == GST_TYPE_BIN && G_OBJECT_TYPE (element) != GST_TYPE_BIN)
761         continue;
762
763       signals = g_signal_list_ids (type, &nsignals);
764       for (i = 0; i < nsignals; i++) {
765         query = g_new0 (GSignalQuery, 1);
766         g_signal_query (signals[i], query);
767
768         if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
769             (k == 1 && (query->signal_flags & G_SIGNAL_ACTION)))
770           found_signals = g_slist_append (found_signals, query);
771       }
772     }
773
774     if (found_signals) {
775       n_print ("\n");
776       if (k == 0)
777         n_print ("Element Signals:\n");
778       else
779         n_print ("Element Actions:\n");
780     } else {
781       continue;
782     }
783
784     for (l = found_signals; l; l = l->next) {
785       gchar *indent;
786       int indent_len;
787
788       query = (GSignalQuery *) l->data;
789       indent_len = strlen (query->signal_name) +
790           strlen (g_type_name (query->return_type)) + 24;
791
792       indent = g_new0 (gchar, indent_len + 1);
793       memset (indent, ' ', indent_len);
794
795       n_print ("  \"%s\" :  %s user_function (%s* object",
796           query->signal_name,
797           g_type_name (query->return_type), g_type_name (type));
798
799       for (j = 0; j < query->n_params; j++) {
800         if (G_TYPE_IS_FUNDAMENTAL (query->param_types[j])) {
801           g_print (",\n%s%s%s arg%d", _name, indent,
802               g_type_name (query->param_types[j]), j);
803         } else if (G_TYPE_IS_ENUM (query->param_types[j])) {
804           g_print (",\n%s%s%s arg%d", _name, indent,
805               g_type_name (query->param_types[j]), j);
806         } else {
807           g_print (",\n%s%s%s* arg%d", _name, indent,
808               g_type_name (query->param_types[j]), j);
809         }
810       }
811
812       if (k == 0)
813         g_print (",\n%s%sgpointer user_data);\n", _name, indent);
814       else
815         g_print (");\n");
816
817       g_free (indent);
818     }
819
820     if (found_signals) {
821       g_slist_foreach (found_signals, (GFunc) g_free, NULL);
822       g_slist_free (found_signals);
823     }
824   }
825 }
826
827 static void
828 print_children_info (GstElement * element)
829 {
830   GList *children;
831
832   if (!GST_IS_BIN (element))
833     return;
834
835   children = (GList *) GST_BIN (element)->children;
836   if (children) {
837     n_print ("\n");
838     g_print ("Children:\n");
839   }
840
841   while (children) {
842     n_print ("  %s\n", GST_ELEMENT_NAME (GST_ELEMENT (children->data)));
843     children = g_list_next (children);
844   }
845 }
846
847 static void
848 print_element_list (gboolean print_all)
849 {
850   int plugincount = 0, featurecount = 0;
851   GList *plugins, *orig_plugins;
852
853   orig_plugins = plugins = gst_default_registry_get_plugin_list ();
854   while (plugins) {
855     GList *features, *orig_features;
856     GstPlugin *plugin;
857
858     plugin = (GstPlugin *) (plugins->data);
859     plugins = g_list_next (plugins);
860     plugincount++;
861
862     orig_features = features =
863         gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
864         plugin->desc.name);
865     while (features) {
866       GstPluginFeature *feature;
867
868       feature = GST_PLUGIN_FEATURE (features->data);
869       featurecount++;
870
871       if (GST_IS_ELEMENT_FACTORY (feature)) {
872         GstElementFactory *factory;
873
874         factory = GST_ELEMENT_FACTORY (feature);
875         if (print_all)
876           print_element_info (factory, TRUE);
877         else
878           g_print ("%s:  %s: %s\n", plugin->desc.name,
879               GST_PLUGIN_FEATURE_NAME (factory), factory->details.longname);
880       }
881 #ifndef GST_DISABLE_INDEX
882       else if (GST_IS_INDEX_FACTORY (feature)) {
883         GstIndexFactory *factory;
884
885         factory = GST_INDEX_FACTORY (feature);
886         if (!print_all)
887           g_print ("%s:  %s: %s\n", plugin->desc.name,
888               GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
889       }
890 #endif
891       else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
892         GstTypeFindFactory *factory;
893
894         factory = GST_TYPE_FIND_FACTORY (feature);
895         if (!print_all)
896           g_print ("%s: %s: ", plugin->desc.name,
897               gst_plugin_feature_get_name (feature));
898         if (factory->extensions) {
899           guint i = 0;
900
901           while (factory->extensions[i]) {
902             if (!print_all)
903               g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
904             i++;
905           }
906           if (!print_all)
907             g_print ("\n");
908         } else {
909           if (!print_all)
910             g_print ("no extensions\n");
911         }
912       } else {
913         if (!print_all)
914           n_print ("%s:  %s (%s)\n", plugin->desc.name,
915               GST_PLUGIN_FEATURE_NAME (feature),
916               g_type_name (G_OBJECT_TYPE (feature)));
917       }
918
919       features = g_list_next (features);
920     }
921
922     gst_plugin_feature_list_free (orig_features);
923   }
924
925   gst_plugin_list_free (orig_plugins);
926
927   g_print ("\n");
928   g_print (_("Total count: "));
929   g_print (ngettext ("%d plugin", "%d plugins", plugincount), plugincount);
930   g_print (", ");
931   g_print (ngettext ("%d feature", "%d features", featurecount), featurecount);
932   g_print ("\n");
933 }
934
935 static void
936 print_plugin_info (GstPlugin * plugin)
937 {
938   n_print ("Plugin Details:\n");
939   n_print ("  Name:\t\t\t%s\n", plugin->desc.name);
940   n_print ("  Description:\t\t%s\n", plugin->desc.description);
941   n_print ("  Filename:\t\t%s\n",
942       plugin->filename ? plugin->filename : "(null)");
943   n_print ("  Version:\t\t%s\n", plugin->desc.version);
944   n_print ("  License:\t\t%s\n", plugin->desc.license);
945   n_print ("  Source module:\t%s\n", plugin->desc.source);
946   n_print ("  Binary package:\t%s\n", plugin->desc.package);
947   n_print ("  Origin URL:\t\t%s\n", plugin->desc.origin);
948   n_print ("\n");
949 }
950
951 static void
952 print_plugin_features (GstPlugin * plugin)
953 {
954   GList *features;
955   gint num_features = 0;
956   gint num_elements = 0;
957   gint num_types = 0;
958   gint num_indexes = 0;
959   gint num_other = 0;
960
961   features =
962       gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
963       plugin->desc.name);
964
965   while (features) {
966     GstPluginFeature *feature;
967
968     feature = GST_PLUGIN_FEATURE (features->data);
969
970     if (GST_IS_ELEMENT_FACTORY (feature)) {
971       GstElementFactory *factory;
972
973       factory = GST_ELEMENT_FACTORY (feature);
974       n_print ("  %s: %s\n", GST_PLUGIN_FEATURE_NAME (factory),
975           factory->details.longname);
976       num_elements++;
977     }
978 #ifndef GST_DISABLE_INDEX
979     else if (GST_IS_INDEX_FACTORY (feature)) {
980       GstIndexFactory *factory;
981
982       factory = GST_INDEX_FACTORY (feature);
983       n_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
984       num_indexes++;
985     }
986 #endif
987     else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
988       GstTypeFindFactory *factory;
989
990       factory = GST_TYPE_FIND_FACTORY (feature);
991       if (factory->extensions) {
992         guint i = 0;
993
994         g_print ("%s type: ", plugin->desc.name);
995         while (factory->extensions[i]) {
996           g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
997           i++;
998         }
999         g_print ("\n");
1000       } else
1001         g_print ("%s type: N/A\n", plugin->desc.name);
1002
1003       num_types++;
1004     } else {
1005       n_print ("  %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)),
1006           g_type_name (G_OBJECT_TYPE (feature)));
1007       num_other++;
1008     }
1009     num_features++;
1010     features = g_list_next (features);
1011   }
1012   n_print ("\n");
1013   n_print ("  %d features:\n", num_features);
1014   if (num_elements > 0)
1015     n_print ("  +-- %d elements\n", num_elements);
1016   if (num_types > 0)
1017     n_print ("  +-- %d types\n", num_types);
1018   if (num_indexes > 0)
1019     n_print ("  +-- %d indexes\n", num_indexes);
1020   if (num_other > 0)
1021     n_print ("  +-- %d other objects\n", num_other);
1022
1023   n_print ("\n");
1024 }
1025
1026 static int
1027 print_element_features (const gchar * element_name)
1028 {
1029   GstPluginFeature *feature;
1030
1031   /* FIXME implement other pretty print function for these */
1032 #ifndef GST_DISABLE_INDEX
1033   feature = gst_default_registry_find_feature (element_name,
1034       GST_TYPE_INDEX_FACTORY);
1035   if (feature) {
1036     n_print ("%s: an index\n", element_name);
1037     return 0;
1038   }
1039 #endif
1040   feature = gst_default_registry_find_feature (element_name,
1041       GST_TYPE_TYPE_FIND_FACTORY);
1042   if (feature) {
1043     n_print ("%s: a typefind function\n", element_name);
1044     return 0;
1045   }
1046
1047   return -1;
1048 }
1049
1050 static int
1051 print_element_info (GstElementFactory * factory, gboolean print_names)
1052 {
1053   GstElement *element;
1054   gint maxlevel = 0;
1055
1056   factory =
1057       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
1058           (factory)));
1059
1060   if (!factory) {
1061     g_print ("element plugin couldn't be loaded\n");
1062     return -1;
1063   }
1064
1065   element = gst_element_factory_create (factory, NULL);
1066   if (!element) {
1067     g_print ("couldn't construct element for some reason\n");
1068     return -1;
1069   }
1070
1071   if (print_names)
1072     _name = g_strdup_printf ("%s: ", GST_PLUGIN_FEATURE (factory)->name);
1073   else
1074     _name = "";
1075
1076   print_factory_details_info (factory);
1077   if (GST_PLUGIN_FEATURE (factory)->plugin_name) {
1078     GstPlugin *plugin;
1079
1080     plugin = gst_registry_find_plugin (gst_registry_get_default (),
1081         GST_PLUGIN_FEATURE (factory)->plugin_name);
1082     if (plugin) {
1083       print_plugin_info (plugin);
1084     }
1085   }
1086
1087   print_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel);
1088   print_interfaces (G_OBJECT_TYPE (element));
1089
1090   print_pad_templates_info (element, factory);
1091   print_element_flag_info (element);
1092   print_implementation_info (element);
1093   print_clocking_info (element);
1094   print_index_info (element);
1095   print_pad_info (element);
1096   print_element_properties_info (element);
1097   print_signal_info (element);
1098   print_children_info (element);
1099
1100   gst_object_unref (factory);
1101   if (_name[0] != '\0')
1102     g_free (_name);
1103
1104   return 0;
1105 }
1106
1107
1108 static void
1109 print_plugin_automatic_install_info_codecs (GstElementFactory * factory)
1110 {
1111   GstPadDirection direction;
1112   const gchar *type_name;
1113   const gchar *klass;
1114   const GList *static_templates, *l;
1115   GstCaps *caps = NULL;
1116   guint i, num;
1117
1118   klass = gst_element_factory_get_klass (factory);
1119   g_return_if_fail (klass != NULL);
1120
1121   if (strstr (klass, "Codec/") == NULL)
1122     return;
1123
1124   if (strstr (klass, "Demuxer") ||
1125       strstr (klass, "Decoder") ||
1126       strstr (klass, "Depay") || strstr (klass, "Parser")) {
1127     type_name = "decoder";
1128     direction = GST_PAD_SINK;
1129   } else if (strstr (klass, "Muxer") ||
1130       strstr (klass, "Encoder") || strstr (klass, "Pay")) {
1131     type_name = "encoder";
1132     direction = GST_PAD_SRC;
1133   } else {
1134     g_printerr ("Unhandled Codec klass: %s\n", klass);
1135     return;
1136   }
1137
1138   /* decoder/demuxer sink pads should always be static and there should only
1139    * be one, the same applies to encoders/muxers and source pads */
1140   static_templates = gst_element_factory_get_static_pad_templates (factory);
1141   for (l = static_templates; l != NULL; l = l->next) {
1142     GstStaticPadTemplate *tmpl = NULL;
1143
1144     tmpl = (GstStaticPadTemplate *) l->data;
1145     if (tmpl->direction == direction) {
1146       caps = gst_static_pad_template_get_caps (tmpl);
1147       break;
1148     }
1149   }
1150
1151   if (caps == NULL) {
1152     g_printerr ("Couldn't find static pad template for %s '%s'\n",
1153         type_name, GST_PLUGIN_FEATURE_NAME (factory));
1154     return;
1155   }
1156
1157   caps = gst_caps_make_writable (caps);
1158   num = gst_caps_get_size (caps);
1159   for (i = 0; i < num; ++i) {
1160     GstStructure *s;
1161     gchar *s_str;
1162
1163     s = gst_caps_get_structure (caps, i);
1164     /* remove fields that are almost always just MIN-MAX of some sort
1165      * in order to make the caps look less messy */
1166     gst_structure_remove_field (s, "pixel-aspect-ratio");
1167     gst_structure_remove_field (s, "framerate");
1168     gst_structure_remove_field (s, "channels");
1169     gst_structure_remove_field (s, "width");
1170     gst_structure_remove_field (s, "height");
1171     gst_structure_remove_field (s, "rate");
1172     gst_structure_remove_field (s, "depth");
1173     gst_structure_remove_field (s, "clock-rate");
1174     s_str = gst_structure_to_string (s);
1175     g_print ("%s-%s\n", type_name, s_str);
1176     g_free (s_str);
1177   }
1178   gst_caps_unref (caps);
1179 }
1180
1181 static void
1182 print_plugin_automatic_install_info_protocols (GstElementFactory * factory)
1183 {
1184   gchar **protocols, **p;
1185
1186   protocols = gst_element_factory_get_uri_protocols (factory);
1187   if (protocols != NULL && *protocols != NULL) {
1188     switch (gst_element_factory_get_uri_type (factory)) {
1189       case GST_URI_SINK:
1190         for (p = protocols; *p != NULL; ++p)
1191           g_print ("urisink-%s\n", *p);
1192         break;
1193       case GST_URI_SRC:
1194         for (p = protocols; *p != NULL; ++p)
1195           g_print ("urisource-%s\n", *p);
1196         break;
1197       default:
1198         break;
1199     }
1200     g_strfreev (protocols);
1201   }
1202 }
1203
1204 static void
1205 print_plugin_automatic_install_info (GstPlugin * plugin)
1206 {
1207   const gchar *plugin_name;
1208   GList *features, *l;
1209
1210   plugin_name = gst_plugin_get_name (plugin);
1211
1212   /* not interested in typefind factories, only element factories */
1213   features = gst_registry_get_feature_list (gst_registry_get_default (),
1214       GST_TYPE_ELEMENT_FACTORY);
1215
1216   for (l = features; l != NULL; l = l->next) {
1217     GstPluginFeature *feature;
1218
1219     feature = GST_PLUGIN_FEATURE (l->data);
1220
1221     /* only interested in the ones that are in the plugin we just loaded */
1222     if (g_str_equal (plugin_name, feature->plugin_name)) {
1223       GstElementFactory *factory;
1224
1225       g_print ("element-%s\n", gst_plugin_feature_get_name (feature));
1226
1227       factory = GST_ELEMENT_FACTORY (feature);
1228       print_plugin_automatic_install_info_protocols (factory);
1229       print_plugin_automatic_install_info_codecs (factory);
1230     }
1231   }
1232
1233   g_list_foreach (features, (GFunc) gst_object_unref, NULL);
1234   g_list_free (features);
1235 }
1236
1237 int
1238 main (int argc, char *argv[])
1239 {
1240   gboolean print_all = FALSE;
1241   gboolean print_aii = FALSE;
1242   GOptionEntry options[] = {
1243     {"print-all", 'a', 0, G_OPTION_ARG_NONE, &print_all,
1244         N_("Print all elements"), NULL},
1245     {"print-plugin-auto-install-info", '\0', 0, G_OPTION_ARG_NONE, &print_aii,
1246         N_("Print a machine-parsable list of features the specified plugin "
1247               "provides.\n                                       "
1248               "Useful in connection with external automatic plugin "
1249               "installation mechanisms"), NULL},
1250     GST_TOOLS_GOPTION_VERSION,
1251     {NULL}
1252   };
1253   GOptionContext *ctx;
1254   GError *err = NULL;
1255
1256 #ifdef ENABLE_NLS
1257   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1258   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1259   textdomain (GETTEXT_PACKAGE);
1260 #endif
1261
1262   if (!g_thread_supported ())
1263     g_thread_init (NULL);
1264
1265   ctx = g_option_context_new ("[ELEMENT-NAME | PLUGIN-NAME]");
1266   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
1267   g_option_context_add_group (ctx, gst_init_get_option_group ());
1268   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1269     g_print ("Error initializing: %s\n", err->message);
1270     exit (1);
1271   }
1272   g_option_context_free (ctx);
1273
1274   gst_tools_print_version ("gst-inspect");
1275
1276   if (print_all && argc > 2) {
1277     g_print ("-a requires no extra arguments\n");
1278     return 1;
1279   }
1280
1281   /* if no arguments, print out list of elements */
1282   if (argc == 1 || print_all) {
1283     print_element_list (print_all);
1284     /* else we try to get a factory */
1285   } else {
1286     GstElementFactory *factory;
1287     GstPlugin *plugin;
1288     const char *arg = argv[argc - 1];
1289     int retval;
1290
1291     factory = gst_element_factory_find (arg);
1292     /* if there's a factory, print out the info */
1293     if (factory) {
1294       retval = print_element_info (factory, print_all);
1295       gst_object_unref (factory);
1296     } else {
1297       retval = print_element_features (arg);
1298     }
1299
1300     /* otherwise check if it's a plugin */
1301     if (retval) {
1302       plugin = gst_default_registry_find_plugin (arg);
1303
1304       /* if there is such a plugin, print out info */
1305       if (plugin) {
1306         if (print_aii) {
1307           print_plugin_automatic_install_info (plugin);
1308         } else {
1309           print_plugin_info (plugin);
1310           print_plugin_features (plugin);
1311         }
1312       } else {
1313         GError *error = NULL;
1314
1315         if (g_file_test (arg, G_FILE_TEST_EXISTS)) {
1316           plugin = gst_plugin_load_file (arg, &error);
1317
1318           if (plugin) {
1319             if (print_aii) {
1320               print_plugin_automatic_install_info (plugin);
1321             } else {
1322               print_plugin_info (plugin);
1323               print_plugin_features (plugin);
1324             }
1325           } else {
1326             g_print (_("Could not load plugin file: %s\n"), error->message);
1327             g_error_free (error);
1328             return -1;
1329           }
1330         } else {
1331           g_print (_("No such element or plugin '%s'\n"), arg);
1332           return -1;
1333         }
1334       }
1335     }
1336   }
1337
1338   return 0;
1339 }