e99b73b7b3702aa007b399805f7c874fee5fbd59
[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 #include <string.h>
31
32 static GList *
33 get_pad_templates_info (GstElement * element, GstElementFactory * factory,
34     GstPadDirection direction)
35 {
36   const GList *pads;
37   GstStaticPadTemplate *padtemplate;
38   GList *caps_list = NULL;
39
40   if (gst_element_factory_get_num_pad_templates (factory) == 0) {
41     g_print ("  none\n");
42     return NULL;
43   }
44
45   pads = gst_element_factory_get_static_pad_templates (factory);
46   while (pads) {
47     padtemplate = (GstStaticPadTemplate *) (pads->data);
48     pads = g_list_next (pads);
49
50     if (padtemplate->direction != direction)
51       continue;
52
53     if (padtemplate->static_caps.string) {
54       caps_list =
55           g_list_append (caps_list,
56           gst_static_caps_get (&padtemplate->static_caps));
57     }
58
59   }
60
61   return caps_list;
62 }
63
64 static GList *
65 _get_pad_caps (const gchar * factory_name, GstPadDirection direction)
66 {
67   GstElementFactory *factory = gst_element_factory_find (factory_name);
68   GstElement *element = gst_element_factory_make (factory_name, NULL);
69
70   if (!element)
71     return NULL;
72   if (!factory)
73     return NULL;
74   factory =
75       GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
76           (factory)));
77   if (!factory)
78     return NULL;
79   return get_pad_templates_info (element, factory, direction);
80 }
81
82 static gboolean
83 _are_linkable (GstPluginFeature * feature, GList * caps_list)
84 {
85   gboolean print = FALSE;
86   GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
87
88   GList *tmp;
89   print = FALSE;
90   for (tmp = caps_list; tmp; tmp = tmp->next) {
91     if (gst_element_factory_can_sink_any_caps (factory, tmp->data)) {
92       print = TRUE;
93       break;
94     }
95   }
96
97   return print;
98 }
99
100 static gboolean
101 _belongs_to_klass (GstElementFactory * factory, const gchar * klass)
102 {
103   const gchar *factory_klass;
104
105
106   factory_klass =
107       gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
108   if (strstr (factory_klass, klass))
109     return TRUE;
110   return FALSE;
111 }
112
113 static void
114 _list_features (const gchar * compatible_with, const gchar * klass,
115     GstCaps * sinkcaps)
116 {
117   GList *plugins, *orig_plugins;
118   GList *caps_list = NULL;
119
120   if (compatible_with) {
121     caps_list = _get_pad_caps (compatible_with, GST_PAD_SRC);
122   }
123
124   orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ());
125   while (plugins) {
126     GList *features, *orig_features;
127     GstPlugin *plugin;
128
129     plugin = (GstPlugin *) (plugins->data);
130     plugins = g_list_next (plugins);
131
132     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED)) {
133       continue;
134     }
135
136     orig_features = features =
137         gst_registry_get_feature_list_by_plugin (gst_registry_get (),
138         gst_plugin_get_name (plugin));
139     while (features) {
140       GstPluginFeature *feature;
141
142       if (G_UNLIKELY (features->data == NULL))
143         goto next;
144       feature = GST_PLUGIN_FEATURE (features->data);
145
146       if (GST_IS_ELEMENT_FACTORY (feature)) {
147         gboolean print = TRUE;
148         if (caps_list)
149           print = _are_linkable (feature, caps_list);
150         if (print && klass)
151           print = _belongs_to_klass (GST_ELEMENT_FACTORY (feature), klass);
152         if (print && sinkcaps)
153           print =
154               gst_element_factory_can_sink_any_caps (GST_ELEMENT_FACTORY
155               (feature), sinkcaps);
156
157         if (print)
158           g_print ("%s ", gst_plugin_feature_get_name (feature));
159       }
160
161     next:
162       features = g_list_next (features);
163     }
164
165     gst_plugin_feature_list_free (orig_features);
166   }
167
168   g_list_free (caps_list);
169   g_print ("\n");
170   gst_plugin_list_free (orig_plugins);
171 }
172
173 static void
174 _print_element_properties_info (GstElement * element)
175 {
176   GParamSpec **property_specs;
177   guint num_properties, i;
178
179   property_specs = g_object_class_list_properties
180       (G_OBJECT_GET_CLASS (element), &num_properties);
181
182   for (i = 0; i < num_properties; i++) {
183     GParamSpec *param = property_specs[i];
184
185     if (param->flags & G_PARAM_WRITABLE) {
186       g_print ("%s= ", g_param_spec_get_name (param));
187     }
188   }
189
190   g_free (property_specs);
191 }
192
193 static void
194 _list_element_properties (const gchar * factory_name)
195 {
196   GstElement *element = gst_element_factory_make (factory_name, NULL);
197
198   _print_element_properties_info (element);
199 }
200
201 int
202 main (int argc, char *argv[])
203 {
204   gboolean list_features = FALSE;
205   gchar *compatible_with = NULL;
206   gchar *element = NULL;
207   gchar *klass = NULL;
208   gchar *caps_str = NULL;
209   GstCaps *sinkcaps = NULL;
210   gint exit_code = EXIT_SUCCESS;
211
212   GOptionEntry options[] = {
213     {"list-features", 'l', 0, G_OPTION_ARG_NONE, &list_features,
214         "list all the available features", NULL},
215     {"compatible-with", '\0', 0, G_OPTION_ARG_STRING, &compatible_with,
216           "Only print the elements that could be queued after this feature name",
217         NULL},
218     {"element-properties", '\0', 0, G_OPTION_ARG_STRING, &element,
219         "The element to list properties on", NULL},
220     {"klass", '\0', 0, G_OPTION_ARG_STRING, &klass,
221         "Only print the elements belonging to that klass", NULL},
222     {"sinkcaps", '\0', 0, G_OPTION_ARG_STRING, &caps_str,
223         "Only print the elements that can sink these caps", NULL},
224     {NULL}
225   };
226
227   GOptionContext *ctx;
228   GError *err = NULL;
229
230   ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
231   g_option_context_add_main_entries (ctx, options, NULL);
232   g_option_context_add_group (ctx, gst_init_get_option_group ());
233   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
234     if (err)
235       g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
236     else
237       g_printerr ("Error initializing: Unknown error!\n");
238     exit (1);
239   }
240   g_option_context_free (ctx);
241
242   if (caps_str) {
243     sinkcaps = gst_caps_from_string (caps_str);
244     if (!sinkcaps) {
245       exit_code = EXIT_FAILURE;
246       goto done;
247     }
248   }
249
250   if (compatible_with || klass || sinkcaps) {
251     _list_features (compatible_with, klass, sinkcaps);
252     goto done;
253   }
254
255   if (element) {
256     _list_element_properties (element);
257     goto done;
258   }
259
260   if (list_features) {
261     _list_features (NULL, NULL, NULL);
262     goto done;
263   }
264
265 done:
266   if (sinkcaps)
267     gst_caps_unref (sinkcaps);
268   exit (exit_code);
269 }