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;
95 g_return_if_fail (element != NULL);
97 property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element),
100 /*--- draw the header information ---*/
101 print_column_titles (c2w, c3w, c4w);
102 print_element_info (element, c2w, c3w, c4w);
105 for (i = 0; i < num_properties; i++) {
107 GValue value = { 0, };
108 GParamSpec *param = property_specs[i];
113 g_value_init (&value, param->value_type);
120 if (param->flags & G_PARAM_READABLE) {
121 g_object_get_property (G_OBJECT (element), param->name, &value);
126 if (param->flags & G_PARAM_WRITABLE)
129 if (param->flags & GST_PARAM_CONTROLLABLE)
132 g_print ("%s |", flags);
133 g_print (" %-*s | ", c2w, g_param_spec_get_name (param));
135 switch (G_VALUE_TYPE (&value)) {
136 case G_TYPE_STRING: // String
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];
143 if (string_val == NULL)
144 sprintf (work_string, "\"%s\"", "null");
146 sprintf (work_string, "\"%s\"", string_val);
147 g_print ("%-*.*s", c3w, c3w, work_string);
149 g_print ("%-*s", c3w, "<not readable>"); /* alt current */
151 g_print (" | %-*s", c4w, "G_TYPE_STRING"); /* type */
153 if (pstring->default_value == NULL)
154 g_print (" | %s", "null"); /* default */
156 g_print (" | \"%s\"", pstring->default_value); /* default */
160 case G_TYPE_BOOLEAN: // Boolean
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"));
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"));
174 case G_TYPE_ULONG: // Unsigned Long
176 GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (param);
177 if (readable) /* current */
178 g_print ("%-*lu", c3w, g_value_get_ulong (&value));
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 */
187 case G_TYPE_LONG: // Long
189 GParamSpecLong *plong = G_PARAM_SPEC_LONG (param);
190 if (readable) /* current */
191 g_print ("%-*ld", c3w, g_value_get_long (&value));
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 */
200 case G_TYPE_UINT: // Unsigned Integer
202 GParamSpecUInt *puint = G_PARAM_SPEC_UINT (param);
203 if (readable) /* current */
204 g_print ("%-*u", c3w, g_value_get_uint (&value));
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 */
213 case G_TYPE_INT: // Integer
215 GParamSpecInt *pint = G_PARAM_SPEC_INT (param);
216 if (readable) /* current */
217 g_print ("%-*d", c3w, g_value_get_int (&value));
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 */
226 case G_TYPE_UINT64: // Unsigned Integer64.
228 GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (param);
229 if (readable) /* current */
230 g_print ("%-*" G_GUINT64_FORMAT, c3w, g_value_get_uint64 (&value));
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 */
239 case G_TYPE_INT64: // Integer64
241 GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (param);
242 if (readable) /* current */
243 g_print ("%-*" G_GINT64_FORMAT, c3w, g_value_get_int64 (&value));
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 */
252 case G_TYPE_FLOAT: // Float.
254 GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (param);
255 if (readable) /* current */
256 g_print ("%-*g", c3w, g_value_get_float (&value));
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 */
265 case G_TYPE_DOUBLE: // Double
267 GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (param);
268 if (readable) /* current */
269 g_print ("%-*g", c3w, g_value_get_double (&value));
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 */
279 if (param->value_type == GST_TYPE_CAPS) {
280 const GstCaps *caps = gst_value_get_caps (&value);
282 g_print ("%-*s | %-*.*s |", c3w, "Caps (NULL)", c4w, c4w, " ");
284 gchar prefix_string[100];
285 sprintf (prefix_string, " | %-*.*s | ", c2w, c2w, " ");
286 print_caps (caps, prefix_string);
290 else if (G_IS_PARAM_SPEC_ENUM (param)) {
291 GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (param);
295 const gchar *def_val_nick = "", *cur_val_nick = "";
296 gchar work_string[100];
298 values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
299 enum_value = g_value_get_enum (&value);
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;
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);
316 else if (G_IS_PARAM_SPEC_FLAGS (param)) {
317 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (param);
320 gchar work_string[100];
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 */
327 sprintf (work_string, "0x%08x, \"%s\"",
328 g_value_get_flags (&value), cur);
329 g_print ("%-*.*s", c3w, c3w, work_string);
332 sprintf (work_string, "Flags \"%s\"",
333 g_type_name (G_VALUE_TYPE (&value)));
334 g_print ("%-*.*s", c4w, c4w, work_string);
337 g_print (" | 0x%08x, \"%s\"", pflags->default_value, def);
340 while (vals[0].value_name) {
341 sprintf (work_string, "\n | %-*.*s | (0x%08x): %-16s - %s",
343 vals[0].value, vals[0].value_nick, vals[0].value_name);
344 g_print ("%s", work_string);
352 else if (G_IS_PARAM_SPEC_OBJECT (param)) {
353 g_print ("%-*.*s | Object of type \"%s\"",
355 g_type_name (param->value_type), g_type_name (param->value_type));
358 else if (G_IS_PARAM_SPEC_BOXED (param)) {
359 g_print ("%-*.*s | Boxed pointer of type \"%s\"",
361 g_type_name (param->value_type), g_type_name (param->value_type));
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\"",
368 g_type_name (param->value_type),
369 g_type_name (param->value_type));
371 g_print ("%-*.*s |", c3w, c3w, "Pointer.");
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\"",
380 g_type_name (pvarray->element_spec->value_type),
381 g_type_name (pvarray->element_spec->value_type));
383 g_print ("%-*.*s :", c3w, c3w, "Array of GValues");
387 else if (GST_IS_PARAM_SPEC_FRACTION (param)) {
388 GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (param);
389 gchar work_string[100];
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);
397 g_print ("%-*s", c3w, "<not readable>");
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);
408 else if (GST_IS_PARAM_SPEC_MINI_OBJECT (param)) {
409 g_print ("%-*.*s | MiniObject of type \"%s\"",
411 g_type_name (param->value_type), g_type_name (param->value_type));
415 g_print ("Unknown type %ld \"%s\"",
416 (glong) param->value_type, g_type_name (param->value_type));
423 g_print (" Write only\n");
427 g_value_reset (&value);
430 if (0 == num_properties)
433 g_free (property_specs);
436 //------------------------------------------------------------------------------
438 print_column_titles (guint c2w, guint c3w, guint c4w)
440 //////////////////////////////////////////////////////////////////////////
442 // Create Header for property listing
443 // RWF | --- element name ---- | ---------c3-------- | -----------c4---------- | --> unspecified
445 //////////////////////////////////////////////////////////////////////////
446 gchar work_string[200];
447 gchar dashes[] = "-----------------------------";
451 /*--- column 1 - RWC ---*/
452 sprintf (work_string, "<-->|<");
454 /*--- column 2 - property name ---*/
455 llen = (c2w - 15) / 2; /* width of " property name " = 15 */
456 rlen = c2w - 15 - llen;
458 strncat (work_string, dashes, llen);
459 strcat (work_string, " property name ");
460 strncat (work_string, dashes, rlen);
461 strcat (work_string, ">|<");
463 /*--- column 3 - current value ---*/
464 llen = (c3w - 15) / 2; /* width of " current value " = 15 */
465 rlen = c3w - 15 - llen;
467 strncat (work_string, dashes, llen);
468 strcat (work_string, " current value ");
469 strncat (work_string, dashes, rlen);
470 strcat (work_string, ">|<");
472 /*--- column 4 - type ---*/
473 llen = (c4w - 6) / 2; /* width of " type " = 6 */
474 rlen = c4w - 6 - llen;
476 strncat (work_string, dashes, llen);
477 strcat (work_string, " type ");
478 strncat (work_string, dashes, rlen);
479 strcat (work_string, ">|<");
481 /*--- column 5 - range and default ---*/
482 strcat (work_string, "----- range and default ----->");
484 g_print ("\n%s\n", work_string);
487 //------------------------------------------------------------------------------
489 print_element_info (GstElement * element, guint c2w, guint c3w, guint c4w)
491 /////////////////////////////////////////////////////////////////////////////
493 // Print element factory and class information as part of each header
495 /////////////////////////////////////////////////////////////////////////////
496 gchar work_string[100];
497 GstElementFactory *factory = gst_element_get_factory (element);
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, "");
505 sprintf (work_string, "ELEMENT FACTORY NAME");
506 g_print (" | %-*s", c2w, work_string);
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));
512 // "Audio Resampler" g_print( " | %-*s", c3w, gst_element_factory_get_longname( gst_element_get_factory( element )) );
517 //------------------------------------------------------------------------------
519 flags_to_string (GFlagsValue * vals, guint flags)
521 /////////////////////////////////////////////////////////////////////////////
523 // List individual flags in separate rows
525 /////////////////////////////////////////////////////////////////////////////
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);
535 s = g_string_new (NULL);
537 /* we assume the values are sorted from lowest to highest value */
541 if (0 != vals[i].value && (flags_left & vals[i].value) == vals[i].value) {
543 g_string_append (s, " | ");
544 g_string_append (s, vals[i].value_nick);
545 flags_left -= vals[i].value;
552 g_string_assign (s, "(none)");
554 return g_string_free (s, FALSE);
558 //------------------------------------------------------------------------------
560 print_caps (const GstCaps * caps, const gchar * pfx)
562 /////////////////////////////////////////////////////////////////////////////
564 // Print each caps value on a separate line
566 /////////////////////////////////////////////////////////////////////////////
569 g_return_if_fail (caps != NULL);
571 if (gst_caps_is_any (caps)) {
572 g_print ("%s | %s", pfx, "ANY | |");
575 if (gst_caps_is_empty (caps)) {
576 g_print ("%s | %s", pfx, "EMPTY | |");
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);
587 //------------------------------------------------------------------------------
589 print_field (GQuark field, const GValue * value, gpointer pfx)
591 /////////////////////////////////////////////////////////////////////////////
593 // printing function for individual caps fields
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);