mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-08 13:18:52 +00:00
When g_option_context_parse fails, context and error variables are not getting free'd which results in memory leaks. Free'ing the same. And replacing g_error_free with g_clear_error, which checks if the error being passed is not NULL and sets the variable to NULL on free'ing. https://bugzilla.gnome.org/show_bug.cgi?id=753851
271 lines
7.1 KiB
C
271 lines
7.1 KiB
C
/* 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);
|
|
}
|