DEBIAN: Debianization
[glsdk/gstreamer0-10.git] / debian / gst-codec-info.c
1 /* GStreamer
2  * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3  *
4  * gst-codec-info.c: tool to print automatic codec installation info
5  *                   for a given list of plugins
6  *
7  * Partially based on gst-inspect from gstreamer.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
26 #include <gst/gst.h>
27 #include <string.h>
29 static const gchar *virtual_packages[] = {
30   "gstreamer0.10-audiosink",
31   "gstreamer0.10-audiosource",
32   "gstreamer0.10-videosink",
33   "gstreamer0.10-videosource",
34   "gstreamer0.10-visualization",
35   NULL
36 };
38 static GList *elements = NULL;
39 static GList *uri_sources = NULL;
40 static GList *uri_sinks = NULL;
41 static GList *provides = NULL;
42 static GstCaps *encoders = NULL, *decoders = NULL;
44 static void
45 free_plugin_info (void)
46 {
47   g_list_foreach (elements, (GFunc) g_free, NULL);
48   g_list_foreach (uri_sources, (GFunc) g_free, NULL);
49   g_list_foreach (uri_sinks, (GFunc) g_free, NULL);
51   g_list_free (elements);
52   g_list_free (uri_sources);
53   g_list_free (uri_sinks);
55   g_list_free (provides);
57   gst_caps_unref (encoders);
58   gst_caps_unref (decoders);
59 }
61 static void
62 print_plugin_info (void)
63 {
64   GList *l;
66   if (elements) {
67     g_print ("gstreamer:Elements=");
68     for (l = elements; l; l = l->next) {
69       if (l->next)
70         g_print ("%s, ", (gchar *) l->data);
71       else
72         g_print ("%s\n", (gchar *) l->data);
73     }
74   }
76   if (provides) {
77     g_print ("gstreamer:Provides=");
78     for (l = provides; l; l = l->next) {
79       if (l->next)
80         g_print ("%s, ", (gchar *) l->data);
81       else
82         g_print ("%s\n", (gchar *) l->data);
83     }
84   }
86   if (uri_sources) {
87     g_print ("gstreamer:URISources=");
88     for (l = uri_sources; l; l = l->next) {
89       if (l->next)
90         g_print ("%s, ", (gchar *) l->data);
91       else
92         g_print ("%s\n", (gchar *) l->data);
93     }
94   }
96   if (uri_sinks) {
97     g_print ("gstreamer:URISinks=");
98     for (l = uri_sinks; l; l = l->next) {
99       if (l->next)
100         g_print ("%s, ", (gchar *) l->data);
101       else
102         g_print ("%s\n", (gchar *) l->data);
103     }
104   }
106   if (!gst_caps_is_empty (encoders)) {
107     gchar *caps = gst_caps_to_string (encoders);
109     g_print ("gstreamer:Encoders=%s\n", caps);
110     g_free (caps);
111   }
113   if (!gst_caps_is_empty (decoders)) {
114     gchar *caps = gst_caps_to_string (decoders);
116     g_print ("gstreamer:Decoders=%s\n", caps);
117     g_free (caps);
118   }
121 static void
122 remove_duplicates (GList * list, gboolean free)
124   GList *l;
125   gchar *previous;
127   if (!list || !list->next)
128     return;
130   previous = list->data;
131   l = list->next;
133   while (l) {
134     if (strcmp (l->data, previous) == 0) {
135       GList *next = l->next;
137       if (free)
138         g_free (l->data);
140       l = g_list_delete_link (l->prev, l);
141       l = next;
142     } else {
143       previous = l->data;
144       l = l->next;
145     }
146   }
149 static void
150 cleanup_plugin_info (void)
152   if (encoders)
153     gst_caps_do_simplify (encoders);
155   if (decoders)
156     gst_caps_do_simplify (decoders);
158   elements = g_list_sort (elements, (GCompareFunc) strcmp);
159   uri_sources = g_list_sort (uri_sources, (GCompareFunc) strcmp);
160   uri_sinks = g_list_sort (uri_sinks, (GCompareFunc) strcmp);
161   provides = g_list_sort (provides, (GCompareFunc) strcmp);
163   remove_duplicates (elements, TRUE);
164   remove_duplicates (uri_sources, TRUE);
165   remove_duplicates (uri_sinks, TRUE);
166   remove_duplicates (provides, FALSE);
169 static void
170 collect_uri_protocols (GstElementFactory * factory)
172   gchar **protocols, **p;
174   protocols = gst_element_factory_get_uri_protocols (factory);
175   if (!protocols)
176     return;
178   switch (gst_element_factory_get_uri_type (factory)) {
179     case GST_URI_SINK:
180       for (p = protocols; *p; p++)
181         uri_sinks = g_list_prepend (uri_sinks, g_strdup (*p));
182       break;
183     case GST_URI_SRC:
184       for (p = protocols; *p; p++)
185         uri_sources = g_list_prepend (uri_sources, g_strdup (*p));
186       break;
187   }
188   g_strfreev (protocols);
191 static void
192 remove_min_max_fields (GstStructure * s)
194   gint i, n;
195   gboolean removed_field = FALSE;
198   do {
199     n = gst_structure_n_fields (s);
200     removed_field = FALSE;
201     for (i = 0; i < n; i++) {
202       const gchar *field_name = gst_structure_nth_field_name (s, i);
203       const GValue *field;
205       field = gst_structure_get_value (s, field_name);
207       if (GST_VALUE_HOLDS_INT_RANGE (field)) {
208         gint min, max;
210         min = gst_value_get_int_range_min (field);
211         max = gst_value_get_int_range_max (field);
213         if (min == 0 && max == G_MAXINT) {
214           gst_structure_remove_field (s, field_name);
215           removed_field = TRUE;
216           break;
217         }
218       } else if (GST_VALUE_HOLDS_LIST (field)) {
219         gint n2 = gst_value_list_get_size (field);
221         if (n2 == 2) {
222           const GValue *val1 = gst_value_list_get_value (field, 0);
223           const GValue *val2 = gst_value_list_get_value (field, 1);
225           if (G_VALUE_TYPE (val1) == G_TYPE_BOOLEAN
226               && G_VALUE_TYPE (val2) == G_TYPE_BOOLEAN
227               && ((g_value_get_boolean (val1) && !g_value_get_boolean (val2))
228                   || (!g_value_get_boolean (val1)
229                       && g_value_get_boolean (val2)))) {
230             gst_structure_remove_field (s, field_name);
231             removed_field = TRUE;
232             break;
233           }
234         }
235       } else if (GST_VALUE_HOLDS_ARRAY (field)) {
236         gint n2 = gst_value_array_get_size (field);
238         if (n2 == 2) {
239           const GValue *val1 = gst_value_array_get_value (field, 0);
240           const GValue *val2 = gst_value_array_get_value (field, 1);
242           if (G_VALUE_TYPE (val1) == G_TYPE_BOOLEAN
243               && G_VALUE_TYPE (val2) == G_TYPE_BOOLEAN
244               && ((g_value_get_boolean (val1) && !g_value_get_boolean (val2))
245                   || (!g_value_get_boolean (val1)
246                       && g_value_get_boolean (val2)))) {
247             gst_structure_remove_field (s, field_name);
248             removed_field = TRUE;
249             break;
250           }
251         }
252       }
253     }
254   } while (removed_field);
257 static void
258 collect_codecs (GstElementFactory * factory)
260   GstPadDirection direction;
261   gboolean encoder;
262   const gchar *klass;
263   const GList *static_templates, *l;
264   GstCaps *caps = NULL;
265   gint i, n;
267   klass = gst_element_factory_get_klass (factory);
268   g_return_if_fail (klass);
270   if (strstr (klass, "Demuxer") ||
271       strstr (klass, "Decoder") ||
272       strstr (klass, "Depay") || strstr (klass, "Parser")) {
274     /* Ignore decoders with a less than marginal rank as they're
275      * not autoplugged by playbin/decodebin */
276     if (gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)) <
277         GST_RANK_MARGINAL)
278       return;
280     encoder = FALSE;
281     direction = GST_PAD_SINK;
282   } else if (strstr (klass, "Muxer") ||
283       strstr (klass, "Encoder") || strstr (klass, "Pay")) {
284     encoder = TRUE;
285     direction = GST_PAD_SRC;
286   } else if (strcmp (klass, "Sink/Audio") == 0) {
287     provides = g_list_prepend (provides, (gchar *) virtual_packages[0]);
288     return;
289   } else if (strcmp (klass, "Source/Audio") == 0) {
290     provides = g_list_prepend (provides, (gchar *) virtual_packages[1]);
291     return;
292   } else if (strcmp (klass, "Sink/Video") == 0) {
293     provides = g_list_prepend (provides, (gchar *) virtual_packages[2]);
294     return;
295   } else if (strcmp (klass, "Source/Video") == 0) {
296     provides = g_list_prepend (provides, (gchar *) virtual_packages[3]);
297     return;
298   } else if (strcmp (klass, "Visualization") == 0) {
299     provides = g_list_prepend (provides, (gchar *) virtual_packages[4]);
300     return;
301   } else {
302     return;
303   }
305   /* decoder/demuxer sink pads should always be static and there should only
306    * be one, the same applies to encoders/muxers and source pads */
307   static_templates = gst_element_factory_get_static_pad_templates (factory);
308   for (l = static_templates; l; l = l->next) {
309     GstStaticPadTemplate *tmpl = l->data;
311     if (tmpl->direction == direction) {
312       caps = gst_static_pad_template_get_caps (tmpl);
313       break;
314     }
315   }
317   if (caps == NULL) {
318     g_printerr ("W: Couldn't find static pad template for '%s'\n",
319         GST_PLUGIN_FEATURE_NAME (factory));
320     return;
321   }
323   caps = gst_caps_make_writable (caps);
324   n = gst_caps_get_size (caps);
325   for (i = 0; i < n; i++) {
326     GstStructure *s = gst_caps_get_structure (caps, i);
328     /* make caps easier to interpret, remove common fields that are likely
329      * to be irrelevant for determining the right plugin (ie. mostly fields
330      * where template caps usually have the standard MIN - MAX range as value) */
331     gst_structure_remove_field (s, "codec_data");
332     gst_structure_remove_field (s, "palette_data");
333     gst_structure_remove_field (s, "pixel-aspect-ratio");
334     gst_structure_remove_field (s, "framerate");
335     gst_structure_remove_field (s, "leaf_size");
336     gst_structure_remove_field (s, "packet_size");
337     gst_structure_remove_field (s, "block_align");
338     gst_structure_remove_field (s, "metadata-interval");        /* icy caps */
339     /* decoders/encoders almost always handle the usual width/height/channel/rate
340      * range (and if we don't remove this then the app will have a much harder
341      * time blacklisting formats it has unsuccessfully tried to install before) */
342     gst_structure_remove_field (s, "width");
343     gst_structure_remove_field (s, "depth");
344     gst_structure_remove_field (s, "height");
345     gst_structure_remove_field (s, "channels");
346     gst_structure_remove_field (s, "rate");
347     /* rtp fields */
348     gst_structure_remove_field (s, "config");
349     gst_structure_remove_field (s, "clock-rate");
350     gst_structure_remove_field (s, "clock-base");
351     gst_structure_remove_field (s, "maxps");
352     gst_structure_remove_field (s, "seqnum-base");
353     gst_structure_remove_field (s, "npt-start");
354     gst_structure_remove_field (s, "npt-stop");
355     gst_structure_remove_field (s, "play-speed");
356     gst_structure_remove_field (s, "play-scale");
357     gst_structure_remove_field (s, "dynamic_range");
359     remove_min_max_fields (s);
361     gst_caps_append_structure ((encoder) ? encoders : decoders,
362         gst_structure_copy (s));
363   }
365   gst_caps_unref (caps);
368 static void
369 collect_plugin_info (GstPlugin * plugin)
371   GList *features, *l;
372   const gchar *plugin_name;
374   plugin_name = gst_plugin_get_name (plugin);
376   features = gst_registry_get_feature_list (gst_registry_get_default (),
377       GST_TYPE_ELEMENT_FACTORY);
379   for (l = features; l; l = l->next) {
380     GstPluginFeature *feature = GST_PLUGIN_FEATURE (l->data);
381     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
383     if (!g_str_equal (plugin_name, feature->plugin_name))
384       continue;
386     elements =
387         g_list_prepend (elements,
388         g_strdup (gst_plugin_feature_get_name (feature)));
389     collect_uri_protocols (factory);
390     collect_codecs (factory);
391   }
393   g_list_foreach (features, (GFunc) gst_object_unref, NULL);
394   g_list_free (features);
397 int
398 main (int argc, char **argv)
400   guint major, minor, micro, nano;
401   gint i;
403   if (!g_thread_supported ())
404     g_thread_init (NULL);
406   gst_init (NULL, NULL);
408   gst_version (&major, &minor, &micro, &nano);
410   if (argc == 1)
411     return 0;
413   encoders = gst_caps_new_empty ();
414   decoders = gst_caps_new_empty ();
416   for (i = 1; i < argc; i++) {
417     GstPlugin *plugin = NULL;
418     GError *error = NULL;
420     if (argv[i] == NULL ||
421         !g_file_test (argv[i], G_FILE_TEST_EXISTS) ||
422         !g_str_has_suffix (argv[i], G_MODULE_SUFFIX)) {
423       g_printerr ("W: '%s' is no valid plugin filename\n", argv[i]);
424       continue;
425     }
427     plugin = gst_plugin_load_file (argv[i], &error);
429     if (!plugin) {
430       g_printerr ("W: Could not load '%s': %s\n", argv[i], error->message);
431       g_error_free (error);
432       continue;
433     }
435     collect_plugin_info (plugin);
436   }
438   if (elements)
439     g_print ("gstreamer:Version=%u.%u\n", major, minor);
441   cleanup_plugin_info ();
442   print_plugin_info ();
443   free_plugin_info ();
445   return 0;