diff options
author | Nicolas Dechesne <n-dechesne@ti.com> | 2011-06-25 14:43:31 +0200 |
---|---|---|
committer | Nicolas Dechesne <n-dechesne@ti.com> | 2011-10-07 23:10:18 +0200 |
commit | 16c3e450684124000dff56d79426e3b27cd28139 (patch) | |
tree | cdd1b661e1077c636ea48064d6668bc68e934de3 /debian/gst-codec-info.c | |
parent | beb43201c942afa12dfc4225218b61fcd6e90923 (diff) |
Initial import of debian/ from gstreamer0.10
Signed-off-by: Nicolas Dechesne <n-dechesne@ti.com>
Diffstat (limited to 'debian/gst-codec-info.c')
-rw-r--r-- | debian/gst-codec-info.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/debian/gst-codec-info.c b/debian/gst-codec-info.c new file mode 100644 index 0000000..f916df2 --- /dev/null +++ b/debian/gst-codec-info.c @@ -0,0 +1,446 @@ +/* GStreamer + * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> + * + * gst-codec-info.c: tool to print automatic codec installation info + * for a given list of plugins + * + * Partially based on gst-inspect from gstreamer. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include <gst/gst.h> +#include <string.h> + +static const gchar *virtual_packages[] = { + "gstreamer0.10-audiosink", + "gstreamer0.10-audiosource", + "gstreamer0.10-videosink", + "gstreamer0.10-videosource", + "gstreamer0.10-visualization", + NULL +}; + +static GList *elements = NULL; +static GList *uri_sources = NULL; +static GList *uri_sinks = NULL; +static GList *provides = NULL; +static GstCaps *encoders = NULL, *decoders = NULL; + +static void +free_plugin_info (void) +{ + g_list_foreach (elements, (GFunc) g_free, NULL); + g_list_foreach (uri_sources, (GFunc) g_free, NULL); + g_list_foreach (uri_sinks, (GFunc) g_free, NULL); + + g_list_free (elements); + g_list_free (uri_sources); + g_list_free (uri_sinks); + + g_list_free (provides); + + gst_caps_unref (encoders); + gst_caps_unref (decoders); +} + +static void +print_plugin_info (void) +{ + GList *l; + + if (elements) { + g_print ("gstreamer:Elements="); + for (l = elements; l; l = l->next) { + if (l->next) + g_print ("%s, ", (gchar *) l->data); + else + g_print ("%s\n", (gchar *) l->data); + } + } + + if (provides) { + g_print ("gstreamer:Provides="); + for (l = provides; l; l = l->next) { + if (l->next) + g_print ("%s, ", (gchar *) l->data); + else + g_print ("%s\n", (gchar *) l->data); + } + } + + if (uri_sources) { + g_print ("gstreamer:URISources="); + for (l = uri_sources; l; l = l->next) { + if (l->next) + g_print ("%s, ", (gchar *) l->data); + else + g_print ("%s\n", (gchar *) l->data); + } + } + + if (uri_sinks) { + g_print ("gstreamer:URISinks="); + for (l = uri_sinks; l; l = l->next) { + if (l->next) + g_print ("%s, ", (gchar *) l->data); + else + g_print ("%s\n", (gchar *) l->data); + } + } + + if (!gst_caps_is_empty (encoders)) { + gchar *caps = gst_caps_to_string (encoders); + + g_print ("gstreamer:Encoders=%s\n", caps); + g_free (caps); + } + + if (!gst_caps_is_empty (decoders)) { + gchar *caps = gst_caps_to_string (decoders); + + g_print ("gstreamer:Decoders=%s\n", caps); + g_free (caps); + } +} + +static void +remove_duplicates (GList * list, gboolean free) +{ + GList *l; + gchar *previous; + + if (!list || !list->next) + return; + + previous = list->data; + l = list->next; + + while (l) { + if (strcmp (l->data, previous) == 0) { + GList *next = l->next; + + if (free) + g_free (l->data); + + l = g_list_delete_link (l->prev, l); + l = next; + } else { + previous = l->data; + l = l->next; + } + } +} + +static void +cleanup_plugin_info (void) +{ + if (encoders) + gst_caps_do_simplify (encoders); + + if (decoders) + gst_caps_do_simplify (decoders); + + elements = g_list_sort (elements, (GCompareFunc) strcmp); + uri_sources = g_list_sort (uri_sources, (GCompareFunc) strcmp); + uri_sinks = g_list_sort (uri_sinks, (GCompareFunc) strcmp); + provides = g_list_sort (provides, (GCompareFunc) strcmp); + + remove_duplicates (elements, TRUE); + remove_duplicates (uri_sources, TRUE); + remove_duplicates (uri_sinks, TRUE); + remove_duplicates (provides, FALSE); +} + +static void +collect_uri_protocols (GstElementFactory * factory) +{ + gchar **protocols, **p; + + protocols = gst_element_factory_get_uri_protocols (factory); + if (!protocols) + return; + + switch (gst_element_factory_get_uri_type (factory)) { + case GST_URI_SINK: + for (p = protocols; *p; p++) + uri_sinks = g_list_prepend (uri_sinks, g_strdup (*p)); + break; + case GST_URI_SRC: + for (p = protocols; *p; p++) + uri_sources = g_list_prepend (uri_sources, g_strdup (*p)); + break; + } + g_strfreev (protocols); +} + +static void +remove_min_max_fields (GstStructure * s) +{ + gint i, n; + gboolean removed_field = FALSE; + + + do { + n = gst_structure_n_fields (s); + removed_field = FALSE; + for (i = 0; i < n; i++) { + const gchar *field_name = gst_structure_nth_field_name (s, i); + const GValue *field; + + field = gst_structure_get_value (s, field_name); + + if (GST_VALUE_HOLDS_INT_RANGE (field)) { + gint min, max; + + min = gst_value_get_int_range_min (field); + max = gst_value_get_int_range_max (field); + + if (min == 0 && max == G_MAXINT) { + gst_structure_remove_field (s, field_name); + removed_field = TRUE; + break; + } + } else if (GST_VALUE_HOLDS_LIST (field)) { + gint n2 = gst_value_list_get_size (field); + + if (n2 == 2) { + const GValue *val1 = gst_value_list_get_value (field, 0); + const GValue *val2 = gst_value_list_get_value (field, 1); + + if (G_VALUE_TYPE (val1) == G_TYPE_BOOLEAN + && G_VALUE_TYPE (val2) == G_TYPE_BOOLEAN + && ((g_value_get_boolean (val1) && !g_value_get_boolean (val2)) + || (!g_value_get_boolean (val1) + && g_value_get_boolean (val2)))) { + gst_structure_remove_field (s, field_name); + removed_field = TRUE; + break; + } + } + } else if (GST_VALUE_HOLDS_ARRAY (field)) { + gint n2 = gst_value_array_get_size (field); + + if (n2 == 2) { + const GValue *val1 = gst_value_array_get_value (field, 0); + const GValue *val2 = gst_value_array_get_value (field, 1); + + if (G_VALUE_TYPE (val1) == G_TYPE_BOOLEAN + && G_VALUE_TYPE (val2) == G_TYPE_BOOLEAN + && ((g_value_get_boolean (val1) && !g_value_get_boolean (val2)) + || (!g_value_get_boolean (val1) + && g_value_get_boolean (val2)))) { + gst_structure_remove_field (s, field_name); + removed_field = TRUE; + break; + } + } + } + } + } while (removed_field); +} + +static void +collect_codecs (GstElementFactory * factory) +{ + GstPadDirection direction; + gboolean encoder; + const gchar *klass; + const GList *static_templates, *l; + GstCaps *caps = NULL; + gint i, n; + + klass = gst_element_factory_get_klass (factory); + g_return_if_fail (klass); + + if (strstr (klass, "Demuxer") || + strstr (klass, "Decoder") || + strstr (klass, "Depay") || strstr (klass, "Parser")) { + + /* Ignore decoders with a less than marginal rank as they're + * not autoplugged by playbin/decodebin */ + if (gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)) < + GST_RANK_MARGINAL) + return; + + encoder = FALSE; + direction = GST_PAD_SINK; + } else if (strstr (klass, "Muxer") || + strstr (klass, "Encoder") || strstr (klass, "Pay")) { + encoder = TRUE; + direction = GST_PAD_SRC; + } else if (strcmp (klass, "Sink/Audio") == 0) { + provides = g_list_prepend (provides, (gchar *) virtual_packages[0]); + return; + } else if (strcmp (klass, "Source/Audio") == 0) { + provides = g_list_prepend (provides, (gchar *) virtual_packages[1]); + return; + } else if (strcmp (klass, "Sink/Video") == 0) { + provides = g_list_prepend (provides, (gchar *) virtual_packages[2]); + return; + } else if (strcmp (klass, "Source/Video") == 0) { + provides = g_list_prepend (provides, (gchar *) virtual_packages[3]); + return; + } else if (strcmp (klass, "Visualization") == 0) { + provides = g_list_prepend (provides, (gchar *) virtual_packages[4]); + return; + } else { + return; + } + + /* decoder/demuxer sink pads should always be static and there should only + * be one, the same applies to encoders/muxers and source pads */ + static_templates = gst_element_factory_get_static_pad_templates (factory); + for (l = static_templates; l; l = l->next) { + GstStaticPadTemplate *tmpl = l->data; + + if (tmpl->direction == direction) { + caps = gst_static_pad_template_get_caps (tmpl); + break; + } + } + + if (caps == NULL) { + g_printerr ("W: Couldn't find static pad template for '%s'\n", + GST_PLUGIN_FEATURE_NAME (factory)); + return; + } + + caps = gst_caps_make_writable (caps); + n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (caps, i); + + /* make caps easier to interpret, remove common fields that are likely + * to be irrelevant for determining the right plugin (ie. mostly fields + * where template caps usually have the standard MIN - MAX range as value) */ + gst_structure_remove_field (s, "codec_data"); + gst_structure_remove_field (s, "palette_data"); + gst_structure_remove_field (s, "pixel-aspect-ratio"); + gst_structure_remove_field (s, "framerate"); + gst_structure_remove_field (s, "leaf_size"); + gst_structure_remove_field (s, "packet_size"); + gst_structure_remove_field (s, "block_align"); + gst_structure_remove_field (s, "metadata-interval"); /* icy caps */ + /* decoders/encoders almost always handle the usual width/height/channel/rate + * range (and if we don't remove this then the app will have a much harder + * time blacklisting formats it has unsuccessfully tried to install before) */ + gst_structure_remove_field (s, "width"); + gst_structure_remove_field (s, "depth"); + gst_structure_remove_field (s, "height"); + gst_structure_remove_field (s, "channels"); + gst_structure_remove_field (s, "rate"); + /* rtp fields */ + gst_structure_remove_field (s, "config"); + gst_structure_remove_field (s, "clock-rate"); + gst_structure_remove_field (s, "clock-base"); + gst_structure_remove_field (s, "maxps"); + gst_structure_remove_field (s, "seqnum-base"); + gst_structure_remove_field (s, "npt-start"); + gst_structure_remove_field (s, "npt-stop"); + gst_structure_remove_field (s, "play-speed"); + gst_structure_remove_field (s, "play-scale"); + gst_structure_remove_field (s, "dynamic_range"); + + remove_min_max_fields (s); + + gst_caps_append_structure ((encoder) ? encoders : decoders, + gst_structure_copy (s)); + } + + gst_caps_unref (caps); +} + +static void +collect_plugin_info (GstPlugin * plugin) +{ + GList *features, *l; + const gchar *plugin_name; + + plugin_name = gst_plugin_get_name (plugin); + + features = gst_registry_get_feature_list (gst_registry_get_default (), + GST_TYPE_ELEMENT_FACTORY); + + for (l = features; l; l = l->next) { + GstPluginFeature *feature = GST_PLUGIN_FEATURE (l->data); + GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); + + if (!g_str_equal (plugin_name, feature->plugin_name)) + continue; + + elements = + g_list_prepend (elements, + g_strdup (gst_plugin_feature_get_name (feature))); + collect_uri_protocols (factory); + collect_codecs (factory); + } + + g_list_foreach (features, (GFunc) gst_object_unref, NULL); + g_list_free (features); +} + +int +main (int argc, char **argv) +{ + guint major, minor, micro, nano; + gint i; + + if (!g_thread_supported ()) + g_thread_init (NULL); + + gst_init (NULL, NULL); + + gst_version (&major, &minor, µ, &nano); + + if (argc == 1) + return 0; + + encoders = gst_caps_new_empty (); + decoders = gst_caps_new_empty (); + + for (i = 1; i < argc; i++) { + GstPlugin *plugin = NULL; + GError *error = NULL; + + if (argv[i] == NULL || + !g_file_test (argv[i], G_FILE_TEST_EXISTS) || + !g_str_has_suffix (argv[i], G_MODULE_SUFFIX)) { + g_printerr ("W: '%s' is no valid plugin filename\n", argv[i]); + continue; + } + + plugin = gst_plugin_load_file (argv[i], &error); + + if (!plugin) { + g_printerr ("W: Could not load '%s': %s\n", argv[i], error->message); + g_error_free (error); + continue; + } + + collect_plugin_info (plugin); + } + + if (elements) + g_print ("gstreamer:Version=%u.%u\n", major, minor); + + cleanup_plugin_info (); + print_plugin_info (); + free_plugin_info (); + + return 0; +} |