8 #include <glib/gprintf.h>
11 #include <glib/gi18n.h>
13 static GRegex *cleanup_caps_field = NULL;
14 static void _add_object_details (GString * json, GString * other_types,
15 GHashTable * seen_other_types, GObject * object, GType gtype,
19 json_strescape (const gchar * str)
27 return g_strdup ("NULL");
31 output = g_string_sized_new (len);
33 for (p = str; p < end; p++) {
34 if (*p == '\\' || *p == '"') {
35 g_string_append_c (output, '\\');
36 g_string_append_c (output, *p);
37 } else if (*p == '%') {
38 g_string_append_c (output, '%');
39 g_string_append_c (output, *p);
40 } else if ((*p > 0 && *p < 0x1f) || *p == 0x7f) {
43 g_string_append (output, "\\b");
46 g_string_append (output, "\\f");
49 g_string_append (output, "\\n");
52 g_string_append (output, "\\r");
55 g_string_append (output, "\\t");
58 g_string_append_printf (output, "\\u00%02x", (guint) * p);
62 g_string_append_c (output, *p);
66 return g_string_free (output, FALSE);
70 flags_to_string (GFlagsValue * values, guint flags)
75 /* first look for an exact match and count the number of values */
76 for (i = 0; values[i].value_name != NULL; ++i) {
77 if (values[i].value == flags)
78 return g_strdup (values[i].value_nick);
81 s = g_string_new (NULL);
83 /* we assume the values are sorted from lowest to highest value */
87 if (values[i].value != 0
88 && (flags_left & values[i].value) == values[i].value) {
90 g_string_append_c (s, '+');
91 g_string_append (s, values[i].value_nick);
92 flags_left -= values[i].value;
99 g_string_assign (s, "(none)");
101 return g_string_free (s, FALSE);
105 _serialize_flags_default (GString * json, GType gtype, GValue * value)
107 GFlagsValue *values = G_FLAGS_CLASS (g_type_class_ref (gtype))->values;
110 cur = flags_to_string (values, g_value_get_flags (value));
111 g_string_append_printf (json, ",\"default\": \"%s\"", cur);
116 _serialize_flags (GString * json, GType gtype)
118 GFlagsValue *values = G_FLAGS_CLASS (g_type_class_ref (gtype))->values;
120 g_string_append_printf (json, "%s\"%s\": { "
121 "\"kind\": \"flags\"," "\"values\": [", json->len ? "," : "",
122 g_type_name (gtype));
124 while (values[0].value_name) {
125 gchar *value_name = json_strescape (values[0].value_name);
126 gchar *value_nick = json_strescape (values[0].value_nick);
128 g_string_append_printf (json, "{\"name\": \"%s\","
129 "\"value\": \"0x%08x\","
130 "\"desc\": \"%s\"}", value_nick, values[0].value, value_name);
133 if (values[0].value_name)
134 g_string_append_c (json, ',');
140 g_string_append (json, "]}");
144 _serialize_enum_default (GString * json, GType gtype, GValue * value)
149 gchar *value_nick = g_strdup ("");
151 values = G_ENUM_CLASS (g_type_class_ref (gtype))->values;
153 enum_value = g_value_get_enum (value);
154 while (values[j].value_name) {
155 if (values[j].value == enum_value) {
157 value_nick = json_strescape (values[j].value_nick);
163 g_string_append_printf (json, ",\"default\": \"%s (%d)\"", value_nick,
169 _serialize_enum (GString * json, GType gtype, GstPluginAPIFlags api_flags)
174 values = G_ENUM_CLASS (g_type_class_ref (gtype))->values;
176 g_string_append_printf (json, "%s\"%s\": { "
177 "\"kind\": \"enum\"", json->len ? "," : "", g_type_name (gtype));
179 if (api_flags & GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS) {
180 g_string_append (json, ",\"ignore-enum-members\": true}");
182 g_string_append (json, ",\"values\": [");
184 while (values[j].value_name) {
185 gchar *value_name = json_strescape (values[j].value_name);
186 gchar *value_nick = json_strescape (values[j].value_nick);
188 g_string_append_printf (json, "{\"name\": \"%s\","
190 "\"desc\": \"%s\"}", value_nick, values[j].value, value_name);
192 if (values[j].value_name)
193 g_string_append_c (json, ',');
199 g_string_append (json, "]}");
203 /* @inst_type is used when serializing base classes in the hierarchy:
204 * we don't instantiate the base class, which may very well be abstract,
205 * but instantiate the final type (@inst_type), and use @type to determine
206 * what properties / signals / etc.. we are actually interested in.
209 _serialize_object (GString * json, GHashTable * seen_other_types, GType gtype,
213 GString *other_types = NULL;
215 g_string_append_printf (json, "%s\"%s\": { "
216 "\"kind\": \"%s\"", json->len ? "," : "", g_type_name (gtype),
217 G_TYPE_IS_INTERFACE (gtype) ? "interface" : "object");
219 other_types = g_string_new ("");
220 g_string_append_c (json, ',');
221 tmpobj = g_object_new (inst_type, NULL);
222 _add_object_details (json, other_types, seen_other_types, tmpobj, gtype,
224 gst_object_unref (tmpobj);
226 g_string_append_c (json, '}');
228 if (other_types && other_types->len) {
229 g_string_append_printf (json, ",%s", other_types->str);
231 g_string_free (other_types, TRUE);
235 _add_signals (GString * json, GString * other_types,
236 GHashTable * seen_other_types, GObject * object, GType type)
238 gboolean opened = FALSE;
239 guint *signals = NULL;
242 GstPluginAPIFlags api_flags;
244 signals = g_signal_list_ids (type, &nsignals);
245 for (i = 0; i < nsignals; i++) {
246 GSignalQuery query = { 0, };
248 g_signal_query (signals[i], &query);
249 g_string_append_printf (json,
250 "%s\"%s\" : {", opened ? "," : ",\"signals\": {", query.signal_name);
254 g_string_append (json, "\"args\": [");
255 for (j = 0; j < query.n_params; j++) {
256 gchar *arg_name = g_strdup_printf ("arg%u", j);
258 g_string_append_c (json, ',');
261 g_string_append_printf (json, "{ \"name\": \"%s\","
262 "\"type\": \"%s\" }", arg_name, g_type_name (query.param_types[j]));
264 if (!g_hash_table_contains (seen_other_types,
265 g_type_name (query.param_types[j])) &&
266 gst_type_is_plugin_api (query.param_types[j], &api_flags)) {
267 g_hash_table_insert (seen_other_types,
268 (gpointer) g_type_name (query.param_types[j]), NULL);
270 if (g_type_is_a (query.param_types[j], G_TYPE_ENUM)) {
271 _serialize_enum (other_types, query.param_types[j], api_flags);
272 } else if (g_type_is_a (query.param_types[j], G_TYPE_FLAGS)) {
273 _serialize_flags (other_types, query.param_types[j]);
274 } else if (g_type_is_a (query.param_types[j], G_TYPE_OBJECT)) {
275 _serialize_object (other_types, seen_other_types,
276 query.param_types[j], query.param_types[j]);
280 g_string_append_c (json, ']');
282 if (g_type_name (query.return_type) &&
283 !g_hash_table_contains (seen_other_types,
284 g_type_name (query.return_type)) &&
285 gst_type_is_plugin_api (query.return_type, &api_flags)) {
286 g_hash_table_insert (seen_other_types,
287 (gpointer) g_type_name (query.return_type), NULL);
288 if (g_type_is_a (query.return_type, G_TYPE_ENUM)) {
289 _serialize_enum (other_types, query.return_type, api_flags);
290 } else if (g_type_is_a (query.return_type, G_TYPE_FLAGS)) {
291 _serialize_flags (other_types, query.return_type);
292 } else if (g_type_is_a (query.return_type, G_TYPE_OBJECT)) {
293 _serialize_object (other_types, seen_other_types, query.return_type,
298 g_string_append_printf (json,
299 ",\"return-type\": \"%s\"", g_type_name (query.return_type));
301 if (query.signal_flags & G_SIGNAL_RUN_FIRST)
302 g_string_append (json, ",\"when\": \"first\"");
303 else if (query.signal_flags & G_SIGNAL_RUN_LAST)
304 g_string_append (json, ",\"when\": \"last\"");
305 else if (query.signal_flags & G_SIGNAL_RUN_CLEANUP)
306 g_string_append (json, ",\"when\": \"cleanup\"");
308 if (query.signal_flags & G_SIGNAL_NO_RECURSE)
309 g_string_append (json, ",\"no-recurse\": true");
311 if (query.signal_flags & G_SIGNAL_DETAILED)
312 g_string_append (json, ",\"detailed\": true");
314 if (query.signal_flags & G_SIGNAL_ACTION)
315 g_string_append (json, ",\"action\": true");
317 if (query.signal_flags & G_SIGNAL_NO_HOOKS)
318 g_string_append (json, ",\"no-hooks\": true");
320 g_string_append_c (json, '}');
327 g_string_append (json, "}");
331 _add_properties (GString * json, GString * other_types,
332 GHashTable * seen_other_types, GObject * object, GObjectClass * klass,
337 gboolean opened = FALSE;
338 GParamSpec **specs, *spec;
339 GstPluginAPIFlags api_flags;
341 specs = g_object_class_list_properties (klass, &n_props);
343 for (i = 0; i < n_props; i++) {
344 GValue value = { 0, };
345 const gchar *mutable_str = NULL;
348 if (spec->owner_type != type)
351 g_value_init (&value, spec->value_type);
352 if (object && ! !(spec->flags & G_PARAM_READABLE) &&
353 !(spec->flags & GST_PARAM_DOC_SHOW_DEFAULT)) {
354 g_object_get_property (G_OBJECT (object), spec->name, &value);
356 /* if we can't read the property value, assume it's set to the default
357 * (which might not be entirely true for sub-classes, but that's an
358 * unlikely corner-case anyway) */
359 g_param_value_set_default (spec, &value);
363 g_string_append (json, ",\"properties\": {");
365 if ((spec->flags & GST_PARAM_MUTABLE_PLAYING)) {
366 mutable_str = "\"playing\"";
367 } else if ((spec->flags & GST_PARAM_MUTABLE_PAUSED)) {
368 mutable_str = "\"paused\"";
369 } else if ((spec->flags & GST_PARAM_MUTABLE_READY)) {
370 mutable_str = "\"ready\"";
372 mutable_str = "\"null\"";
375 tmpstr = json_strescape (g_param_spec_get_blurb (spec));
376 g_string_append_printf (json,
379 "\"construct-only\": %s,"
384 "\"controllable\": %s,"
385 "\"conditionally-available\": %s,"
390 spec->flags & G_PARAM_CONSTRUCT_ONLY ? "true" : "false",
391 spec->flags & G_PARAM_CONSTRUCT ? "true" : "false",
392 spec->flags & G_PARAM_READABLE ? "true" : "false",
393 spec->flags & G_PARAM_WRITABLE ? "true" : "false", tmpstr,
394 spec->flags & GST_PARAM_CONTROLLABLE ? "true" : "false",
395 spec->flags & GST_PARAM_CONDITIONALLY_AVAILABLE ? "true" : "false",
396 mutable_str, g_type_name (G_PARAM_SPEC_VALUE_TYPE (spec)));
399 if (!g_hash_table_contains (seen_other_types,
400 g_type_name (spec->value_type))
401 && gst_type_is_plugin_api (spec->value_type, &api_flags)) {
402 g_hash_table_insert (seen_other_types,
403 (gpointer) g_type_name (spec->value_type), NULL);
404 if (G_IS_PARAM_SPEC_ENUM (spec)) {
405 _serialize_enum (other_types, spec->value_type, api_flags);
406 } else if (G_IS_PARAM_SPEC_FLAGS (spec)) {
407 _serialize_flags (other_types, spec->value_type);
408 } else if (G_IS_PARAM_SPEC_OBJECT (spec)) {
409 _serialize_object (other_types, seen_other_types, spec->value_type,
414 switch (G_VALUE_TYPE (&value)) {
417 const char *string_val = g_value_get_string (&value);
418 gchar *tmpstr = json_strescape (string_val);
420 g_string_append_printf (json, ",\"default\": \"%s\"", tmpstr);;
426 gboolean bool_val = g_value_get_boolean (&value);
428 g_string_append_printf (json, ",\"default\": \"%s\"",
429 bool_val ? "true" : "false");
434 GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (spec);
436 g_string_append_printf (json,
437 ",\"default\": \"%lu\""
440 g_value_get_ulong (&value), pulong->minimum, pulong->maximum);
442 GST_ERROR_OBJECT (object,
443 "property '%s' of type ulong: consider changing to " "uint/uint64",
444 g_param_spec_get_name (spec));
449 GParamSpecLong *plong = G_PARAM_SPEC_LONG (spec);
451 g_string_append_printf (json,
452 ",\"default\": \"%ld\""
455 g_value_get_long (&value), plong->minimum, plong->maximum);
457 GST_ERROR_OBJECT (object,
458 "property '%s' of type long: consider changing to " "int/int64",
459 g_param_spec_get_name (spec));
464 GParamSpecUInt *puint = G_PARAM_SPEC_UINT (spec);
466 g_string_append_printf (json,
467 ",\"default\": \"%d\""
470 g_value_get_uint (&value), puint->minimum, puint->maximum);
475 GParamSpecInt *pint = G_PARAM_SPEC_INT (spec);
477 g_string_append_printf (json,
478 ",\"default\": \"%d\""
481 g_value_get_int (&value), pint->minimum, pint->maximum);
486 GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64 (spec);
488 g_string_append_printf (json,
489 ",\"default\": \"%" G_GUINT64_FORMAT
490 "\",\"min\": \"%" G_GUINT64_FORMAT
491 "\",\"max\": \"%" G_GUINT64_FORMAT "\"",
492 g_value_get_uint64 (&value), puint64->minimum, puint64->maximum);
497 GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64 (spec);
499 g_string_append_printf (json,
500 ",\"default\": \"%" G_GUINT64_FORMAT
501 "\",\"min\": \"%" G_GINT64_FORMAT
502 "\",\"max\": \"%" G_GINT64_FORMAT "\"",
503 g_value_get_int64 (&value), pint64->minimum, pint64->maximum);
508 GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (spec);
510 g_string_append_printf (json,
511 ",\"default\": \"%g\""
514 g_value_get_float (&value), pfloat->minimum, pfloat->maximum);
519 GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (spec);
521 g_string_append_printf (json,
522 ",\"default\": \"%g\""
525 g_value_get_double (&value), pdouble->minimum, pdouble->maximum);
530 GST_ERROR_OBJECT (object,
531 "property '%s' of type char: consider changing to " "int/string",
532 g_param_spec_get_name (spec));
535 if (spec->value_type == GST_TYPE_CAPS) {
536 const GstCaps *caps = gst_value_get_caps (&value);
539 gchar *capsstr = gst_caps_to_string (caps);
540 gchar *tmpcapsstr = json_strescape (capsstr);
542 g_string_append_printf (json, ",\"default\": \"%s\"", tmpcapsstr);
546 } else if (G_IS_PARAM_SPEC_BOXED (spec)) {
547 if (spec->value_type == GST_TYPE_STRUCTURE) {
548 const GstStructure *s = gst_value_get_structure (&value);
550 gchar *str = gst_structure_to_string (s);
551 gchar *tmpstr = json_strescape (str);
553 g_string_append_printf (json, ",\"default\": \"%s\"", tmpstr);
558 } else if (GST_IS_PARAM_SPEC_FRACTION (spec)) {
559 GstParamSpecFraction *pfraction = GST_PARAM_SPEC_FRACTION (spec);
561 g_string_append_printf (json,
562 ",\"default\": \"%d/%d\""
563 ",\"min\": \"%d/%d\""
564 ",\"max\": \"%d/%d\"",
565 gst_value_get_fraction_numerator (&value),
566 gst_value_get_fraction_denominator (&value),
567 pfraction->min_num, pfraction->min_den,
568 pfraction->max_num, pfraction->max_den);
569 } else if (G_IS_PARAM_SPEC_ENUM (spec)) {
570 _serialize_enum_default (json, spec->value_type, &value);
571 } else if (G_IS_PARAM_SPEC_FLAGS (spec)) {
572 _serialize_flags_default (json, spec->value_type, &value);
577 g_string_append_c (json, '}');
584 g_string_append (json, "}");
589 print_field (GQuark field, const GValue * value, GString * jcaps)
591 gchar *tmp, *str = gst_value_serialize (value);
593 if (!g_strcmp0 (g_quark_to_string (field), "format") ||
594 !g_strcmp0 (g_quark_to_string (field), "rate")) {
595 if (!cleanup_caps_field)
596 cleanup_caps_field = g_regex_new ("\\(string\\)|\\(rate\\)", 0, 0, NULL);
599 str = g_regex_replace (cleanup_caps_field, str, -1, 0, "", 0, NULL);;
603 g_string_append_printf (jcaps, "%15s: %s\n", g_quark_to_string (field), str);
609 _build_caps (const GstCaps * caps)
613 GString *jcaps = g_string_new (NULL);
615 if (gst_caps_is_any (caps)) {
616 g_string_append (jcaps, "ANY");
617 return g_string_free (jcaps, FALSE);
620 if (gst_caps_is_empty (caps)) {
621 g_string_append (jcaps, "EMPTY");
622 return g_string_free (jcaps, FALSE);
625 for (i = 0; i < gst_caps_get_size (caps); i++) {
626 GstStructure *structure = gst_caps_get_structure (caps, i);
627 GstCapsFeatures *features = gst_caps_get_features (caps, i);
629 if (features && (gst_caps_features_is_any (features) ||
630 !gst_caps_features_is_equal (features,
631 GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))) {
632 gchar *features_string = gst_caps_features_to_string (features);
634 g_string_append_printf (jcaps, "%s%s(%s):\n",
635 i ? "\n" : "", gst_structure_get_name (structure), features_string);
636 g_free (features_string);
638 g_string_append_printf (jcaps, "%s:\n",
639 gst_structure_get_name (structure));
641 gst_structure_foreach (structure, (GstStructureForeachFunc) print_field,
645 res = json_strescape (jcaps->str);
646 g_string_free (jcaps, TRUE);
652 _add_element_pad_templates (GString * json, GString * other_types,
653 GHashTable * seen_other_types, GstElement * element,
654 GstElementFactory * factory)
656 gboolean opened = FALSE;
658 GstStaticPadTemplate *padtemplate;
659 GRegex *re = g_regex_new ("%", 0, 0, NULL);
660 GstPluginAPIFlags api_flags;
662 pads = gst_element_factory_get_static_pad_templates (factory);
664 GstCaps *documentation_caps;
667 GstPadTemplate *tmpl;
668 padtemplate = (GstStaticPadTemplate *) (pads->data);
669 pads = g_list_next (pads);
671 tmpl = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
672 padtemplate->name_template);
674 name = g_regex_replace (re, padtemplate->name_template,
675 -1, 0, "%%", 0, NULL);;
676 documentation_caps = gst_pad_template_get_documentation_caps (tmpl);
677 caps = _build_caps (documentation_caps);
678 gst_caps_replace (&documentation_caps, NULL);
679 g_string_append_printf (json, "%s"
682 "\"direction\": \"%s\","
683 "\"presence\": \"%s\"",
684 opened ? "," : ",\"pad-templates\": {",
686 padtemplate->direction ==
687 GST_PAD_SRC ? "src" : padtemplate->direction ==
688 GST_PAD_SINK ? "sink" : "unknown",
689 padtemplate->presence ==
690 GST_PAD_ALWAYS ? "always" : padtemplate->presence ==
691 GST_PAD_SOMETIMES ? "sometimes" : padtemplate->presence ==
692 GST_PAD_REQUEST ? "request" : "unknown");
696 pad_type = GST_PAD_TEMPLATE_GTYPE (tmpl);
697 if (pad_type != G_TYPE_NONE && pad_type != GST_TYPE_PAD) {
698 g_string_append_printf (json, ", \"type\": \"%s\"",
699 g_type_name (pad_type));
701 if (!g_hash_table_contains (seen_other_types, g_type_name (pad_type))
702 && gst_type_is_plugin_api (pad_type, &api_flags)) {
703 g_hash_table_insert (seen_other_types,
704 (gpointer) g_type_name (pad_type), NULL);
705 _serialize_object (other_types, seen_other_types, pad_type, pad_type);
708 g_string_append_c (json, '}');
711 g_string_append_c (json, '}');
717 get_rank_name (char *s, gint rank)
719 static const int ranks[4] = {
720 GST_RANK_NONE, GST_RANK_MARGINAL, GST_RANK_SECONDARY, GST_RANK_PRIMARY
722 static const char *rank_names[4] = { "none", "marginal", "secondary",
729 for (i = 0; i < 4; i++) {
730 if (rank == ranks[i])
731 return rank_names[i];
732 if (abs (rank - ranks[i]) < abs (rank - ranks[best_i])) {
737 sprintf (s, "%s %c %d", rank_names[best_i],
738 (rank - ranks[best_i] > 0) ? '+' : '-', abs (ranks[best_i] - rank));
744 _add_factory_details (GString * json, GstElementFactory * factory)
749 keys = gst_element_factory_get_metadata_keys (factory);
751 for (k = keys; *k != NULL; ++k) {
755 val = json_strescape (gst_element_factory_get_metadata (factory, key));
756 g_string_append_printf (json, "%s\"%s\": \"%s\"", f ? "" : ",", key, val);
761 g_string_append (json, ",");
766 _add_object_details (GString * json, GString * other_types,
767 GHashTable * seen_other_types, GObject * object, GType type,
774 g_string_append (json, "\"hierarchy\": [");
776 for (;; ptype = g_type_parent (ptype)) {
777 g_string_append_printf (json, "\"%s\"%c", g_type_name (ptype),
778 ((ptype == G_TYPE_OBJECT || ptype == G_TYPE_INTERFACE) ? ' ' : ','));
780 if (!g_hash_table_contains (seen_other_types, g_type_name (ptype))
781 && gst_type_is_plugin_api (ptype, NULL)) {
782 g_hash_table_insert (seen_other_types, (gpointer) g_type_name (ptype),
784 _serialize_object (other_types, seen_other_types, ptype, inst_type);
787 if (ptype == G_TYPE_OBJECT || ptype == G_TYPE_INTERFACE)
790 g_string_append (json, "]");
792 interfaces = g_type_interfaces (type, &n_interfaces);
796 g_string_append (json, ",\"interfaces\": [");
797 for (iface = interfaces; *iface; iface++, n_interfaces--) {
798 g_string_append_printf (json, "\"%s\"%c", g_type_name (*iface),
799 n_interfaces > 1 ? ',' : ' ');
801 if (!g_hash_table_contains (seen_other_types, g_type_name (*iface))
802 && gst_type_is_plugin_api (*iface, NULL)) {
803 g_hash_table_insert (seen_other_types, (gpointer) g_type_name (*iface),
805 _serialize_object (other_types, seen_other_types, *iface, inst_type);
809 g_string_append (json, "]");
813 _add_properties (json, other_types, seen_other_types, object,
814 G_OBJECT_GET_CLASS (object), type);
815 _add_signals (json, other_types, seen_other_types, object, type);
819 _add_element_details (GString * json, GString * other_types,
820 GHashTable * seen_other_types, GstPluginFeature * feature)
822 GstElement *element =
823 gst_element_factory_create (GST_ELEMENT_FACTORY (feature), NULL);
827 g_error ("Couldn't not make `%s`", GST_OBJECT_NAME (feature));
829 g_string_append_printf (json,
832 GST_OBJECT_NAME (feature),
833 get_rank_name (s, gst_plugin_feature_get_rank (feature)));
835 _add_factory_details (json, GST_ELEMENT_FACTORY (feature));
836 _add_object_details (json, other_types, seen_other_types, G_OBJECT (element),
837 G_OBJECT_TYPE (element), G_OBJECT_TYPE (element));
839 _add_element_pad_templates (json, other_types, seen_other_types, element,
840 GST_ELEMENT_FACTORY (feature));
842 g_string_append (json, "}");
846 main (int argc, char *argv[])
849 GError *error = NULL;
851 GString *other_types;
852 GHashTable *seen_other_types;
855 GList *features, *tmp;
857 gboolean first = TRUE;
860 g_assert (argc >= 3);
862 setlocale (LC_ALL, "");
863 setlocale (LC_NUMERIC, "C");
866 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
867 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
868 textdomain (GETTEXT_PACKAGE);
871 gst_init (NULL, NULL);
873 json = g_string_new ("{");
874 for (i = 2; i < argc; i++) {
875 gchar *basename, **splitext, *filename;
877 plugin = gst_plugin_load_file (libfile, &error);
879 g_printerr ("%s could not be loaded as a GstPlugin: %s", libfile,
880 error->message ? error->message : "no known reasons");
881 g_clear_error (&error);
886 other_types = g_string_new ("");
887 seen_other_types = g_hash_table_new (g_str_hash, g_str_equal);
889 basename = g_filename_display_basename (libfile);
890 splitext = g_strsplit (basename, ".", 2);
892 g_str_has_prefix (splitext[0], "lib") ? &splitext[0][3] : splitext[0];
893 g_string_append_printf (json,
895 "\"description\":\"%s\","
896 "\"filename\":\"%s\","
898 "\"package\":\"%s\","
899 "\"license\":\"%s\","
903 gst_plugin_get_name (plugin),
904 gst_plugin_get_description (plugin),
906 gst_plugin_get_source (plugin),
907 gst_plugin_get_package (plugin),
908 gst_plugin_get_license (plugin), gst_plugin_get_origin (plugin));
910 g_strfreev (splitext);
914 gst_registry_get_feature_list_by_plugin (gst_registry_get (),
915 gst_plugin_get_name (plugin));
918 for (tmp = features; tmp; tmp = tmp->next) {
919 GstPluginFeature *feature = tmp->data;
920 if (GST_IS_ELEMENT_FACTORY (feature)) {
921 GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
922 if (gst_element_factory_get_skip_documentation (factory))
926 g_string_append_printf (json, ",");
927 _add_element_details (json, other_types, seen_other_types, feature);
932 g_string_append (json, "}, \"tracers\": {");
933 gst_plugin_feature_list_free (features);
937 gst_registry_get_feature_list_by_plugin (gst_registry_get (),
938 gst_plugin_get_name (plugin));
939 for (tmp = features; tmp; tmp = tmp->next) {
940 GstPluginFeature *feature = tmp->data;
942 if (GST_IS_TRACER_FACTORY (feature)) {
944 g_string_append_printf (json, ",");
945 g_string_append_printf (json, "\"%s\": {}", GST_OBJECT_NAME (feature));
949 g_string_append_printf (json, "}, \"other-types\": {%s}}",
951 gst_plugin_feature_list_free (features);
953 g_hash_table_unref (seen_other_types);
954 g_string_free (other_types, TRUE);
957 g_string_append_c (json, '}');
958 if (!g_file_set_contents (argv[1], json->str, -1, &err)) {
959 g_printerr ("Could not set json to %s: %s", argv[1], err->message);
960 g_clear_error (&err);
964 g_string_free (json, TRUE);