Convert %lld and %llu in printf formats to G_G[U]INT64_FORMAT. Fix pointer<->int...
[platform/upstream/gstreamer.git] / tools / gst-inspect.c
1 #include <gst/gst.h>
2 #include <gst/control/control.h>
3 #include <string.h>
4
5 static void 
6 print_prop (GstPropsEntry *prop, gboolean showname, const gchar *pfx) 
7 {
8   GstPropsType type;
9
10   if (showname)
11     g_print("%s%-20.20s: ", pfx, gst_props_entry_get_name (prop));
12   else
13     g_print(pfx);
14
15   type = gst_props_entry_get_type (prop);
16
17   switch (type) {
18     case GST_PROPS_INT_TYPE:
19     {
20       gint val;
21       gst_props_entry_get_int (prop, &val);
22       g_print("Integer: %d\n", val);
23       break;
24     }
25     case GST_PROPS_INT_RANGE_TYPE:
26     {
27       gint min, max;
28       gst_props_entry_get_int_range (prop, &min, &max);
29       g_print("Integer range: %d - %d\n", min, max);
30       break;
31     }
32     case GST_PROPS_FLOAT_TYPE:
33     {
34       gfloat val;
35       gst_props_entry_get_float (prop, &val);
36       g_print("Float: %f\n", val);
37       break;
38     }
39     case GST_PROPS_FLOAT_RANGE_TYPE:
40     {
41       gfloat min, max;
42       gst_props_entry_get_float_range (prop, &min, &max);
43       g_print("Float range: %f - %f\n", min, max);
44       break;
45     }
46     case GST_PROPS_BOOLEAN_TYPE:
47     {
48       gboolean val;
49       gst_props_entry_get_boolean (prop, &val);
50       g_print("Boolean: %s\n", val ? "TRUE" : "FALSE");
51       break;
52     }
53     case GST_PROPS_STRING_TYPE:
54     {
55       const gchar *val;
56       gst_props_entry_get_string (prop, &val);
57       g_print("String: \"%s\"\n", val);
58       break;
59     }
60     case GST_PROPS_FOURCC_TYPE:
61     {
62       guint32 val;
63       gst_props_entry_get_fourcc_int (prop, &val);
64       g_print("FourCC: '%c%c%c%c'\n",
65              (gchar)( val        & 0xff), 
66              (gchar)((val >> 8)  & 0xff),
67              (gchar)((val >> 16) & 0xff), 
68              (gchar)((val >> 24) & 0xff));
69       break;
70     }
71     case GST_PROPS_LIST_TYPE:
72     {
73       const GList *list;
74       gchar *longprefix;
75
76       gst_props_entry_get_list (prop, &list);
77       g_print ("List:\n");
78       longprefix = g_strdup_printf ("%s ", pfx);
79       while (list) {
80         GstPropsEntry *listentry;
81
82         listentry = (GstPropsEntry*) (list->data);
83         print_prop (listentry, FALSE, longprefix);
84
85         list = g_list_next (list);
86       }
87       g_free (longprefix);
88       break;
89     }
90     default:
91       g_print("unknown props %d\n", type);
92   }
93 }
94
95 static void 
96 print_props (GstProps *properties, const gchar *pfx) 
97 {
98   GList *props;
99   GstPropsEntry *prop;
100
101   props = properties->properties;
102   while (props) {
103     prop = (GstPropsEntry*)(props->data);
104     props = g_list_next(props);
105
106     print_prop(prop,TRUE,pfx);
107   }
108 }
109
110 static void 
111 print_caps (const GstCaps *caps, const gchar *pfx) 
112 {
113   while (caps) {
114     GstType *type;
115
116     g_print ("%s'%s': (%sfixed)\n", pfx, caps->name, (GST_CAPS_IS_FIXED (caps) ? "" : "NOT "));
117
118     type = gst_type_find_by_id (caps->id);
119     if (type) 
120       g_print ("%s  MIME type: '%s':\n", pfx, type->mime);
121     else
122       g_print ("%s  MIME type: 'unknown/unknown':\n", pfx);
123
124     if (caps->properties) {
125       gchar *prefix = g_strdup_printf ("%s  ", pfx);
126
127       print_props(caps->properties, prefix);
128
129       g_free (prefix);
130     }
131
132     caps = caps->next;
133   }
134 }
135
136 static void 
137 print_formats (const GstFormat *formats) 
138 {
139   while (formats && *formats) {
140     const GstFormatDefinition *definition;
141
142     definition = gst_format_get_details (*formats);
143     if (definition)
144       g_print ("\t\t(%d):\t%s (%s)\n", *formats,
145                definition->nick, definition->description);
146     else
147       g_print ("\t\t(%d):\tUnknown format\n", *formats);
148
149     formats++;
150   }
151 }
152
153 static void 
154 print_query_types (const GstQueryType *types) 
155 {
156   while (types && *types) {
157     const GstQueryTypeDefinition *definition;
158
159     definition = gst_query_type_get_details (*types);
160     if (definition)
161       g_print ("\t\t(%d):\t%s (%s)\n", *types,
162                definition->nick, definition->description);
163     else
164       g_print ("\t\t(%d):\tUnknown query format\n", *types);
165
166     types++;
167   }
168 }
169
170 static void 
171 print_event_masks (const GstEventMask *masks) 
172 {
173   GType event_type;
174   GEnumClass *klass;
175   GType event_flags;
176   GFlagsClass *flags_class = NULL;
177
178   event_type = gst_event_type_get_type();
179   klass = (GEnumClass *) g_type_class_ref (event_type);
180
181   while (masks && masks->type) {
182     GEnumValue *value;
183     gint flags = 0, index = 0;
184
185     switch (masks->type) {
186       case GST_EVENT_SEEK:
187         flags = masks->flags;
188         event_flags = gst_seek_type_get_type ();
189         flags_class = (GFlagsClass *) g_type_class_ref (event_flags);
190         break;
191       default:
192         break;
193     }
194     
195     value = g_enum_get_value (klass, masks->type);
196     g_print ("\t\t%s ", value->value_nick);
197
198     while (flags) {
199       GFlagsValue *value;
200
201       if (flags & 1) {
202         value = g_flags_get_first_value (flags_class, 1 << index);
203
204         if (value)
205           g_print ("| %s ", value->value_nick);
206         else
207           g_print ("| ? ");
208       }
209       flags >>= 1;
210       index++;
211     }
212     g_print ("\n");
213     
214     masks++;
215   }
216 }
217
218 static void
219 output_hierarchy (GType type, gint level, gint *maxlevel)
220 {
221   GType parent;
222   gint i;
223
224   parent = g_type_parent (type);
225
226   *maxlevel = *maxlevel + 1;
227   level++;
228
229   if (parent)
230     output_hierarchy (parent, level, maxlevel);
231   
232   for (i=1; i<*maxlevel-level; i++)
233    g_print ("      ");
234   if (*maxlevel-level)
235     g_print (" +----");
236
237   g_print ("%s\n", g_type_name (type));
238           
239   if (level == 1)
240     g_print ("\n");
241 }
242
243 static void
244 print_element_properties (GstElement *element) 
245 {
246   GParamSpec **property_specs;
247   gint num_properties,i;
248   gboolean readable;
249   
250
251   property_specs = g_object_class_list_properties 
252                      (G_OBJECT_GET_CLASS (element), &num_properties);
253   g_print("\nElement Arguments:\n");
254
255   for (i = 0; i < num_properties; i++) {
256     GValue value = { 0, };
257     GParamSpec *param = property_specs[i];
258     readable = FALSE;
259
260     g_value_init (&value, param->value_type);
261     if (param->flags & G_PARAM_READABLE) {
262       g_object_get_property (G_OBJECT (element), param->name, &value);
263       readable = TRUE;
264     }
265
266     g_print("  %-20s: %s\n", g_param_spec_get_name (param),
267                                g_param_spec_get_blurb (param));
268
269     switch (G_VALUE_TYPE (&value)) {
270       case G_TYPE_STRING: 
271         g_print ("%-23.23s String. ", "");
272         if (readable) g_print ("(Default \"%s\")", g_value_get_string (&value));
273         break;
274       case G_TYPE_BOOLEAN: 
275         g_print ("%-23.23s Boolean. ", "");
276         if (readable) g_print ("(Default %s)", (g_value_get_boolean (&value) ? "true" : "false"));
277         break;
278       case G_TYPE_ULONG: 
279       {
280         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
281         g_print("%-23.23s Unsigned Long. ", ""); 
282         if (readable) g_print("Range: %lu - %lu (Default %lu)",  
283                         pulong->minimum, pulong->maximum, g_value_get_ulong (&value));
284         break;
285       }
286       case G_TYPE_LONG: 
287       {
288         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
289         g_print("%-23.23s Long. ", ""); 
290         if (readable) g_print("Range: %ld - %ld (Default %ld)",  
291                         plong->minimum, plong->maximum, g_value_get_long (&value));
292         break;
293       }
294       case G_TYPE_UINT: 
295       {
296         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
297         g_print("%-23.23s Unsigned Integer. ", "");
298         if (readable) g_print("Range: %u - %u (Default %u)",  
299                         puint->minimum, puint->maximum, g_value_get_uint (&value));
300         break;
301       }
302       case G_TYPE_INT: 
303       {
304         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
305         g_print("%-23.23s Integer. ", ""); 
306         if (readable) g_print("Range: %d - %d (Default %d)", 
307                         pint->minimum, pint->maximum, g_value_get_int (&value));
308         break;
309       }
310       case G_TYPE_UINT64: 
311       {
312         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
313         g_print("%-23.23s Unsigned Integer64. ", ""); 
314         if (readable) g_print("Range: %" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT " (Default %" G_GUINT64_FORMAT ")", 
315                         puint64->minimum, puint64->maximum, g_value_get_uint64 (&value));
316         break;
317       }
318       case G_TYPE_INT64: 
319       {
320         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
321         g_print("%-23.23s Integer64. ", ""); 
322         if (readable) g_print("Range: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (Default %" G_GINT64_FORMAT ")", 
323                         pint64->minimum, pint64->maximum, g_value_get_int64 (&value));
324         break;
325       }
326       case G_TYPE_FLOAT: 
327       {
328         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
329         g_print("%-23.23s Float. Default: %-8.8s %15.7g\n", "", "", 
330                 g_value_get_float (&value));
331         g_print("%-23.23s Range: %15.7g - %15.7g", "", 
332                pfloat->minimum, pfloat->maximum);
333         break;
334       }
335       case G_TYPE_DOUBLE: 
336       {
337         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
338         g_print("%-23.23s Double. Default: %-8.8s %15.7g\n", "", "", 
339                 g_value_get_double (&value));
340         g_print("%-23.23s Range: %15.7g - %15.7g", "", 
341                pdouble->minimum, pdouble->maximum);
342         break;
343       }
344       default:
345         if (param->value_type == GST_TYPE_FILENAME) {
346           g_print("%-23.23s Filename", "");
347         }
348         if (param->value_type == GST_TYPE_CAPS) {
349           GstCaps *caps = g_value_peek_pointer (&value);
350
351           if (!caps) 
352             g_print("%-23.23s Caps (NULL)", "");
353           else {
354             print_caps (caps, "                           ");
355           }
356         }
357         else if (G_IS_PARAM_SPEC_ENUM (param)) {
358           GEnumValue *values;
359           guint j = 0;
360           gint enum_value;
361
362           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
363           enum_value = g_value_get_enum (&value);
364
365           while (values[j].value_name) {
366             if (values[j].value == enum_value)
367               break;
368             j++; 
369           }
370
371           g_print ("%-23.23s Enum \"%s\" (default %d, \"%s\")", "", 
372                           g_type_name (G_VALUE_TYPE (&value)),
373                           enum_value, values[j].value_nick);
374
375           j = 0;
376           while (values[j].value_name) {
377             g_print("\n%-23.23s    (%d): \t%s", "", 
378                             values[j].value, values[j].value_nick);
379             j++; 
380           }
381           /* g_type_class_unref (ec); */
382         }
383         else if (G_IS_PARAM_SPEC_FLAGS (param)) {
384           GFlagsValue *values;
385           guint j = 0;
386           gint flags_value;
387           GString *flags = NULL;
388
389           values = G_FLAGS_CLASS (g_type_class_ref (param->value_type))->values;
390           flags_value = g_value_get_flags (&value);
391
392           while (values[j].value_name) {
393             if (values[j].value & flags_value) {
394               if (flags) {
395                 g_string_append_printf (flags, " | %s", values[j].value_nick);
396               }
397               else {
398                 flags = g_string_new (values[j].value_nick);
399               }
400             }
401             j++;
402           }
403
404           g_print ("%-23.23s Flags \"%s\" (default %d, \"%s\")", "", 
405                           g_type_name (G_VALUE_TYPE (&value)),
406                           flags_value, (flags ? flags->str : "(none)"));
407
408           j = 0;
409           while (values[j].value_name) {
410             g_print("\n%-23.23s    (%d): \t%s", "", 
411                             values[j].value, values[j].value_nick);
412             j++; 
413           }
414
415           if (flags)
416             g_string_free (flags, TRUE);
417         }
418         else if (G_IS_PARAM_SPEC_OBJECT (param)) {
419           g_print("%-23.23s Object of type \"%s\"", "",
420                           g_type_name(param->value_type));
421         }
422         else {
423           g_print ("%-23.23s Unknown type %ld \"%s\"", "",param->value_type, 
424                         g_type_name(param->value_type));
425         }
426         break;
427     }
428     if (!readable) 
429       g_print (" Write only\n");
430     else 
431       g_print ("\n");
432   }
433   if (num_properties == 0) 
434     g_print ("  none\n");
435 }
436
437 static gint
438 print_element_info (GstElementFactory *factory)
439 {
440   GstElement *element;
441   GstObjectClass *gstobject_class;
442   GstElementClass *gstelement_class;
443   GList *pads;
444   GstPad *pad;
445   GstRealPad *realpad;
446   GstPadTemplate *padtemplate;
447   GList *children;
448   GstElement *child;
449   gboolean have_flags;
450   gint maxlevel = 0;
451
452   element = gst_element_factory_create (factory, "element");
453   if (!element) {
454     g_print ("couldn't construct element for some reason\n");
455     return -1;
456   }
457
458   gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element));
459   gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
460
461   g_print ("Factory Details:\n");
462   g_print ("  Long name:\t%s\n",   factory->details->longname);
463   g_print ("  Class:\t%s\n",       factory->details->klass);
464   g_print ("  License:\t%s\n",     factory->details->license);
465   g_print ("  Description:\t%s\n", factory->details->description);
466   g_print ("  Version:\t%s\n",     factory->details->version);
467   g_print ("  Author(s):\t%s\n",   factory->details->author);
468   g_print ("  Copyright:\t%s\n",   factory->details->copyright);
469   g_print ("\n");
470
471   output_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel);
472
473   g_print ("Pad Templates:\n");
474   if (factory->numpadtemplates) {
475     pads = factory->padtemplates;
476     while (pads) {
477       padtemplate = (GstPadTemplate*)(pads->data);
478       pads = g_list_next(pads);
479
480       if (padtemplate->direction == GST_PAD_SRC)
481         g_print ("  SRC template: '%s'\n", padtemplate->name_template);
482       else if (padtemplate->direction == GST_PAD_SINK)
483         g_print ("  SINK template: '%s'\n", padtemplate->name_template);
484       else
485         g_print ("  UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
486
487       if (padtemplate->presence == GST_PAD_ALWAYS)
488         g_print ("    Availability: Always\n");
489       else if (padtemplate->presence == GST_PAD_SOMETIMES)
490         g_print ("    Availability: Sometimes\n");
491       else if (padtemplate->presence == GST_PAD_REQUEST) {
492         g_print ("    Availability: On request\n");
493         g_print ("      Has request_new_pad() function: %s\n",
494                 GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad));
495       }
496       else
497         g_print ("    Availability: UNKNOWN!!!\n");
498
499       if (padtemplate->caps) {
500         g_print ("    Capabilities:\n");
501         print_caps (padtemplate->caps, "      ");
502       }
503
504       g_print ("\n");
505     }
506   } else
507     g_print ("  none\n");
508
509   have_flags = FALSE;
510
511   g_print ("\nElement Flags:\n");
512   if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
513     g_print ("  GST_ELEMENT_COMPLEX\n");
514     have_flags = TRUE;
515   }
516   if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
517     g_print ("  GST_ELEMENT_DECOUPLED\n");
518     have_flags = TRUE;
519   }
520   if (GST_FLAG_IS_SET (element, GST_ELEMENT_THREAD_SUGGESTED)) {
521     g_print ("  GST_ELEMENT_THREADSUGGESTED\n");
522     have_flags = TRUE;
523   }
524   if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
525     g_print("  GST_ELEMENT_EVENT_AWARE\n");
526     have_flags = TRUE;
527   }
528   if (!have_flags)
529     g_print("  no flags set\n");
530
531   if (GST_IS_BIN (element)) {
532     g_print ("\nBin Flags:\n");
533     if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
534       g_print ("  GST_BIN_FLAG_MANAGER\n");
535       have_flags = TRUE;
536     }
537     if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
538       g_print ("  GST_BIN_SELF_SCHEDULABLE\n");
539       have_flags = TRUE;
540     }
541     if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_PREFER_COTHREADS)) {
542       g_print ("  GST_BIN_FLAG_PREFER_COTHREADS\n");
543       have_flags = TRUE;
544     }
545     if (!have_flags)
546       g_print ("  no flags set\n");
547   }
548
549
550
551   g_print ("\nElement Implementation:\n");
552
553   if (element->loopfunc)
554     g_print ("  loopfunc()-based element: %s\n",
555             GST_DEBUG_FUNCPTR_NAME (element->loopfunc));
556   else
557     g_print ("  No loopfunc(), must be chain-based or not configured yet\n");
558
559   g_print ("  Has change_state() function: %s\n",
560           GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
561 #ifndef GST_DISABLE_LOADSAVE
562   g_print ("  Has custom save_thyself() function: %s\n",
563           GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself));
564   g_print ("  Has custom restore_thyself() function: %s\n",
565           GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself));
566 #endif
567
568   have_flags = FALSE;
569
570   g_print ("\nClocking Interaction:\n");
571   if (gst_element_requires_clock (element)) {
572     g_print ("  element requires a clock\n");
573     have_flags = TRUE;
574   }
575   if (gst_element_provides_clock (element)) {
576     GstClock *clock;
577
578     clock = gst_element_get_clock (element);
579     if (clock)
580       g_print ("  element provides a clock: %s\n", GST_OBJECT_NAME(clock));
581     else
582       g_print ("  element is supposed to provide a clock but returned NULL\n");
583     have_flags = TRUE;
584   }
585   if (!have_flags) {
586     g_print ("  none\n");
587   }
588
589   g_print ("\nIndexing capabilities:\n");
590   if (gst_element_is_indexable (element)) {
591     g_print ("  element can do indexing\n");
592   }
593   else {
594     g_print ("  none\n");
595   }
596
597   g_print ("\nPads:\n");
598   if (element->numpads) {
599     const GList *pads;
600     pads = gst_element_get_pad_list (element);
601     while (pads) {
602       pad = GST_PAD (pads->data);
603       pads = g_list_next (pads);
604       realpad = GST_PAD_REALIZE (pad);
605
606       if (gst_pad_get_direction (pad) == GST_PAD_SRC)
607         g_print ("  SRC: '%s'", gst_pad_get_name (pad));
608       else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
609         g_print ("  SINK: '%s'", gst_pad_get_name (pad));
610       else
611         g_print ("  UNKNOWN!!!: '%s'\n", gst_pad_get_name (pad));
612
613       if (GST_IS_GHOST_PAD (pad))
614         g_print (", ghost of real pad %s:%s\n", GST_DEBUG_PAD_NAME (realpad));
615       else
616         g_print ("\n");
617
618       g_print ("    Implementation:\n");
619       if (realpad->chainfunc)
620         g_print ("      Has chainfunc(): %s\n",
621                 GST_DEBUG_FUNCPTR_NAME (realpad->chainfunc));
622       if (realpad->getfunc)
623         g_print ("      Has getfunc(): %s\n",
624                 GST_DEBUG_FUNCPTR_NAME (realpad->getfunc));
625       if (realpad->formatsfunc != gst_pad_get_formats_default) {
626         g_print ("      Supports seeking/conversion/query formats:\n");
627         print_formats (gst_pad_get_formats (GST_PAD (realpad)));
628       }
629       if (realpad->convertfunc != gst_pad_convert_default)
630         g_print ("      Has custom convertfunc(): %s\n",
631                 GST_DEBUG_FUNCPTR_NAME (realpad->convertfunc));
632       if (realpad->eventfunc != gst_pad_event_default)
633         g_print ("      Has custom eventfunc(): %s\n",
634                 GST_DEBUG_FUNCPTR_NAME (realpad->eventfunc));
635       if (realpad->eventmaskfunc != gst_pad_get_event_masks_default) {
636         g_print ("        Provides event masks:\n");
637         print_event_masks (gst_pad_get_event_masks (GST_PAD (realpad)));
638       }
639       if (realpad->queryfunc != gst_pad_query_default)
640         g_print ("      Has custom queryfunc(): %s\n",
641                 GST_DEBUG_FUNCPTR_NAME (realpad->queryfunc));
642       if (realpad->querytypefunc != gst_pad_get_query_types_default) {
643         g_print ("        Provides query types:\n");
644         print_query_types (gst_pad_get_query_types (GST_PAD (realpad)));
645       }
646
647       if (realpad->intlinkfunc != gst_pad_get_internal_links_default)
648         g_print ("      Has custom intconnfunc(): %s\n",
649                 GST_DEBUG_FUNCPTR_NAME(realpad->intlinkfunc));
650
651       if (realpad->bufferpoolfunc)
652         g_print ("      Has bufferpoolfunc(): %s\n",
653                 GST_DEBUG_FUNCPTR_NAME(realpad->bufferpoolfunc));
654
655       if (pad->padtemplate)
656         g_print ("    Pad Template: '%s'\n",
657                 pad->padtemplate->name_template);
658
659       if (realpad->caps) {
660         g_print ("    Capabilities:\n");
661         print_caps (realpad->caps, "      ");
662       }
663     }
664   } else
665     g_print ("  none\n");
666
667   print_element_properties (element);
668
669   /* Dynamic Parameters block */
670   {
671     GstDParamManager* dpman;
672     GParamSpec** specs;
673     gint x;
674     
675     g_print ("\nDynamic Parameters:\n");
676     if((dpman = gst_dpman_get_manager (element))) {
677       specs = gst_dpman_list_dparam_specs (dpman);
678       for (x = 0; specs[x] != NULL; x++) {
679         g_print ("  %-20.20s: ", g_param_spec_get_name (specs[x]));
680
681         switch (G_PARAM_SPEC_VALUE_TYPE (specs[x])) {
682           case G_TYPE_INT64: 
683             g_print ("64 Bit Integer (Default %" G_GINT64_FORMAT ", Range %" G_GINT64_FORMAT " -> %" G_GINT64_FORMAT ")", 
684             ((GParamSpecInt64 *) specs[x])->default_value,
685             ((GParamSpecInt64 *) specs[x])->minimum, 
686             ((GParamSpecInt64 *) specs[x])->maximum);
687             break;
688           case G_TYPE_INT: 
689             g_print ("Integer (Default %d, Range %d -> %d)", 
690             ((GParamSpecInt *) specs[x])->default_value,
691             ((GParamSpecInt *) specs[x])->minimum, 
692             ((GParamSpecInt *) specs[x])->maximum);
693             break;
694           case G_TYPE_FLOAT: 
695             g_print ("Float. Default: %-8.8s %15.7g\n", "",
696               ((GParamSpecFloat *) specs[x])->default_value);
697             g_print ("%-23.23s Range: %15.7g - %15.7g", "", 
698               ((GParamSpecFloat *) specs[x])->minimum, 
699               ((GParamSpecFloat *) specs[x])->maximum);
700             break;
701         default: g_print ("unknown %ld", G_PARAM_SPEC_VALUE_TYPE (specs[x]));
702         }
703         g_print ("\n");
704       }
705       g_free (specs);
706     }
707     else {
708       g_print ("  none\n");
709     }
710   }
711
712   /* Signals/Actions Block */  
713   {
714     guint *signals;
715     guint nsignals;
716     gint i, k;
717     GSignalQuery *query;
718     
719     signals = g_signal_list_ids (G_OBJECT_TYPE (element), &nsignals);
720     for (k = 0; k < 2; k++) {
721       gint counted = 0;
722
723       if (k == 0)
724         g_print ("\nElement Signals:\n");
725       else
726         g_print ("\nElement Actions:\n");
727
728       for (i = 0; i < nsignals; i++) {
729         gint n_params;
730         GType return_type;
731         const GType *param_types;
732         gint j;
733       
734         query = g_new0 (GSignalQuery,1);
735         g_signal_query (signals[i], query);
736
737         if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
738             (k == 1 &&  (query->signal_flags & G_SIGNAL_ACTION))) {
739           n_params = query->n_params;
740           return_type = query->return_type;
741           param_types = query->param_types;
742
743           g_print ("  \"%s\" :\t %s user_function (%s* object", 
744                   query->signal_name, g_type_name (return_type),
745                   g_type_name (G_OBJECT_TYPE (element)));
746
747           for (j = 0; j < n_params; j++) {
748             g_print (",\n    \t\t\t\t%s arg%d", g_type_name (param_types[j]), j);
749           }
750           if (k == 0)
751             g_print (",\n    \t\t\t\tgpointer user_data);\n");
752           else
753             g_print (");\n");
754
755           counted++;
756         }
757
758         g_free (query);
759       }
760       if (counted == 0) g_print ("  none\n");
761     }
762   }
763   
764
765   /* for compound elements */
766   if (GST_IS_BIN (element)) {
767     g_print ("\nChildren:\n");
768     children = (GList *) gst_bin_get_list (GST_BIN (element));
769     if (!children) 
770       g_print ("  none\n");
771     else {
772       while (children) {
773         child = GST_ELEMENT (children->data);
774         children = g_list_next (children);
775
776         g_print ("  %s\n", GST_ELEMENT_NAME (child));
777       }
778     }
779   }
780
781   return 0;
782 }
783
784 static void 
785 print_element_list (void) 
786 {
787   GList *plugins;
788
789   plugins = gst_registry_pool_plugin_list();
790   while (plugins) {
791     GList *features;
792     GstPlugin *plugin;
793     
794     plugin = (GstPlugin*)(plugins->data);
795     plugins = g_list_next (plugins);
796
797     features = gst_plugin_get_feature_list (plugin);
798     while (features) {
799       GstPluginFeature *feature;
800
801       feature = GST_PLUGIN_FEATURE (features->data);
802
803       if (GST_IS_ELEMENT_FACTORY (feature)) {
804         GstElementFactory *factory;
805
806         factory = GST_ELEMENT_FACTORY (feature);
807         g_print ("%s:  %s: %s\n", plugin->name, 
808                 GST_PLUGIN_FEATURE_NAME (factory) ,factory->details->longname);
809       }
810       else if (GST_IS_AUTOPLUG_FACTORY (feature)) {
811         GstAutoplugFactory *factory;
812
813         factory = GST_AUTOPLUG_FACTORY (feature);
814         g_print ("%s:  %s: %s\n", plugin->name, 
815                 GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
816       }
817       else if (GST_IS_INDEX_FACTORY (feature)) {
818         GstIndexFactory *factory;
819
820         factory = GST_INDEX_FACTORY (feature);
821         g_print ("%s:  %s: %s\n", plugin->name, 
822                 GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
823       }
824       else if (GST_IS_TYPE_FACTORY (feature)) {
825         GstTypeFactory *factory;
826
827         factory = GST_TYPE_FACTORY (feature);
828         g_print ("%s type:  %s: %s\n", plugin->name, 
829                 factory->mime, factory->exts);
830
831         if (factory->typefindfunc)
832           g_print ("      Has typefind function: %s\n",
833                   GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
834       }
835       else if (GST_IS_SCHEDULER_FACTORY (feature)) {
836         GstSchedulerFactory *factory;
837
838         factory = GST_SCHEDULER_FACTORY (feature);
839         g_print ("%s:  %s: %s\n", plugin->name, 
840                 GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
841       }
842       else if (GST_IS_URI_HANDLER (feature)) {
843         GstURIHandler *handler;
844
845         handler = GST_URI_HANDLER (feature);
846         g_print ("%s:  %s: \"%s\" (%s) element \"%s\" property \"%s\"\n", plugin->name, 
847                 GST_PLUGIN_FEATURE_NAME (handler), handler->uri, handler->longdesc,
848                 handler->element, handler->property);
849       }
850       else {
851         g_print ("%s:  %s (%s)\n", plugin->name, 
852                 GST_PLUGIN_FEATURE_NAME (feature), 
853                 g_type_name (G_OBJECT_TYPE (feature)));
854       }
855
856       features = g_list_next (features);
857     }
858   }
859 }
860
861 static void
862 print_plugin_info (GstPlugin *plugin)
863 {
864   GList *features;
865   gint num_features = 0;
866   gint num_elements = 0;
867   gint num_autoplug = 0;
868   gint num_types = 0;
869   gint num_schedulers = 0;
870   gint num_indexes = 0;
871   gint num_other = 0;
872   
873   g_print ("Plugin Details:\n");
874   g_print ("  Name:\t\t%s\n",    plugin->name);
875   g_print ("  Long Name:\t%s\n", plugin->longname);
876   g_print ("  Filename:\t%s\n",  plugin->filename);
877   g_print ("\n");
878
879   features = gst_plugin_get_feature_list (plugin);
880
881   while (features) {
882     GstPluginFeature *feature;
883
884     feature = GST_PLUGIN_FEATURE (features->data);
885
886     if (GST_IS_ELEMENT_FACTORY (feature)) {
887       GstElementFactory *factory;
888
889       factory = GST_ELEMENT_FACTORY (feature);
890       g_print ("  %s: %s\n", GST_OBJECT_NAME (factory),
891               factory->details->longname);
892       num_elements++;
893     }
894     else if (GST_IS_AUTOPLUG_FACTORY (feature)) {
895       GstAutoplugFactory *factory;
896
897       factory = GST_AUTOPLUG_FACTORY (feature);
898       g_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
899       num_autoplug++;
900     }
901     else if (GST_IS_INDEX_FACTORY (feature)) {
902       GstIndexFactory *factory;
903
904       factory = GST_INDEX_FACTORY (feature);
905       g_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
906       num_indexes++;
907     }
908     else if (GST_IS_TYPE_FACTORY (feature)) {
909       GstTypeFactory *factory;
910
911       factory = GST_TYPE_FACTORY (feature);
912       g_print ("  %s: %s\n", factory->mime, factory->exts);
913
914       if (factory->typefindfunc)
915         g_print ("      Has typefind function: %s\n", 
916                 GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
917       num_types++;
918     }
919     else if (GST_IS_SCHEDULER_FACTORY (feature)) {
920       GstSchedulerFactory *factory;
921
922       factory = GST_SCHEDULER_FACTORY (feature);
923       g_print ("  %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc);
924       num_schedulers++;
925     }
926     else {
927       g_print ("  %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)), 
928                              g_type_name (G_OBJECT_TYPE (feature)));
929       num_other++;
930     }
931     num_features++;
932     features = g_list_next (features);
933   }
934   g_print ("\n  %d features:\n", num_features);
935   if (num_elements > 0)
936     g_print ("  +-- %d elements\n", num_elements);
937   if (num_autoplug > 0)
938     g_print ("  +-- %d autopluggers\n", num_autoplug);
939   if (num_types > 0)
940     g_print ("  +-- %d types\n", num_types);
941   if (num_schedulers > 0)
942     g_print ("  +-- %d schedulers\n", num_schedulers);
943   if (num_indexes > 0)
944     g_print ("  +-- %d indexes\n", num_indexes);
945   if (num_other > 0)
946     g_print ("  +-- %d other objects\n", num_other);
947   
948   g_print ("\n");
949 }
950
951
952 int 
953 main (int argc, char *argv[]) 
954 {
955   GstElementFactory *factory;
956   GstPlugin *plugin;
957   gchar *so;
958   struct poptOption options[] = {
959     {"gst-inspect-plugin",  'p',  POPT_ARG_STRING|POPT_ARGFLAG_STRIP,   NULL,   0,
960                    "Show plugin details", NULL},
961     {"gst-inspect-scheduler",  's',  POPT_ARG_STRING|POPT_ARGFLAG_STRIP,   NULL,   0,
962                    "Show scheduler details", NULL},
963     POPT_TABLEEND
964   };
965
966   gst_init_with_popt_table (&argc, &argv, options);
967   gst_control_init (&argc, &argv);
968   
969   /* if no arguments, print out list of elements */
970   if (argc == 1) {
971     print_element_list();
972
973   /* else we try to get a factory */
974   } else {
975     /* first check for help */
976     if (strstr (argv[1], "-help")) {
977       g_print ("Usage: %s\t\t\tList all registered elements\n",argv[0]);
978       g_print ("       %s element-name\tShow element details\n",argv[0]);
979       g_print ("       %s plugin-name[.so]\tShow information about plugin\n",
980               argv[0]);
981       return 0;
982     }
983
984     /* only search for a factory if there's not a '.so' */
985     if (! strstr (argv[1], ".so")) {
986       factory = gst_element_factory_find (argv[1]);
987
988       /* if there's a factory, print out the info */
989       if (factory)
990         return print_element_info (factory);
991       else {
992          GstPluginFeature* feature;
993
994          /* FIXME implement other pretty print function for these */
995          feature = gst_registry_pool_find_feature (argv[1], GST_TYPE_SCHEDULER_FACTORY);
996          if (feature) {
997            g_print ("%s: a scheduler\n", argv[1]);
998            return 0;
999          }
1000          feature = gst_registry_pool_find_feature (argv[1], GST_TYPE_INDEX_FACTORY);
1001          if (feature) {
1002            g_print ("%s: an index\n", argv[1]);
1003            return 0;
1004          }
1005          feature = gst_registry_pool_find_feature (argv[1], GST_TYPE_AUTOPLUG_FACTORY);
1006          if (feature) {
1007            g_print ("%s: an autoplugger\n", argv[1]);
1008            return 0;
1009          }
1010          feature = gst_registry_pool_find_feature (argv[1], GST_TYPE_TYPE_FACTORY);
1011          if (feature) {
1012            g_print ("%s: an type\n", argv[1]);
1013            return 0;
1014          }
1015          feature = gst_registry_pool_find_feature (argv[1], GST_TYPE_URI_HANDLER);
1016          if (feature) {
1017            g_print ("%s: an uri handler\n", argv[1]);
1018            return 0;
1019          }
1020       }
1021     } else {
1022       /* strip the .so */
1023       so = strstr(argv[1],".so");
1024       so[0] = '\0';
1025     }
1026
1027     /* otherwise assume it's a plugin */
1028     plugin = gst_registry_pool_find_plugin (argv[1]);
1029
1030     /* if there is such a plugin, print out info */
1031
1032     if (plugin) {
1033       print_plugin_info (plugin);
1034
1035     } else {
1036       g_print("no such element or plugin '%s'\n", argv[1]);
1037       return -1;
1038     }
1039   }
1040
1041   return 0;
1042 }