2 * Copyright (C) 2010 Wesley Miller <wmiller@sdr.com>
5 * gst_element_print_properties(): a tool to inspect GStreamer
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.
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.
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/>.
29 #include "gst_element_print_properties.h"
33 gst_element_print_properties (GstElement * element)
35 /////////////////////////////////////////////////////////////////////////////
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.
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.
48 // Most properties use this format. Multivalued items like CAPS, certain
49 // GST_TYPEs and enums are different.
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"
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).
63 // String values are enclosed in double quotes. A missing right quote
64 // inidicates the string had been truncated.
67 // ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9--->
69 // formatted columns with built in gutters
70 // --- | ---------c2---------- | ---------c3-------- | -----------c4---------- | --> unspecified
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
79 /////////////////////////////////////////////////////////////////////////////
81 const guint c2w = 21; // column 2 width
82 const guint c3w = 19; // column 3 width
83 const guint c4w = 23; // column 4 width
85 /////////////////////////////////////////////////////////////////////////////
86 // end configuration variables.
87 /////////////////////////////////////////////////////////////////////////////
89 GParamSpec **property_specs;
90 guint num_properties, i;
94 g_return_if_fail (element != NULL);
96 property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element),
99 /*--- draw the header information ---*/
100 print_column_titles (c2w, c3w, c4w);
101 print_element_info (element, c2w, c3w, c4w);
104 for (i = 0; i < num_properties; i++) {
106 GValue value = { 0, };
107 GParamSpec *param = property_specs[i];
111 g_value_init (&value, param->value_type);
118 if (param->flags & G_PARAM_READABLE) {
119 g_object_get_property (G_OBJECT (element), param->name, &value);
124 if (param->flags & G_PARAM_WRITABLE)
127 if (param->flags & GST_PARAM_CONTROLLABLE)
130 g_print ("%s |", flags);
131 g_print (" %-*s | ", c2w, g_param_spec_get_name (param));
133 switch (G_VALUE_TYPE (&value)) {
134 case G_TYPE_STRING: // String
136 GParamSpecString *pstring = G_PARAM_SPEC_STRING (param);
137 if (readable) { /* current */
138 const char *string_val = g_value_get_string (&value);
139 gchar work_string[100];
141 if (string_val == NULL)
142 sprintf (work_string, "\"%s\"", "null");
144 sprintf (work_string, "\"%s\"", string_val);
145 g_print ("%-*.*s", c3w, c3w, work_string);
147 g_print ("%-*s", c3w, "<not readable>"); /* alt current */
149 g_print (" | %-*s", c4w, "G_TYPE_STRING"); /* type */
151 if (pstring->default_value == NULL)
152 g_print (" | %s", "null"); /* default */
154 g_print (" | \"%s\"", pstring->default_value); /* default */
158 case G_TYPE_BOOLEAN: // Boolean
160 GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (param);
161 if (readable) /* current */
162 g_print ("%-*s", c3w,
163 (g_value_get_boolean (&value) ? "true" : "false"));
165 g_print ("%-*s", c3w, "<not readable>");
166 g_print (" | %-*s", c4w, "G_TYPE_BOOLEAN"); /* type */
167 g_print (" | %s ", /* default */
168 (pboolean->default_value ? "true" : "false"));
172 case G_TYPE_ULONG: // Unsigned Long
174 GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
175 if (readable) /* current */
176 g_print ("%-*lu", c3w, g_value_get_ulong (&value));
178 g_print ("%-*s", c3w, "<not readable>");
179 g_print (" | %-*s", c4w, "G_TYPE_ULONG"); /* type */
180 g_print (" | (%lu - %lu) %lu ", pulong->minimum, pulong->maximum, /* range */
181 pulong->default_value); /* default */
185 case G_TYPE_LONG: // Long
187 GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
188 if (readable) /* current */
189 g_print ("%-*ld", c3w, g_value_get_long (&value));
191 g_print ("%-*s", c3w, "<not readable>");
192 g_print (" | %-*s", c4w, "G_TYPE_LONG"); /* type */
193 g_print (" | (%ld - %ld) %ld ", plong->minimum, plong->maximum, /* range */
194 plong->default_value); /* default */
198 case G_TYPE_UINT: // Unsigned Integer
200 GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
201 if (readable) /* current */
202 g_print ("%-*u", c3w, g_value_get_uint (&value));
204 g_print ("%-*s", c3w, "<not readable>");
205 g_print (" | %-*s", c4w, "G_TYPE_UINT"); /* type */
206 g_print (" | (%u - %u) %u ", puint->minimum, puint->maximum, /* range */
207 puint->default_value); /* default */
211 case G_TYPE_INT: // Integer
213 GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
214 if (readable) /* current */
215 g_print ("%-*d", c3w, g_value_get_int (&value));
217 g_print ("%-*s", c3w, "<not readable>");
218 g_print (" | %-*s", c4w, "G_TYPE_INT"); /* type */
219 g_print (" | (%d - %d) %d ", pint->minimum, pint->maximum, /* range */
220 pint->default_value); /* default */
224 case G_TYPE_UINT64: // Unsigned Integer64.
226 GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
227 if (readable) /* current */
228 g_print ("%-*" G_GUINT64_FORMAT, c3w, g_value_get_uint64 (&value));
230 g_print ("%-*s", c3w, "<not readable>");
231 g_print (" | %-*s", c4w, "G_TYPE_UINT64"); /* type */
232 g_print (" | (%" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT ")" " %" G_GUINT64_FORMAT " ", puint64->minimum, puint64->maximum, /* range */
233 puint64->default_value); /* default */
237 case G_TYPE_INT64: // Integer64
239 GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
240 if (readable) /* current */
241 g_print ("%-*" G_GINT64_FORMAT, c3w, g_value_get_int64 (&value));
243 g_print ("%-*s", c3w, "<not readable>");
244 g_print (" | %-*s", c4w, "G_TYPE_INT64"); /* type */
245 g_print (" | (%" G_GINT64_FORMAT " - %" G_GINT64_FORMAT ")" " %" G_GINT64_FORMAT " ", pint64->minimum, pint64->maximum, /* range */
246 pint64->default_value); /* default */
250 case G_TYPE_FLOAT: // Float.
252 GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
253 if (readable) /* current */
254 g_print ("%-*g", c3w, g_value_get_float (&value));
256 g_print ("%-*s", c3w, "<not readable>");
257 g_print (" | %-*s", c4w, "G_TYPE_FLOAT"); /* type */
258 g_print (" | (%g - %g) %g ", pfloat->minimum, pfloat->maximum, /* range */
259 pfloat->default_value); /* default */
263 case G_TYPE_DOUBLE: // Double
265 GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
266 if (readable) /* current */
267 g_print ("%-*g", c3w, g_value_get_double (&value));
269 g_print ("%-*s", c3w, "<not readable>");
270 g_print (" | %-*s", c4w, "G_TYPE_DOUBLE"); /* type */
271 g_print (" | (%g - %g) %g ", pdouble->minimum, pdouble->maximum, /* range */
272 pdouble->default_value); /* default */
277 if (param->value_type == GST_TYPE_CAPS) {
278 const GstCaps *caps = gst_value_get_caps (&value);
280 g_print ("%-*s | %-*.*s |", c3w, "Caps (NULL)", c4w, c4w, " ");
282 gchar prefix_string[100];
283 sprintf (prefix_string, " | %-*.*s | ", c2w, c2w, " ");
284 print_caps (caps, prefix_string);
288 else if (G_IS_PARAM_SPEC_ENUM (param)) {
289 GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (param);
293 const gchar *def_val_nick = "", *cur_val_nick = "";
294 gchar work_string[100];
296 values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
297 enum_value = g_value_get_enum (&value);
299 while (values[j].value_name) {
300 if (values[j].value == enum_value)
301 cur_val_nick = values[j].value_nick;
302 if (values[j].value == penum->default_value)
303 def_val_nick = values[j].value_nick;
307 sprintf (work_string, "%d, \"%s\"", enum_value, cur_val_nick);
308 g_print ("%-*.*s", c3w, c3w, work_string);
309 g_print (" | Enum \"%s\" : %d, \"%s\"",
310 g_type_name (G_VALUE_TYPE (&value)),
311 penum->default_value, def_val_nick);
314 else if (G_IS_PARAM_SPEC_FLAGS (param)) {
315 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (param);
318 gchar work_string[100];
320 vals = pflags->flags_class->values;
321 cur = flags_to_string (vals, g_value_get_flags (&value)); /* current */
322 def = flags_to_string (vals, pflags->default_value); /* default */
325 sprintf (work_string, "0x%08x, \"%s\"",
326 g_value_get_flags (&value), cur);
327 g_print ("%-*.*s", c3w, c3w, work_string);
330 sprintf (work_string, "Flags \"%s\"",
331 g_type_name (G_VALUE_TYPE (&value)));
332 g_print ("%-*.*s", c4w, c4w, work_string);
335 g_print (" | 0x%08x, \"%s\"", pflags->default_value, def);
338 while (vals[0].value_name) {
339 sprintf (work_string, "\n | %-*.*s | (0x%08x): %-16s - %s",
341 vals[0].value, vals[0].value_nick, vals[0].value_name);
342 g_print ("%s", work_string);
350 else if (G_IS_PARAM_SPEC_OBJECT (param)) {
351 g_print ("%-*.*s | Object of type \"%s\"",
353 g_type_name (param->value_type), g_type_name (param->value_type));
356 else if (G_IS_PARAM_SPEC_BOXED (param)) {
357 g_print ("%-*.*s | Boxed pointer of type \"%s\"",
359 g_type_name (param->value_type), g_type_name (param->value_type));
362 else if (G_IS_PARAM_SPEC_POINTER (param)) {
363 if (param->value_type != G_TYPE_POINTER) {
364 g_print ("%-*.*s | Pointer of type \"%s\"",
366 g_type_name (param->value_type),
367 g_type_name (param->value_type));
369 g_print ("%-*.*s |", c3w, c3w, "Pointer.");
373 else if (param->value_type == G_TYPE_VALUE_ARRAY) {
374 GParamSpecValueArray *pvarray = G_PARAM_SPEC_VALUE_ARRAY (param);
375 if (pvarray->element_spec) {
376 g_print ("%-*.*s :Array of GValues of type \"%s\"",
378 g_type_name (pvarray->element_spec->value_type),
379 g_type_name (pvarray->element_spec->value_type));
381 g_print ("%-*.*s :", c3w, c3w, "Array of GValues");
385 else if (GST_IS_PARAM_SPEC_FRACTION (param)) {
386 GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (param);
387 gchar work_string[100];
389 if (readable) { /* current */
390 sprintf (work_string, "%d/%d",
391 gst_value_get_fraction_numerator (&value),
392 gst_value_get_fraction_denominator (&value));
393 g_print ("%-*.*s", c3w, c3w, work_string);
395 g_print ("%-*s", c3w, "<not readable>");
397 g_print (" | %-*.*s", /* type */
398 c3w, c3w, " Fraction. ");
399 g_print (" | (%d/%d - %d/%d)", /* range */
400 pfraction->min_num, pfraction->min_den,
401 pfraction->max_num, pfraction->max_den);
402 g_print (" %d/%d ", /* default */
403 pfraction->def_num, pfraction->def_den);
406 else if (GST_IS_PARAM_SPEC_MINI_OBJECT (param)) {
407 g_print ("%-*.*s | MiniObject of type \"%s\"",
409 g_type_name (param->value_type), g_type_name (param->value_type));
413 g_print ("Unknown type %ld \"%s\"",
414 (glong) param->value_type, g_type_name (param->value_type));
421 g_print (" Write only\n");
425 g_value_reset (&value);
428 if (0 == num_properties)
431 g_free (property_specs);
434 //------------------------------------------------------------------------------
436 print_column_titles (guint c2w, guint c3w, guint c4w)
438 //////////////////////////////////////////////////////////////////////////
440 // Create Header for property listing
441 // RWF | --- element name ---- | ---------c3-------- | -----------c4---------- | --> unspecified
443 //////////////////////////////////////////////////////////////////////////
444 gchar work_string[200];
445 gchar dashes[] = "-----------------------------";
449 /*--- column 1 - RWC ---*/
450 sprintf (work_string, "<-->|<");
452 /*--- column 2 - property name ---*/
453 llen = (c2w - 15) / 2; /* width of " property name " = 15 */
454 rlen = c2w - 15 - llen;
456 strncat (work_string, dashes, llen);
457 strcat (work_string, " property name ");
458 strncat (work_string, dashes, rlen);
459 strcat (work_string, ">|<");
461 /*--- column 3 - current value ---*/
462 llen = (c3w - 15) / 2; /* width of " current value " = 15 */
463 rlen = c3w - 15 - llen;
465 strncat (work_string, dashes, llen);
466 strcat (work_string, " current value ");
467 strncat (work_string, dashes, rlen);
468 strcat (work_string, ">|<");
470 /*--- column 4 - type ---*/
471 llen = (c4w - 6) / 2; /* width of " type " = 6 */
472 rlen = c4w - 6 - llen;
474 strncat (work_string, dashes, llen);
475 strcat (work_string, " type ");
476 strncat (work_string, dashes, rlen);
477 strcat (work_string, ">|<");
479 /*--- column 5 - range and default ---*/
480 strcat (work_string, "----- range and default ----->");
482 g_print ("\n%s\n", work_string);
485 //------------------------------------------------------------------------------
487 print_element_info (GstElement * element, guint c2w, guint c3w, guint c4w)
489 /////////////////////////////////////////////////////////////////////////////
491 // Print element factory and class information as part of each header
493 /////////////////////////////////////////////////////////////////////////////
494 gchar work_string[100];
495 GstElementFactory *factory = gst_element_get_factory (element);
497 sprintf (work_string, "ELEMENT CLASS NAME");
498 g_print (" | %-*s", c2w, work_string);
499 g_print (" | %-*s", c3w, g_type_name (G_OBJECT_TYPE (element)));
500 g_print (" | %-*s | \n", c4w, "");
503 sprintf (work_string, "ELEMENT FACTORY NAME");
504 g_print (" | %-*s", c2w, work_string);
506 g_print (" | %-*s", c3w,
507 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
508 g_print (" | %-*s | \n", c4w, gst_element_factory_get_longname (factory));
510 // "Audio Resampler" g_print( " | %-*s", c3w, gst_element_factory_get_longname( gst_element_get_factory( element )) );
515 //------------------------------------------------------------------------------
517 flags_to_string (GFlagsValue * vals, guint flags)
519 /////////////////////////////////////////////////////////////////////////////
521 // List individual flags in separate rows
523 /////////////////////////////////////////////////////////////////////////////
527 /* first look for an exact match and count the number of values */
528 for (i = 0; vals[i].value_name != NULL; ++i) {
529 if (vals[i].value == flags)
530 return g_strdup (vals[i].value_nick);
533 s = g_string_new (NULL);
535 /* we assume the values are sorted from lowest to highest value */
539 if (0 != vals[i].value && (flags_left & vals[i].value) == vals[i].value) {
541 g_string_append (s, " | ");
542 g_string_append (s, vals[i].value_nick);
543 flags_left -= vals[i].value;
550 g_string_assign (s, "(none)");
552 return g_string_free (s, FALSE);
556 //------------------------------------------------------------------------------
558 print_caps (const GstCaps * caps, const gchar * pfx)
560 /////////////////////////////////////////////////////////////////////////////
562 // Print each caps value on a separate line
564 /////////////////////////////////////////////////////////////////////////////
567 g_return_if_fail (caps != NULL);
569 if (gst_caps_is_any (caps)) {
570 g_print ("%s | %s", pfx, "ANY | |");
573 if (gst_caps_is_empty (caps)) {
574 g_print ("%s | %s", pfx, "EMPTY | |");
578 for (i = 0; i < gst_caps_get_size (caps); i++) {
579 GstStructure *structure = gst_caps_get_structure (caps, i);
580 g_print ("%s", gst_structure_get_name (structure));
581 gst_structure_foreach (structure, print_field, (gpointer) pfx);
585 //------------------------------------------------------------------------------
587 print_field (GQuark field, const GValue * value, gpointer pfx)
589 /////////////////////////////////////////////////////////////////////////////
591 // printing function for individual caps fields
593 /////////////////////////////////////////////////////////////////////////////
594 gchar *str = gst_value_serialize (value);
595 g_print ("\n%s %-15.15s - %s",
596 (gchar *) pfx, g_quark_to_string (field), str);