bash-completion: Implement in a different way.
[platform/upstream/gstreamer.git] / libs / gst / helpers / gst-completion-helper.c
1 /* GStreamer
2  * Copyright (C) 2015 Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
3  *
4  * gst-completion-helper.c: tool to let other tools enjoy fast and powerful
5  * gstreamer-aware completion
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include <gst/gst.h>
28 #include <glib.h>
29 #include <stdlib.h>
30
31 static GList *
32 get_pad_templates_info (GstElement * element, GstElementFactory * factory,
33     GstPadDirection direction)
34 {
35   const GList *pads;
36   GstStaticPadTemplate *padtemplate;
37   GList *caps_list = NULL;
38
39   if (gst_element_factory_get_num_pad_templates (factory) == 0) {
40     g_print ("  none\n");
41     return NULL;
42   }
43
44   pads = gst_element_factory_get_static_pad_templates (factory);
45   while (pads) {
46     padtemplate = (GstStaticPadTemplate *) (pads->data);
47     pads = g_list_next (pads);
48
49     if (padtemplate->direction != direction)
50       continue;
51
52     if (padtemplate->static_caps.string) {
53       caps_list =
54           g_list_append (caps_list,
55           gst_static_caps_get (&padtemplate->static_caps));
56     }
57
58   }
59
60   return caps_list;
61 }
62
63 static GList *
64 _get_pad_caps (const gchar * factory_name, GstPadDirection direction)
65 {
66   GstElementFactory *factory = gst_element_factory_find (factory_name);
67   GstElement *element = gst_element_factory_make (factory_name, NULL);
68
69   if (!element)
70     return NULL;
71   if (!factory)
72     return NULL;
73   factory =
74       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
75           (factory)));
76   if (!factory)
77     return NULL;
78   return get_pad_templates_info (element, factory, direction);
79 }
80
81 static gboolean
82 _are_linkable (GstPluginFeature * feature, GList * caps_list)
83 {
84   gboolean print = FALSE;
85   GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
86
87   GList *tmp;
88   print = FALSE;
89   for (tmp = caps_list; tmp; tmp = tmp->next) {
90     if (gst_element_factory_can_sink_any_caps (factory, tmp->data)) {
91       print = TRUE;
92       break;
93     }
94   }
95
96   return print;
97 }
98
99 static void
100 _list_features (const gchar * compatible_with)
101 {
102   GList *plugins, *orig_plugins;
103   GList *caps_list = NULL;
104
105   if (compatible_with) {
106     caps_list = _get_pad_caps (compatible_with, GST_PAD_SRC);
107   }
108
109   orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ());
110   while (plugins) {
111     GList *features, *orig_features;
112     GstPlugin *plugin;
113
114     plugin = (GstPlugin *) (plugins->data);
115     plugins = g_list_next (plugins);
116
117     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED)) {
118       continue;
119     }
120
121     orig_features = features =
122         gst_registry_get_feature_list_by_plugin (gst_registry_get (),
123         gst_plugin_get_name (plugin));
124     while (features) {
125       GstPluginFeature *feature;
126
127       if (G_UNLIKELY (features->data == NULL))
128         goto next;
129       feature = GST_PLUGIN_FEATURE (features->data);
130
131       if (GST_IS_ELEMENT_FACTORY (feature)) {
132         gboolean print = TRUE;
133         if (caps_list)
134           print = _are_linkable (feature, caps_list);
135         if (print)
136           g_print ("%s ", gst_plugin_feature_get_name (feature));
137       }
138
139     next:
140       features = g_list_next (features);
141     }
142
143     gst_plugin_feature_list_free (orig_features);
144   }
145
146   g_list_free (caps_list);
147   g_print ("\n");
148   gst_plugin_list_free (orig_plugins);
149 }
150
151 static void
152 _print_element_properties_info (GstElement * element)
153 {
154   GParamSpec **property_specs;
155   guint num_properties, i;
156
157   property_specs = g_object_class_list_properties
158       (G_OBJECT_GET_CLASS (element), &num_properties);
159
160   for (i = 0; i < num_properties; i++) {
161     GParamSpec *param = property_specs[i];
162
163     if (param->flags & G_PARAM_WRITABLE) {
164       g_print ("%s= ", g_param_spec_get_name (param));
165     }
166   }
167
168   g_free (property_specs);
169 }
170
171 static void
172 _list_element_properties (const gchar * factory_name)
173 {
174   GstElement *element = gst_element_factory_make (factory_name, NULL);
175
176   _print_element_properties_info (element);
177 }
178
179 int
180 main (int argc, char *argv[])
181 {
182   gboolean list_features = FALSE;
183   gchar *compatible_with = NULL;
184   gchar *element = NULL;
185
186   GOptionEntry options[] = {
187     {"list-features", 'l', 0, G_OPTION_ARG_NONE, &list_features,
188         "list all the available features", NULL},
189     {"compatible-with", '\0', 0, G_OPTION_ARG_STRING, &compatible_with,
190           "Only print the elements that could be queued after this feature name",
191         NULL},
192     {"element-properties", '\0', 0, G_OPTION_ARG_STRING, &element,
193         "The element to list properties on", NULL},
194     {NULL}
195   };
196
197   GOptionContext *ctx;
198   GError *err = NULL;
199
200   ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
201   g_option_context_add_main_entries (ctx, options, NULL);
202   g_option_context_add_group (ctx, gst_init_get_option_group ());
203   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
204     if (err)
205       g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
206     else
207       g_printerr ("Error initializing: Unknown error!\n");
208     exit (1);
209   }
210   g_option_context_free (ctx);
211
212   if (compatible_with) {
213     _list_features (compatible_with);
214     exit (EXIT_SUCCESS);
215   }
216
217   if (element) {
218     _list_element_properties (element);
219     exit (EXIT_SUCCESS);
220   }
221
222   if (list_features) {
223     _list_features (NULL);
224     exit (EXIT_SUCCESS);
225   }
226 }