/* GStreamer * Copyright (C) 2015 Mathieu Duponchelle * * gst-completion-helper.c: tool to let other tools enjoy fast and powerful * gstreamer-aware completion * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include static GList * get_pad_templates_info (GstElement * element, GstElementFactory * factory, GstPadDirection direction) { const GList *pads; GstStaticPadTemplate *padtemplate; GList *caps_list = NULL; if (gst_element_factory_get_num_pad_templates (factory) == 0) { g_print (" none\n"); return NULL; } pads = gst_element_factory_get_static_pad_templates (factory); while (pads) { padtemplate = (GstStaticPadTemplate *) (pads->data); pads = g_list_next (pads); if (padtemplate->direction != direction) continue; if (padtemplate->static_caps.string) { caps_list = g_list_append (caps_list, gst_static_caps_get (&padtemplate->static_caps)); } } return caps_list; } static GList * _get_pad_caps (const gchar * factory_name, GstPadDirection direction) { GstElementFactory *factory = gst_element_factory_find (factory_name); GstElement *element = gst_element_factory_make (factory_name, NULL); if (!element) return NULL; if (!factory) return NULL; factory = GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE (factory))); if (!factory) return NULL; return get_pad_templates_info (element, factory, direction); } static gboolean _are_linkable (GstPluginFeature * feature, GList * caps_list) { gboolean print = FALSE; GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); GList *tmp; print = FALSE; for (tmp = caps_list; tmp; tmp = tmp->next) { if (gst_element_factory_can_sink_any_caps (factory, tmp->data)) { print = TRUE; break; } } return print; } static gboolean _belongs_to_klass (GstElementFactory * factory, const gchar * klass) { const gchar *factory_klass; factory_klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); if (strstr (factory_klass, klass)) return TRUE; return FALSE; } static void _list_features (const gchar * compatible_with, const gchar * klass, GstCaps * sinkcaps) { GList *plugins, *orig_plugins; GList *caps_list = NULL; if (compatible_with) { caps_list = _get_pad_caps (compatible_with, GST_PAD_SRC); } orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ()); while (plugins) { GList *features, *orig_features; GstPlugin *plugin; plugin = (GstPlugin *) (plugins->data); plugins = g_list_next (plugins); if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED)) { continue; } orig_features = features = gst_registry_get_feature_list_by_plugin (gst_registry_get (), gst_plugin_get_name (plugin)); while (features) { GstPluginFeature *feature; if (G_UNLIKELY (features->data == NULL)) goto next; feature = GST_PLUGIN_FEATURE (features->data); if (GST_IS_ELEMENT_FACTORY (feature)) { gboolean print = TRUE; if (caps_list) print = _are_linkable (feature, caps_list); if (print && klass) print = _belongs_to_klass (GST_ELEMENT_FACTORY (feature), klass); if (print && sinkcaps) print = gst_element_factory_can_sink_any_caps (GST_ELEMENT_FACTORY (feature), sinkcaps); if (print) g_print ("%s ", gst_plugin_feature_get_name (feature)); } next: features = g_list_next (features); } gst_plugin_feature_list_free (orig_features); } g_list_free (caps_list); g_print ("\n"); gst_plugin_list_free (orig_plugins); } static void _print_element_properties_info (GstElement * element) { GParamSpec **property_specs; guint num_properties, i; property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element), &num_properties); for (i = 0; i < num_properties; i++) { GParamSpec *param = property_specs[i]; if (param->flags & G_PARAM_WRITABLE) { g_print ("%s= ", g_param_spec_get_name (param)); } } g_free (property_specs); } static void _list_element_properties (const gchar * factory_name) { GstElement *element = gst_element_factory_make (factory_name, NULL); _print_element_properties_info (element); } int main (int argc, char *argv[]) { gboolean list_features = FALSE; gchar *compatible_with = NULL; gchar *element = NULL; gchar *klass = NULL; gchar *caps_str = NULL; GstCaps *sinkcaps = NULL; gint exit_code = EXIT_SUCCESS; GOptionEntry options[] = { {"list-features", 'l', 0, G_OPTION_ARG_NONE, &list_features, "list all the available features", NULL}, {"compatible-with", '\0', 0, G_OPTION_ARG_STRING, &compatible_with, "Only print the elements that could be queued after this feature name", NULL}, {"element-properties", '\0', 0, G_OPTION_ARG_STRING, &element, "The element to list properties on", NULL}, {"klass", '\0', 0, G_OPTION_ARG_STRING, &klass, "Only print the elements belonging to that klass", NULL}, {"sinkcaps", '\0', 0, G_OPTION_ARG_STRING, &caps_str, "Only print the elements that can sink these caps", NULL}, {NULL} }; GOptionContext *ctx; GError *err = NULL; ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); g_option_context_add_main_entries (ctx, options, NULL); g_option_context_add_group (ctx, gst_init_get_option_group ()); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { if (err) g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message)); else g_printerr ("Error initializing: Unknown error!\n"); exit (1); } g_option_context_free (ctx); if (caps_str) { sinkcaps = gst_caps_from_string (caps_str); if (!sinkcaps) { exit_code = EXIT_FAILURE; goto done; } } if (compatible_with || klass || sinkcaps) { _list_features (compatible_with, klass, sinkcaps); goto done; } if (element) { _list_element_properties (element); goto done; } if (list_features) { _list_features (NULL, NULL, NULL); goto done; } done: if (sinkcaps) gst_caps_unref (sinkcaps); exit (exit_code); }