28d23b9cddb41f81c1c6ee5f30c9614cdec9ed32
[platform/upstream/gstreamer.git] / tests / examples / opencv / gst_element_print_properties.c
1 /* GStreamer
2  * Copyright (C) 2010 Wesley Miller <wmiller@sdr.com>
3  *
4  *
5  *  gst_element_print_properties(): a tool to inspect GStreamer
6  *                                  element properties
7  *
8  *  This program is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program 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
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22
23
24 #include <gst/gst.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <locale.h>
28
29 #include "gst_element_print_properties.h"
30
31
32 void
33 gst_element_print_properties (GstElement * element)
34 {
35   /////////////////////////////////////////////////////////////////////////////
36   //
37   // Formatting setup
38   //
39   //    Change the valuses of c2w, c3w and c4w to adjust the 2nd, 3rd and 4th
40   //    column widths, respectively.  The gutter width is fixed at 3 and
41   //    alwasys prints as " | ".  Column 1 has a fixed width of 3.
42   //
43   //    The first two rows for each element's output are its element class
44   //    name (e.g. "GstAudioResample") and its element factory name
45   //    ("audioresample").  The long element factory name ("Audio resampler")
46   //    is in column 4 following the element factory name.
47   //
48   //    Most properties use this format.  Multivalued items like CAPS, certain
49   //    GST_TYPEs and enums are different.
50   //
51   //      Column 1  contains the rwc, "readable", "writable", "controllable"
52   //                flags of the property.
53   //      Column 2  contains the property name
54   //      Column 3  contains the current value
55   //      Column 4  contains the property type, e.g. G_TYPE_INT
56   //      Column 5  contains the range, if there is one, and the default.
57   //                The range is encosed in parentheses. e.g.  "(1-10)   5"
58   //
59   //    CAPS, enums, flags and some undefined items have no columns 4 or 5 and
60   //    column 3 will contain a description of the item.  Additional rows may
61   //    list specific valused (CAPS and flags).
62   //
63   //    String values are enclosed in double quotes.  A missing right quote
64   //    inidicates the string had been truncated.
65   //
66   //  Screen column
67   //  ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9--->
68   //
69   //  formatted columns with built in gutters
70   //  --- | ---------c2---------- | ---------c3-------- | -----------c4---------- | --> unspecified
71   //
72   //  <-->|<--- property name --->|<-- current value -->|<-------- type --------->|<----- range and default ----->
73   //      | ELEMENT CLASS NAME    | GstAudioResample    |                         |
74   //      | ELEMENT FACTORY NAME  | audioresample       | Audio resampler         |
75   //  RW- | name                  | "audioResampler"    | G_TYPE_STRING           | null
76   //  RW- | qos                   | false               | G_TYPE_BOOLEAN          | false
77   //  RW- | quality               | 8                   | G_TYPE_INT              | (0 - 10)   4
78   //
79   /////////////////////////////////////////////////////////////////////////////
80
81   const guint c2w = 21;         // column 2 width
82   const guint c3w = 19;         // column 3 width
83   const guint c4w = 23;         // column 4 width
84
85   /////////////////////////////////////////////////////////////////////////////
86   // end configuration variables.
87   /////////////////////////////////////////////////////////////////////////////
88
89   GParamSpec **property_specs;
90   guint num_properties, i;
91   gboolean readable;
92   gboolean first_flag;
93
94
95   g_return_if_fail (element != NULL);
96
97   property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element),
98       &num_properties);
99
100    /*--- draw the header information ---*/
101   print_column_titles (c2w, c3w, c4w);
102   print_element_info (element, c2w, c3w, c4w);
103
104
105   for (i = 0; i < num_properties; i++) {
106     gchar flags[4];
107     GValue value = { 0, };
108     GParamSpec *param = property_specs[i];
109
110     readable = FALSE;
111     first_flag = TRUE;
112
113     g_value_init (&value, param->value_type);
114
115     flags[0] = '-';
116     flags[1] = '-';
117     flags[2] = '-';
118     flags[3] = 0x0;
119
120     if (param->flags & G_PARAM_READABLE) {
121       g_object_get_property (G_OBJECT (element), param->name, &value);
122       readable = TRUE;
123       flags[0] = 'r';
124     }
125
126     if (param->flags & G_PARAM_WRITABLE)
127       flags[1] = 'w';
128
129     if (param->flags & GST_PARAM_CONTROLLABLE)
130       flags[2] = 'c';
131
132     g_print ("%s |", flags);
133     g_print (" %-*s | ", c2w, g_param_spec_get_name (param));
134
135     switch (G_VALUE_TYPE (&value)) {
136       case G_TYPE_STRING:      // String
137       {
138         GParamSpecString *pstring = G_PARAM_SPEC_STRING (param);
139         if (readable) {         /* current */
140           const char *string_val = g_value_get_string (&value);
141           gchar work_string[100];
142
143           if (string_val == NULL)
144             sprintf (work_string, "\"%s\"", "null");
145           else
146             sprintf (work_string, "\"%s\"", string_val);
147           g_print ("%-*.*s", c3w, c3w, work_string);
148         } else {
149           g_print ("%-*s", c3w, "<not readable>");      /* alt current */
150         }
151         g_print (" | %-*s", c4w, "G_TYPE_STRING");      /* type */
152
153         if (pstring->default_value == NULL)
154           g_print (" | %s", "null");    /* default */
155         else
156           g_print (" | \"%s\"", pstring->default_value);        /* default */
157         break;
158       }
159
160       case G_TYPE_BOOLEAN:     //  Boolean
161       {
162         GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (param);
163         if (readable)           /* current */
164           g_print ("%-*s", c3w,
165               (g_value_get_boolean (&value) ? "true" : "false"));
166         else
167           g_print ("%-*s", c3w, "<not readable>");
168         g_print (" | %-*s", c4w, "G_TYPE_BOOLEAN");     /* type */
169         g_print (" | %s ",      /* default */
170             (pboolean->default_value ? "true" : "false"));
171         break;
172       }
173
174       case G_TYPE_ULONG:       //  Unsigned Long
175       {
176         GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
177         if (readable)           /* current */
178           g_print ("%-*lu", c3w, g_value_get_ulong (&value));
179         else
180           g_print ("%-*s", c3w, "<not readable>");
181         g_print (" | %-*s", c4w, "G_TYPE_ULONG");       /* type */
182         g_print (" | (%lu - %lu)   %lu ", pulong->minimum, pulong->maximum,     /* range */
183             pulong->default_value);     /* default */
184         break;
185       }
186
187       case G_TYPE_LONG:        //  Long
188       {
189         GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
190         if (readable)           /* current */
191           g_print ("%-*ld", c3w, g_value_get_long (&value));
192         else
193           g_print ("%-*s", c3w, "<not readable>");
194         g_print (" | %-*s", c4w, "G_TYPE_LONG");        /* type */
195         g_print (" | (%ld - %ld)   %ld ", plong->minimum, plong->maximum,       /* range */
196             plong->default_value);      /* default */
197         break;
198       }
199
200       case G_TYPE_UINT:        //  Unsigned Integer
201       {
202         GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
203         if (readable)           /* current */
204           g_print ("%-*u", c3w, g_value_get_uint (&value));
205         else
206           g_print ("%-*s", c3w, "<not readable>");
207         g_print (" | %-*s", c4w, "G_TYPE_UINT");        /* type */
208         g_print (" | (%u - %u)   %u ", puint->minimum, puint->maximum,  /* range */
209             puint->default_value);      /* default */
210         break;
211       }
212
213       case G_TYPE_INT:         //  Integer
214       {
215         GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
216         if (readable)           /* current */
217           g_print ("%-*d", c3w, g_value_get_int (&value));
218         else
219           g_print ("%-*s", c3w, "<not readable>");
220         g_print (" | %-*s", c4w, "G_TYPE_INT"); /* type */
221         g_print (" | (%d - %d)   %d ", pint->minimum, pint->maximum,    /* range */
222             pint->default_value);       /* default */
223         break;
224       }
225
226       case G_TYPE_UINT64:      //  Unsigned Integer64.
227       {
228         GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
229         if (readable)           /* current */
230           g_print ("%-*" G_GUINT64_FORMAT, c3w, g_value_get_uint64 (&value));
231         else
232           g_print ("%-*s", c3w, "<not readable>");
233         g_print (" | %-*s", c4w, "G_TYPE_UINT64");      /* type */
234         g_print (" | (%" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT ")" "   %" G_GUINT64_FORMAT " ", puint64->minimum, puint64->maximum,  /* range */
235             puint64->default_value);    /* default */
236         break;
237       }
238
239       case G_TYPE_INT64:       // Integer64
240       {
241         GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
242         if (readable)           /* current */
243           g_print ("%-*" G_GINT64_FORMAT, c3w, g_value_get_int64 (&value));
244         else
245           g_print ("%-*s", c3w, "<not readable>");
246         g_print (" | %-*s", c4w, "G_TYPE_INT64");       /* type */
247         g_print (" | (%" G_GINT64_FORMAT " - %" G_GINT64_FORMAT ")" "   %" G_GINT64_FORMAT " ", pint64->minimum, pint64->maximum,       /* range */
248             pint64->default_value);     /* default */
249         break;
250       }
251
252       case G_TYPE_FLOAT:       //  Float.
253       {
254         GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
255         if (readable)           /* current */
256           g_print ("%-*g", c3w, g_value_get_float (&value));
257         else
258           g_print ("%-*s", c3w, "<not readable>");
259         g_print (" | %-*s", c4w, "G_TYPE_FLOAT");       /* type */
260         g_print (" | (%g - %g)   %g ", pfloat->minimum, pfloat->maximum,        /* range */
261             pfloat->default_value);     /* default */
262         break;
263       }
264
265       case G_TYPE_DOUBLE:      //  Double
266       {
267         GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
268         if (readable)           /* current */
269           g_print ("%-*g", c3w, g_value_get_double (&value));
270         else
271           g_print ("%-*s", c3w, "<not readable>");
272         g_print (" | %-*s", c4w, "G_TYPE_DOUBLE");      /* type */
273         g_print (" | (%g - %g)   %g ", pdouble->minimum, pdouble->maximum,      /* range */
274             pdouble->default_value);    /* default */
275         break;
276       }
277
278       default:
279         if (param->value_type == GST_TYPE_CAPS) {
280           const GstCaps *caps = gst_value_get_caps (&value);
281           if (!caps)
282             g_print ("%-*s | %-*.*s |", c3w, "Caps (NULL)", c4w, c4w, " ");
283           else {
284             gchar prefix_string[100];
285             sprintf (prefix_string, "    | %-*.*s | ", c2w, c2w, " ");
286             print_caps (caps, prefix_string);
287           }
288         }
289
290         else if (G_IS_PARAM_SPEC_ENUM (param)) {
291           GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (param);
292           GEnumValue *values;
293           guint j = 0;
294           gint enum_value;
295           const gchar *def_val_nick = "", *cur_val_nick = "";
296           gchar work_string[100];
297
298           values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
299           enum_value = g_value_get_enum (&value);
300
301           while (values[j].value_name) {
302             if (values[j].value == enum_value)
303               cur_val_nick = values[j].value_nick;
304             if (values[j].value == penum->default_value)
305               def_val_nick = values[j].value_nick;
306             j++;
307           }
308
309           sprintf (work_string, "%d, \"%s\"", enum_value, cur_val_nick);
310           g_print ("%-*.*s", c3w, c3w, work_string);
311           g_print (" | Enum \"%s\" : %d, \"%s\"",
312               g_type_name (G_VALUE_TYPE (&value)),
313               penum->default_value, def_val_nick);
314         }
315
316         else if (G_IS_PARAM_SPEC_FLAGS (param)) {
317           GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (param);
318           GFlagsValue *vals;
319           gchar *cur, *def;
320           gchar work_string[100];
321
322           vals = pflags->flags_class->values;
323           cur = flags_to_string (vals, g_value_get_flags (&value));     /* current */
324           def = flags_to_string (vals, pflags->default_value);  /* default */
325
326           /* current */
327           sprintf (work_string, "0x%08x, \"%s\"",
328               g_value_get_flags (&value), cur);
329           g_print ("%-*.*s", c3w, c3w, work_string);
330
331           /* type */
332           sprintf (work_string, "Flags \"%s\"",
333               g_type_name (G_VALUE_TYPE (&value)));
334           g_print ("%-*.*s", c4w, c4w, work_string);
335
336           /* default */
337           g_print (" | 0x%08x, \"%s\"", pflags->default_value, def);
338
339           /* values list */
340           while (vals[0].value_name) {
341             sprintf (work_string, "\n    | %-*.*s |   (0x%08x): %-16s - %s",
342                 c2w, c2w, "",
343                 vals[0].value, vals[0].value_nick, vals[0].value_name);
344             g_print ("%s", work_string);
345             ++vals;
346           }
347
348           g_free (cur);
349           g_free (def);
350         }
351
352         else if (G_IS_PARAM_SPEC_OBJECT (param)) {
353           g_print ("%-*.*s | Object of type \"%s\"",
354               c3w, c3w,
355               g_type_name (param->value_type), g_type_name (param->value_type));
356         }
357
358         else if (G_IS_PARAM_SPEC_BOXED (param)) {
359           g_print ("%-*.*s | Boxed pointer of type \"%s\"",
360               c3w, c3w,
361               g_type_name (param->value_type), g_type_name (param->value_type));
362         }
363
364         else if (G_IS_PARAM_SPEC_POINTER (param)) {
365           if (param->value_type != G_TYPE_POINTER) {
366             g_print ("%-*.*s | Pointer of type \"%s\"",
367                 c3w, c3w,
368                 g_type_name (param->value_type),
369                 g_type_name (param->value_type));
370           } else {
371             g_print ("%-*.*s |", c3w, c3w, "Pointer.");
372           }
373         }
374
375         else if (param->value_type == G_TYPE_VALUE_ARRAY) {
376           GParamSpecValueArray *pvarray = G_PARAM_SPEC_VALUE_ARRAY (param);
377           if (pvarray->element_spec) {
378             g_print ("%-*.*s :Array of GValues of type \"%s\"",
379                 c3w, c3w,
380                 g_type_name (pvarray->element_spec->value_type),
381                 g_type_name (pvarray->element_spec->value_type));
382           } else {
383             g_print ("%-*.*s :", c3w, c3w, "Array of GValues");
384           }
385         }
386
387         else if (GST_IS_PARAM_SPEC_FRACTION (param)) {
388           GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (param);
389           gchar work_string[100];
390
391           if (readable) {       /* current */
392             sprintf (work_string, "%d/%d",
393                 gst_value_get_fraction_numerator (&value),
394                 gst_value_get_fraction_denominator (&value));
395             g_print ("%-*.*s", c3w, c3w, work_string);
396           } else
397             g_print ("%-*s", c3w, "<not readable>");
398
399           g_print (" | %-*.*s", /* type */
400               c3w, c3w, " Fraction. ");
401           g_print (" | (%d/%d - %d/%d)",        /* range */
402               pfraction->min_num, pfraction->min_den,
403               pfraction->max_num, pfraction->max_den);
404           g_print ("   %d/%d ", /* default */
405               pfraction->def_num, pfraction->def_den);
406         }
407
408         else if (GST_IS_PARAM_SPEC_MINI_OBJECT (param)) {
409           g_print ("%-*.*s | MiniObject of type \"%s\"",
410               c3w, c3w,
411               g_type_name (param->value_type), g_type_name (param->value_type));
412         }
413
414         else {
415           g_print ("Unknown type %ld \"%s\"",
416               (glong) param->value_type, g_type_name (param->value_type));
417
418         }
419         break;
420     }
421
422     if (!readable)
423       g_print (" Write only\n");
424     else
425       g_print ("\n");
426
427     g_value_reset (&value);
428   }
429
430   if (0 == num_properties)
431     g_print ("  none\n");
432
433   g_free (property_specs);
434 }
435
436 //------------------------------------------------------------------------------
437 void
438 print_column_titles (guint c2w, guint c3w, guint c4w)
439 {
440   //////////////////////////////////////////////////////////////////////////
441   //
442   // Create Header for property listing
443   // RWF | --- element name ---- | ---------c3-------- | -----------c4---------- | --> unspecified
444   //
445   //////////////////////////////////////////////////////////////////////////
446   gchar work_string[200];
447   gchar dashes[] = "-----------------------------";
448   gint llen = 0;
449   gint rlen = 0;
450
451       /*--- column 1 - RWC ---*/
452   sprintf (work_string, "<-->|<");
453
454       /*--- column 2 - property name ---*/
455   llen = (c2w - 15) / 2;        /* width of " property name " = 15 */
456   rlen = c2w - 15 - llen;
457
458   strncat (work_string, dashes, llen);
459   strcat (work_string, " property name ");
460   strncat (work_string, dashes, rlen);
461   strcat (work_string, ">|<");
462
463       /*--- column 3 - current value ---*/
464   llen = (c3w - 15) / 2;        /* width of " current value " = 15 */
465   rlen = c3w - 15 - llen;
466
467   strncat (work_string, dashes, llen);
468   strcat (work_string, " current value ");
469   strncat (work_string, dashes, rlen);
470   strcat (work_string, ">|<");
471
472       /*--- column 4 - type ---*/
473   llen = (c4w - 6) / 2;         /* width of " type " = 6 */
474   rlen = c4w - 6 - llen;
475
476   strncat (work_string, dashes, llen);
477   strcat (work_string, " type ");
478   strncat (work_string, dashes, rlen);
479   strcat (work_string, ">|<");
480
481       /*--- column 5 - range and default ---*/
482   strcat (work_string, "----- range and default ----->");
483
484   g_print ("\n%s\n", work_string);
485 }
486
487 //------------------------------------------------------------------------------
488 void
489 print_element_info (GstElement * element, guint c2w, guint c3w, guint c4w)
490 {
491   /////////////////////////////////////////////////////////////////////////////
492   //
493   // Print element factory and class information as part of each header
494   //
495   /////////////////////////////////////////////////////////////////////////////
496   gchar work_string[100];
497   GstElementFactory *factory = gst_element_get_factory (element);
498
499   sprintf (work_string, "ELEMENT CLASS NAME");
500   g_print ("    | %-*s", c2w, work_string);
501   g_print (" | %-*s", c3w, g_type_name (G_OBJECT_TYPE (element)));
502   g_print (" | %-*s | \n", c4w, "");
503
504
505   sprintf (work_string, "ELEMENT FACTORY NAME");
506   g_print ("    | %-*s", c2w, work_string);
507
508   g_print (" | %-*s", c3w,
509       gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
510   g_print (" | %-*s | \n", c4w, gst_element_factory_get_longname (factory));
511
512 // "Audio Resampler"   g_print( " | %-*s",      c3w, gst_element_factory_get_longname( gst_element_get_factory( element )) );
513
514
515 }
516
517 //------------------------------------------------------------------------------
518 gchar *
519 flags_to_string (GFlagsValue * vals, guint flags)
520 {
521   /////////////////////////////////////////////////////////////////////////////
522   //
523   // List individual flags in separate rows
524   //
525   /////////////////////////////////////////////////////////////////////////////
526   GString *s = NULL;
527   guint flags_left, i;
528
529   /* first look for an exact match and count the number of values */
530   for (i = 0; vals[i].value_name != NULL; ++i) {
531     if (vals[i].value == flags)
532       return g_strdup (vals[i].value_nick);
533   }
534
535   s = g_string_new (NULL);
536
537   /* we assume the values are sorted from lowest to highest value */
538   flags_left = flags;
539   while (i > 0) {
540     --i;
541     if (0 != vals[i].value && (flags_left & vals[i].value) == vals[i].value) {
542       if (0 < s->len)
543         g_string_append (s, " | ");
544       g_string_append (s, vals[i].value_nick);
545       flags_left -= vals[i].value;
546       if (0 == flags_left)
547         break;
548     }
549   }
550
551   if (0 == s->len)
552     g_string_assign (s, "(none)");
553
554   return g_string_free (s, FALSE);
555 }
556
557
558 //------------------------------------------------------------------------------
559 void
560 print_caps (const GstCaps * caps, const gchar * pfx)
561 {
562   /////////////////////////////////////////////////////////////////////////////
563   //
564   // Print each caps value on a separate line
565   //
566   /////////////////////////////////////////////////////////////////////////////
567   guint i;
568
569   g_return_if_fail (caps != NULL);
570
571   if (gst_caps_is_any (caps)) {
572     g_print ("%s | %s", pfx, "ANY                 |                     |");
573     return;
574   }
575   if (gst_caps_is_empty (caps)) {
576     g_print ("%s | %s", pfx, "EMPTY               |                     |");
577     return;
578   }
579
580   for (i = 0; i < gst_caps_get_size (caps); i++) {
581     GstStructure *structure = gst_caps_get_structure (caps, i);
582     g_print ("%s", gst_structure_get_name (structure));
583     gst_structure_foreach (structure, print_field, (gpointer) pfx);
584   }
585 }
586
587 //------------------------------------------------------------------------------
588 gboolean
589 print_field (GQuark field, const GValue * value, gpointer pfx)
590 {
591   /////////////////////////////////////////////////////////////////////////////
592   //
593   // printing function for individual caps fields
594   //
595   /////////////////////////////////////////////////////////////////////////////
596   gchar *str = gst_value_serialize (value);
597   g_print ("\n%s  %-15.15s - %s",
598       (gchar *) pfx, g_quark_to_string (field), str);
599   g_free (str);
600   return TRUE;
601 }