blob: 95821c8ab20118711b93f3631e680f266132e691 [file] [log] [blame]
/* GStreamer
* Copyright (C) 2015 Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
*
* 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 <gst/gst.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
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");
g_clear_error (&err);
g_option_context_free (ctx);
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);
}