From ebc08ddfb985adb7b4ac669a250ae231c8155c69 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 24 May 2008 15:33:53 +0000 Subject: [PATCH] API: gst_parse_launch_full() Original commit message from CVS: * docs/gst/gstreamer-sections.txt: * gst/gst.c: (init_post): * gst/gst_private.h: (_GstParseContext): * gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new), (gst_parse_context_free), (gst_parse_context_get_missing_elements), (gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch), (gst_parse_launch_full): * gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS), (GstParseFlags), (GstParseContext): * gst/gstutils.c: (gst_parse_bin_from_description), (gst_parse_bin_from_description_full): * gst/gstutils.h: * gst/parse/grammar.y: * gst/parse/types.h: * win32/common/libgstreamer.def: Add new gst_parse_*_full API (#528178): API: gst_parse_launch_full() API: gst_parse_launchv_full() API: gst_parse_bin_from_description_full() API: gst_parse_context_new() API: gst_parse_context_free() API: gst_parse_context_get_missing_elements() --- ChangeLog | 25 ++++++ docs/gst/gstreamer-sections.txt | 11 +++ gst/gst.c | 1 + gst/gst_private.h | 5 ++ gst/gstparse.c | 170 ++++++++++++++++++++++++++++++++++++---- gst/gstparse.h | 53 ++++++++++++- gst/gstutils.c | 35 ++++++++- gst/gstutils.h | 13 ++- gst/parse/grammar.y | 14 +++- gst/parse/types.h | 3 + win32/common/libgstreamer.def | 7 ++ 11 files changed, 316 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7120d30..a641f64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2008-05-24 Tim-Philipp Müller + + * docs/gst/gstreamer-sections.txt: + * gst/gst.c: (init_post): + * gst/gst_private.h: (_GstParseContext): + * gst/gstparse.c: (gst_parse_error_quark), (gst_parse_context_new), + (gst_parse_context_free), (gst_parse_context_get_missing_elements), + (gst_parse_launchv), (gst_parse_launchv_full), (gst_parse_launch), + (gst_parse_launch_full): + * gst/gstparse.h: (GST_PARSE_FLAG_NONE), (GST_PARSE_FLAG_FATAL_ERRORS), + (GstParseFlags), (GstParseContext): + * gst/gstutils.c: (gst_parse_bin_from_description), + (gst_parse_bin_from_description_full): + * gst/gstutils.h: + * gst/parse/grammar.y: + * gst/parse/types.h: + * win32/common/libgstreamer.def: + Add new gst_parse_*_full API (#528178): + API: gst_parse_launch_full() + API: gst_parse_launchv_full() + API: gst_parse_bin_from_description_full() + API: gst_parse_context_new() + API: gst_parse_context_free() + API: gst_parse_context_get_missing_elements() + 2008-05-23 Stefan Kost patch by: Suresh Kumar P diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 9d81be9..f89e18a 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -1521,13 +1521,24 @@ gst_param_spec_fraction_get_type gst_parse_error_quark GST_PARSE_ERROR GstParseError +GstParseContext +GstParseFlags gst_parse_launch +gst_parse_launch_full gst_parse_launchv +gst_parse_launchv_full gst_parse_bin_from_description +gst_parse_bin_from_description_full + +gst_parse_context_new +gst_parse_context_free +gst_parse_context_get_missing_elements GST_TYPE_PARSE_ERROR +GST_TYPE_PARSE_FLAGS gst_parse_error_get_type +gst_parse_flags_get_type diff --git a/gst/gst.c b/gst/gst.c index 5df4955..acce140 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -1051,6 +1051,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data, g_type_class_ref (gst_type_find_probability_get_type ()); g_type_class_ref (gst_uri_type_get_type ()); g_type_class_ref (gst_parse_error_get_type ()); + g_type_class_ref (gst_parse_flags_get_type ()); #endif gst_structure_get_type (); diff --git a/gst/gst_private.h b/gst/gst_private.h index 26f51cf..ba1060c 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -43,6 +43,11 @@ extern const char g_log_domain_gstreamer[]; G_BEGIN_DECLS +/* used by gstparse.c and grammar.y */ +struct _GstParseContext { + GList * missing_elements; +}; + gboolean _priv_gst_in_valgrind (void); /* Initialize GStreamer private quark storage */ diff --git a/gst/gstparse.c b/gst/gstparse.c index 5dd06cc..f72b6b3 100644 --- a/gst/gstparse.c +++ b/gst/gstparse.c @@ -2,6 +2,7 @@ * Copyright (C) 1999,2000 Erik Walthinsen * 2000 Wim Taymans * 2002 Andy Wingo + * 2008 Tim-Philipp Müller * * gstparse.c: get a pipeline from a text pipeline description * @@ -37,7 +38,8 @@ #include "gsterror.h" #include "gstinfo.h" -extern GstElement *_gst_parse_launch (const gchar *, GError **); +extern GstElement *_gst_parse_launch (const gchar *, GError **, + GstParseContext *, GstParseFlags); /** * gst_parse_error_quark: @@ -56,6 +58,94 @@ gst_parse_error_quark (void) return quark; } + +/** + * gst_parse_context_new: + * + * Allocates a parse context for use with gst_parse_launch_full() or + * gst_parse_launchv_full(). + * + * Returns: a newly-allocated parse context. Free with gst_parse_context_free() + * when no longer needed. + * + * Since: 0.10.20 + */ +GstParseContext * +gst_parse_context_new (void) +{ +#ifndef GST_DISABLE_PARSE + GstParseContext *ctx; + + ctx = g_slice_new (GstParseContext); + ctx->missing_elements = NULL; + + return ctx; +#else + return NULL; +#endif +} + +/** + * gst_parse_context_free: + * @context: a #GstParseContext + * + * Frees a parse context previously allocated with gst_parse_context_new(). + * + * Since: 0.10.20 + */ +void +gst_parse_context_free (GstParseContext * context) +{ +#ifndef GST_DISABLE_PARSE + if (context) { + g_list_foreach (context->missing_elements, (GFunc) g_free, NULL); + g_list_free (context->missing_elements); + g_slice_free (GstParseContext, context); + } +#endif +} + +/** + * gst_parse_context_get_missing_elements: + * @context: a #GstParseContext + * + * Retrieve missing elements from a previous run of gst_parse_launch_full() + * or gst_parse_launchv_full(). Will only return results if an error code + * of %GST_PARSE_ERROR_NO_SUCH_ELEMENT was returned. + * + * Returns: a NULL-terminated array of element factory name strings of + * missing elements. Free with g_strfreev() when no longer needed. + * + * Since: 0.10.20 + */ +gchar ** +gst_parse_context_get_missing_elements (GstParseContext * context) +{ +#ifndef GST_DISABLE_PARSE + gchar **arr; + GList *l; + guint len, i; + + g_return_val_if_fail (context != NULL, NULL); + + len = g_list_length (context->missing_elements); + + if (G_UNLIKELY (len == 0)) + return NULL; + + arr = g_new (gchar *, len + 1); + + for (i = 0, l = context->missing_elements; l != NULL; l = l->next, ++i) + arr[i] = g_strdup (l->data); + + arr[i] = NULL; + + return arr; +#else + return NULL; +#endif +} + #ifndef GST_DISABLE_PARSE static gchar * _gst_parse_escape (const gchar * str) @@ -91,6 +181,31 @@ _gst_parse_escape (const gchar * str) GstElement * gst_parse_launchv (const gchar ** argv, GError ** error) { + return gst_parse_launchv_full (argv, NULL, 0, error); +} + +/** + * gst_parse_launchv_full: + * @argv: null-terminated array of arguments + * @context: a parse context allocated with gst_parse_context_new(), or %NULL + * @flags: parsing options, or #GST_PARSE_FLAG_NONE + * @error: pointer to a #GError (which must be initialised to %NULL) + * + * Create a new element based on command line syntax. + * @error will contain an error message if an erroneous pipeline is specified. + * An error does not mean that the pipeline could not be constructed. + * + * Returns: a new element on success; on failure, either %NULL or a + * partially-constructed bin or element will be returned and @error will be set + * (unless you passed #GST_PARSE_FLAG_FATAL_ERRORS in @flags, then %NULL will + * always be returned on failure) + * + * Since: 0.10.20 + */ +GstElement * +gst_parse_launchv_full (const gchar ** argv, GstParseContext * context, + GstParseFlags flags, GError ** error) +{ #ifndef GST_DISABLE_PARSE GstElement *element; GString *str; @@ -113,21 +228,14 @@ gst_parse_launchv (const gchar ** argv, GError ** error) argvp++; } - element = gst_parse_launch (str->str, error); + element = gst_parse_launch_full (str->str, context, flags, error); g_string_free (str, TRUE); return element; #else - gchar *msg; - - GST_WARNING ("Disabled API called"); - - msg = gst_error_get_message (GST_CORE_ERROR, GST_CORE_ERROR_DISABLED); - g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_DISABLED, "%s", msg); - g_free (msg); - - return NULL; + /* gst_parse_launch_full() will set a GST_CORE_ERROR_DISABLED error for us */ + return gst_parse_launch_full ("", NULL, 0, error); #endif } @@ -148,21 +256,55 @@ gst_parse_launchv (const gchar ** argv, GError ** error) GstElement * gst_parse_launch (const gchar * pipeline_description, GError ** error) { + return gst_parse_launch_full (pipeline_description, NULL, 0, error); +} + +/** + * gst_parse_launch_full: + * @pipeline_description: the command line describing the pipeline + * @context: a parse context allocated with gst_parse_context_new(), or %NULL + * @flags: parsing options, or #GST_PARSE_FLAG_NONE + * @error: the error message in case of an erroneous pipeline. + * + * Create a new pipeline based on command line syntax. + * Please note that you might get a return value that is not %NULL even though + * the @error is set. In this case there was a recoverable parsing error and you + * can try to play the pipeline. + * + * Returns: a new element on success, %NULL on failure. If more than one toplevel + * element is specified by the @pipeline_description, all elements are put into + * a #GstPipeline, which then is returned. + * + * Since: 0.10.20 + */ +GstElement * +gst_parse_launch_full (const gchar * pipeline_description, + GstParseContext * context, GstParseFlags flags, GError ** error) +{ #ifndef GST_DISABLE_PARSE GstElement *element; g_return_val_if_fail (pipeline_description != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); - GST_CAT_INFO (GST_CAT_PIPELINE, "parsing pipeline description %s", + GST_CAT_INFO (GST_CAT_PIPELINE, "parsing pipeline description '%s'", pipeline_description); - element = _gst_parse_launch (pipeline_description, error); + element = _gst_parse_launch (pipeline_description, error, context, flags); + + /* don't return partially constructed pipeline if FATAL_ERRORS was given */ + if (G_UNLIKELY (error != NULL && *error != NULL && element != NULL)) { + if ((flags & GST_PARSE_FLAG_FATAL_ERRORS)) { + gst_object_unref (element); + element = NULL; + } + } return element; #else gchar *msg; - GST_WARNING ("Disabled API called: gst_parse_launch()"); + GST_WARNING ("Disabled API called"); msg = gst_error_get_message (GST_CORE_ERROR, GST_CORE_ERROR_DISABLED); g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_DISABLED, "%s", msg); diff --git a/gst/gstparse.h b/gst/gstparse.h index 39ebfc7..b4a9e96 100644 --- a/gst/gstparse.h +++ b/gst/gstparse.h @@ -58,9 +58,58 @@ typedef enum GST_PARSE_ERROR_EMPTY } GstParseError; +/** + * GstParseFlags: + * @GST_PARSE_FLAG_NONE: Do not use any special parsing options. + * @GST_PARSE_FLAG_FATAL_ERRORS: Always return NULL when an error occurs + * (default behaviour is to return partially constructed bins or elements + * in some cases) + * + * Parsing options. + * + * Since: 0.10.20 + */ +typedef enum +{ + GST_PARSE_FLAG_NONE = 0, + GST_PARSE_FLAG_FATAL_ERRORS = (1 << 0) +} GstParseFlags; + +/** + * GstParseContext: + * + * Opaque structure. + * + * Since: 0.10.20 + */ +typedef struct _GstParseContext GstParseContext; + +/* create, process and free a parse context */ + +GstParseContext * gst_parse_context_new (void); + +gchar ** gst_parse_context_get_missing_elements (GstParseContext * context); + +void gst_parse_context_free (GstParseContext * context); + + +/* parse functions */ + +GstElement * gst_parse_launch (const gchar * pipeline_description, + GError ** error); + +GstElement * gst_parse_launchv (const gchar ** argv, + GError ** error); + +GstElement * gst_parse_launch_full (const gchar * pipeline_description, + GstParseContext * context, + GstParseFlags flags, + GError ** error); -GstElement* gst_parse_launch (const gchar *pipeline_description, GError **error); -GstElement* gst_parse_launchv (const gchar **argv, GError **error); +GstElement * gst_parse_launchv_full (const gchar ** argv, + GstParseContext * context, + GstParseFlags flags, + GError ** error); G_END_DECLS diff --git a/gst/gstutils.c b/gst/gstutils.c index d000f90..1e2476c 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -3340,6 +3340,39 @@ GstElement * gst_parse_bin_from_description (const gchar * bin_description, gboolean ghost_unconnected_pads, GError ** err) { + return gst_parse_bin_from_description_full (bin_description, + ghost_unconnected_pads, NULL, 0, err); +} + +/** + * gst_parse_bin_from_description_full: + * @bin_description: command line describing the bin + * @ghost_unconnected_pads: whether to automatically create ghost pads + * for unconnected source or sink pads within + * the bin + * @context: a parse context allocated with gst_parse_context_new(), or %NULL + * @flags: parsing options, or #GST_PARSE_FLAG_NONE + * @err: where to store the error message in case of an error, or NULL + * + * This is a convenience wrapper around gst_parse_launch() to create a + * #GstBin from a gst-launch-style pipeline description. See + * gst_parse_launch() and the gst-launch man page for details about the + * syntax. Ghost pads on the bin for unconnected source or sink pads + * within the bin can automatically be created (but only a maximum of + * one ghost pad for each direction will be created; if you expect + * multiple unconnected source pads or multiple unconnected sink pads + * and want them all ghosted, you will have to create the ghost pads + * yourself). + * + * Returns: a newly-created bin, or NULL if an error occurred. + * + * Since: 0.10.20 + */ +GstElement * +gst_parse_bin_from_description_full (const gchar * bin_description, + gboolean ghost_unconnected_pads, GstParseContext * context, + GstParseFlags flags, GError ** err) +{ #ifndef GST_DISABLE_PARSE GstPad *pad = NULL; GstBin *bin; @@ -3352,7 +3385,7 @@ gst_parse_bin_from_description (const gchar * bin_description, /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s )", bin_description); - bin = (GstBin *) gst_parse_launch (desc, err); + bin = (GstBin *) gst_parse_launch_full (desc, context, flags, err); g_free (desc); if (bin == NULL || (err && *err != NULL)) { diff --git a/gst/gstutils.h b/gst/gstutils.h index c6ed717..e26b0cd 100644 --- a/gst/gstutils.h +++ b/gst/gstutils.h @@ -27,6 +27,7 @@ #include #include +#include G_BEGIN_DECLS @@ -722,9 +723,15 @@ void gst_element_found_tags (GstElement * element, GstTagList * list); /* parse utility functions */ -GstElement * gst_parse_bin_from_description (const gchar * bin_description, - gboolean ghost_unconnected_pads, - GError ** err); +GstElement * gst_parse_bin_from_description (const gchar * bin_description, + gboolean ghost_unconnected_pads, + GError ** err); + +GstElement * gst_parse_bin_from_description_full (const gchar * bin_description, + gboolean ghost_unconnected_pads, + GstParseContext * context, + GstParseFlags flags, + GError ** err); GstClockTime gst_util_get_timestamp (void); diff --git a/gst/parse/grammar.y b/gst/parse/grammar.y index db02abd..a6cbdbb3 100644 --- a/gst/parse/grammar.y +++ b/gst/parse/grammar.y @@ -12,6 +12,7 @@ #include "../gstparse.h" #include "../gstinfo.h" #include "../gsterror.h" +#include "../gststructure.h" #include "../gsturi.h" #include "../gstutils.h" #include "../gstvalue.h" @@ -213,6 +214,12 @@ YYPRINTF(const char *format, ...) #endif /* GST_DISABLE_GST_DEBUG */ +#define ADD_MISSING_ELEMENT(graph,name) G_STMT_START { \ + if ((graph)->ctx) { \ + (graph)->ctx->missing_elements = \ + g_list_append ((graph)->ctx->missing_elements, g_strdup (name)); \ + } } G_STMT_END + #define GST_BIN_MAKE(res, type, chainval, assign, free_string) \ G_STMT_START { \ chain_t *chain = chainval; \ @@ -228,6 +235,7 @@ G_STMT_START { \ gst_parse_strfree (type); /* Need to clean up the string */ \ YYERROR; \ } else if (!bin) { \ + ADD_MISSING_ELEMENT((graph_t *) graph, type); \ SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, \ _("no bin \"%s\", skipping"), type); \ g_slist_foreach (assign, (GFunc) gst_parse_strfree, NULL); \ @@ -555,6 +563,7 @@ static int yyerror (void *scanner, graph_t *graph, const char *s); element: IDENTIFIER { $$ = gst_element_factory_make ($1, NULL); if ($$ == NULL) { + ADD_MISSING_ELEMENT ((graph_t *) graph, $1); SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), $1); gst_parse_strfree ($1); YYERROR; @@ -784,7 +793,8 @@ yyerror (void *scanner, graph_t *graph, const char *s) GstElement * -_gst_parse_launch (const gchar *str, GError **error) +_gst_parse_launch (const gchar *str, GError **error, GstParseContext *ctx, + GstParseFlags flags) { graph_t g; gchar *dstr; @@ -799,6 +809,8 @@ _gst_parse_launch (const gchar *str, GError **error) g.chain = NULL; g.links = NULL; g.error = error; + g.ctx = ctx; + g.flags = flags; #ifdef __GST_PARSE_TRACE GST_CAT_DEBUG (GST_CAT_PIPELINE, "TRACE: tracing enabled"); diff --git a/gst/parse/types.h b/gst/parse/types.h index 205a755..27aee32 100644 --- a/gst/parse/types.h +++ b/gst/parse/types.h @@ -3,6 +3,7 @@ #include #include "../gstelement.h" +#include "../gstparse.h" typedef struct { GstElement *src; @@ -27,6 +28,8 @@ struct _graph_t { chain_t *chain; /* links are supposed to be done now */ GSList *links; GError **error; + GstParseContext *ctx; /* may be NULL */ + GstParseFlags flags; }; diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 4d51de7..82e9557 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -609,10 +609,17 @@ EXPORTS gst_param_spec_mini_object gst_param_spec_mini_object_get_type gst_parse_bin_from_description + gst_parse_bin_from_description_full + gst_parse_context_free + gst_parse_context_get_missing_elements + gst_parse_context_new gst_parse_error_get_type gst_parse_error_quark + gst_parse_flags_get_type gst_parse_launch + gst_parse_launch_full gst_parse_launchv + gst_parse_launchv_full gst_pipeline_auto_clock gst_pipeline_flags_get_type gst_pipeline_get_auto_flush_bus -- 2.7.4